diff options
Diffstat (limited to 'lib/Sema')
33 files changed, 9240 insertions, 4240 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 9efae61..7a14855e 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -486,7 +486,8 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { const char *initialization = 0; QualType VariableTy = VD->getType().getCanonicalType(); - if (VariableTy->getAs<ObjCObjectPointerType>()) { + if (VariableTy->isObjCObjectPointerType() || + VariableTy->isBlockPointerType()) { // Check if 'nil' is defined. if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) initialization = " = nil"; @@ -499,6 +500,13 @@ static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { initialization = " = false"; else if (VariableTy->isEnumeralType()) return; + else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { + // Check if 'NULL' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) + initialization = " = NULL"; + else + initialization = " = 0"; + } else if (VariableTy->isScalarType()) initialization = " = 0"; @@ -589,7 +597,17 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckUnreachable = 0; } -clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) + : S(s), + NumFunctionsAnalyzed(0), + NumFunctionsWithBadCFGs(0), + NumCFGBlocks(0), + MaxCFGBlocksPerFunction(0), + NumUninitAnalysisFunctions(0), + NumUninitAnalysisVariables(0), + MaxUninitAnalysisVariablesPerFunction(0), + NumUninitAnalysisBlockVisits(0), + MaxUninitAnalysisBlockVisitsPerFunction(0) { Diagnostic &D = S.getDiagnostics(); DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) != @@ -705,8 +723,68 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, != Diagnostic::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); + UninitVariablesAnalysisStats stats; + std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats)); runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, - reporter); + reporter, stats); + + if (S.CollectStats && stats.NumVariablesAnalyzed > 0) { + ++NumUninitAnalysisFunctions; + NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; + NumUninitAnalysisBlockVisits += stats.NumBlockVisits; + MaxUninitAnalysisVariablesPerFunction = + std::max(MaxUninitAnalysisVariablesPerFunction, + stats.NumVariablesAnalyzed); + MaxUninitAnalysisBlockVisitsPerFunction = + std::max(MaxUninitAnalysisBlockVisitsPerFunction, + stats.NumBlockVisits); + } } } + + // Collect statistics about the CFG if it was built. + if (S.CollectStats && AC.isCFGBuilt()) { + ++NumFunctionsAnalyzed; + if (CFG *cfg = AC.getCFG()) { + // If we successfully built a CFG for this context, record some more + // detail information about it. + NumCFGBlocks += cfg->getNumBlockIDs(); + MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, + cfg->getNumBlockIDs()); + } else { + ++NumFunctionsWithBadCFGs; + } + } +} + +void clang::sema::AnalysisBasedWarnings::PrintStats() const { + llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; + + unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; + unsigned AvgCFGBlocksPerFunction = + !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; + llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" + << NumFunctionsWithBadCFGs << " w/o CFGs).\n" + << " " << NumCFGBlocks << " CFG blocks built.\n" + << " " << AvgCFGBlocksPerFunction + << " average CFG blocks per function.\n" + << " " << MaxCFGBlocksPerFunction + << " max CFG blocks per function.\n"; + + unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 + : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; + unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 + : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; + llvm::errs() << NumUninitAnalysisFunctions + << " functions analyzed for uninitialiazed variables\n" + << " " << NumUninitAnalysisVariables << " variables analyzed.\n" + << " " << AvgUninitVariablesPerFunction + << " average variables per function.\n" + << " " << MaxUninitAnalysisVariablesPerFunction + << " max variables per function.\n" + << " " << NumUninitAnalysisBlockVisits << " block visits.\n" + << " " << AvgUninitBlockVisitsPerFunction + << " average block visits per function.\n" + << " " << MaxUninitAnalysisBlockVisitsPerFunction + << " max block visits per function.\n"; } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 619a5b9..5a8330b 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -107,6 +107,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { return llvm::StringSwitch<AttributeList::Kind>(AttrName) .Case("weak", AT_weak) .Case("weakref", AT_weakref) + .Case("objc_arc_weak_reference_unavailable", AT_arc_weakref_unavailable) .Case("pure", AT_pure) .Case("mode", AT_mode) .Case("used", AT_used) @@ -177,6 +178,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("cf_consumed", AT_cf_consumed) .Case("cf_returns_not_retained", AT_cf_returns_not_retained) .Case("cf_returns_retained", AT_cf_returns_retained) + .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased) + .Case("ns_consumes_self", AT_ns_consumes_self) + .Case("ns_consumed", AT_ns_consumed) + .Case("objc_ownership", AT_objc_ownership) + .Case("objc_precise_lifetime", AT_objc_precise_lifetime) .Case("ownership_returns", AT_ownership_returns) .Case("ownership_holds", AT_ownership_holds) .Case("ownership_takes", AT_ownership_takes) diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 0a67019..6521981 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -23,6 +23,7 @@ add_clang_library(clangSema SemaExceptionSpec.cpp SemaExpr.cpp SemaExprCXX.cpp + SemaExprMember.cpp SemaExprObjC.cpp SemaInit.cpp SemaLookup.cpp diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 2334ab5..d7dc5b2 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -46,7 +46,9 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_ObjCImplementation: case CCC_ObjCIvarList: case CCC_ClassStructUnion: - case CCC_MemberAccess: + case CCC_DotMemberAccess: + case CCC_ArrowMemberAccess: + case CCC_ObjCPropertyAccess: case CCC_EnumTag: case CCC_UnionTag: case CCC_ClassOrStructTag: @@ -64,6 +66,10 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_TypeQualifiers: case CCC_Other: case CCC_OtherWithMacros: + case CCC_ObjCInstanceMessage: + case CCC_ObjCClassMessage: + case CCC_ObjCSuperclass: + case CCC_ObjCCategoryName: return false; } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 5be16e7..c87f2cf 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -13,8 +13,10 @@ #include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency! #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/LocInfoType.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TypeLoc.h" #include "clang/Lex/Preprocessor.h" @@ -124,6 +126,12 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { Builder.Adopt(Other); } +SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const { + if (!Builder.getRepresentation()) + return SourceLocation(); + return Builder.getTemporary().getLocalBeginLoc(); +} + NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) const { if (!Builder.getRepresentation()) @@ -141,6 +149,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, + SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, SourceLocation ESpecLoc, @@ -166,6 +175,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, I.Fun.ArgInfo = 0; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); + I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); I.Fun.NumExceptions = 0; @@ -213,6 +223,73 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, return I; } +bool Declarator::isDeclarationOfFunction() const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Function: + return true; + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return false; + } + llvm_unreachable("Invalid type chunk"); + return false; + } + + switch (DS.getTypeSpecType()) { + case TST_auto: + case TST_bool: + case TST_char: + case TST_char16: + case TST_char32: + case TST_class: + case TST_decimal128: + case TST_decimal32: + case TST_decimal64: + case TST_double: + case TST_enum: + case TST_error: + case TST_float: + case TST_int: + case TST_struct: + case TST_union: + case TST_unknown_anytype: + case TST_unspecified: + case TST_void: + case TST_wchar: + return false; + + case TST_decltype: + case TST_typeofExpr: + if (Expr *E = DS.getRepAsExpr()) + return E->getType()->isFunctionType(); + return false; + + case TST_underlyingType: + case TST_typename: + case TST_typeofType: { + QualType QT = DS.getRepAsType().get(); + if (QT.isNull()) + return false; + + if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) + QT = LIT->getType(); + + if (QT.isNull()) + return false; + + return QT->isFunctionType(); + } + } + + return false; +} + /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this /// declaration specifier includes. /// @@ -792,9 +869,6 @@ bool DeclSpec::isMissingDeclaratorOk() { } void UnqualifiedId::clear() { - if (Kind == IK_TemplateId) - TemplateId->Destroy(); - Kind = IK_Identifier; Identifier = 0; StartLocation = SourceLocation(); diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index af548fe..c6744ed 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -47,5 +47,8 @@ void DelayedDiagnostic::Destroy() { case Deprecation: delete [] DeprecationData.Message; break; + + case ForbiddenType: + break; } } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index ae154aa..59bc263 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -68,7 +68,10 @@ public: JumpScopeChecker(Stmt *Body, Sema &S); private: void BuildScopeInformation(Decl *D, unsigned &ParentScope); - void BuildScopeInformation(Stmt *S, unsigned ParentScope); + void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, + unsigned &ParentScope); + void BuildScopeInformation(Stmt *S, unsigned &origParentScope); + void VerifyJumps(); void VerifyIndirectJumps(); void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, @@ -87,7 +90,8 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { // Build information for the top level compound statement, so that we have a // defined scope record for every "goto" and label. - BuildScopeInformation(Body, 0); + unsigned BodyParentScope = 0; + BuildScopeInformation(Body, BodyParentScope); // Check that all jumps we saw are kosher. VerifyJumps(); @@ -111,87 +115,110 @@ unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) { return A; } +typedef std::pair<unsigned,unsigned> ScopePair; + /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. -static std::pair<unsigned,unsigned> - GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { +static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { unsigned InDiag = 0, OutDiag = 0; if (VD->getType()->isVariablyModifiedType()) InDiag = diag::note_protected_by_vla; - if (VD->hasAttr<BlocksAttr>()) { - InDiag = diag::note_protected_by___block; - OutDiag = diag::note_exits___block; - } else if (VD->hasAttr<CleanupAttr>()) { - InDiag = diag::note_protected_by_cleanup; - OutDiag = diag::note_exits_cleanup; - } else if (isCPlusPlus) { - if (!VD->hasLocalStorage()) - return std::make_pair(InDiag, OutDiag); - - ASTContext &Context = D->getASTContext(); - QualType T = Context.getBaseElementType(VD->getType()); - if (!T->isDependentType()) { - // C++0x [stmt.dcl]p3: - // A program that jumps from a point where a variable with automatic - // storage duration is not in scope to a point where it is in scope - // is ill-formed unless the variable has scalar type, class type with - // a trivial default constructor and a trivial destructor, a - // cv-qualified version of one of these types, or an array of one of - // the preceding types and is declared without an initializer (8.5). - // Check whether this is a C++ class. - CXXRecordDecl *Record = T->getAsCXXRecordDecl(); - - if (const Expr *Init = VD->getInit()) { - bool CallsTrivialConstructor = false; - if (Record) { - // FIXME: With generalized initializer lists, this may - // classify "X x{};" as having no initializer. - if (const CXXConstructExpr *Construct - = dyn_cast<CXXConstructExpr>(Init)) - if (const CXXConstructorDecl *Constructor - = Construct->getConstructor()) - if ((Context.getLangOptions().CPlusPlus0x - ? Record->hasTrivialDefaultConstructor() - : Record->isPOD()) && - Constructor->isDefaultConstructor()) - CallsTrivialConstructor = true; + if (VD->hasAttr<BlocksAttr>()) + return ScopePair(diag::note_protected_by___block, + diag::note_exits___block); + + if (VD->hasAttr<CleanupAttr>()) + return ScopePair(diag::note_protected_by_cleanup, + diag::note_exits_cleanup); + + if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) { + switch (VD->getType().getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + return ScopePair(diag::note_protected_by_objc_ownership, + diag::note_exits_objc_ownership); + } + } + + if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) { + // C++0x [stmt.dcl]p3: + // A program that jumps from a point where a variable with automatic + // storage duration is not in scope to a point where it is in scope + // is ill-formed unless the variable has scalar type, class type with + // a trivial default constructor and a trivial destructor, a + // cv-qualified version of one of these types, or an array of one of + // the preceding types and is declared without an initializer. + + // C++03 [stmt.dcl.p3: + // A program that jumps from a point where a local variable + // with automatic storage duration is not in scope to a point + // where it is in scope is ill-formed unless the variable has + // POD type and is declared without an initializer. + + if (const Expr *init = VD->getInit()) { + // We actually give variables of record type (or array thereof) + // an initializer even if that initializer only calls a trivial + // ctor. Detect that case. + // FIXME: With generalized initializer lists, this may + // classify "X x{};" as having no initializer. + unsigned inDiagToUse = diag::note_protected_by_variable_init; + + const CXXRecordDecl *record = 0; + + if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) { + const CXXConstructorDecl *ctor = cce->getConstructor(); + record = ctor->getParent(); + + if (ctor->isTrivial() && ctor->isDefaultConstructor()) { + if (Context.getLangOptions().CPlusPlus0x) { + inDiagToUse = (record->hasTrivialDestructor() ? 0 : + diag::note_protected_by_variable_nontriv_destructor); + } else { + if (record->isPOD()) + inDiagToUse = 0; + } } - - if (!CallsTrivialConstructor) - InDiag = diag::note_protected_by_variable_init; + } else if (VD->getType()->isArrayType()) { + record = VD->getType()->getBaseElementTypeUnsafe() + ->getAsCXXRecordDecl(); } - - // Note whether we have a class with a non-trivial destructor. - if (Record && !Record->hasTrivialDestructor()) + + if (inDiagToUse) + InDiag = inDiagToUse; + + // Also object to indirect jumps which leave scopes with dtors. + if (record && !record->hasTrivialDestructor()) OutDiag = diag::note_exits_dtor; } } - return std::make_pair(InDiag, OutDiag); + return ScopePair(InDiag, OutDiag); } if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) - return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0); + return ScopePair(diag::note_protected_by_vla_typedef, 0); } if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) - return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0); + return ScopePair(diag::note_protected_by_vla_type_alias, 0); } - return std::make_pair(0U, 0U); + return ScopePair(0U, 0U); } /// \brief Build scope information for a declaration that is part of a DeclStmt. void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { - bool isCPlusPlus = this->S.getLangOptions().CPlusPlus; - // If this decl causes a new scope, push and switch to it. - std::pair<unsigned,unsigned> Diags - = GetDiagForGotoScopeDecl(D, isCPlusPlus); + std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D); if (Diags.first || Diags.second) { Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second, D->getLocation())); @@ -205,11 +232,55 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { BuildScopeInformation(Init, ParentScope); } +/// \brief Build scope information for a captured block literal variables. +void JumpScopeChecker::BuildScopeInformation(VarDecl *D, + const BlockDecl *BDecl, + unsigned &ParentScope) { + // exclude captured __block variables; there's no destructor + // associated with the block literal for them. + if (D->hasAttr<BlocksAttr>()) + return; + QualType T = D->getType(); + QualType::DestructionKind destructKind = T.isDestructedType(); + if (destructKind != QualType::DK_none) { + std::pair<unsigned,unsigned> Diags; + switch (destructKind) { + case QualType::DK_cxx_destructor: + Diags = ScopePair(diag::note_enters_block_captures_cxx_obj, + diag::note_exits_block_captures_cxx_obj); + break; + case QualType::DK_objc_strong_lifetime: + Diags = ScopePair(diag::note_enters_block_captures_strong, + diag::note_exits_block_captures_strong); + break; + case QualType::DK_objc_weak_lifetime: + Diags = ScopePair(diag::note_enters_block_captures_weak, + diag::note_exits_block_captures_weak); + break; + case QualType::DK_none: + llvm_unreachable("no-liftime captured variable"); + } + SourceLocation Loc = D->getLocation(); + if (Loc.isInvalid()) + Loc = BDecl->getLocation(); + Scopes.push_back(GotoScope(ParentScope, + Diags.first, Diags.second, Loc)); + ParentScope = Scopes.size()-1; + } +} + /// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively /// walking the AST as needed. -void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { +void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) { + // If this is a statement, rather than an expression, scopes within it don't + // propagate out into the enclosing scope. Otherwise we have to worry + // about block literals, which have the lifetime of their enclosing statement. + unsigned independentParentScope = origParentScope; + unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S)) + ? origParentScope : independentParentScope); + bool SkipFirstSubStmt = false; // If we found a label, remember that it is in ParentScope scope. @@ -291,17 +362,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { BuildScopeInformation(*I, ParentScope); continue; } - // Disallow jumps into any part of an @try statement by pushing a scope and // walking all sub-stmts in that scope. if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { + unsigned newParentScope; // Recursively walk the AST for the @try part. Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_try, diag::note_exits_objc_try, AT->getAtTryLoc())); if (Stmt *TryPart = AT->getTryBody()) - BuildScopeInformation(TryPart, Scopes.size()-1); + BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1)); // Jump from the catch to the finally or try is not valid. for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { @@ -311,7 +382,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { diag::note_exits_objc_catch, AC->getAtCatchLoc())); // @catches are nested and it isn't - BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); + BuildScopeInformation(AC->getCatchBody(), + (newParentScope = Scopes.size()-1)); } // Jump from the finally to the try or catch is not valid. @@ -320,12 +392,13 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { diag::note_protected_by_objc_finally, diag::note_exits_objc_finally, AF->getAtFinallyLoc())); - BuildScopeInformation(AF, Scopes.size()-1); + BuildScopeInformation(AF, (newParentScope = Scopes.size()-1)); } continue; } - + + unsigned newParentScope; // Disallow jumps into the protected statement of an @synchronized, but // allow jumps into the object expression it protects. if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ @@ -339,7 +412,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { diag::note_protected_by_objc_synchronized, diag::note_exits_objc_synchronized, AS->getAtSynchronizedLoc())); - BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); + BuildScopeInformation(AS->getSynchBody(), + (newParentScope = Scopes.size()-1)); continue; } @@ -351,7 +425,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { diag::note_exits_cxx_try, TS->getSourceRange().getBegin())); if (Stmt *TryBlock = TS->getTryBlock()) - BuildScopeInformation(TryBlock, Scopes.size()-1); + BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); // Jump from the catch into the try is not allowed either. for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { @@ -360,12 +434,34 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { diag::note_protected_by_cxx_catch, diag::note_exits_cxx_catch, CS->getSourceRange().getBegin())); - BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); + BuildScopeInformation(CS->getHandlerBlock(), + (newParentScope = Scopes.size()-1)); } continue; } + // Disallow jumps into the protected statement of an @autoreleasepool. + if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){ + // Recursively walk the AST for the @autoreleasepool part, protected by a new + // scope. + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_autoreleasepool, + diag::note_exits_objc_autoreleasepool, + AS->getAtLoc())); + BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1)); + continue; + } + + if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) { + const BlockDecl *BDecl = BE->getBlockDecl(); + for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(), + ce = BDecl->capture_end(); ci != ce; ++ci) { + VarDecl *variable = ci->getVariable(); + BuildScopeInformation(variable, BDecl, ParentScope); + } + } + // Recursively walk the AST. BuildScopeInformation(SubStmt, ParentScope); } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 8297b31..fdf3bb3 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -141,9 +141,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()), LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - PackContext(0), MSStructPragmaOn(false), VisContext(0), - LateTemplateParser(0), OpaqueParser(0), + CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter), + CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0), + ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), @@ -154,6 +154,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AnalysisWarnings(*this) { TUScope = 0; + LoadedExternalKnownNamespaces = false; + if (getLangOptions().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); @@ -162,7 +164,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, &Context); ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); + ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false)); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); } @@ -202,22 +204,61 @@ Sema::~Sema() { ExternalSema->ForgetSema(); } + +/// makeUnavailableInSystemHeader - There is an error in the current +/// context. If we're still in a system header, and we can plausibly +/// make the relevant declaration unavailable instead of erroring, do +/// so and return true. +bool Sema::makeUnavailableInSystemHeader(SourceLocation loc, + llvm::StringRef msg) { + // If we're not in a function, it's an error. + FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext); + if (!fn) return false; + + // If we're in template instantiation, it's an error. + if (!ActiveTemplateInstantiations.empty()) + return false; + + // If that function's not in a system header, it's an error. + if (!Context.getSourceManager().isInSystemHeader(loc)) + return false; + + // If the function is already unavailable, it's not an error. + if (fn->hasAttr<UnavailableAttr>()) return true; + + fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg)); + return true; +} + ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } +/// \brief Print out statistics about the semantic analysis. +void Sema::PrintStats() const { + llvm::errs() << "\n*** Semantic Analysis Stats:\n"; + llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n"; + + BumpAlloc.PrintStats(); + AnalysisWarnings.PrintStats(); +} + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Kind, ExprValueKind VK, - const CXXCastPath *BasePath) { + const CXXCastPath *BasePath, + CheckedConversionKind CCK) { QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return Owned(E); + if (getLangOptions().ObjCAutoRefCount) + CheckObjCARCConversion(SourceRange(), Ty, E, CCK); + // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CK_DerivedToBase && @@ -729,8 +770,8 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP, /// \brief Determine whether any errors occurred within this function/method/ /// block. -bool Sema::hasAnyErrorsInThisFunction() const { - return getCurFunction()->ErrorTrap.hasErrorOccurred(); +bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const { + return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred(); } BlockScopeInfo *Sema::getCurBlock() { @@ -748,6 +789,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) { return std::pair<ObjCMethodList, ObjCMethodList>(); } +void ExternalSemaSource::ReadKnownNamespaces( + llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) { +} + void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index e46ad5b..d053d5a 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -63,7 +63,8 @@ static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, CastKind &Kind, CXXCastPath &BasePath); -static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); +static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, + bool CheckCVR, bool CheckObjCLifetime); // The Try functions attempt a specific way of casting. If they succeed, they // return TC_Success. If their way of casting is not appropriate for the given @@ -109,12 +110,14 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp CXXCastPath &BasePath); static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, bool CStyle, + QualType DestType, + Sema::CheckedConversionKind CCK, const SourceRange &OpRange, unsigned &msg, CastKind &Kind); static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, bool CStyle, + QualType DestType, + Sema::CheckedConversionKind CCK, const SourceRange &OpRange, unsigned &msg, CastKind &Kind, @@ -131,17 +134,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, ParsedType Ty, + SourceLocation LAngleBracketLoc, Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc) { - - TypeSourceInfo *DestTInfo; - QualType DestType = GetTypeFromParser(Ty, &DestTInfo); - if (!DestTInfo) - DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation()); - return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E), + assert(!D.isInvalidType()); + + TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType()); + if (D.isInvalidType()) + return ExprError(); + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E), SourceRange(LAngleBracketLoc, RAngleBracketLoc), SourceRange(LParenLoc, RParenLoc)); } @@ -248,8 +257,10 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, InitializedEntity entity = InitializedEntity::InitializeTemporary(destType); InitializationKind initKind - = InitializationKind::CreateCast(/*type range?*/ range, - (CT == CT_CStyle || CT == CT_Functional)); + = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(), + range) + : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range) + : InitializationKind::CreateCast(/*type range?*/ range); InitializationSequence sequence(S, entity, initKind, &src, 1); assert(sequence.Failed() && "initialization succeeded on second try?"); @@ -373,8 +384,19 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by /// the cast checkers. Both arguments must denote pointer (possibly to member) /// types. +/// +/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers. +/// +/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers. static bool -CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { +CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, + bool CheckCVR, bool CheckObjCLifetime) { + // If the only checking we care about is for Objective-C lifetime qualifiers, + // and we're not in ARC mode, there's nothing to check. + if (!CheckCVR && CheckObjCLifetime && + !Self.Context.getLangOptions().ObjCAutoRefCount) + return false; + // Casting away constness is defined in C++ 5.2.11p8 with reference to // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since // the rules are non-trivial. So first we construct Tcv *...cv* as described @@ -394,13 +416,23 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // purpose of this check, because other qualifiers (address spaces, // Objective-C GC, etc.) are part of the type's identity. while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { - Qualifiers SrcQuals; + // Determine the relevant qualifiers at this level. + Qualifiers SrcQuals, DestQuals; Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals); - cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers())); - - Qualifiers DestQuals; Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals); - cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers())); + + Qualifiers RetainedSrcQuals, RetainedDestQuals; + if (CheckCVR) { + RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers()); + RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers()); + } + + if (CheckObjCLifetime && + !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals)) + return true; + + cv1.push_back(RetainedSrcQuals); + cv2.push_back(RetainedDestQuals); } if (cv1.empty()) return false; @@ -420,8 +452,10 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { } // Test if they're compatible. + bool ObjCLifetimeConversion; return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false); + !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false, + ObjCLifetimeConversion); } /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. @@ -595,9 +629,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, - msg, Kind) - != TC_Success && msg != 0) + TryCastResult tcr = + TryReinterpretCast(Self, SrcExpr, DestType, + /*CStyle*/false, OpRange, msg, Kind); + if (tcr != TC_Success && msg != 0) { if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -611,7 +646,12 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } - } + } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { + Expr *Exp = SrcExpr.get(); + // Note that Exp does not change with CCK_OtherCast cast type + Self.CheckObjCARCConversion(OpRange, DestType, + Exp, Sema::CCK_OtherCast); + } } @@ -654,8 +694,10 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, - Kind, BasePath) != TC_Success && msg != 0) { + TryCastResult tcr + = TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg, + Kind, BasePath); + if (tcr != TC_Success && msg != 0) { if (SrcExpr.isInvalid()) return; if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { @@ -667,6 +709,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else { diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType); } + } else if (tcr == TC_Success) { + if (Kind == CK_BitCast) + Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); + if (Self.getLangOptions().ObjCAutoRefCount) { + Expr *Exp = SrcExpr.get(); + // Note that Exp does not change with CCK_OtherCast cast type + Self.CheckObjCARCConversion(OpRange, DestType, + Exp, Sema::CCK_OtherCast); + } } else if (Kind == CK_BitCast) Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); @@ -676,10 +727,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// possible. If @p CStyle, ignore access restrictions on hierarchy casting /// and casting away constness. static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, - QualType DestType, bool CStyle, + QualType DestType, + Sema::CheckedConversionKind CCK, const SourceRange &OpRange, unsigned &msg, CastKind &Kind, CXXCastPath &BasePath) { + // Determine whether we have the semantics of a C-style cast. + bool CStyle + = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast); + // The order the tests is not entirely arbitrary. There is one conversion // that can be handled in two different ways. Given: // struct A {}; @@ -715,7 +771,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. - tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg, + tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind); if (SrcExpr.isInvalid()) return TC_Failed; @@ -792,10 +848,20 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestPointee = DestPointer->getPointeeType(); if (DestPointee->isIncompleteOrObjectType()) { // This is definitely the intended conversion, but it might fail due - // to a const violation. - if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; + // to a qualifier violation. Note that we permit Objective-C lifetime + // and GC qualifier mismatches here. + if (!CStyle) { + Qualifiers DestPointeeQuals = DestPointee.getQualifiers(); + Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers(); + DestPointeeQuals.removeObjCGCAttr(); + DestPointeeQuals.removeObjCLifetime(); + SrcPointeeQuals.removeObjCGCAttr(); + SrcPointeeQuals.removeObjCLifetime(); + if (DestPointeeQuals != SrcPointeeQuals && + !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) { + msg = diag::err_bad_cxx_cast_qualifiers_away; + return TC_Failed; + } } Kind = CK_BitCast; return TC_Success; @@ -845,6 +911,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; bool ObjCConversion; + bool ObjCLifetimeConversion; QualType FromType = SrcExpr->getType(); QualType ToType = R->getPointeeType(); if (CStyle) { @@ -854,8 +921,9 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), ToType, FromType, - DerivedToBase, ObjCConversion) < - Sema::Ref_Compatible_With_Added_Qualification) { + DerivedToBase, ObjCConversion, + ObjCLifetimeConversion) + < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; return TC_Failed; } @@ -1172,7 +1240,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType, /// @c static_cast if the declaration "T t(e);" is well-formed [...]. TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - bool CStyle, const SourceRange &OpRange, unsigned &msg, + Sema::CheckedConversionKind CCK, + const SourceRange &OpRange, unsigned &msg, CastKind &Kind) { if (DestType->isRecordType()) { if (Self.RequireCompleteType(OpRange.getBegin(), DestType, @@ -1184,7 +1253,11 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); InitializationKind InitKind - = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle); + = (CCK == Sema::CCK_CStyleCast) + ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange) + : (CCK == Sema::CCK_FunctionalCast) + ? InitializationKind::CreateFunctionalCast(OpRange) + : InitializationKind::CreateCast(OpRange); Expr *SrcExprRaw = SrcExpr.get(); InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1); @@ -1193,7 +1266,8 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // There is no other way that works. // On the other hand, if we're checking a C-style cast, we've still got // the reinterpret_cast way. - + bool CStyle + = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast); if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; @@ -1428,7 +1502,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // constness. // A reinterpret_cast followed by a const_cast can, though, so in C-style, // we accept it. - if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { + if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1543,7 +1618,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. // The C-style cast operator can. - if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { + if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) { msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1675,11 +1751,14 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, if (tcr == TC_Success) Kind = CK_NoOp; + Sema::CheckedConversionKind CCK + = FunctionalStyle? Sema::CCK_FunctionalCast + : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... ExprResult CastExprRes = Owned(CastExpr); - tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg, - Kind, BasePath); + tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind, + BasePath); if (CastExprRes.isInvalid()) return ExprError(); CastExpr = CastExprRes.take(); @@ -1694,6 +1773,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, } } + if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success) + CheckObjCARCConversion(R, CastTy, CastExpr, CCK); + if (tcr != TC_Success && msg != 0) { if (CastExpr->getType() == Context.OverloadTy) { DeclAccessPair Found; diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 61d9e93..5f8c9c6 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -211,25 +211,40 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC) { assert(DC != 0 && "given null context"); - if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + if (TagDecl *tag = dyn_cast<TagDecl>(DC)) { // If this is a dependent type, then we consider it complete. - if (Tag->isDependentContext()) + if (tag->isDependentContext()) return false; // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. - const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>(); - if (TagT && TagT->isBeingDefined()) + QualType type = Context.getTypeDeclType(tag); + const TagType *tagType = type->getAs<TagType>(); + if (tagType && tagType->isBeingDefined()) return false; + SourceLocation loc = SS.getLastQualifierNameLoc(); + if (loc.isInvalid()) loc = SS.getRange().getBegin(); + // The type must be complete. - if (RequireCompleteType(SS.getRange().getBegin(), - Context.getTypeDeclType(Tag), + if (RequireCompleteType(loc, type, PDiag(diag::err_incomplete_nested_name_spec) << SS.getRange())) { SS.SetInvalid(SS.getRange()); return true; } + + // Fixed enum types are complete, but they aren't valid as scopes + // until we see a definition, so awkwardly pull out this special + // case. + if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) { + if (!enumType->getDecl()->isDefinition()) { + Diag(loc, diag::err_incomplete_nested_name_spec) + << type << SS.getRange(); + SS.SetInvalid(SS.getRange()); + return true; + } + } } return false; @@ -464,26 +479,29 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); - if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext, - CTC_NoKeywords) && - Found.isSingleResult() && - isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { + TypoCorrection Corrected; + Found.clear(); + if ((Corrected = CorrectTypo(Found.getLookupNameInfo(), + Found.getLookupKind(), S, &SS, LookupCtx, + EnteringContext, CTC_NoKeywords)) && + isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) { + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) - << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << FixItHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << Name << LookupCtx << CorrectedQuotedStr << SS.getRange() + << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) - << Name << Found.getLookupName() - << FixItHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << Name << CorrectedQuotedStr + << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); - if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) - Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); + if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; + Found.addDecl(ND); + } + Found.setLookupName(Corrected.getCorrection()); } else { - Found.clear(); Found.setLookupName(&Identifier); } } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 05c257a..690a29d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -22,6 +22,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -319,12 +320,41 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { } // Memset/memcpy/memmove handling - if (FDecl->getLinkage() == ExternalLinkage && - (!getLangOptions().CPlusPlus || FDecl->isExternC())) { - if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") || - FnInfo->isStr("memmove")) - CheckMemsetcpymoveArguments(TheCall, FnInfo); + int CMF = -1; + switch (FDecl->getBuiltinID()) { + case Builtin::BI__builtin_memset: + case Builtin::BI__builtin___memset_chk: + case Builtin::BImemset: + CMF = CMF_Memset; + break; + + case Builtin::BI__builtin_memcpy: + case Builtin::BI__builtin___memcpy_chk: + case Builtin::BImemcpy: + CMF = CMF_Memcpy; + break; + + case Builtin::BI__builtin_memmove: + case Builtin::BI__builtin___memmove_chk: + case Builtin::BImemmove: + CMF = CMF_Memmove; + break; + + default: + if (FDecl->getLinkage() == ExternalLinkage && + (!getLangOptions().CPlusPlus || FDecl->isExternC())) { + if (FnInfo->isStr("memset")) + CMF = CMF_Memset; + else if (FnInfo->isStr("memcpy")) + CMF = CMF_Memcpy; + else if (FnInfo->isStr("memmove")) + CMF = CMF_Memmove; + } + break; } + + if (CMF != -1) + CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo); return false; } @@ -382,14 +412,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // casts here. // FIXME: We don't allow floating point scalars as input. Expr *FirstArg = TheCall->getArg(0); - if (!FirstArg->getType()->isPointerType()) { + const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>(); + if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) << FirstArg->getType() << FirstArg->getSourceRange(); return ExprError(); } - QualType ValType = - FirstArg->getType()->getAs<PointerType>()->getPointeeType(); + QualType ValType = pointerType->getPointeeType(); if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr) @@ -397,6 +427,20 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + switch (ValType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + // okay + break; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Autoreleasing: + Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) + << ValType << FirstArg->getSourceRange(); + return ExprError(); + } + // The majority of builtins return a value, but a few have special return // types, so allow them to override appropriately below. QualType ResultType = ValType; @@ -518,7 +562,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { CastKind Kind = CK_Invalid; ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath); + Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(), + ValType, Arg.take(), Kind, VK, BasePath); if (Arg.isInvalid()) return ExprError(); @@ -1812,6 +1857,27 @@ static bool isDynamicClassType(QualType T) { return false; } +/// \brief If E is a sizeof expression, returns its argument expression, +/// otherwise returns NULL. +static const Expr *getSizeOfExprArg(const Expr* E) { + if (const UnaryExprOrTypeTraitExpr *SizeOf = + dyn_cast<UnaryExprOrTypeTraitExpr>(E)) + if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) + return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); + + return 0; +} + +/// \brief If E is a sizeof expression, returns its argument type. +static QualType getSizeOfArgType(const Expr* E) { + if (const UnaryExprOrTypeTraitExpr *SizeOf = + dyn_cast<UnaryExprOrTypeTraitExpr>(E)) + if (SizeOf->getKind() == clang::UETT_SizeOf) + return SizeOf->getTypeOfArgument(); + + return QualType(); +} + /// \brief Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified @@ -1819,35 +1885,95 @@ static bool isDynamicClassType(QualType T) { /// /// \param Call The call expression to diagnose. void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, - const IdentifierInfo *FnName) { + CheckedMemoryFunction CMF, + IdentifierInfo *FnName) { // It is possible to have a non-standard definition of memset. Validate - // we have the proper number of arguments, and if not, abort further - // checking. - if (Call->getNumArgs() != 3) + // we have enough arguments, and if not, abort further checking. + if (Call->getNumArgs() < 3) return; - unsigned LastArg = FnName->isStr("memset")? 1 : 2; + unsigned LastArg = (CMF == CMF_Memset? 1 : 2); + const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts(); + + // We have special checking when the length is a sizeof expression. + QualType SizeOfArgTy = getSizeOfArgType(LenExpr); + const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); + llvm::FoldingSetNodeID SizeOfArgID; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); + SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); QualType DestTy = Dest->getType(); if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { QualType PointeeTy = DestPtrTy->getPointeeType(); + + // Never warn about void type pointers. This can be used to suppress + // false positives. if (PointeeTy->isVoidType()) continue; + // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by + // actually comparing the expressions for equality. Because computing the + // expression IDs can be expensive, we only do this if the diagnostic is + // enabled. + if (SizeOfArg && + Diags.getDiagnosticLevel(diag::warn_sizeof_pointer_expr_memaccess, + SizeOfArg->getExprLoc())) { + // We only compute IDs for expressions if the warning is enabled, and + // cache the sizeof arg's ID. + if (SizeOfArgID == llvm::FoldingSetNodeID()) + SizeOfArg->Profile(SizeOfArgID, Context, true); + llvm::FoldingSetNodeID DestID; + Dest->Profile(DestID, Context, true); + if (DestID == SizeOfArgID) { + unsigned ActionIdx = 0; // Default is to suggest dereferencing. + if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest)) + if (UnaryOp->getOpcode() == UO_AddrOf) + ActionIdx = 1; // If its an address-of operator, just remove it. + if (Context.getTypeSize(PointeeTy) == Context.getCharWidth()) + ActionIdx = 2; // If the pointee's size is sizeof(char), + // suggest an explicit length. + DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest, + PDiag(diag::warn_sizeof_pointer_expr_memaccess) + << FnName << ArgIdx << ActionIdx + << Dest->getSourceRange() + << SizeOfArg->getSourceRange()); + break; + } + } + + // Also check for cases where the sizeof argument is the exact same + // type as the memory argument, and where it points to a user-defined + // record type. + if (SizeOfArgTy != QualType()) { + if (PointeeTy->isRecordType() && + Context.typesAreCompatible(SizeOfArgTy, DestTy)) { + DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest, + PDiag(diag::warn_sizeof_pointer_type_memaccess) + << FnName << SizeOfArgTy << ArgIdx + << PointeeTy << Dest->getSourceRange() + << LenExpr->getSourceRange()); + break; + } + } + + unsigned DiagID; + // Always complain about dynamic classes. - if (isDynamicClassType(PointeeTy)) { - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, - PDiag(diag::warn_dyn_class_memaccess) - << ArgIdx << FnName << PointeeTy - << Call->getCallee()->getSourceRange()); - } else { + if (isDynamicClassType(PointeeTy)) + DiagID = diag::warn_dyn_class_memaccess; + else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset) + DiagID = diag::warn_arc_object_memaccess; + else continue; - } - SourceRange ArgRange = Call->getArg(0)->getSourceRange(); + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(DiagID) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); + DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::note_bad_memaccess_silence) @@ -1873,7 +1999,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. - if (lhsType->isPointerType() || lhsType->isBlockPointerType()) { + if (lhsType->isPointerType() || + (!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) { stackE = EvalAddr(RetValExp, refVars); } else if (lhsType->isReferenceType()) { stackE = EvalVal(RetValExp, refVars); @@ -2044,7 +2171,8 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { // pointer values, and pointer-to-pointer conversions. case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: - case Stmt::CXXFunctionalCastExprClass: { + case Stmt::CXXFunctionalCastExprClass: + case Stmt::ObjCBridgedCastExprClass: { Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); QualType T = SubExpr->getType(); @@ -2077,6 +2205,14 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { return NULL; } + case Stmt::MaterializeTemporaryExprClass: + if (Expr *Result = EvalAddr( + cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars)) + return Result; + + return E; + // Everything else: we simply don't reason about them. default: return NULL; @@ -2178,6 +2314,14 @@ do { return EvalVal(M->getBase(), refVars); } + case Stmt::MaterializeTemporaryExprClass: + if (Expr *Result = EvalVal( + cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars)) + return Result; + + return E; + default: // Check that we don't return or take the address of a reference to a // temporary. This is only useful in C++. @@ -2442,15 +2586,24 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { case BO_NE: return IntRange::forBoolType(); - // The type of these compound assignments is the type of the LHS, - // so the RHS is not necessarily an integer. + // The type of the assignments is the type of the LHS, so the RHS + // is not necessarily the same type. case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: + case BO_XorAssign: + case BO_OrAssign: + // TODO: bitfields? return IntRange::forValueOfType(C, E->getType()); + // Simple assignments just pass through the RHS, which will have + // been coerced to the LHS type. + case BO_Assign: + // TODO: bitfields? + return GetExprRange(C, BO->getRHS(), MaxWidth); + // Operations with opaque sources are black-listed. case BO_PtrMemD: case BO_PtrMemI: @@ -2506,14 +2659,54 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { case BO_Sub: if (BO->getLHS()->getType()->isPointerType()) return IntRange::forValueOfType(C, E->getType()); - // fallthrough + break; - default: + // The width of a division result is mostly determined by the size + // of the LHS. + case BO_Div: { + // Don't 'pre-truncate' the operands. + unsigned opWidth = C.getIntWidth(E->getType()); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth); + + // If the divisor is constant, use that. + llvm::APSInt divisor; + if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) { + unsigned log2 = divisor.logBase2(); // floor(log_2(divisor)) + if (log2 >= L.Width) + L.Width = (L.NonNegative ? 0 : 1); + else + L.Width = std::min(L.Width - log2, MaxWidth); + return L; + } + + // Otherwise, just use the LHS's width. + IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + return IntRange(L.Width, L.NonNegative && R.NonNegative); + } + + // The result of a remainder can't be larger than the result of + // either side. + case BO_Rem: { + // Don't 'pre-truncate' the operands. + unsigned opWidth = C.getIntWidth(E->getType()); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth); + IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + + IntRange meet = IntRange::meet(L, R); + meet.Width = std::min(meet.Width, MaxWidth); + return meet; + } + + // The default behavior is okay for these. + case BO_Mul: + case BO_Add: + case BO_Xor: + case BO_Or: break; } - // Treat every other operator as if it were closed on the - // narrowest type that encompasses both operands. + // The default case is to treat the operation as if it were closed + // on the narrowest type that encompasses both operands. IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); return IntRange::join(L, R); @@ -2837,18 +3030,16 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble) return; - // Try to convert this exactly to an 64-bit integer. FIXME: It would be - // nice to support arbitrarily large integers here. + // Try to convert this exactly to an integer. bool isExact = false; - uint64_t IntegerPart; - if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true, + llvm::APSInt IntegerValue(S.Context.getIntWidth(T), + T->hasUnsignedIntegerRepresentation()); + if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, &isExact) != llvm::APFloat::opOK || !isExact) return; - llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true); - - std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true); + std::string LiteralValue = IntegerValue.toString(10); S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer) << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue); } @@ -2895,6 +3086,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } + + // If the vector cast is cast between two vectors of the same size, it is + // a bitcast, not a conversion. + if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) + return; Source = cast<VectorType>(Source)->getElementType().getTypePtr(); Target = cast<VectorType>(Target)->getElementType().getTypePtr(); @@ -2989,9 +3185,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } - // People want to build with -Wshorten-64-to-32 and not -Wconversion - // and by god we'll let them. - + // People want to build with -Wshorten-64-to-32 and not -Wconversion. if (isFromSystemMacro(S, CC)) return; @@ -3356,3 +3550,268 @@ void Sema::CheckArrayAccess(const Expr *expr) { } } } + +//===--- CHECK: Objective-C retain cycles ----------------------------------// + +namespace { + struct RetainCycleOwner { + RetainCycleOwner() : Variable(0), Indirect(false) {} + VarDecl *Variable; + SourceRange Range; + SourceLocation Loc; + bool Indirect; + + void setLocsFrom(Expr *e) { + Loc = e->getExprLoc(); + Range = e->getSourceRange(); + } + }; +} + +/// Consider whether capturing the given variable can possibly lead to +/// a retain cycle. +static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) { + // In ARC, it's captured strongly iff the variable has __strong + // lifetime. In MRR, it's captured strongly if the variable is + // __block and has an appropriate type. + if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong) + return false; + + owner.Variable = var; + owner.setLocsFrom(ref); + return true; +} + +static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) { + while (true) { + e = e->IgnoreParens(); + if (CastExpr *cast = dyn_cast<CastExpr>(e)) { + switch (cast->getCastKind()) { + case CK_BitCast: + case CK_LValueBitCast: + case CK_LValueToRValue: + case CK_ObjCReclaimReturnedObject: + e = cast->getSubExpr(); + continue; + + case CK_GetObjCProperty: { + // Bail out if this isn't a strong explicit property. + const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty(); + if (pre->isImplicitProperty()) return false; + ObjCPropertyDecl *property = pre->getExplicitProperty(); + if (!(property->getPropertyAttributes() & + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_strong)) && + !(property->getPropertyIvarDecl() && + property->getPropertyIvarDecl()->getType() + .getObjCLifetime() == Qualifiers::OCL_Strong)) + return false; + + owner.Indirect = true; + e = const_cast<Expr*>(pre->getBase()); + continue; + } + + default: + return false; + } + } + + if (ObjCIvarRefExpr *ref = dyn_cast<ObjCIvarRefExpr>(e)) { + ObjCIvarDecl *ivar = ref->getDecl(); + if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong) + return false; + + // Try to find a retain cycle in the base. + if (!findRetainCycleOwner(ref->getBase(), owner)) + return false; + + if (ref->isFreeIvar()) owner.setLocsFrom(ref); + owner.Indirect = true; + return true; + } + + if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) { + VarDecl *var = dyn_cast<VarDecl>(ref->getDecl()); + if (!var) return false; + return considerVariable(var, ref, owner); + } + + if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) { + owner.Variable = ref->getDecl(); + owner.setLocsFrom(ref); + return true; + } + + if (MemberExpr *member = dyn_cast<MemberExpr>(e)) { + if (member->isArrow()) return false; + + // Don't count this as an indirect ownership. + e = member->getBase(); + continue; + } + + // Array ivars? + + return false; + } +} + +namespace { + struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> { + FindCaptureVisitor(ASTContext &Context, VarDecl *variable) + : EvaluatedExprVisitor<FindCaptureVisitor>(Context), + Variable(variable), Capturer(0) {} + + VarDecl *Variable; + Expr *Capturer; + + void VisitDeclRefExpr(DeclRefExpr *ref) { + if (ref->getDecl() == Variable && !Capturer) + Capturer = ref; + } + + void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) { + if (ref->getDecl() == Variable && !Capturer) + Capturer = ref; + } + + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) { + if (Capturer) return; + Visit(ref->getBase()); + if (Capturer && ref->isFreeIvar()) + Capturer = ref; + } + + void VisitBlockExpr(BlockExpr *block) { + // Look inside nested blocks + if (block->getBlockDecl()->capturesVariable(Variable)) + Visit(block->getBlockDecl()->getBody()); + } + }; +} + +/// Check whether the given argument is a block which captures a +/// variable. +static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) { + assert(owner.Variable && owner.Loc.isValid()); + + e = e->IgnoreParenCasts(); + BlockExpr *block = dyn_cast<BlockExpr>(e); + if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable)) + return 0; + + FindCaptureVisitor visitor(S.Context, owner.Variable); + visitor.Visit(block->getBlockDecl()->getBody()); + return visitor.Capturer; +} + +static void diagnoseRetainCycle(Sema &S, Expr *capturer, + RetainCycleOwner &owner) { + assert(capturer); + assert(owner.Variable && owner.Loc.isValid()); + + S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle) + << owner.Variable << capturer->getSourceRange(); + S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner) + << owner.Indirect << owner.Range; +} + +/// Check for a keyword selector that starts with the word 'add' or +/// 'set'. +static bool isSetterLikeSelector(Selector sel) { + if (sel.isUnarySelector()) return false; + + llvm::StringRef str = sel.getNameForSlot(0); + while (!str.empty() && str.front() == '_') str = str.substr(1); + if (str.startswith("set") || str.startswith("add")) + str = str.substr(3); + else + return false; + + if (str.empty()) return true; + return !islower(str.front()); +} + +/// Check a message send to see if it's likely to cause a retain cycle. +void Sema::checkRetainCycles(ObjCMessageExpr *msg) { + // Only check instance methods whose selector looks like a setter. + if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector())) + return; + + // Try to find a variable that the receiver is strongly owned by. + RetainCycleOwner owner; + if (msg->getReceiverKind() == ObjCMessageExpr::Instance) { + if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner)) + return; + } else { + assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance); + owner.Variable = getCurMethodDecl()->getSelfDecl(); + owner.Loc = msg->getSuperLoc(); + owner.Range = msg->getSuperLoc(); + } + + // Check whether the receiver is captured by any of the arguments. + for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) + if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) + return diagnoseRetainCycle(*this, capturer, owner); +} + +/// Check a property assign to see if it's likely to cause a retain cycle. +void Sema::checkRetainCycles(Expr *receiver, Expr *argument) { + RetainCycleOwner owner; + if (!findRetainCycleOwner(receiver, owner)) + return; + + if (Expr *capturer = findCapturingExpr(*this, argument, owner)) + diagnoseRetainCycle(*this, capturer, owner); +} + +bool Sema::checkUnsafeAssigns(SourceLocation Loc, + QualType LHS, Expr *RHS) { + Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); + if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone) + return false; + // strip off any implicit cast added to get to the one arc-specific + while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { + if (cast->getCastKind() == CK_ObjCConsumeObject) { + Diag(Loc, diag::warn_arc_retained_assign) + << (LT == Qualifiers::OCL_ExplicitNone) + << RHS->getSourceRange(); + return true; + } + RHS = cast->getSubExpr(); + } + return false; +} + +void Sema::checkUnsafeExprAssigns(SourceLocation Loc, + Expr *LHS, Expr *RHS) { + QualType LHSType = LHS->getType(); + if (checkUnsafeAssigns(Loc, LHSType, RHS)) + return; + Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + // FIXME. Check for other life times. + if (LT != Qualifiers::OCL_None) + return; + + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) { + if (PRE->isImplicitProperty()) + return; + const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); + if (!PD) + return; + + unsigned Attributes = PD->getPropertyAttributes(); + if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) + while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { + if (cast->getCastKind() == CK_ObjCConsumeObject) { + Diag(Loc, diag::warn_arc_retained_property_assign) + << RHS->getSourceRange(); + return; + } + RHS = cast->getSubExpr(); + } + } +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e328eeb..b555c8a 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1676,6 +1676,34 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, // Fall through: conditions and statements can have expressions. case Sema::PCC_ParenthesizedExpression: + if (SemaRef.getLangOptions().ObjCAutoRefCount && + CCC == Sema::PCC_ParenthesizedExpression) { + // (__bridge <type>)<expression> + Builder.AddTypedTextChunk("__bridge"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); + + // (__bridge_transfer <Objective-C type>)<expression> + Builder.AddTypedTextChunk("__bridge_transfer"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("Objective-C type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); + + // (__bridge_retained <CF type>)<expression> + Builder.AddTypedTextChunk("__bridge_retained"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("CF type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); + } + // Fall through + case Sema::PCC_Expression: { if (SemaRef.getLangOptions().CPlusPlus) { // 'this', if we're in a non-static member function. @@ -1828,7 +1856,8 @@ static const char *GetCompletionTypeString(QualType T, CodeCompletionAllocator &Allocator) { PrintingPolicy Policy(Context.PrintingPolicy); Policy.AnonymousTagLocations = false; - + Policy.SuppressStrongLifetime = true; + if (!T.getLocalQualifiers()) { // Built-in type names are constant strings. if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) @@ -1878,9 +1907,9 @@ static void AddResultTypeChunk(ASTContext &Context, T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext())); else if (isa<UnresolvedUsingValueDecl>(ND)) { /* Do nothing: ignore unresolved using declarations*/ - } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) + } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) { T = Value->getType(); - else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) + } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND)) T = Property->getType(); if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) @@ -1907,6 +1936,10 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod, static std::string FormatFunctionParameter(ASTContext &Context, ParmVarDecl *Param, bool SuppressName = false) { + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -1917,8 +1950,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) Result = Param->getIdentifier()->getName(); - Param->getType().getAsStringInternal(Result, - Context.PrintingPolicy); + Param->getType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { Result = "(" + Result; @@ -1968,8 +2000,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, // We were unable to find a FunctionProtoTypeLoc with parameter names // for the block; just use the parameter type as a placeholder. std::string Result; - Param->getType().getUnqualifiedType(). - getAsStringInternal(Result, Context.PrintingPolicy); + Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { Result = "(" + Result; @@ -1986,7 +2017,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, std::string Result; QualType ResultType = Block->getTypePtr()->getResultType(); if (!ResultType->isVoidType()) - ResultType.getAsStringInternal(Result, Context.PrintingPolicy); + ResultType.getAsStringInternal(Result, Policy); Result = '^' + Result; if (!BlockProto || Block->getNumArgs() == 0) { @@ -2071,6 +2102,9 @@ static void AddTemplateParameterChunks(ASTContext &Context, unsigned MaxParameters = 0, unsigned Start = 0, bool InDefaultArg = false) { + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + typedef CodeCompletionString::Chunk Chunk; bool FirstParameter = true; @@ -2098,8 +2132,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) PlaceholderStr = NTTP->getIdentifier()->getName(); - NTTP->getType().getAsStringInternal(PlaceholderStr, - Context.PrintingPolicy); + NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); HasDefaultArg = NTTP->hasDefaultArgument(); } else { assert(isa<TemplateTemplateParmDecl>(*P)); @@ -2286,6 +2319,10 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, typedef CodeCompletionString::Chunk Chunk; CodeCompletionBuilder Result(Allocator, Priority, Availability); + PrintingPolicy Policy(S.Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + if (Kind == RK_Pattern) { Pattern->Priority = Priority; Pattern->Availability = Availability; @@ -2470,7 +2507,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) Arg = FormatFunctionParameter(S.Context, *P, true); else { - (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy); + (*P)->getType().getAsStringInternal(Arg, Policy); Arg = "(" + Arg + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) @@ -2519,7 +2556,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Sema &S, CodeCompletionAllocator &Allocator) const { typedef CodeCompletionString::Chunk Chunk; - + PrintingPolicy Policy(S.Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available); FunctionDecl *FDecl = getFunction(); @@ -2545,7 +2585,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( else Result.AddTextChunk( Result.getAllocator().CopyString( - Proto->getResultType().getAsString(S.Context.PrintingPolicy))); + Proto->getResultType().getAsString(Policy))); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); @@ -2563,7 +2603,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( ArgType = Proto->getArgType(I); } - ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy); + ArgType.getAsStringInternal(ArgString, Policy); if (I == CurrentArg) Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, @@ -3204,8 +3244,23 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, return; } + enum CodeCompletionContext::Kind contextKind; + + if (IsArrow) { + contextKind = CodeCompletionContext::CCC_ArrowMemberAccess; + } + else { + if (BaseType->isObjCObjectPointerType() || + BaseType->isObjCObjectOrInterfaceType()) { + contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess; + } + else { + contextKind = CodeCompletionContext::CCC_DotMemberAccess; + } + } + ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess, + CodeCompletionContext(contextKind, BaseType), &ResultBuilder::IsMember); Results.EnterNewScope(); @@ -3431,10 +3486,17 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); - if (CodeCompleter->includeMacros()) + //We need to make sure we're setting the right context, + //so only say we include macros if the code completer says we do + enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other; + if (CodeCompleter->includeMacros()) { AddMacroResults(PP, Results); + kind = CodeCompletionContext::CCC_OtherWithMacros; + } + + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_OtherWithMacros, + kind, Results.data(),Results.size()); } @@ -3786,6 +3848,10 @@ void Sema::CodeCompleteOperatorName(Scope *S) { void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, CXXCtorInitializer** Initializers, unsigned NumInitializers) { + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + CXXConstructorDecl *Constructor = static_cast<CXXConstructorDecl *>(ConstructorD); if (!Constructor) @@ -3825,7 +3891,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Builder.AddTypedTextChunk( Results.getAllocator().CopyString( - Base->getType().getAsString(Context.PrintingPolicy))); + Base->getType().getAsString(Policy))); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); @@ -3850,7 +3916,7 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Builder.AddTypedTextChunk( Builder.getAllocator().CopyString( - Base->getType().getAsString(Context.PrintingPolicy))); + Base->getType().getAsString(Policy))); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); @@ -4126,18 +4192,24 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain))) + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong))) return true; - // Check for more than one of { assign, copy, retain }. + // Check for more than one of { assign, copy, retain, strong }. unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain); + ObjCDeclSpec::DQ_PR_retain| + ObjCDeclSpec::DQ_PR_strong); if (AssignCopyRetMask && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain) + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong) return true; return false; @@ -4157,10 +4229,15 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("readonly")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) Results.AddResult(CodeCompletionResult("assign")); + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCDeclSpec::DQ_PR_unsafe_unretained)) + Results.AddResult(CodeCompletionResult("unsafe_unretained")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) Results.AddResult(CodeCompletionResult("readwrite")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) Results.AddResult(CodeCompletionResult("retain")); + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong)) + Results.AddResult(CodeCompletionResult("strong")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) Results.AddResult(CodeCompletionResult("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) @@ -4522,6 +4599,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { if (Method->isInstanceMethod()) return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName()) .Case("retain", IFace) + .Case("strong", IFace) .Case("autorelease", IFace) .Case("copy", IFace) .Case("copyWithZone", IFace) @@ -4878,7 +4956,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, bool AtArgumentExpression, bool IsSuper) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCClassMessage); AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, AtArgumentExpression, IsSuper, Results); @@ -4898,7 +4976,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCClassMessage, Results.data(), Results.size()); } @@ -4941,7 +5019,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // Build the set of methods we can see. ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCInstanceMessage); Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send @@ -5054,7 +5132,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCInstanceMessage, Results.data(),Results.size()); } @@ -5245,8 +5323,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { false, Results); Results.ExitScope(); - // FIXME: Add a special context for this, use cached global completion - // results. + // FIXME: Use cached global completion results. HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); @@ -5255,7 +5332,7 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCSuperclass); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. @@ -5269,10 +5346,9 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, false, Results); Results.ExitScope(); - // FIXME: Add a special context for this, use cached global completion - // results. + // FIXME: Use cached global completion results. HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCSuperclass, Results.data(),Results.size()); } @@ -5286,8 +5362,7 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { true, Results); Results.ExitScope(); - // FIXME: Add a special context for this, use cached global completion - // results. + // FIXME: Use cached global completion results. HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, Results.data(),Results.size()); @@ -5299,7 +5374,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCCategoryName); // Ignore any categories we find that have already been implemented by this // interface. @@ -5323,7 +5398,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCCategoryName, Results.data(),Results.size()); } @@ -5342,7 +5417,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCCategoryName); // Add all of the categories that have have corresponding interface // declarations in this class and any of its superclasses, except for @@ -5363,7 +5438,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCCategoryName, Results.data(),Results.size()); } @@ -6273,6 +6348,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Results.EnterNewScope(); PrintingPolicy Policy(Context.PrintingPolicy); Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9446c0e..9d91a48 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -45,7 +45,12 @@ using namespace clang; using namespace sema; -Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) { +Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { + if (OwnedType) { + Decl *Group[2] = { OwnedType, Ptr }; + return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2)); + } + return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } @@ -287,41 +292,42 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. - LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName, - NotForRedeclaration); + if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc), + LookupOrdinaryName, S, SS, NULL, + false, CTC_Type)) { + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); - if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) { - if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) { + if (Corrected.isKeyword()) { + // We corrected to a keyword. + // FIXME: Actually recover with the keyword we suggest, and emit a fix-it. + Diag(IILoc, diag::err_unknown_typename_suggest) + << &II << CorrectedQuotedStr; + return true; + } else { + NamedDecl *Result = Corrected.getCorrectionDecl(); if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) && !Result->isInvalidDecl()) { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) Diag(IILoc, diag::err_unknown_typename_suggest) - << &II << Lookup.getLookupName() - << FixItHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << &II << CorrectedQuotedStr + << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) - << &II << DC << Lookup.getLookupName() << SS->getRange() - << FixItHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << &II << DC << CorrectedQuotedStr << SS->getRange() + << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); else llvm_unreachable("could not have corrected a typo here"); Diag(Result->getLocation(), diag::note_previous_decl) - << Result->getDeclName(); + << CorrectedQuotedStr; SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS, false, false, ParsedType(), /*NonTrivialTypeSourceInfo=*/true); return true; } - } else if (Lookup.empty()) { - // We corrected to a keyword. - // FIXME: Actually recover with the keyword we suggest, and emit a fix-it. - Diag(IILoc, diag::err_unknown_typename_suggest) - << &II << Corrected; - return true; } } @@ -509,11 +515,15 @@ Corrected: // Perform typo correction to determine if there is another name that is // close to this name. if (!SecondTry) { - if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) { + SecondTry = true; + if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), + Result.getLookupKind(), S, &SS)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); - NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin(); + NamedDecl *FirstDecl = Corrected.getCorrectionDecl(); NamedDecl *UnderlyingFirstDecl = FirstDecl? FirstDecl->getUnderlyingDecl() : 0; if (getLangOptions().CPlusPlus && NextToken.is(tok::less) && @@ -527,26 +537,33 @@ Corrected: UnqualifiedDiag = diag::err_unknown_typename_suggest; QualifiedDiag = diag::err_unknown_nested_typename_suggest; } - + if (SS.isEmpty()) Diag(NameLoc, UnqualifiedDiag) - << Name << Corrected - << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString()); + << Name << CorrectedQuotedStr + << FixItHint::CreateReplacement(NameLoc, CorrectedStr); else Diag(NameLoc, QualifiedDiag) - << Name << computeDeclContext(SS, false) << Corrected + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString()); + << FixItHint::CreateReplacement(NameLoc, CorrectedStr); // Update the name, so that the caller has the new name. - Name = Corrected.getAsIdentifierInfo(); + Name = Corrected.getCorrectionAsIdentifierInfo(); + // Also update the LookupResult... + // FIXME: This should probably go away at some point + Result.clear(); + Result.setLookupName(Corrected.getCorrection()); + if (FirstDecl) Result.addDecl(FirstDecl); + // Typo correction corrected to a keyword. - if (Result.empty()) - return Corrected.getAsIdentifierInfo(); + if (Corrected.isKeyword()) + return Corrected.getCorrectionAsIdentifierInfo(); - Diag(FirstDecl->getLocation(), diag::note_previous_decl) - << FirstDecl->getDeclName(); + if (FirstDecl) + Diag(FirstDecl->getLocation(), diag::note_previous_decl) + << CorrectedQuotedStr; // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to @@ -1137,17 +1154,18 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// class could not be found. ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, - bool TypoCorrection) { + bool DoTypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName); - if (!IDecl && TypoCorrection) { + if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - LookupResult R(*this, Id, IdLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && - (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + TypoCorrection C; + if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, + TUScope, NULL, NULL, false, CTC_NoKeywords)) && + (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) { Diag(IdLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString()); @@ -1359,7 +1377,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { // The types match. Link up the redeclaration chain if the old // declaration was a typedef. - // FIXME: this is a potential source of wierdness if the type + // FIXME: this is a potential source of weirdness if the type // spellings don't match exactly. if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old)) New->setPreviousDeclaration(Typedef); @@ -1527,7 +1545,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { /// GNU89 mode. static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { - return (LangOpts.GNUInline && !LangOpts.CPlusPlus && + return ((FD->hasAttr<GNUInlineAttr>() || LangOpts.GNUInline) && + !LangOpts.CPlusPlus && FD->isInlineSpecified() && FD->getStorageClass() == SC_Extern); } @@ -1927,6 +1946,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { return false; } + void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, const ObjCMethodDecl *oldMethod) { // Merge the attributes. @@ -2037,6 +2057,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } mergeDeclAttributes(New, Old, Context); + // Warn if an already-declared variable is made a weak_import in a subsequent declaration + if (New->getAttr<WeakImportAttr>() && + Old->getStorageClass() == SC_None && + !Old->getAttr<WeakImportAttr>()) { + Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + // Remove weak_import attribute on new declaration. + New->dropAttr<WeakImportAttr>(); + } // Merge the types. MergeVarDeclTypes(New, Old); @@ -2597,7 +2626,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } // Mock up a declarator. - Declarator Dc(DS, Declarator::TypeNameContext); + Declarator Dc(DS, Declarator::MemberContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct/union"); @@ -2736,6 +2765,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { switch (Name.getKind()) { + case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: NameInfo.setName(Name.Identifier); NameInfo.setLoc(Name.StartLocation); @@ -2924,10 +2954,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, return false; } -Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D, - bool IsFunctionDefinition) { +Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), - IsFunctionDefinition); + /*IsFunctionDefinition=*/false); } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: @@ -3274,8 +3303,18 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { // The previous declaration was found on the identifer resolver // chain, so remove it from its scope. - while (S && !S->isDeclScope(PrevDecl)) - S = S->getParent(); + + if (S->isDeclScope(PrevDecl)) { + // Special case for redeclarations in the SAME scope. + // Because this declaration is going to be added to the identifier chain + // later, we should temporarily take it OFF the chain. + IdResolver.RemoveDecl(ND); + + } else { + // Find the scope for the original declaration. + while (S && !S->isDeclScope(PrevDecl)) + S = S->getParent(); + } if (S) S->RemoveDecl(PrevDecl); @@ -3472,6 +3511,50 @@ static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext())); } +bool Sema::inferObjCARCLifetime(ValueDecl *decl) { + QualType type = decl->getType(); + Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); + if (lifetime == Qualifiers::OCL_Autoreleasing) { + // Various kinds of declaration aren't allowed to be __autoreleasing. + unsigned kind = -1U; + if (VarDecl *var = dyn_cast<VarDecl>(decl)) { + if (var->hasAttr<BlocksAttr>()) + kind = 0; // __block + else if (!var->hasLocalStorage()) + kind = 1; // global + } else if (isa<ObjCIvarDecl>(decl)) { + kind = 3; // ivar + } else if (isa<FieldDecl>(decl)) { + kind = 2; // field + } + + if (kind != -1U) { + Diag(decl->getLocation(), diag::err_arc_autoreleasing_var) + << kind; + } + } else if (lifetime == Qualifiers::OCL_None) { + // Try to infer lifetime. + if (!type->isObjCLifetimeType()) + return false; + + lifetime = type->getObjCARCImplicitLifetime(); + type = Context.getLifetimeQualifiedType(type, lifetime); + decl->setType(type); + } + + if (VarDecl *var = dyn_cast<VarDecl>(decl)) { + // Thread-local variables cannot have lifetime. + if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && + var->isThreadSpecified()) { + Diag(var->getLocation(), diag::err_arc_thread_ownership) + << var->getType(); + return true; + } + } + + return false; +} + NamedDecl* Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, QualType R, TypeSourceInfo *TInfo, @@ -3630,6 +3713,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); + // In auto-retain/release, infer strong retension for variables of + // retainable type. + if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewVD)) + NewVD->setInvalidDecl(); + // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. @@ -4007,10 +4095,10 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { + MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { - MD->addOverriddenMethod(OldMD->getCanonicalDecl()); AddedAny = true; } } @@ -4035,7 +4123,7 @@ static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { } NamedDecl* -Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, +Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -4611,9 +4699,18 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) if (SC != SC_None) { - Diag(NewFD->getLocation(), - diag::err_explicit_specialization_storage_class) - << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); + if (SC != NewFD->getStorageClass()) + Diag(NewFD->getLocation(), + diag::err_explicit_specialization_inconsistent_storage_class) + << SC + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); + + else + Diag(NewFD->getLocation(), + diag::ext_explicit_specialization_storage_class) + << FixItHint::CreateRemoval( + D.getDeclSpec().getStorageClassSpecLoc()); } } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { @@ -5208,12 +5305,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl); if (!VDecl) { - if (getLangOptions().CPlusPlus && - RealDecl->getLexicalDeclContext()->isRecord() && - isa<NamedDecl>(RealDecl)) - Diag(RealDecl->getLocation(), diag::err_member_initialization); - else - Diag(RealDecl->getLocation(), diag::err_illegal_initializer); + assert(!isa<FieldDecl>(RealDecl) && "field init shouldn't get here"); + Diag(RealDecl->getLocation(), diag::err_illegal_initializer); RealDecl->setInvalidDecl(); return; } @@ -5232,6 +5325,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setTypeSourceInfo(DeducedType); VDecl->setType(DeducedType->getType()); + // In ARC, infer lifetime. + if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) + VDecl->setInvalidDecl(); + // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDeclaration()) @@ -5372,15 +5469,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // We allow integer constant expressions in all cases. } else if (T->isIntegralOrEnumerationType()) { - if (!Init->isValueDependent()) { - // Check whether the expression is a constant expression. - llvm::APSInt Value; - SourceLocation Loc; - if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) { - Diag(Loc, diag::err_in_class_initializer_non_constant) - << Init->getSourceRange(); - VDecl->setInvalidDecl(); - } + // Check whether the expression is a constant expression. + SourceLocation Loc; + if (Init->isValueDependent()) + ; // Nothing to check. + else if (Init->isIntegerConstantExpr(Context, &Loc)) + ; // Ok, it's an ICE! + else if (Init->isEvaluatable(Context)) { + // If we can constant fold the initializer through heroics, accept it, + // but report this as a use of an extension for -pedantic. + Diag(Loc, diag::ext_in_class_initializer_non_constant) + << Init->getSourceRange(); + } else { + // Otherwise, this is some crazy unknown case. Report the issue at the + // location provided by the isIntegerConstantExpr failed check. + Diag(Loc, diag::err_in_class_initializer_non_constant) + << Init->getSourceRange(); + VDecl->setInvalidDecl(); } // We allow floating-point constants as an extension in C++03, and @@ -5466,7 +5571,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); - + + if (!VDecl->isInvalidDecl()) + checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); @@ -5735,6 +5843,23 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) { void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; + // In ARC, don't allow jumps past the implicit initialization of a + // local retaining variable. + if (getLangOptions().ObjCAutoRefCount && + var->hasLocalStorage()) { + switch (var->getType().getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + getCurFunction()->setHasBranchProtectedScope(); + break; + } + } + // All the following checks are C++ only. if (!getLangOptions().CPlusPlus) return; @@ -5874,21 +5999,13 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DiagnoseFunctionSpecifiers(D); - TagDecl *OwnedDecl = 0; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType parmDeclType = TInfo->getType(); if (getLangOptions().CPlusPlus) { // Check that there are no default arguments inside the type of this // parameter. CheckExtraCXXDefaultArguments(D); - - if (OwnedDecl && OwnedDecl->isDefinition()) { - // C++ [dcl.fct]p6: - // Types shall not be defined in return or parameter types. - Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) - << Context.getTypeDeclType(OwnedDecl); - } // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { @@ -6003,7 +6120,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, // Warn if the return value is pass-by-value and larger than the specified // threshold. - if (ReturnTy->isPODType()) { + if (ReturnTy.isPODType(Context)) { unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag(D->getLocation(), diag::warn_return_value_size) @@ -6014,7 +6131,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, // threshold. for (; Param != ParamEnd; ++Param) { QualType T = (*Param)->getType(); - if (!T->isPODType()) + if (!T.isPODType(Context)) continue; unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) @@ -6028,8 +6145,31 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, QualType T, TypeSourceInfo *TSInfo, VarDecl::StorageClass StorageClass, VarDecl::StorageClass StorageClassAsWritten) { + // In ARC, infer a lifetime qualifier for appropriate parameter types. + if (getLangOptions().ObjCAutoRefCount && + T.getObjCLifetime() == Qualifiers::OCL_None && + T->isObjCLifetimeType()) { + + Qualifiers::ObjCLifetime lifetime; + + // Special cases for arrays: + // - if it's const, use __unsafe_unretained + // - otherwise, it's an error + if (T->isArrayType()) { + if (!T.isConstQualified()) { + Diag(NameLoc, diag::err_arc_array_param_no_ownership) + << TSInfo->getTypeLoc().getSourceRange(); + } + lifetime = Qualifiers::OCL_ExplicitNone; + } else { + lifetime = T->getObjCARCImplicitLifetime(); + } + T = Context.getLifetimeQualifiedType(T, lifetime); + } + ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, - adjustParameterType(T), TSInfo, + Context.getAdjustedParameterType(T), + TSInfo, StorageClass, StorageClassAsWritten, 0); @@ -6318,6 +6458,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); WP.disableCheckFallThrough(); + } else if (FD->hasAttr<NakedAttr>()) { + // If the function is marked 'naked', don't complain about missing return + // statements. + WP.disableCheckFallThrough(); } // MSVC permits the use of pure specifier (=0) on function definition, @@ -6364,7 +6508,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Verify that that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !dcl->isInvalidDecl() && - !hasAnyErrorsInThisFunction()) + !hasAnyUnrecoverableErrorsInThisFunction()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) { @@ -6379,15 +6523,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (PP.getDiagnostics().hasErrorOccurred() || - PP.getDiagnostics().getSuppressAllDiagnostics()) + PP.getDiagnostics().getSuppressAllDiagnostics()) { ExprTemporaries.clear(); - else if (!isa<FunctionTemplateDecl>(dcl)) { + ExprNeedsCleanups = false; + } else if (!isa<FunctionTemplateDecl>(dcl)) { // Since the body is valid, issue any analysis-based warnings that are // enabled. ActivePolicy = &WP; } assert(ExprTemporaries.empty() && "Leftover temporaries in function"); + assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); } if (!IsInstantiation) @@ -6398,8 +6544,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (getDiagnostics().hasErrorOccurred()) + if (getDiagnostics().hasErrorOccurred()) { ExprTemporaries.clear(); + ExprNeedsCleanups = false; + } return dcl; } @@ -6439,6 +6587,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), + SourceLocation(), EST_None, SourceLocation(), 0, 0, 0, 0, Loc, Loc, D), DS.getAttributes(), @@ -6466,6 +6615,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /// These attributes can apply both to implicitly-declared builtins /// (like __builtin___printf_chk) or to library-declared functions /// like NSLog or printf. +/// +/// We need to check for duplicate attributes both here and where user-written +/// attributes are applied to declarations. void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (FD->isInvalidDecl()) return; @@ -6499,9 +6651,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } - if (Context.BuiltinInfo.isNoThrow(BuiltinID)) + if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>()) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); - if (Context.BuiltinInfo.isConst(BuiltinID)) + if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>()) FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } @@ -7728,6 +7880,11 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // FIXME: What to pass instead of TUScope? ProcessDeclAttributes(TUScope, NewFD, *D); + // In auto-retain/release, infer strong retension for fields of + // retainable type. + if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewFD)) + NewFD->setInvalidDecl(); + if (T.isObjCGCWeak()) Diag(Loc, diag::warn_attribute_weak_on_field); @@ -7761,6 +7918,21 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { member = CXXDestructor; if (member != CXXInvalid) { + if (getLangOptions().ObjCAutoRefCount && RDecl->hasObjectMember()) { + // Objective-C++ ARC: it is an error to have a non-trivial field of + // a union. However, system headers in Objective-C programs + // occasionally have Objective-C lifetime objects within unions, + // and rather than cause the program to fail, we make those + // members unavailable. + SourceLocation Loc = FD->getLocation(); + if (getSourceManager().isInSystemHeader(Loc)) { + if (!FD->hasAttr<UnavailableAttr>()) + FD->addAttr(new (Context) UnavailableAttr(Loc, Context, + "this system field has retaining ownership")); + return false; + } + } + Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member) << (int)FD->getParent()->isUnion() << FD->getDeclName() << member; DiagnoseNontrivial(RT, member); @@ -7913,6 +8085,21 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { return; } } + + if (EltTy->isObjCLifetimeType()) { + switch (EltTy.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + break; + + case Qualifiers::OCL_Autoreleasing: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + Diag((*fi)->getLocation(), diag::note_nontrivial_objc_ownership) + << QT << EltTy.getObjCLifetime(); + return; + } + } } assert(0 && "found no explanation for non-trivial member"); @@ -8022,6 +8209,10 @@ Decl *Sema::ActOnIvar(Scope *S, if (D.isInvalidType()) NewID->setInvalidDecl(); + // In ARC, infer 'retaining' for ivars of retainable type. + if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID)) + NewID->setInvalidDecl(); + if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. @@ -8093,6 +8284,7 @@ void Sema::ActOnFields(Scope* S, llvm::SmallVector<FieldDecl*, 32> RecFields; RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); + bool ARCErrReported = false; for (unsigned i = 0; i != NumFields; ++i) { FieldDecl *FD = cast<FieldDecl>(Fields[i]); @@ -8158,7 +8350,7 @@ void Sema::ActOnFields(Scope* S, continue; } if (!FD->getType()->isDependentType() && - !Context.getBaseElementType(FD->getType())->isPODType()) { + !Context.getBaseElementType(FD->getType()).isPODType(Context)) { Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type) << FD->getDeclName() << FD->getType(); FD->setInvalidDecl(); @@ -8205,17 +8397,45 @@ void Sema::ActOnFields(Scope* S, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (getLangOptions().ObjC1 && + } + else if (!getLangOptions().CPlusPlus) { + if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) { + // It's an error in ARC if a field has lifetime. + // We don't want to report this in a system header, though, + // so we just make the field unavailable. + // FIXME: that's really not sufficient; we need to make the type + // itself invalid to, say, initialize or copy. + QualType T = FD->getType(); + Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime(); + if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) { + SourceLocation loc = FD->getLocation(); + if (getSourceManager().isInSystemHeader(loc)) { + if (!FD->hasAttr<UnavailableAttr>()) { + FD->addAttr(new (Context) UnavailableAttr(loc, Context, + "this system field has retaining ownership")); + } + } else { + Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct); + } + ARCErrReported = true; + } + } + else if (getLangOptions().ObjC1 && getLangOptions().getGCMode() != LangOptions::NonGC && - Record && - (FD->getType()->isObjCObjectPointerType() || - FD->getType().isObjCGCStrong())) - Record->setHasObjectMember(true); - else if (Context.getAsArrayType(FD->getType())) { - QualType BaseType = Context.getBaseElementType(FD->getType()); - if (Record && BaseType->isRecordType() && - BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()) - Record->setHasObjectMember(true); + Record && !Record->hasObjectMember()) { + if (FD->getType()->isObjCObjectPointerType() || + FD->getType().isObjCGCStrong()) + Record->setHasObjectMember(true); + else if (Context.getAsArrayType(FD->getType())) { + QualType BaseType = Context.getBaseElementType(FD->getType()); + if (BaseType->isRecordType() && + BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()) + Record->setHasObjectMember(true); + else if (BaseType->isObjCObjectPointerType() || + BaseType.isObjCGCStrong()) + Record->setHasObjectMember(true); + } + } } // Keep track of the number of named members. if (FD->getIdentifier()) @@ -8234,6 +8454,42 @@ void Sema::ActOnFields(Scope* S, Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { + // Objective-C Automatic Reference Counting: + // If a class has a non-static data member of Objective-C pointer + // type (or array thereof), it is a non-POD type and its + // default constructor (if any), copy constructor, copy assignment + // operator, and destructor are non-trivial. + // + // This rule is also handled by CXXRecordDecl::completeDefinition(). + // However, here we check whether this particular class is only + // non-POD because of the presence of an Objective-C pointer member. + // If so, objects of this type cannot be shared between code compiled + // with instant objects and code compiled with manual retain/release. + if (getLangOptions().ObjCAutoRefCount && + CXXRecord->hasObjectMember() && + CXXRecord->getLinkage() == ExternalLinkage) { + if (CXXRecord->isPOD()) { + Diag(CXXRecord->getLocation(), + diag::warn_arc_non_pod_class_with_object_member) + << CXXRecord; + } else { + // FIXME: Fix-Its would be nice here, but finding a good location + // for them is going to be tricky. + if (CXXRecord->hasTrivialCopyConstructor()) + Diag(CXXRecord->getLocation(), + diag::warn_arc_trivial_member_function_with_object_member) + << CXXRecord << 0; + if (CXXRecord->hasTrivialCopyAssignment()) + Diag(CXXRecord->getLocation(), + diag::warn_arc_trivial_member_function_with_object_member) + << CXXRecord << 1; + if (CXXRecord->hasTrivialDestructor()) + Diag(CXXRecord->getLocation(), + diag::warn_arc_trivial_member_function_with_object_member) + << CXXRecord << 2; + } + } + // Adjust user-defined destructor exception spec. if (getLangOptions().CPlusPlus0x && CXXRecord->hasUserDeclaredDestructor()) @@ -8807,7 +9063,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Adjust the Expr initializer and type. if (ECD->getInitExpr() && - !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) + !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, CK_IntegralCast, ECD->getInitExpr(), diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 7f93ab7..61b7b3e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" @@ -48,14 +49,14 @@ enum { // Helper functions //===----------------------------------------------------------------------===// -static const FunctionType *getFunctionType(const Decl *d, +static const FunctionType *getFunctionType(const Decl *D, bool blocksToo = true) { QualType Ty; - if (const ValueDecl *decl = dyn_cast<ValueDecl>(d)) + if (const ValueDecl *decl = dyn_cast<ValueDecl>(D)) Ty = decl->getType(); - else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d)) + else if (const FieldDecl *decl = dyn_cast<FieldDecl>(D)) Ty = decl->getType(); - else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(d)) + else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D)) Ty = decl->getUnderlyingType(); else return 0; @@ -73,46 +74,47 @@ static const FunctionType *getFunctionType(const Decl *d, /// isFunction - Return true if the given decl has function /// type (function or function-typed variable). -static bool isFunction(const Decl *d) { - return getFunctionType(d, false) != NULL; +static bool isFunction(const Decl *D) { + return getFunctionType(D, false) != NULL; } /// isFunctionOrMethod - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method. -static bool isFunctionOrMethod(const Decl *d) { - return isFunction(d)|| isa<ObjCMethodDecl>(d); +static bool isFunctionOrMethod(const Decl *D) { + return isFunction(D)|| isa<ObjCMethodDecl>(D); } /// isFunctionOrMethodOrBlock - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method or a block. -static bool isFunctionOrMethodOrBlock(const Decl *d) { - if (isFunctionOrMethod(d)) +static bool isFunctionOrMethodOrBlock(const Decl *D) { + if (isFunctionOrMethod(D)) return true; // check for block is more involved. - if (const VarDecl *V = dyn_cast<VarDecl>(d)) { + if (const VarDecl *V = dyn_cast<VarDecl>(D)) { QualType Ty = V->getType(); return Ty->isBlockPointerType(); } - return isa<BlockDecl>(d); + return isa<BlockDecl>(D); } /// Return true if the given decl has a declarator that should have /// been processed by Sema::GetTypeForDeclarator. -static bool hasDeclarator(const Decl *d) { - // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl. - return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d); +static bool hasDeclarator(const Decl *D) { + // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. + return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) || + isa<ObjCPropertyDecl>(D); } /// hasFunctionProto - Return true if the given decl has a argument /// information. This decl should have already passed /// isFunctionOrMethod or isFunctionOrMethodOrBlock. -static bool hasFunctionProto(const Decl *d) { - if (const FunctionType *FnTy = getFunctionType(d)) +static bool hasFunctionProto(const Decl *D) { + if (const FunctionType *FnTy = getFunctionType(D)) return isa<FunctionProtoType>(FnTy); else { - assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d)); + assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D)); return true; } } @@ -120,42 +122,42 @@ static bool hasFunctionProto(const Decl *d) { /// getFunctionOrMethodNumArgs - Return number of function or method /// arguments. It is an error to call this on a K&R function (use /// hasFunctionProto first). -static unsigned getFunctionOrMethodNumArgs(const Decl *d) { - if (const FunctionType *FnTy = getFunctionType(d)) +static unsigned getFunctionOrMethodNumArgs(const Decl *D) { + if (const FunctionType *FnTy = getFunctionType(D)) return cast<FunctionProtoType>(FnTy)->getNumArgs(); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getNumParams(); - return cast<ObjCMethodDecl>(d)->param_size(); + return cast<ObjCMethodDecl>(D)->param_size(); } -static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) { - if (const FunctionType *FnTy = getFunctionType(d)) +static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) { + if (const FunctionType *FnTy = getFunctionType(D)) return cast<FunctionProtoType>(FnTy)->getArgType(Idx); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getParamDecl(Idx)->getType(); - return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType(); + return cast<ObjCMethodDecl>(D)->param_begin()[Idx]->getType(); } -static QualType getFunctionOrMethodResultType(const Decl *d) { - if (const FunctionType *FnTy = getFunctionType(d)) +static QualType getFunctionOrMethodResultType(const Decl *D) { + if (const FunctionType *FnTy = getFunctionType(D)) return cast<FunctionProtoType>(FnTy)->getResultType(); - return cast<ObjCMethodDecl>(d)->getResultType(); + return cast<ObjCMethodDecl>(D)->getResultType(); } -static bool isFunctionOrMethodVariadic(const Decl *d) { - if (const FunctionType *FnTy = getFunctionType(d)) { +static bool isFunctionOrMethodVariadic(const Decl *D) { + if (const FunctionType *FnTy = getFunctionType(D)) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); - } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->isVariadic(); else { - return cast<ObjCMethodDecl>(d)->isVariadic(); + return cast<ObjCMethodDecl>(D)->isVariadic(); } } -static bool isInstanceMethod(const Decl *d) { - if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(d)) +static bool isInstanceMethod(const Decl *D) { + if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) return MethodDecl->isInstance(); return false; } @@ -192,6 +194,16 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } +static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, + unsigned int Num) { + if (Attr.getNumArgs() != Num) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num; + return false; + } + + return true; +} + //===----------------------------------------------------------------------===// // Attribute Implementations //===----------------------------------------------------------------------===// @@ -200,9 +212,9 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { // least add some helper functions to check most argument patterns (# // and types of args). -static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, - const AttributeList &Attr, Sema &S) { - TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(d); +static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, + const AttributeList &Attr) { + TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D); if (tDecl == 0) { S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); return; @@ -217,13 +229,17 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, CXXScopeSpec SS; UnqualifiedId id; id.setIdentifier(Attr.getParameterName(), Attr.getLoc()); - sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>(); + + ExprResult Size = S.ActOnIdExpression(scope, SS, id, false, false); + if (Size.isInvalid()) + return; + + sizeExpr = Size.get(); } else { // check the attribute arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if (!checkAttributeNumArgs(S, Attr, 1)) return; - } + sizeExpr = Attr.getArg(0); } @@ -239,16 +255,14 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, } } -static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() > 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (TagDecl *TD = dyn_cast<TagDecl>(d)) + if (TagDecl *TD = dyn_cast<TagDecl>(D)) TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) { + else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. if (!FD->getType()->isIncompleteType() && @@ -261,49 +275,45 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } -static void HandleMsStructAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (TagDecl *TD = dyn_cast<TagDecl>(d)) +static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (TagDecl *TD = dyn_cast<TagDecl>(D)) TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } -static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() > 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } // The IBAction attributes only apply to instance methods. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->isInstanceMethod()) { - d->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context)); return; } S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName(); } -static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() > 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } // The IBOutlet attributes only apply to instance variables of // Objective-C classes. - if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) { - d->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context)); + if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) { + D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context)); return; } S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); } -static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleIBOutletCollection(Sema &S, Decl *D, + const AttributeList &Attr) { // The iboutletcollection attribute can have zero or one arguments. if (Attr.getParameterName() && Attr.getNumArgs() > 0) { @@ -313,17 +323,17 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, // The IBOutletCollection attributes only apply to instance variables of // Objective-C classes. - if (!(isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d))) { + if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); return; } - if (const ValueDecl *VD = dyn_cast<ValueDecl>(d)) + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) if (!VD->getType()->getAs<ObjCObjectPointerType>()) { S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) << VD->getType() << 0; return; } - if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(d)) + if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) if (!PD->getType()->getAs<ObjCObjectPointerType>()) { S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) << PD->getType() << 1; @@ -335,7 +345,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, II = &S.Context.Idents.get("id"); ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(), - S.getScopeForContext(d->getDeclContext()->getParent())); + S.getScopeForContext(D->getDeclContext()->getParent())); if (!TypeRep) { S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; return; @@ -350,14 +360,29 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; return; } - d->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context, QT)); } -static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void possibleTransparentUnionPointerType(QualType &T) { + if (const RecordType *UT = T->getAsUnionType()) + if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { + RecordDecl *UD = UT->getDecl(); + for (RecordDecl::field_iterator it = UD->field_begin(), + itend = UD->field_end(); it != itend; ++it) { + QualType QT = it->getType(); + if (QT->isAnyPointerType() || QT->isBlockPointerType()) { + T = QT; + return; + } + } + } +} + +static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // GCC ignores the nonnull attribute on K&R style function prototypes, so we // ignore it as well - if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { + if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; @@ -365,8 +390,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // In C++ the implicit 'this' function parameter also counts, and they are // counted from one. - bool HasImplicitThisParam = isInstanceMethod(d); - unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; + bool HasImplicitThisParam = isInstanceMethod(D); + unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; // The nonnull attribute only applies to pointers. llvm::SmallVector<unsigned, 10> NonNullArgs; @@ -405,7 +430,9 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType(); + QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType(); + possibleTransparentUnionPointerType(T); + if (!T->isAnyPointerType() && !T->isBlockPointerType()) { // FIXME: Should also highlight argument in decl. S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only) @@ -419,23 +446,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // If no arguments were specified to __attribute__((nonnull)) then all pointer // arguments have a nonnull attribute. if (NonNullArgs.empty()) { - for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) { - QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType(); + for (unsigned I = 0, E = getFunctionOrMethodNumArgs(D); I != E; ++I) { + QualType T = getFunctionOrMethodArgType(D, I).getNonReferenceType(); + possibleTransparentUnionPointerType(T); if (T->isAnyPointerType() || T->isBlockPointerType()) NonNullArgs.push_back(I); - else if (const RecordType *UT = T->getAsUnionType()) { - if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { - RecordDecl *UD = UT->getDecl(); - for (RecordDecl::field_iterator it = UD->field_begin(), - itend = UD->field_end(); it != itend; ++it) { - T = it->getType(); - if (T->isAnyPointerType() || T->isBlockPointerType()) { - NonNullArgs.push_back(I); - break; - } - } - } - } } // No pointer arguments? @@ -451,11 +466,11 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned* start = &NonNullArgs[0]; unsigned size = NonNullArgs.size(); llvm::array_pod_sort(start, start + size); - d->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start, + D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start, size)); } -static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { +static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { // This attribute must be applied to a function declaration. // The first argument to the attribute must be a string, // the name of the resource, for example "malloc". @@ -500,7 +515,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { llvm_unreachable("Unknown ownership attribute"); } - if (!isFunction(d) || !hasFunctionProto(d)) { + if (!isFunction(D) || !hasFunctionProto(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL.getName() << ExpectedFunction; return; @@ -508,8 +523,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { // In C++ the implicit 'this' function parameter also counts, and they are // counted from one. - bool HasImplicitThisParam = isInstanceMethod(d); - unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; + bool HasImplicitThisParam = isInstanceMethod(D); + unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; llvm::StringRef Module = AL.getParameterName()->getName(); @@ -552,7 +567,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { case OwnershipAttr::Takes: case OwnershipAttr::Holds: { // Is the function argument a pointer type? - QualType T = getFunctionOrMethodArgType(d, x); + QualType T = getFunctionOrMethodArgType(D, x); if (!T->isAnyPointerType() && !T->isBlockPointerType()) { // FIXME: Should also highlight argument in decl. S.Diag(AL.getLoc(), diag::err_ownership_type) @@ -584,8 +599,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { // Check we don't have a conflict with another ownership attribute. for (specific_attr_iterator<OwnershipAttr> - i = d->specific_attr_begin<OwnershipAttr>(), - e = d->specific_attr_end<OwnershipAttr>(); + i = D->specific_attr_begin<OwnershipAttr>(), + e = D->specific_attr_end<OwnershipAttr>(); i != e; ++i) { if ((*i)->getOwnKind() != K) { for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end(); @@ -609,7 +624,7 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { return; } - d->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module, + D->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size)); } @@ -633,20 +648,20 @@ static bool hasEffectivelyInternalLinkage(NamedDecl *D) { return false; } -static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { + if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariableOrFunction; return; } - NamedDecl *nd = cast<NamedDecl>(d); + NamedDecl *nd = cast<NamedDecl>(D); // gcc rejects // class c { @@ -658,7 +673,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { // static int a __attribute__((weakref ("v2"))); // } // we reject them - const DeclContext *Ctx = d->getDeclContext()->getRedeclContext(); + const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << nd->getNameAsString(); @@ -704,14 +719,14 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); } - d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); } -static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -735,55 +750,52 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: check if target symbol exists in current file - d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); } -static void HandleNakedAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<FunctionDecl>(d)) { + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context)); } -static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleAlwaysInlineAttr(Sema &S, Decl *D, + const AttributeList &Attr) { // Check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - if (!isa<FunctionDecl>(d)) { + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context)); } -static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { QualType RetTy = FD->getResultType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { - d->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context)); return; } } @@ -791,46 +803,44 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); } -static void HandleMayAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - d->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context)); } -static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { - assert(Attr.isInvalid() == false); - if (isa<VarDecl>(d)) - d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); +static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { + assert(!Attr.isInvalid()); + if (isa<VarDecl>(D)) + D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; } -static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { - assert(Attr.isInvalid() == false); - if (isa<VarDecl>(d)) - d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); +static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { + assert(!Attr.isInvalid()); + if (isa<VarDecl>(D)) + D->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; } -static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) { - if (hasDeclarator(d)) return; +static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { + if (hasDeclarator(D)) return; if (S.CheckNoReturnAttr(attr)) return; - if (!isa<ObjCMethodDecl>(d)) { + if (!isa<ObjCMethodDecl>(D)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) << attr.getName() << ExpectedFunctionOrMethod; return; } - d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context)); } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { @@ -843,19 +853,17 @@ bool Sema::CheckNoReturnAttr(const AttributeList &attr) { return false; } -static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, + const AttributeList &Attr) { // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } + if(!checkAttributeNumArgs(S, Attr, 0)) + return; - if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) { - ValueDecl *VD = dyn_cast<ValueDecl>(d); + if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) { + ValueDecl *VD = dyn_cast<ValueDecl>(D); if (VD == 0 || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), @@ -866,12 +874,11 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, } } - d->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context)); } // PS3 PPU-specific. -static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { /* Returning a Vector Class in Registers @@ -895,18 +902,18 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, return result; // This will be returned in a register } */ - if (!isa<RecordDecl>(d)) { + if (!isa<RecordDecl>(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedClass; return; } - if (d->getAttr<VecReturnAttr>()) { + if (D->getAttr<VecReturnAttr>()) { S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn"; return; } - RecordDecl *record = cast<RecordDecl>(d); + RecordDecl *record = cast<RecordDecl>(D); int count = 0; if (!isa<CXXRecordDecl>(record)) { @@ -928,11 +935,11 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, count++; } - d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); } -static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) { +static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!isFunctionOrMethod(D) && !isa<ParmVarDecl>(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionMethodOrParameter; return; @@ -940,45 +947,45 @@ static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: Actually store the attribute on the declaration } -static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) && - !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) { + if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) && + !isa<TypeDecl>(D) && !isa<LabelDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariableFunctionOrLabel; return; } - d->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context)); } -static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - if (const VarDecl *VD = dyn_cast<VarDecl>(d)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasLocalStorage() || VD->hasExternalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used"; return; } - } else if (!isFunctionOrMethod(d)) { + } else if (!isFunctionOrMethod(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariableOrFunction; return; } - d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); } -static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; @@ -998,17 +1005,17 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { priority = Idx.getZExtValue(); } - if (!isa<FunctionDecl>(d)) { + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, priority)); } -static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; @@ -1028,17 +1035,17 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { priority = Idx.getZExtValue(); } - if (!isa<FunctionDecl>(d)) { + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, priority)); } -static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = Attr.getNumArgs(); if (NumArgs > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; @@ -1057,10 +1064,10 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { Str = SE->getString(); } - d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str)); } -static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = Attr.getNumArgs(); if (NumArgs > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; @@ -1078,11 +1085,23 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { } Str = SE->getString(); } - d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); +} + +static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + unsigned NumArgs = Attr.getNumArgs(); + if (NumArgs > 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 0; + return; + } + + D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr( + Attr.getLoc(), S.Context)); } -static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleAvailabilityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { IdentifierInfo *Platform = Attr.getParameterName(); SourceLocation PlatformLoc = Attr.getParameterLoc(); @@ -1126,7 +1145,7 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr, return; } - d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, Platform, Introduced.Version, Deprecated.Version, @@ -1134,12 +1153,10 @@ static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr, IsUnavailable)); } -static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if(!checkAttributeNumArgs(S, Attr, 1)) return; - } Expr *Arg = Attr.getArg(0); Arg = Arg->IgnoreParenCasts(); @@ -1167,30 +1184,30 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); } -static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr, - Sema &S) { +static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, + const AttributeList &Attr) { ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl); if (!method) { - S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type) + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << ExpectedMethod; return; } - if (attr.getNumArgs() != 0 || !attr.getParameterName()) { - if (!attr.getParameterName() && attr.getNumArgs() == 1) { - S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + if (Attr.getNumArgs() != 0 || !Attr.getParameterName()) { + if (!Attr.getParameterName() && Attr.getNumArgs() == 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_method_family" << 1; } else { - S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; } - attr.setInvalid(); + Attr.setInvalid(); return; } - llvm::StringRef param = attr.getParameterName()->getName(); + llvm::StringRef param = Attr.getParameterName()->getName(); ObjCMethodFamilyAttr::FamilyKind family; if (param == "none") family = ObjCMethodFamilyAttr::OMF_None; @@ -1207,20 +1224,26 @@ static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr, else { // Just warn and ignore it. This is future-proof against new // families being used in system headers. - S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family); + S.Diag(Attr.getParameterLoc(), diag::warn_unknown_method_family); return; } - decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(), - S.Context, family)); + if (family == ObjCMethodFamilyAttr::OMF_init && + !method->getResultType()->isObjCObjectPointerType()) { + S.Diag(method->getLocation(), diag::err_init_method_bad_return_type) + << method->getResultType(); + // Ignore the attribute. + return; + } + + method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(), + S.Context, family)); } -static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, - Sema &S) { - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; +static void handleObjCExceptionAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D); if (OCI == 0) { @@ -1231,7 +1254,7 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context)); } -static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1248,7 +1271,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { } static void -HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { +handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1262,7 +1285,7 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context)); } -static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "blocks" << 1; @@ -1283,10 +1306,10 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type)); } -static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 2) { S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; @@ -1333,7 +1356,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { } } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { const FunctionType *FT = FD->getType()->getAs<FunctionType>(); assert(FT && "FunctionDecl has non-function type?"); @@ -1346,19 +1369,19 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) { + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (!MD->isVariadic()) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (isa<BlockDecl>(d)) { + } else if (isa<BlockDecl>(D)) { // Note! BlockDecl is typeless. Variadic diagnostics will be issued by the // caller. ; - } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) { + } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { - const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d) + const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(D) : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; @@ -1375,16 +1398,14 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } - d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, + D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, nullPos)); } -static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -1407,36 +1428,35 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context)); } -static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) { +static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (attr.hasParameterOrArguments()) { - S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (Attr.hasParameterOrArguments()) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { - S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedVariableOrFunction; + if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedVariableOrFunction; return; } - NamedDecl *nd = cast<NamedDecl>(d); + NamedDecl *nd = cast<NamedDecl>(D); // 'weak' only applies to declarations with external linkage. if (hasEffectivelyInternalLinkage(nd)) { - S.Diag(attr.getLoc(), diag::err_attribute_weak_static); + S.Diag(Attr.getLoc(), diag::err_attribute_weak_static); return; } - nd->addAttr(::new (S.Context) WeakAttr(attr.getLoc(), S.Context)); + nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context)); } -static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } + // weak_import only applies to variable & function declarations. bool isDef = false; @@ -1459,13 +1479,11 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context)); } -static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, - Sema &S) { +static void handleReqdWorkGroupSize(Sema &S, Decl *D, + const AttributeList &Attr) { // Attribute has 3 arguments. - if (Attr.getNumArgs() != 3) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if (!checkAttributeNumArgs(S, Attr, 3)) return; - } unsigned WGSize[3]; for (unsigned i = 0; i < 3; ++i) { @@ -1484,12 +1502,10 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, WGSize[2])); } -static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Attribute has no arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if (!checkAttributeNumArgs(S, Attr, 1)) return; - } // Make sure that there is a string literal as the sections's single // argument. @@ -1519,37 +1535,45 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { } -static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - - d->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context)); + + if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) { + if (Existing->getLocation().isInvalid()) + Existing->setLocation(Attr.getLoc()); + } else { + D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context)); + } } -static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - d->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context)); + if (ConstAttr *Existing = D->getAttr<ConstAttr>()) { + if (Existing->getLocation().isInvalid()) + Existing->setLocation(Attr.getLoc()); + } else { + D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context)); + } } -static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - d->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context)); } -static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1560,7 +1584,7 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - VarDecl *VD = dyn_cast<VarDecl>(d); + VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD || !VD->hasLocalStorage()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup"; @@ -1605,18 +1629,17 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); + D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD); } /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; +static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeNumArgs(S, Attr, 1)) return; - } - if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { + + if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; @@ -1624,8 +1647,8 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { // In C++ the implicit 'this' function parameter also counts, and they are // counted from one. - bool HasImplicitThisParam = isInstanceMethod(d); - unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; + bool HasImplicitThisParam = isInstanceMethod(D); + unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; unsigned FirstIdx = 1; // checks for the 2nd argument @@ -1656,7 +1679,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // make sure the format string is really a string - QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); + QualType Ty = getFunctionOrMethodArgType(D, ArgIdx); bool not_nsstring_type = !isNSStringType(Ty, S.Context); if (not_nsstring_type && @@ -1669,7 +1692,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { << IdxExpr->getSourceRange(); return; } - Ty = getFunctionOrMethodResultType(d); + Ty = getFunctionOrMethodResultType(D); if (!isNSStringType(Ty, S.Context) && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || @@ -1681,7 +1704,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, Idx.getZExtValue())); } @@ -1722,19 +1745,19 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { /// Handle __attribute__((init_priority(priority))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html -static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleInitPriorityAttr(Sema &S, Decl *D, + const AttributeList &Attr) { if (!S.getLangOptions().CPlusPlus) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } - if (!isa<VarDecl>(d) || S.getCurFunctionOrMethodDecl()) { + if (!isa<VarDecl>(D) || S.getCurFunctionOrMethodDecl()) { S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); Attr.setInvalid(); return; } - QualType T = dyn_cast<VarDecl>(d)->getType(); + QualType T = dyn_cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); if (!T->getAs<RecordType>()) { @@ -1765,13 +1788,13 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr, Attr.setInvalid(); return; } - d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, prioritynum)); } /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) @@ -1784,7 +1807,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) { + if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; @@ -1792,8 +1815,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // In C++ the implicit 'this' function parameter also counts, and they are // counted from one. - bool HasImplicitThisParam = isInstanceMethod(d); - unsigned NumArgs = getFunctionOrMethodNumArgs(d) + HasImplicitThisParam; + bool HasImplicitThisParam = isInstanceMethod(D); + unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; unsigned FirstIdx = 1; llvm::StringRef Format = Attr.getParameterName()->getName(); @@ -1844,7 +1867,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // make sure the format string is really a string - QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); + QualType Ty = getFunctionOrMethodArgType(D, ArgIdx); if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { @@ -1881,10 +1904,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check if the function is variadic if the 3rd argument non-zero if (FirstArg != 0) { - if (isFunctionOrMethodVariadic(d)) { + if (isFunctionOrMethodVariadic(D)) { ++NumArgs; // +1 for ... } else { - S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); + S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic); return; } } @@ -1904,26 +1927,42 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format, + // Check whether we already have an equivalent format attribute. + for (specific_attr_iterator<FormatAttr> + i = D->specific_attr_begin<FormatAttr>(), + e = D->specific_attr_end<FormatAttr>(); + i != e ; ++i) { + FormatAttr *f = *i; + if (f->getType() == Format && + f->getFormatIdx() == (int)Idx.getZExtValue() && + f->getFirstArg() == (int)FirstArg.getZExtValue()) { + // If we don't have a valid location for this attribute, adopt the + // location. + if (f->getLocation().isInvalid()) + f->setLocation(Attr.getLoc()); + return; + } + } + + D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format, Idx.getZExtValue(), FirstArg.getZExtValue())); } -static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleTransparentUnionAttr(Sema &S, Decl *D, + const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } + // Try to find the underlying union declaration. RecordDecl *RD = 0; - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(d); + TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); else - RD = dyn_cast<RecordDecl>(d); + RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -1977,12 +2016,11 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context)); } -static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if (!checkAttributeNumArgs(S, Attr, 1)) return; - } + Expr *ArgExpr = Attr.getArg(0); StringLiteral *SE = dyn_cast<StringLiteral>(ArgExpr); @@ -1992,11 +2030,11 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, SE->getString())); } -static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -2045,21 +2083,20 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) { return; } -/// HandleModeAttr - This attribute modifies the width of a decl with primitive +/// handleModeAttr - This attribute modifies the width of a decl with primitive /// type. /// /// Despite what would be logical, the mode attribute is a decl attribute, not a /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be /// HImode, not an intermediate pointer. -static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { +static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. // Check that there aren't any arguments - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } + IdentifierInfo *Name = Attr.getParameterName(); if (!Name) { @@ -2216,57 +2253,53 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { cast<ValueDecl>(D)->setType(NewTy); } -static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() > 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isFunctionOrMethod(d)) { + if (!isFunctionOrMethod(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context)); } -static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<FunctionDecl>(d)) { + + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context)); } -static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, - Sema &S) { +static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, + const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<FunctionDecl>(d)) { + + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), S.Context)); } -static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. if (Attr.hasParameterOrArguments()) { @@ -2274,19 +2307,19 @@ static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa<VarDecl>(d)) { + if (!isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; return; } - d->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant"; } } -static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { @@ -2294,33 +2327,31 @@ static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) { + if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariableOrFunction; return; } - d->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; } } -static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<FunctionDecl>(d)) { + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - FunctionDecl *FD = cast<FunctionDecl>(d); + FunctionDecl *FD = cast<FunctionDecl>(D); if (!FD->getResultType()->isVoidType()) { TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) { @@ -2335,60 +2366,56 @@ static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global"; } } -static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<FunctionDecl>(d)) { + + if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; return; } - d->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; } } -static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CUDA) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - if (!isa<VarDecl>(d)) { + + if (!isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; return; } - d->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared"; } } -static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + if (!checkAttributeNumArgs(S, Attr, 0)) return; - } - FunctionDecl *Fn = dyn_cast<FunctionDecl>(d); + FunctionDecl *Fn = dyn_cast<FunctionDecl>(D); if (Fn == 0) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunction; @@ -2400,47 +2427,47 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); } -static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { - if (hasDeclarator(d)) return; +static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (hasDeclarator(D)) return; - // Diagnostic is emitted elsewhere: here we store the (valid) attr + // Diagnostic is emitted elsewhere: here we store the (valid) Attr // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(attr, CC)) + if (S.CheckCallingConvAttr(Attr, CC)) return; - if (!isa<ObjCMethodDecl>(d)) { - S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedFunctionOrMethod; + if (!isa<ObjCMethodDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; return; } - switch (attr.getKind()) { + switch (Attr.getKind()) { case AttributeList::AT_fastcall: - d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_stdcall: - d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_thiscall: - d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_cdecl: - d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_pascal: - d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_pcs: { - Expr *Arg = attr.getArg(0); + Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); if (Str == 0 || Str->isWide()) { - S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "pcs" << 1; - attr.setInvalid(); + Attr.setInvalid(); return; } @@ -2451,12 +2478,12 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { else if (StrRef == "aapcs-vfp") PCS = PcsAttr::AAPCS_VFP; else { - S.Diag(attr.getLoc(), diag::err_invalid_pcs); - attr.setInvalid(); + S.Diag(Attr.getLoc(), diag::err_invalid_pcs); + Attr.setInvalid(); return; } - d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS)); + D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS)); } default: llvm_unreachable("unexpected attribute kind"); @@ -2464,9 +2491,9 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { } } -static void HandleOpenCLKernelAttr(Decl *d, const AttributeList &Attr, Sema &S){ - assert(Attr.isInvalid() == false); - d->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context)); +static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ + assert(!Attr.isInvalid()); + D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context)); } bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { @@ -2515,63 +2542,63 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { return false; } -static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) { - if (hasDeclarator(d)) return; +static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (hasDeclarator(D)) return; unsigned numParams; - if (S.CheckRegparmAttr(attr, numParams)) + if (S.CheckRegparmAttr(Attr, numParams)) return; - if (!isa<ObjCMethodDecl>(d)) { - S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << ExpectedFunctionOrMethod; + if (!isa<ObjCMethodDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; return; } - d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams)); + D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams)); } /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. -bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) { - if (attr.isInvalid()) +bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { + if (Attr.isInvalid()) return true; - if (attr.getNumArgs() != 1) { - Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - attr.setInvalid(); + if (Attr.getNumArgs() != 1) { + Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return true; } - Expr *NumParamsExpr = attr.getArg(0); + Expr *NumParamsExpr = Attr.getArg(0); llvm::APSInt NumParams(32); if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() || !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) { - Diag(attr.getLoc(), diag::err_attribute_argument_not_int) + Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "regparm" << NumParamsExpr->getSourceRange(); - attr.setInvalid(); + Attr.setInvalid(); return true; } if (Context.Target.getRegParmMax() == 0) { - Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); - attr.setInvalid(); + Attr.setInvalid(); return true; } numParams = NumParams.getZExtValue(); if (numParams > Context.Target.getRegParmMax()) { - Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number) + Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); - attr.setInvalid(); + Attr.setInvalid(); return true; } return false; } -static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){ +static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ if (S.LangOpts.CUDA) { // check the attribute arguments. if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { @@ -2580,7 +2607,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){ return; } - if (!isFunctionOrMethod(d)) { + if (!isFunctionOrMethod(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionOrMethod; return; @@ -2608,7 +2635,7 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){ } } - d->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context, MaxThreads.getZExtValue(), MinBlocks.getZExtValue())); } else { @@ -2627,16 +2654,16 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { return type->isPointerType() || isValidSubjectOfNSAttribute(S, type); } -static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) { - ParmVarDecl *param = dyn_cast<ParmVarDecl>(d); +static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + ParmVarDecl *param = dyn_cast<ParmVarDecl>(D); if (!param) { - S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(attr.getLoc()) << attr.getName() << ExpectedParameter; + S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter; return; } bool typeOK, cf; - if (attr.getKind() == AttributeList::AT_ns_consumed) { + if (Attr.getKind() == AttributeList::AT_ns_consumed) { typeOK = isValidSubjectOfNSAttribute(S, param->getType()); cf = false; } else { @@ -2645,47 +2672,52 @@ static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) { } if (!typeOK) { - S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << SourceRange(attr.getLoc()) << attr.getName() << cf; + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) + << SourceRange(Attr.getLoc()) << Attr.getName() << cf; return; } if (cf) - param->addAttr(::new (S.Context) CFConsumedAttr(attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context)); else - param->addAttr(::new (S.Context) NSConsumedAttr(attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context)); } -static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr, - Sema &S) { - if (!isa<ObjCMethodDecl>(d)) { - S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(attr.getLoc()) << attr.getName() << ExpectedMethod; +static void handleNSConsumesSelfAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!isa<ObjCMethodDecl>(D)) { + S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod; return; } - d->addAttr(::new (S.Context) NSConsumesSelfAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context)); } -static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr, - Sema &S) { +static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { QualType returnType; - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) returnType = MD->getResultType(); - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) + else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) + returnType = PD->getType(); + else if (S.getLangOptions().ObjCAutoRefCount && hasDeclarator(D) && + (Attr.getKind() == AttributeList::AT_ns_returns_retained)) + return; // ignore: was handled as a type attribute + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) returnType = FD->getResultType(); else { - S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(attr.getLoc()) << attr.getName() + S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) + << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedFunctionOrMethod; return; } bool typeOK; bool cf; - switch (attr.getKind()) { + switch (Attr.getKind()) { default: llvm_unreachable("invalid ownership attribute"); return; case AttributeList::AT_ns_returns_autoreleased: case AttributeList::AT_ns_returns_retained: @@ -2702,39 +2734,95 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr, } if (!typeOK) { - S.Diag(d->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(attr.getLoc()) - << attr.getName() << isa<ObjCMethodDecl>(d) << cf; + S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(Attr.getLoc()) + << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; return; } - switch (attr.getKind()) { + switch (Attr.getKind()) { default: assert(0 && "invalid ownership attribute"); return; case AttributeList::AT_ns_returns_autoreleased: - d->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_cf_returns_not_retained: - d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_cf_returns_retained: - d->addAttr(::new (S.Context) CFReturnsRetainedAttr(attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_retained: - d->addAttr(::new (S.Context) NSReturnsRetainedAttr(attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), S.Context)); return; }; } +static void handleObjCOwnershipAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (hasDeclarator(D)) return; + + SourceLocation L = Attr.getLoc(); + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(L, L) << Attr.getName() << 12 /* variable */; +} + +static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) { + SourceLocation L = Attr.getLoc(); + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(L, L) << Attr.getName() << 12 /* variable */; + return; + } + + ValueDecl *vd = cast<ValueDecl>(D); + QualType type = vd->getType(); + + if (!type->isDependentType() && + !type->isObjCLifetimeType()) { + S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type) + << type; + return; + } + + Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); + + // If we have no lifetime yet, check the lifetime we're presumably + // going to infer. + if (lifetime == Qualifiers::OCL_None && !type->isDependentType()) + lifetime = type->getObjCARCImplicitLifetime(); + + switch (lifetime) { + case Qualifiers::OCL_None: + assert(type->isDependentType() && + "didn't infer lifetime for non-dependent type?"); + break; + + case Qualifiers::OCL_Weak: // meaningful + case Qualifiers::OCL_Strong: // meaningful + break; + + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless) + << (lifetime == Qualifiers::OCL_Autoreleasing); + break; + } + + D->addAttr(::new (S.Context) + ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context)); +} + static bool isKnownDeclSpecAttr(const AttributeList &Attr) { return Attr.getKind() == AttributeList::AT_dllimport || Attr.getKind() == AttributeList::AT_dllexport || @@ -2745,13 +2833,12 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) { // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// -static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.Microsoft || S.LangOpts.Borland) { // check the attribute arguments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + if (!checkAttributeNumArgs(S, Attr, 1)) return; - } + Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); if (Str == 0 || Str->isWide()) { @@ -2794,7 +2881,7 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) { I++; } - d->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context, Str->getString())); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid"; @@ -2804,24 +2891,24 @@ static void HandleUuidAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Top Level Sema Entry Points //===----------------------------------------------------------------------===// -static void ProcessNonInheritableDeclAttr(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) { +static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, + const AttributeList &Attr) { switch (Attr.getKind()) { - case AttributeList::AT_device: HandleDeviceAttr (D, Attr, S); break; - case AttributeList::AT_host: HandleHostAttr (D, Attr, S); break; - case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; + case AttributeList::AT_device: handleDeviceAttr (S, D, Attr); break; + case AttributeList::AT_host: handleHostAttr (S, D, Attr); break; + case AttributeList::AT_overloadable:handleOverloadableAttr(S, D, Attr); break; default: break; } } -static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S) { +static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, + const AttributeList &Attr) { switch (Attr.getKind()) { - case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; - case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; + case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break; + case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break; case AttributeList::AT_IBOutletCollection: - HandleIBOutletCollection(D, Attr, S); break; + handleIBOutletCollection(S, D, Attr); break; case AttributeList::AT_address_space: case AttributeList::AT_opencl_image_access: case AttributeList::AT_objc_gc: @@ -2837,100 +2924,108 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, // Ignore, this is a non-inheritable attribute, handled // by ProcessNonInheritableDeclAttr. break; - case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; - case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; + case AttributeList::AT_alias: handleAliasAttr (S, D, Attr); break; + case AttributeList::AT_aligned: handleAlignedAttr (S, D, Attr); break; case AttributeList::AT_always_inline: - HandleAlwaysInlineAttr (D, Attr, S); break; + handleAlwaysInlineAttr (S, D, Attr); break; case AttributeList::AT_analyzer_noreturn: - HandleAnalyzerNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; - case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break; + handleAnalyzerNoReturnAttr (S, D, Attr); break; + case AttributeList::AT_annotate: handleAnnotateAttr (S, D, Attr); break; + case AttributeList::AT_availability:handleAvailabilityAttr(S, D, Attr); break; case AttributeList::AT_carries_dependency: - HandleDependencyAttr (D, Attr, S); break; - case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break; - case AttributeList::AT_constant: HandleConstantAttr (D, Attr, S); break; - case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; - case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; - case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; + handleDependencyAttr (S, D, Attr); break; + case AttributeList::AT_common: handleCommonAttr (S, D, Attr); break; + case AttributeList::AT_constant: handleConstantAttr (S, D, Attr); break; + case AttributeList::AT_constructor: handleConstructorAttr (S, D, Attr); break; + case AttributeList::AT_deprecated: handleDeprecatedAttr (S, D, Attr); break; + case AttributeList::AT_destructor: handleDestructorAttr (S, D, Attr); break; case AttributeList::AT_ext_vector_type: - HandleExtVectorTypeAttr(scope, D, Attr, S); + handleExtVectorTypeAttr(S, scope, D, Attr); break; - case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; - case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; - case AttributeList::AT_global: HandleGlobalAttr (D, Attr, S); break; - case AttributeList::AT_gnu_inline: HandleGNUInlineAttr (D, Attr, S); break; + case AttributeList::AT_format: handleFormatAttr (S, D, Attr); break; + case AttributeList::AT_format_arg: handleFormatArgAttr (S, D, Attr); break; + case AttributeList::AT_global: handleGlobalAttr (S, D, Attr); break; + case AttributeList::AT_gnu_inline: handleGNUInlineAttr (S, D, Attr); break; case AttributeList::AT_launch_bounds: - HandleLaunchBoundsAttr(D, Attr, S); + handleLaunchBoundsAttr(S, D, Attr); break; - case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; - case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; - case AttributeList::AT_may_alias: HandleMayAliasAttr (D, Attr, S); break; - case AttributeList::AT_nocommon: HandleNoCommonAttr (D, Attr, S); break; - case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; + case AttributeList::AT_mode: handleModeAttr (S, D, Attr); break; + case AttributeList::AT_malloc: handleMallocAttr (S, D, Attr); break; + case AttributeList::AT_may_alias: handleMayAliasAttr (S, D, Attr); break; + case AttributeList::AT_nocommon: handleNoCommonAttr (S, D, Attr); break; + case AttributeList::AT_nonnull: handleNonNullAttr (S, D, Attr); break; case AttributeList::AT_ownership_returns: case AttributeList::AT_ownership_takes: case AttributeList::AT_ownership_holds: - HandleOwnershipAttr (D, Attr, S); break; - case AttributeList::AT_naked: HandleNakedAttr (D, Attr, S); break; - case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; - case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; - case AttributeList::AT_shared: HandleSharedAttr (D, Attr, S); break; - case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break; + handleOwnershipAttr (S, D, Attr); break; + case AttributeList::AT_naked: handleNakedAttr (S, D, Attr); break; + case AttributeList::AT_noreturn: handleNoReturnAttr (S, D, Attr); break; + case AttributeList::AT_nothrow: handleNothrowAttr (S, D, Attr); break; + case AttributeList::AT_shared: handleSharedAttr (S, D, Attr); break; + case AttributeList::AT_vecreturn: handleVecReturnAttr (S, D, Attr); break; + + case AttributeList::AT_objc_ownership: + handleObjCOwnershipAttr(S, D, Attr); break; + case AttributeList::AT_objc_precise_lifetime: + handleObjCPreciseLifetimeAttr(S, D, Attr); break; // Checker-specific. case AttributeList::AT_cf_consumed: - case AttributeList::AT_ns_consumed: HandleNSConsumedAttr (D, Attr, S); break; + case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break; case AttributeList::AT_ns_consumes_self: - HandleNSConsumesSelfAttr(D, Attr, S); break; + handleNSConsumesSelfAttr(S, D, Attr); break; case AttributeList::AT_ns_returns_autoreleased: case AttributeList::AT_ns_returns_not_retained: case AttributeList::AT_cf_returns_not_retained: case AttributeList::AT_ns_returns_retained: case AttributeList::AT_cf_returns_retained: - HandleNSReturnsRetainedAttr(D, Attr, S); break; + handleNSReturnsRetainedAttr(S, D, Attr); break; case AttributeList::AT_reqd_wg_size: - HandleReqdWorkGroupSize(D, Attr, S); break; + handleReqdWorkGroupSize(S, D, Attr); break; case AttributeList::AT_init_priority: - HandleInitPriorityAttr(D, Attr, S); break; + handleInitPriorityAttr(S, D, Attr); break; - case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; - case AttributeList::AT_MsStruct: HandleMsStructAttr (D, Attr, S); break; - case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; - case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; - case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; - case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; - case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break; - case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); + case AttributeList::AT_packed: handlePackedAttr (S, D, Attr); break; + case AttributeList::AT_MsStruct: handleMsStructAttr (S, D, Attr); break; + case AttributeList::AT_section: handleSectionAttr (S, D, Attr); break; + case AttributeList::AT_unavailable: handleUnavailableAttr (S, D, Attr); break; + case AttributeList::AT_arc_weakref_unavailable: + handleArcWeakrefUnavailableAttr (S, D, Attr); break; - case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; - case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break; - case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; + case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break; + case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break; + case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break; + case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr); + break; + case AttributeList::AT_weak: handleWeakAttr (S, D, Attr); break; + case AttributeList::AT_weakref: handleWeakRefAttr (S, D, Attr); break; + case AttributeList::AT_weak_import: handleWeakImportAttr (S, D, Attr); break; case AttributeList::AT_transparent_union: - HandleTransparentUnionAttr(D, Attr, S); + handleTransparentUnionAttr(S, D, Attr); break; case AttributeList::AT_objc_exception: - HandleObjCExceptionAttr(D, Attr, S); + handleObjCExceptionAttr(S, D, Attr); break; case AttributeList::AT_objc_method_family: - HandleObjCMethodFamilyAttr(D, Attr, S); + handleObjCMethodFamilyAttr(S, D, Attr); break; - case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; - case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; - case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; - case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; - case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; - case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; - case AttributeList::AT_nodebug: HandleNoDebugAttr (D, Attr, S); break; - case AttributeList::AT_noinline: HandleNoInlineAttr (D, Attr, S); break; - case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; + case AttributeList::AT_nsobject: handleObjCNSObject (S, D, Attr); break; + case AttributeList::AT_blocks: handleBlocksAttr (S, D, Attr); break; + case AttributeList::AT_sentinel: handleSentinelAttr (S, D, Attr); break; + case AttributeList::AT_const: handleConstAttr (S, D, Attr); break; + case AttributeList::AT_pure: handlePureAttr (S, D, Attr); break; + case AttributeList::AT_cleanup: handleCleanupAttr (S, D, Attr); break; + case AttributeList::AT_nodebug: handleNoDebugAttr (S, D, Attr); break; + case AttributeList::AT_noinline: handleNoInlineAttr (S, D, Attr); break; + case AttributeList::AT_regparm: handleRegparmAttr (S, D, Attr); break; case AttributeList::IgnoredAttribute: // Just ignore break; case AttributeList::AT_no_instrument_function: // Interacts with -pg. - HandleNoInstrumentFunctionAttr(D, Attr, S); + handleNoInstrumentFunctionAttr(S, D, Attr); break; case AttributeList::AT_stdcall: case AttributeList::AT_cdecl: @@ -2938,13 +3033,13 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_thiscall: case AttributeList::AT_pascal: case AttributeList::AT_pcs: - HandleCallConvAttr(D, Attr, S); + handleCallConvAttr(S, D, Attr); break; case AttributeList::AT_opencl_kernel_function: - HandleOpenCLKernelAttr(D, Attr, S); + handleOpenCLKernelAttr(S, D, Attr); break; case AttributeList::AT_uuid: - HandleUuidAttr(D, Attr, S); + handleUuidAttr(S, D, Attr); break; default: // Ask target about the attribute. @@ -2960,8 +3055,8 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to /// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). -static void ProcessDeclAttribute(Scope *scope, Decl *D, - const AttributeList &Attr, Sema &S, +static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, + const AttributeList &Attr, bool NonInheritable, bool Inheritable) { if (Attr.isInvalid()) return; @@ -2971,10 +3066,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, return; if (NonInheritable) - ProcessNonInheritableDeclAttr(scope, D, Attr, S); + ProcessNonInheritableDeclAttr(S, scope, D, Attr); if (Inheritable) - ProcessInheritableDeclAttr(scope, D, Attr, S); + ProcessInheritableDeclAttr(S, scope, D, Attr); } /// ProcessDeclAttributeList - Apply all the decl attributes in the specified @@ -2983,7 +3078,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList, bool NonInheritable, bool Inheritable) { for (const AttributeList* l = AttrList; l; l = l->getNext()) { - ProcessDeclAttribute(S, D, *l, *this, NonInheritable, Inheritable); + ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable); } // GCC accepts @@ -3085,6 +3180,32 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); } +/// Is the given declaration allowed to use a forbidden type? +static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { + // Private ivars are always okay. Unfortunately, people don't + // always properly make their ivars private, even in system headers. + // Plus we need to make fields okay, too. + if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl)) + return false; + + // Require it to be declared in a system header. + return S.Context.getSourceManager().isInSystemHeader(decl->getLocation()); +} + +/// Handle a delayed forbidden-type diagnostic. +static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, + Decl *decl) { + if (decl && isForbiddenTypeAllowed(S, decl)) { + decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context, + "this system declaration uses an unsupported type")); + return; + } + + S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) + << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); + diag.Triggered = true; +} + // This duplicates a vector push_back but hides the need to know the // size of the type. void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) { @@ -3126,7 +3247,7 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, // We only want to actually emit delayed diagnostics when we // successfully parsed a decl. - if (decl) { + if (decl && !decl->isInvalidDecl()) { // We emit all the active diagnostics, not just those starting // from the saved state. The idea is this: we get one push for a // decl spec and another for each declarator; in a decl group like: @@ -3147,6 +3268,10 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, case DelayedDiagnostic::Access: S.HandleDelayedAccessCheck(diag, decl); break; + + case DelayedDiagnostic::ForbiddenType: + handleDelayedForbiddenType(S, diag, decl); + break; } } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ce99efb..d793daf 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -185,9 +185,9 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { // FIXME: // // C++0x [except.spec]p14: - // [An] implicit exception-specification specifies the type-id T if and - // only if T is allowed by the exception-specification of a function directly - // invoked by f’s implicit definition; f shall allow all exceptions if any + // [An] implicit exception-specification specifies the type-id T if and + // only if T is allowed by the exception-specification of a function directly + // invoked by f's implicit definition; f shall allow all exceptions if any // function it directly invokes allows all exceptions, and f shall allow no // exceptions if every function it directly invokes allows no exceptions. // @@ -762,13 +762,6 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, QualType NewBaseType = Context.getCanonicalType(Bases[idx]->getType()); NewBaseType = NewBaseType.getLocalUnqualifiedType(); - if (!Class->hasObjectMember()) { - if (const RecordType *FDTTy = - NewBaseType.getTypePtr()->getAs<RecordType>()) - if (FDTTy->getDecl()->hasObjectMember()) - Class->setHasObjectMember(true); - } - if (KnownBaseTypes[NewBaseType]) { // C++ [class.mi]p3: // A class shall not be specified as a direct base class of a @@ -1086,14 +1079,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(!DS.isFriendSpecified()); assert(!Init || !HasDeferredInit); - bool isFunc = false; - if (D.isFunctionDeclarator()) - isFunc = true; - else if (D.getNumTypeObjects() == 0 && - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename) { - QualType TDType = GetTypeFromParser(DS.getRepAsType()); - isFunc = TDType->isFunctionType(); - } + bool isFunc = D.isDeclarationOfFunction(); // C++ 9.2p6: A member shall not be declared to have automatic storage // duration (auto, register) or with the extern storage-class-specifier. @@ -1440,25 +1426,27 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, } // If no results were found, try to correct typos. + TypoCorrection Corr; if (R.empty() && BaseType.isNull() && - CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && - R.isSingleResult()) { - if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { + (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, + ClassDecl, false, CTC_NoKeywords))) { + std::string CorrectedStr(Corr.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions())); + if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) { if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) { // We have found a non-static data member with a similar // name to what was typed; complain and initialize that // member. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) - << MemberOrBase << true << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << MemberOrBase << true << CorrectedQuotedStr + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); Diag(Member->getLocation(), diag::note_previous_decl) - << Member->getDeclName(); + << CorrectedQuotedStr; return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, LParenLoc, RParenLoc); } - } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) { + } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) { const CXXBaseSpecifier *DirectBaseSpec; const CXXBaseSpecifier *VirtualBaseSpec; if (FindBaseInitializer(*this, ClassDecl, @@ -1468,9 +1456,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, // similar name to what was typed; complain and initialize // that base class. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) - << MemberOrBase << false << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << MemberOrBase << false << CorrectedQuotedStr + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec : VirtualBaseSpec; @@ -1617,14 +1604,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc); - - // Erase any temporaries within this evaluation context; we're not - // going to track them in the AST, since we'll be rebuilding the - // ASTs during template instantiation. - ExprTemporaries.erase( - ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, - ExprTemporaries.end()); + RParenLoc, + Member->getType().getNonReferenceType()); + + DiscardCleanupsInEvaluationContext(); } else { // Initialize the member. InitializedEntity MemberEntity = @@ -1658,8 +1641,9 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. if (CurContext->isDependentContext()) - Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc); + Init = new (Context) ParenListExpr( + Context, LParenLoc, Args, NumArgs, RParenLoc, + Member->getType().getNonReferenceType()); else Init = MemberInit.get(); } @@ -1715,22 +1699,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, if (DelegationInit.isInvalid()) return true; - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the base - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) { - ExprResult Init - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, - NumArgs, RParenLoc)); - return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, - Constructor, Init.takeAs<Expr>(), - RParenLoc); - } - + assert(!CurContext->isDependentContext()); return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, DelegationInit.takeAs<Expr>(), RParenLoc); @@ -1815,14 +1784,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // any of the arguments are type-dependent expressions. ExprResult BaseInit = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc)); + RParenLoc, BaseType)); - // Erase any temporaries within this evaluation context; we're not - // going to track them in the AST, since we'll be rebuilding the - // ASTs during template instantiation. - ExprTemporaries.erase( - ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, - ExprTemporaries.end()); + DiscardCleanupsInEvaluationContext(); return new (Context) CXXCtorInitializer(Context, BaseTInfo, /*IsVirtual=*/false, @@ -1878,7 +1842,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (CurContext->isDependentContext()) { ExprResult Init = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc)); + RParenLoc, BaseType)); return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), LParenLoc, @@ -1989,6 +1953,11 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, if (ImplicitInitKind == IIK_Copy) { ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); + + // Suppress copying zero-width bitfields. + if (const Expr *Width = Field->getBitWidth()) + if (Width->EvaluateAsInt(SemaRef.Context) == 0) + return false; Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, @@ -2134,6 +2103,20 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, } } + if (SemaRef.getLangOptions().ObjCAutoRefCount && + FieldBaseElementType->isObjCRetainableType() && + FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None && + FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { + // Instant objects: + // Default-initialize Objective-C pointers to NULL. + CXXMemberInit + = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + Loc, Loc, + new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()), + Loc); + return false; + } + // Nothing to initialize. CXXMemberInit = 0; return false; @@ -2207,11 +2190,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, } } - // Fallthrough and construct a default initializer for the union as - // a whole, which can call its default constructor if such a thing exists - // (C++0x perhaps). FIXME: It's not clear that this is the correct - // behavior going forward with C++0x, when anonymous unions there are - // finalized, we should revisit this. + // FIXME: C++0x unrestricted unions might call a default constructor here. + return false; } else { // For structs, we simply descend through to initialize all members where // necessary. @@ -2259,11 +2239,10 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, return false; } -bool -Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, - CXXCtorInitializer **Initializers, - unsigned NumInitializers, - bool AnyErrors) { +bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, + CXXCtorInitializer **Initializers, + unsigned NumInitializers, + bool AnyErrors) { if (Constructor->getDeclContext()->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. @@ -3405,7 +3384,7 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *RD = CD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus0x) + if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; SourceLocation Loc = CD->getLocation(); @@ -3586,7 +3565,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *RD = CD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus0x) + if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; SourceLocation Loc = CD->getLocation(); @@ -3636,7 +3615,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { // resolution, as applied to B's [copy] constructor, results in an // ambiguity or a function that is deleted or inaccessible from the // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); if (!BaseCtor || BaseCtor->isDeleted()) return true; if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != @@ -3664,7 +3643,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { // resolution, as applied to B's [copy] constructor, results in an // ambiguity or a function that is deleted or inaccessible from the // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals); + CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); if (!BaseCtor || BaseCtor->isDeleted()) return true; if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != @@ -3726,8 +3705,8 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { // cannot be [copied] because overload resolution, as applied to B's // [copy] constructor, results in an ambiguity or a function that is // deleted or inaccessible from the defaulted constructor - CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord, - ArgQuals); + CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord, + ArgQuals); if (!FieldCtor || FieldCtor->isDeleted()) return true; if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), @@ -3742,7 +3721,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus0x) + if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; SourceLocation Loc = MD->getLocation(); @@ -3752,19 +3731,15 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { bool Union = RD->isUnion(); - bool ConstArg = - MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified(); + unsigned ArgQuals = + MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? + Qualifiers::Const : 0; // We do this because we should never actually use an anonymous // union's constructor. if (Union && RD->isAnonymousStructOrUnion()) return false; - DeclarationName OperatorName = - Context.DeclarationNames.getCXXOperatorName(OO_Equal); - LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName); - R.suppressDiagnostics(); - // FIXME: We should put some diagnostic logic right into this function. // C++0x [class.copy]/11 @@ -3786,37 +3761,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { // resolution, as applied to B's [copy] assignment operator, results in // an ambiguity or a function that is deleted or inaccessible from the // assignment operator - - LookupQualifiedName(R, BaseDecl, false); - - // Filter out any result that isn't a copy-assignment operator. - LookupResult::Filter F = R.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - if (Method->isCopyAssignmentOperator()) - continue; - - F.erase(); - } - F.done(); - - // Build a fake argument expression - QualType ArgType = BaseType; - QualType ThisType = BaseType; - if (ConstArg) - ArgType.addConst(); - Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) - , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) - }; - - OverloadCandidateSet OCS((Loc)); - OverloadCandidateSet::iterator Best; - - AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); - - if (OCS.BestViableFunction(*this, Loc, Best, false) != - OR_Success) + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) + return true; + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } @@ -3831,37 +3780,11 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { // resolution, as applied to B's [copy] assignment operator, results in // an ambiguity or a function that is deleted or inaccessible from the // assignment operator - - LookupQualifiedName(R, BaseDecl, false); - - // Filter out any result that isn't a copy-assignment operator. - LookupResult::Filter F = R.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - if (Method->isCopyAssignmentOperator()) - continue; - - F.erase(); - } - F.done(); - - // Build a fake argument expression - QualType ArgType = BaseType; - QualType ThisType = BaseType; - if (ConstArg) - ArgType.addConst(); - Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) - , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) - }; - - OverloadCandidateSet OCS((Loc)); - OverloadCandidateSet::iterator Best; - - AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); - - if (OCS.BestViableFunction(*this, Loc, Best, false) != - OR_Success) + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) + return true; + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } @@ -3908,37 +3831,12 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { return true; } - LookupQualifiedName(R, FieldRecord, false); - - // Filter out any result that isn't a copy-assignment operator. - LookupResult::Filter F = R.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - if (Method->isCopyAssignmentOperator()) - continue; - - F.erase(); - } - F.done(); - - // Build a fake argument expression - QualType ArgType = FieldType; - QualType ThisType = FieldType; - if (ConstArg) - ArgType.addConst(); - Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue) - , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue) - }; - - OverloadCandidateSet OCS((Loc)); - OverloadCandidateSet::iterator Best; - - AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS); - - if (OCS.BestViableFunction(*this, Loc, Best, false) != - OR_Success) - return true; + CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals, + false, 0); + if (!CopyOper || CopyOper->isDeleted()) + return false; + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) + return false; } } @@ -3948,7 +3846,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) { CXXRecordDecl *RD = DD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus0x) + if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; SourceLocation Loc = DD->getLocation(); @@ -4806,6 +4704,13 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // Make our StdNamespace cache point at the first real definition of the // "std" namespace. StdNamespace = Namespc; + + // Add this instance of "std" to the set of known namespaces + KnownNamespaces[Namespc] = false; + } else if (!Namespc->isInline()) { + // Since this is an "original" namespace, add it to the known set of + // namespaces if it is not an inline namespace. + KnownNamespaces[Namespc] = false; } PushOnScopeChains(Namespc, DeclRegionScope); @@ -4941,6 +4846,39 @@ static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { } } +static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident) { + R.clear(); + if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(), + R.getLookupKind(), Sc, &SS, NULL, + false, S.CTC_NoKeywords, NULL)) { + if (Corrected.getCorrectionDeclAs<NamespaceDecl>() || + Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) { + std::string CorrectedStr(Corrected.getAsString(S.getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions())); + if (DeclContext *DC = S.computeDeclContext(SS, false)) + S.Diag(IdentLoc, diag::err_using_directive_member_suggest) + << Ident << DC << CorrectedQuotedStr << SS.getRange() + << FixItHint::CreateReplacement(IdentLoc, CorrectedStr); + else + S.Diag(IdentLoc, diag::err_using_directive_suggest) + << Ident << CorrectedQuotedStr + << FixItHint::CreateReplacement(IdentLoc, CorrectedStr); + + S.Diag(Corrected.getCorrectionDecl()->getLocation(), + diag::note_namespace_defined_here) << CorrectedQuotedStr; + + Ident = Corrected.getCorrectionAsIdentifierInfo(); + R.addDecl(Corrected.getCorrectionDecl()); + return true; + } + R.setLookupName(Ident); + } + return false; +} + Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, @@ -4969,6 +4907,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, return 0; if (R.empty()) { + R.clear(); // Allow "using namespace std;" or "using namespace ::std;" even if // "std" hasn't been defined yet, for GCC compatibility. if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) && @@ -4978,27 +4917,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, R.resolveKind(); } // Otherwise, attempt typo correction. - else if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, - CTC_NoKeywords, 0)) { - if (R.getAsSingle<NamespaceDecl>() || - R.getAsSingle<NamespaceAliasDecl>()) { - if (DeclContext *DC = computeDeclContext(SS, false)) - Diag(IdentLoc, diag::err_using_directive_member_suggest) - << NamespcName << DC << Corrected << SS.getRange() - << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString()); - else - Diag(IdentLoc, diag::err_using_directive_suggest) - << NamespcName << Corrected - << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString()); - Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here) - << Corrected; - - NamespcName = Corrected.getAsIdentifierInfo(); - } else { - R.clear(); - R.setLookupName(NamespcName); - } - } + else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName); } if (!R.empty()) { @@ -5065,6 +4984,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); switch (Name.getKind()) { + case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: @@ -5916,30 +5836,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, return 0; if (R.empty()) { - if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, - CTC_NoKeywords, 0)) { - if (R.getAsSingle<NamespaceDecl>() || - R.getAsSingle<NamespaceAliasDecl>()) { - if (DeclContext *DC = computeDeclContext(SS, false)) - Diag(IdentLoc, diag::err_using_directive_member_suggest) - << Ident << DC << Corrected << SS.getRange() - << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString()); - else - Diag(IdentLoc, diag::err_using_directive_suggest) - << Ident << Corrected - << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString()); - - Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here) - << Corrected; - - Ident = Corrected.getAsIdentifierInfo(); - } else { - R.clear(); - R.setLookupName(Ident); - } - } - - if (R.empty()) { + if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) { Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange(); return 0; } @@ -5982,6 +5879,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(Context); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; // Direct base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), @@ -6355,7 +6254,9 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { // An implicitly declared special member function (Clause 12) shall have // an exception-specification. ImplicitExceptionSpecification ExceptSpec(Context); - + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + // Direct base-class destructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); @@ -6687,61 +6588,12 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Loc, Copy.take()); } -/// \brief Determine whether the given class has a copy assignment operator -/// that accepts a const-qualified argument. -static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) { - CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(CClass); - - if (!Class->hasDeclaredCopyAssignment()) - S.DeclareImplicitCopyAssignment(Class); - - QualType ClassType = S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)); - DeclarationName OpName - = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); - - DeclContext::lookup_const_iterator Op, OpEnd; - for (llvm::tie(Op, OpEnd) = Class->lookup(OpName); Op != OpEnd; ++Op) { - // C++ [class.copy]p9: - // A user-declared copy assignment operator is a non-static non-template - // member function of class X with exactly one parameter of type X, X&, - // const X&, volatile X& or const volatile X&. - const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); - if (!Method) - continue; - - if (Method->isStatic()) - continue; - if (Method->getPrimaryTemplate()) - continue; - const FunctionProtoType *FnType = - Method->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Overloaded operator has no prototype."); - // Don't assert on this; an invalid decl might have been left in the AST. - if (FnType->getNumArgs() != 1 || FnType->isVariadic()) - continue; - bool AcceptsConst = true; - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()){ - ArgType = Ref->getPointeeType(); - // Is it a non-const lvalue reference? - if (!ArgType.isConstQualified()) - AcceptsConst = false; - } - if (!S.Context.hasSameUnqualifiedType(ArgType, ClassType)) - continue; - - // We have a single argument of type cv X or cv X&, i.e. we've found the - // copy assignment operator. Return whether it accepts const arguments. - return AcceptsConst; - } - assert(Class->isInvalidDecl() && - "No copy assignment operator declared in valid code."); - return false; -} - std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( CXXRecordDecl *ClassDecl) { + if (ClassDecl->isInvalidDecl()) + return std::make_pair(ImplicitExceptionSpecification(Context), false); + // C++ [class.copy]p10: // If the class definition does not explicitly declare a copy // assignment operator, one is declared implicitly. @@ -6759,11 +6611,28 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); HasConstCopyAssignment && Base != BaseEnd; ++Base) { + // We'll handle this below + if (LangOpts.CPlusPlus0x && Base->isVirtual()) + continue; + assert(!Base->getType()->isDependentType() && "Cannot generate implicit members for class with dependent bases."); - const CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - HasConstCopyAssignment = hasConstCopyAssignment(*this, BaseClassDecl); + CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); + LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0, + &HasConstCopyAssignment); + } + + // In C++0x, the above citation has "or virtual added" + if (LangOpts.CPlusPlus0x) { + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + HasConstCopyAssignment && Base != BaseEnd; ++Base) { + assert(!Base->getType()->isDependentType() && + "Cannot generate implicit members for class with dependent bases."); + CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl(); + LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0, + &HasConstCopyAssignment); + } } // -- for all the nonstatic data members of X that are of a class @@ -6775,10 +6644,9 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( HasConstCopyAssignment && Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - const CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - HasConstCopyAssignment = hasConstCopyAssignment(*this, FieldClassDecl); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const, false, 0, + &HasConstCopyAssignment); } } @@ -6790,36 +6658,48 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] + + // It is unspecified whether or not an implicit copy assignment operator + // attempts to deduplicate calls to assignment operators of virtual bases are + // made. As such, this exception specification is effectively unspecified. + // Based on a similar decision made for constness in C++0x, we're erring on + // the side of assuming such calls to be made regardless of whether they + // actually happen. ImplicitExceptionSpecification ExceptSpec(Context); + unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { + if (Base->isVirtual()) + continue; + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - if (!BaseClassDecl->hasDeclaredCopyAssignment()) - DeclareImplicitCopyAssignment(BaseClassDecl); + if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, + ArgQuals, false, 0)) + ExceptSpec.CalledDecl(CopyAssign); + } - if (CXXMethodDecl *CopyAssign - = BaseClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment)) + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + Base != BaseEnd; ++Base) { + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl, + ArgQuals, false, 0)) ExceptSpec.CalledDecl(CopyAssign); } + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - - if (!FieldClassDecl->hasDeclaredCopyAssignment()) - DeclareImplicitCopyAssignment(FieldClassDecl); - - if (CXXMethodDecl *CopyAssign - = FieldClassDecl->getCopyAssignmentOperator(HasConstCopyAssignment)) - ExceptSpec.CalledDecl(CopyAssign); - } + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + if (CXXMethodDecl *CopyAssign = + LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0)) + ExceptSpec.CalledDecl(CopyAssign); + } } return std::make_pair(ExceptSpec, HasConstCopyAssignment); @@ -6875,7 +6755,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); - if (ShouldDeleteCopyAssignmentOperator(CopyAssignment)) + // C++0x [class.copy]p18: + // ... If the class definition declares a move constructor or move + // assignment operator, the implicitly declared copy assignment operator is + // defined as deleted; ... + if (ClassDecl->hasUserDeclaredMoveConstructor() || + ClassDecl->hasUserDeclaredMoveAssignment() || + ShouldDeleteCopyAssignmentOperator(CopyAssignment)) CopyAssignment->setDeletedAsWritten(); AddOverriddenMethods(ClassDecl, CopyAssignment); @@ -7014,6 +6900,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, Invalid = true; continue; } + + // Suppress assigning zero-width bitfields. + if (const Expr *Width = Field->getBitWidth()) + if (Width->EvaluateAsInt(Context) == 0) + continue; QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { @@ -7041,10 +6932,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // explicit assignments, do so. This optimization only applies for arrays // of scalars and arrays of class type with trivial copy-assignment // operators. - if (FieldType->isArrayType() && - (!BaseType->isRecordType() || - cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()) - ->hasTrivialCopyAssignment())) { + if (FieldType->isArrayType() && + BaseType.hasTrivialCopyAssignment(Context)) { // Compute the size of the memory buffer to be copied. QualType SizeType = Context.getSizeType(); llvm::APInt Size(Context.getTypeSize(SizeType), @@ -7179,6 +7068,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { + if (ClassDecl->isInvalidDecl()) + return std::make_pair(ImplicitExceptionSpecification(Context), false); + // C++ [class.copy]p5: // The implicitly-declared copy constructor for a class X will // have the form @@ -7202,8 +7094,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7212,8 +7104,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { ++Base) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - LookupCopyConstructor(BaseClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } // -- for all the nonstatic data members of X that are of a @@ -7226,8 +7118,8 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { ++Field) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { - LookupCopyConstructor(FieldClassDecl, Qualifiers::Const, - &HasConstCopyConstructor); + LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const, + &HasConstCopyConstructor); } } // Otherwise, the implicitly declared copy constructor will have @@ -7251,7 +7143,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *CopyConstructor = - LookupCopyConstructor(BaseClassDecl, Quals)) + LookupCopyingConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), @@ -7261,7 +7153,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *CopyConstructor = - LookupCopyConstructor(BaseClassDecl, Quals)) + LookupCopyingConstructor(BaseClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -7271,7 +7163,7 @@ Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { QualType FieldType = Context.getBaseElementType((*Field)->getType()); if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { if (CXXConstructorDecl *CopyConstructor = - LookupCopyConstructor(FieldClassDecl, Quals)) + LookupCopyingConstructor(FieldClassDecl, Quals)) ExceptSpec.CalledDecl(CopyConstructor); } } @@ -7334,7 +7226,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); - if (ShouldDeleteCopyConstructor(CopyConstructor)) + // C++0x [class.copy]p7: + // ... If the class definition declares a move constructor or move + // assignment operator, the implicitly declared constructor is defined as + // deleted; ... + if (ClassDecl->hasUserDeclaredMoveConstructor() || + ClassDecl->hasUserDeclaredMoveAssignment() || + ShouldDeleteCopyConstructor(CopyConstructor)) CopyConstructor->setDeletedAsWritten(); return CopyConstructor; @@ -7523,6 +7421,10 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, VDecl->setTypeSourceInfo(DeducedType); VDecl->setType(DeducedType->getType()); + // In ARC, infer lifetime. + if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) + VDecl->setInvalidDecl(); + // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDeclaration()) @@ -7605,9 +7507,9 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, // Store the initialization expressions as a ParenListExpr. unsigned NumExprs = Exprs.size(); - VDecl->setInit(new (Context) ParenListExpr(Context, LParenLoc, - (Expr **)Exprs.release(), - NumExprs, RParenLoc)); + VDecl->setInit(new (Context) ParenListExpr( + Context, LParenLoc, (Expr **)Exprs.release(), NumExprs, RParenLoc, + VDecl->getType().getNonReferenceType())); return; } @@ -8143,10 +8045,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Diag(Loc, diag::err_objc_object_catch); Invalid = true; } else if (T->isObjCObjectPointerType()) { - if (!getLangOptions().ObjCNonFragileABI) { - Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile); - Invalid = true; - } + if (!getLangOptions().ObjCNonFragileABI) + Diag(Loc, diag::warn_objc_pointer_cxx_catch_fragile); } } @@ -8154,7 +8054,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, ExDeclType, TInfo, SC_None, SC_None); ExDecl->setExceptionVariable(true); - if (!Invalid) { + if (!Invalid && !ExDeclType->isDependentType()) { if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) { // C++ [except.handle]p16: // The object declared in an exception-declaration or, if the @@ -9020,25 +8920,16 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { // new class or enumeration. assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); - - TagDecl *OwnedTag = 0; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag); - QualType Ty = TInfo->getType(); - - if (Ty->isFunctionType()) { // The declarator shall not specify a function... - // We exit without creating a CXXConditionDeclExpr because a FunctionDecl - // would be created and CXXConditionDeclExpr wants a VarDecl. - Diag(D.getIdentifierLoc(), diag::err_invalid_use_of_function_type) - << D.getSourceRange(); - return DeclResult(); - } else if (OwnedTag && OwnedTag->isDefinition()) { - // The type-specifier-seq shall not declare a new class or enumeration. - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); - } - + Decl *Dcl = ActOnDeclarator(S, D); if (!Dcl) - return DeclResult(); + return true; + + if (isa<FunctionDecl>(Dcl)) { // The declarator shall not specify a function. + Diag(Dcl->getLocation(), diag::err_invalid_use_of_function_type) + << D.getSourceRange(); + return true; + } return Dcl; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index de9097e..aa8152b 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -16,14 +16,96 @@ #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceManager.h" #include "clang/Sema/DeclSpec.h" #include "llvm/ADT/DenseSet.h" using namespace clang; +/// Check whether the given method, which must be in the 'init' +/// family, is a valid member of that family. +/// +/// \param receiverTypeIfCall - if null, check this as if declaring it; +/// if non-null, check this as if making a call to it with the given +/// receiver type +/// +/// \return true to indicate that there was an error and appropriate +/// actions were taken +bool Sema::checkInitMethod(ObjCMethodDecl *method, + QualType receiverTypeIfCall) { + if (method->isInvalidDecl()) return true; + + // This castAs is safe: methods that don't return an object + // pointer won't be inferred as inits and will reject an explicit + // objc_method_family(init). + + // We ignore protocols here. Should we? What about Class? + + const ObjCObjectType *result = method->getResultType() + ->castAs<ObjCObjectPointerType>()->getObjectType(); + + if (result->isObjCId()) { + return false; + } else if (result->isObjCClass()) { + // fall through: always an error + } else { + ObjCInterfaceDecl *resultClass = result->getInterface(); + assert(resultClass && "unexpected object type!"); + + // It's okay for the result type to still be a forward declaration + // if we're checking an interface declaration. + if (resultClass->isForwardDecl()) { + if (receiverTypeIfCall.isNull() && + !isa<ObjCImplementationDecl>(method->getDeclContext())) + return false; + + // Otherwise, we try to compare class types. + } else { + // If this method was declared in a protocol, we can't check + // anything unless we have a receiver type that's an interface. + const ObjCInterfaceDecl *receiverClass = 0; + if (isa<ObjCProtocolDecl>(method->getDeclContext())) { + if (receiverTypeIfCall.isNull()) + return false; + + receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>() + ->getInterfaceDecl(); + + // This can be null for calls to e.g. id<Foo>. + if (!receiverClass) return false; + } else { + receiverClass = method->getClassInterface(); + assert(receiverClass && "method not associated with a class!"); + } + + // If either class is a subclass of the other, it's fine. + if (receiverClass->isSuperClassOf(resultClass) || + resultClass->isSuperClassOf(receiverClass)) + return false; + } + } + + SourceLocation loc = method->getLocation(); + + // If we're in a system header, and this is not a call, just make + // the method unusable. + if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) { + method->addAttr(new (Context) UnavailableAttr(loc, Context, + "init method returns a type unrelated to its receiver type")); + return true; + } + + // Otherwise, it's an error. + Diag(loc, diag::err_arc_init_method_unrelated_result_type); + method->setInvalidDecl(); + return true; +} + bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden, bool IsImplementation) { @@ -36,7 +118,7 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, QualType ResultType = NewMethod->getResultType(); SourceRange ResultTypeRange; if (const TypeSourceInfo *ResultTypeInfo - = NewMethod->getResultTypeSourceInfo()) + = NewMethod->getResultTypeSourceInfo()) ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); // Figure out which class this method is part of, if any. @@ -73,7 +155,15 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, return false; } - +/// \brief Check for consistency between a given method declaration and the +/// methods it overrides within the class hierarchy. +/// +/// This method walks the inheritance hierarchy starting at the given +/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with +/// the given new method (\p NewMethod) and any method it directly overrides +/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for +/// checking consistency, e.g., among return types for methods that return a +/// related result type. static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, DeclContext *DC, bool SkipCurrent = true) { @@ -99,10 +189,10 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, if (CheckObjCMethodOverrides(S, NewMethod, Category, false)) return true; } - + // Look through protocols. for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(), - IEnd = Class->protocol_end(); + IEnd = Class->protocol_end(); I != IEnd; ++I) if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) return true; @@ -115,7 +205,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) { // Look through protocols. for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(), - IEnd = Category->protocol_end(); + IEnd = Category->protocol_end(); I != IEnd; ++I) if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) return true; @@ -126,7 +216,7 @@ static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) { // Look through protocols. for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(), - IEnd = Protocol->protocol_end(); + IEnd = Protocol->protocol_end(); I != IEnd; ++I) if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) return true; @@ -141,13 +231,13 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC) { if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC)) return ::CheckObjCMethodOverrides(*this, NewMethod, Class); - + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) return ::CheckObjCMethodOverrides(*this, NewMethod, Category); - + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol); - + if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC)) return ::CheckObjCMethodOverrides(*this, NewMethod, Impl->getClassInterface()); @@ -159,6 +249,55 @@ bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext); } +/// \brief Check a method declaration for compatibility with the Objective-C +/// ARC conventions. +static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { + ObjCMethodFamily family = method->getMethodFamily(); + switch (family) { + case OMF_None: + case OMF_dealloc: + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_retainCount: + case OMF_self: + return false; + + case OMF_init: + // If the method doesn't obey the init rules, don't bother annotating it. + if (S.checkInitMethod(method, QualType())) + return true; + + method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(), + S.Context)); + + // Don't add a second copy of this attribute, but otherwise don't + // let it be suppressed. + if (method->hasAttr<NSReturnsRetainedAttr>()) + return false; + break; + + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + if (method->hasAttr<NSReturnsRetainedAttr>() || + method->hasAttr<NSReturnsNotRetainedAttr>() || + method->hasAttr<NSReturnsAutoreleasedAttr>()) + return false; + break; + + case OMF_performSelector: + // we don't annotate performSelector's + return true; + + } + + method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), + S.Context)); + return false; +} + static void DiagnoseObjCImplementedDeprecations(Sema &S, NamedDecl *ND, SourceLocation ImplLoc, @@ -212,6 +351,31 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { if ((*PI)->getIdentifier()) PushOnScopeChains(*PI, FnBodyScope); } + + // In ARC, disallow definition of retain/release/autorelease/retainCount + if (getLangOptions().ObjCAutoRefCount) { + switch (MDecl->getMethodFamily()) { + case OMF_retain: + case OMF_retainCount: + case OMF_release: + case OMF_autorelease: + Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def) + << MDecl->getSelector(); + break; + + case OMF_None: + case OMF_dealloc: + case OMF_alloc: + case OMF_init: + case OMF_mutableCopy: + case OMF_copy: + case OMF_new: + case OMF_self: + case OMF_performSelector: + break; + } + } + // Warn on implementating deprecated methods under // -Wdeprecated-implementations flag. if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) @@ -284,9 +448,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (!PrevDecl) { // Try to correct for a typo in the superclass name. - LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && - (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope, + NULL, NULL, false, CTC_NoKeywords); + if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) { Diag(SuperLoc, diag::err_undef_superclass_suggest) << SuperName << ClassName << PrevDecl->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_previous_decl) @@ -333,10 +498,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (!SuperClassDecl) Diag(SuperLoc, diag::err_undef_superclass) << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (SuperClassDecl->isForwardDecl()) - Diag(SuperLoc, diag::err_undef_superclass) + else if (SuperClassDecl->isForwardDecl()) { + Diag(SuperLoc, diag::err_forward_superclass) << SuperClassDecl->getDeclName() << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + Diag(SuperClassDecl->getLocation(), diag::note_forward_class); + SuperClassDecl = 0; + } } IDecl->setSuperClass(SuperClassDecl); IDecl->setSuperClassLoc(SuperLoc); @@ -494,12 +662,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); if (!PDecl) { - LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second, - LookupObjCProtocolName); - if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && - (PDecl = R.getAsSingle<ObjCProtocolDecl>())) { + TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second), + LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords); + if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) - << ProtocolId[i].first << R.getLookupName(); + << ProtocolId[i].first << Corrected.getCorrection(); Diag(PDecl->getLocation(), diag::note_previous_decl) << PDecl->getDeclName(); } @@ -736,20 +904,20 @@ Decl *Sema::ActOnStartClassImplementation( } else { // We did not find anything with the name ClassName; try to correct for // typos in the class name. - LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && - (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope, + NULL, NULL, false, CTC_NoKeywords); + if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) { // Suggest the (potentially) correct interface name. However, put the // fix-it hint itself in a separate note, since changing the name in // the warning would make the fix-it change semantics.However, don't // provide a code-modification hint or use the typo name for recovery, // because this is just a warning. The program may actually be correct. + DeclarationName CorrectedName = Corrected.getCorrection(); Diag(ClassLoc, diag::warn_undef_interface_suggest) - << ClassName << R.getLookupName(); - Diag(IDecl->getLocation(), diag::note_previous_decl) - << R.getLookupName() - << FixItHint::CreateReplacement(ClassLoc, - R.getLookupName().getAsString()); + << ClassName << CorrectedName; + Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName + << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString()); IDecl = 0; } else { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; @@ -915,6 +1083,9 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, bool &IncompleteImpl, unsigned DiagID) { + // No point warning no definition of method which is 'unavailable'. + if (method->hasAttr<UnavailableAttr>()) + return; if (!IncompleteImpl) { Diag(ImpLoc, diag::warn_incomplete_impl); IncompleteImpl = true; @@ -1091,11 +1262,84 @@ static void CheckMethodOverrideParam(Sema &S, S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) << getTypeRange(IfaceVar->getTypeSourceInfo()); } - + +/// In ARC, check whether the conventional meanings of the two methods +/// match. If they don't, it's a hard error. +static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, + ObjCMethodDecl *decl) { + ObjCMethodFamily implFamily = impl->getMethodFamily(); + ObjCMethodFamily declFamily = decl->getMethodFamily(); + if (implFamily == declFamily) return false; + + // Since conventions are sorted by selector, the only possibility is + // that the types differ enough to cause one selector or the other + // to fall out of the family. + assert(implFamily == OMF_None || declFamily == OMF_None); + + // No further diagnostics required on invalid declarations. + if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true; + + const ObjCMethodDecl *unmatched = impl; + ObjCMethodFamily family = declFamily; + unsigned errorID = diag::err_arc_lost_method_convention; + unsigned noteID = diag::note_arc_lost_method_convention; + if (declFamily == OMF_None) { + unmatched = decl; + family = implFamily; + errorID = diag::err_arc_gained_method_convention; + noteID = diag::note_arc_gained_method_convention; + } + + // Indexes into a %select clause in the diagnostic. + enum FamilySelector { + F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new + }; + FamilySelector familySelector = FamilySelector(); + + switch (family) { + case OMF_None: llvm_unreachable("logic error, no method convention"); + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_dealloc: + case OMF_retainCount: + case OMF_self: + case OMF_performSelector: + // Mismatches for these methods don't change ownership + // conventions, so we don't care. + return false; + + case OMF_init: familySelector = F_init; break; + case OMF_alloc: familySelector = F_alloc; break; + case OMF_copy: familySelector = F_copy; break; + case OMF_mutableCopy: familySelector = F_mutableCopy; break; + case OMF_new: familySelector = F_new; break; + } + + enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn }; + ReasonSelector reasonSelector; + + // The only reason these methods don't fall within their families is + // due to unusual result types. + if (unmatched->getResultType()->isObjCObjectPointerType()) { + reasonSelector = R_UnrelatedReturn; + } else { + reasonSelector = R_NonObjectReturn; + } + + S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector; + S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector; + + return true; +} void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl) { + if (getLangOptions().ObjCAutoRefCount && + checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl)) + return; + CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, IsProtocolMethodDecl); @@ -1204,7 +1448,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl); } -/// MatchAllMethodDeclarations - Check methods declaraed in interface or +/// MatchAllMethodDeclarations - Check methods declared in interface /// or protocol against those declared in their implementations. /// void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, @@ -1422,48 +1666,117 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, return CDecl; } +static bool tryMatchRecordTypes(ASTContext &Context, + Sema::MethodMatchStrategy strategy, + const Type *left, const Type *right); + +static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy, + QualType leftQT, QualType rightQT) { + const Type *left = + Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr(); + const Type *right = + Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr(); + + if (left == right) return true; + + // If we're doing a strict match, the types have to match exactly. + if (strategy == Sema::MMS_strict) return false; + + if (left->isIncompleteType() || right->isIncompleteType()) return false; + + // Otherwise, use this absurdly complicated algorithm to try to + // validate the basic, low-level compatibility of the two types. + + // As a minimum, require the sizes and alignments to match. + if (Context.getTypeInfo(left) != Context.getTypeInfo(right)) + return false; + + // Consider all the kinds of non-dependent canonical types: + // - functions and arrays aren't possible as return and parameter types + + // - vector types of equal size can be arbitrarily mixed + if (isa<VectorType>(left)) return isa<VectorType>(right); + if (isa<VectorType>(right)) return false; + + // - references should only match references of identical type + // - structs, unions, and Objective-C objects must match more-or-less + // exactly + // - everything else should be a scalar + if (!left->isScalarType() || !right->isScalarType()) + return tryMatchRecordTypes(Context, strategy, left, right); + + // Make scalars agree in kind, except count bools as chars. + Type::ScalarTypeKind leftSK = left->getScalarTypeKind(); + Type::ScalarTypeKind rightSK = right->getScalarTypeKind(); + if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral; + if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral; + + // Note that data member pointers and function member pointers don't + // intermix because of the size differences. + + return (leftSK == rightSK); +} + +static bool tryMatchRecordTypes(ASTContext &Context, + Sema::MethodMatchStrategy strategy, + const Type *lt, const Type *rt) { + assert(lt && rt && lt != rt); + + if (!isa<RecordType>(lt) || !isa<RecordType>(rt)) return false; + RecordDecl *left = cast<RecordType>(lt)->getDecl(); + RecordDecl *right = cast<RecordType>(rt)->getDecl(); + + // Require union-hood to match. + if (left->isUnion() != right->isUnion()) return false; + + // Require an exact match if either is non-POD. + if ((isa<CXXRecordDecl>(left) && !cast<CXXRecordDecl>(left)->isPOD()) || + (isa<CXXRecordDecl>(right) && !cast<CXXRecordDecl>(right)->isPOD())) + return false; + + // Require size and alignment to match. + if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false; + + // Require fields to match. + RecordDecl::field_iterator li = left->field_begin(), le = left->field_end(); + RecordDecl::field_iterator ri = right->field_begin(), re = right->field_end(); + for (; li != le && ri != re; ++li, ++ri) { + if (!matchTypes(Context, strategy, li->getType(), ri->getType())) + return false; + } + return (li == le && ri == re); +} /// MatchTwoMethodDeclarations - Checks that two methods have matching type and /// returns true, or false, accordingly. /// TODO: Handle protocol list; such as id<p1,p2> in type comparisons -bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, - const ObjCMethodDecl *PrevMethod, - bool matchBasedOnSizeAndAlignment, - bool matchBasedOnStrictEqulity) { - QualType T1 = Context.getCanonicalType(Method->getResultType()); - QualType T2 = Context.getCanonicalType(PrevMethod->getResultType()); - - if (T1 != T2) { - // The result types are different. - if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity) - return false; - // Incomplete types don't have a size and alignment. - if (T1->isIncompleteType() || T2->isIncompleteType()) - return false; - // Check is based on size and alignment. - if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2)) - return false; - } +bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, + const ObjCMethodDecl *right, + MethodMatchStrategy strategy) { + if (!matchTypes(Context, strategy, + left->getResultType(), right->getResultType())) + return false; - ObjCMethodDecl::param_iterator ParamI = Method->param_begin(), - E = Method->param_end(); - ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin(); + if (getLangOptions().ObjCAutoRefCount && + (left->hasAttr<NSReturnsRetainedAttr>() + != right->hasAttr<NSReturnsRetainedAttr>() || + left->hasAttr<NSConsumesSelfAttr>() + != right->hasAttr<NSConsumesSelfAttr>())) + return false; - for (; ParamI != E; ++ParamI, ++PrevI) { - assert(PrevI != PrevMethod->param_end() && "Param mismatch"); - T1 = Context.getCanonicalType((*ParamI)->getType()); - T2 = Context.getCanonicalType((*PrevI)->getType()); - if (T1 != T2) { - // The result types are different. - if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity) - return false; - // Incomplete types don't have a size and alignment. - if (T1->isIncompleteType() || T2->isIncompleteType()) - return false; - // Check is based on size and alignment. - if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2)) - return false; - } + ObjCMethodDecl::param_iterator + li = left->param_begin(), le = left->param_end(), ri = right->param_begin(); + + for (; li != le; ++li, ++ri) { + assert(ri != right->param_end() && "Param mismatch"); + ParmVarDecl *lparm = *li, *rparm = *ri; + + if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType())) + return false; + + if (getLangOptions().ObjCAutoRefCount && + lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>()) + return false; } return true; } @@ -1505,8 +1818,10 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, // We've seen a method with this name, see if we have already seen this type // signature. - for (ObjCMethodList *List = &Entry; List; List = List->Next) - if (MatchTwoMethodDeclarations(Method, List->Method)) { + for (ObjCMethodList *List = &Entry; List; List = List->Next) { + bool match = MatchTwoMethodDeclarations(Method, List->Method); + + if (match) { ObjCMethodDecl *PrevObjCMethod = List->Method; PrevObjCMethod->setDefined(impl); // If a method is deprecated, push it in the global pool. @@ -1523,6 +1838,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, } return; } + } // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". @@ -1530,6 +1846,25 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next); } +/// Determines if this is an "acceptable" loose mismatch in the global +/// method pool. This exists mostly as a hack to get around certain +/// global mismatches which we can't afford to make warnings / errors. +/// Really, what we want is a way to take a method out of the global +/// method pool. +static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, + ObjCMethodDecl *other) { + if (!chosen->isInstanceMethod()) + return false; + + Selector sel = chosen->getSelector(); + if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length") + return false; + + // Don't complain about mismatches for -length if the method we + // chose has an integral result type. + return (chosen->getResultType()->isIntegerType()); +} + ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool warn, bool instance) { @@ -1543,32 +1878,52 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; - bool strictSelectorMatch = receiverIdOrClass && warn && - (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, - R.getBegin()) != - Diagnostic::Ignored); if (warn && MethList.Method && MethList.Next) { - bool issueWarning = false; + bool issueDiagnostic = false, issueError = false; + + // We support a warning which complains about *any* difference in + // method signature. + bool strictSelectorMatch = + (receiverIdOrClass && warn && + (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, + R.getBegin()) != + Diagnostic::Ignored)); if (strictSelectorMatch) for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { - // This checks if the methods differ in type mismatch. - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true)) - issueWarning = true; + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, + MMS_strict)) { + issueDiagnostic = true; + break; + } } - if (!issueWarning) + // If we didn't see any strict differences, we won't see any loose + // differences. In ARC, however, we also need to check for loose + // mismatches, because most of them are errors. + if (!strictSelectorMatch || + (issueDiagnostic && getLangOptions().ObjCAutoRefCount)) for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { - // This checks if the methods differ by size & alignment. - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) - issueWarning = true; + // This checks if the methods differ in type mismatch. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, + MMS_loose) && + !isAcceptableMethodMismatch(MethList.Method, Next->Method)) { + issueDiagnostic = true; + if (getLangOptions().ObjCAutoRefCount) + issueError = true; + break; + } } - if (issueWarning) { - if (strictSelectorMatch) + if (issueDiagnostic) { + if (issueError) + Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R; + else if (strictSelectorMatch) Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R; else Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using) + + Diag(MethList.Method->getLocStart(), + issueError ? diag::note_possibility : diag::note_using) << MethList.Method->getSourceRange(); for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) Diag(Next->Method->getLocStart(), diag::note_also_found) @@ -1796,6 +2151,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, DefaultSynthesizeProperties(S, IC, IDecl); ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); + DiagnoseOwningPropertyGetterSynthesis(IC); if (LangOpts.ObjCNonFragileABI2) while (IDecl->getSuperClass()) { @@ -1968,7 +2324,7 @@ Decl *Sema::ActOnMethodDeclaration( } else { ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI); // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). - ArgType = adjustParameterType(ArgType); + ArgType = Context.getAdjustedParameterType(ArgType); } LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc, @@ -2015,7 +2371,7 @@ Decl *Sema::ActOnMethodDeclaration( ArgType = Context.getObjCIdType(); else // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). - ArgType = adjustParameterType(ArgType); + ArgType = Context.getAdjustedParameterType(ArgType); if (ArgType->isObjCObjectType()) { Diag(Param->getLocation(), diag::err_object_cannot_be_passed_returned_by_value) @@ -2104,7 +2460,11 @@ Decl *Sema::ActOnMethodDeclaration( mergeObjCMethodDecls(ObjCMethod, InterfaceMD); } - if (!ObjCMethod->hasRelatedResultType() && + bool ARCError = false; + if (getLangOptions().ObjCAutoRefCount) + ARCError = CheckARCMethodDecl(*this, ObjCMethod); + + if (!ObjCMethod->hasRelatedResultType() && !ARCError && getLangOptions().ObjCInferRelatedResultType) { bool InferRelatedResultType = false; switch (ObjCMethod->getMethodFamily()) { @@ -2114,6 +2474,7 @@ Decl *Sema::ActOnMethodDeclaration( case OMF_mutableCopy: case OMF_release: case OMF_retainCount: + case OMF_performSelector: break; case OMF_alloc: @@ -2255,15 +2616,8 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - TagDecl *OwnedDecl = 0; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType ExceptionType = TInfo->getType(); - - if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { - // Objective-C++: Types shall not be defined in exception types. - Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) - << Context.getTypeDeclType(OwnedDecl); - } VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getSourceRange().getBegin(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0549e94..5efc365 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -87,7 +87,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { Diag(Loc, diag::err_deleted_function_use); - Diag(D->getLocation(), diag::note_unavailable_here) << true; + Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true; return true; } } @@ -104,17 +104,20 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, break; case AR_Unavailable: - if (Message.empty()) { - if (!UnknownObjCClass) - Diag(Loc, diag::err_unavailable) << D->getDeclName(); - else - Diag(Loc, diag::warn_unavailable_fwdclass_message) - << D->getDeclName(); + if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) { + if (Message.empty()) { + if (!UnknownObjCClass) + Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else + Diag(Loc, diag::err_unavailable_message) + << D->getDeclName() << Message; + Diag(D->getLocation(), diag::note_unavailable_here) + << isa<FunctionDecl>(D) << false; } - else - Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << Message; - Diag(D->getLocation(), diag::note_unavailable_here) << 0; break; } @@ -437,8 +440,12 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { /// will warn if the resulting type is not a POD type, and rejects ObjC /// interfaces passed by value. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, - FunctionDecl *FDecl) { - ExprResult ExprRes = DefaultArgumentPromotion(E); + FunctionDecl *FDecl) { + ExprResult ExprRes = CheckPlaceholderExpr(E); + if (ExprRes.isInvalid()) + return ExprError(); + + ExprRes = DefaultArgumentPromotion(E); if (ExprRes.isInvalid()) return ExprError(); E = ExprRes.take(); @@ -456,7 +463,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, << E->getType() << CT)) return ExprError(); - if (!E->getType()->isPODType()) { + if (!E->getType().isPODType(Context)) { // C++0x [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) // having a non-trivial copy constructor, a non-trivial move constructor, @@ -471,6 +478,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, TrivialEnough = true; } } + + if (!TrivialEnough && + getLangOptions().ObjCAutoRefCount && + E->getType()->isObjCLifetimeType()) + TrivialEnough = true; if (TrivialEnough) { // Nothing to diagnose. This is okay. @@ -1004,7 +1016,6 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { // Pass &StringTokLocs[0], StringTokLocs.size() to factory! return Owned(StringLiteral::Create(Context, Literal.GetString(), - Literal.GetStringLength(), Literal.AnyWide, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size())); @@ -1271,125 +1282,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, return Owned(E); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - const CXXScopeSpec &SS, FieldDecl *Field, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo); - -ExprResult -Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, - SourceLocation loc, - IndirectFieldDecl *indirectField, - Expr *baseObjectExpr, - SourceLocation opLoc) { - // First, build the expression that refers to the base object. - - bool baseObjectIsPointer = false; - Qualifiers baseQuals; - - // Case 1: the base of the indirect field is not a field. - VarDecl *baseVariable = indirectField->getVarDecl(); - CXXScopeSpec EmptySS; - if (baseVariable) { - assert(baseVariable->getType()->isRecordType()); - - // In principle we could have a member access expression that - // accesses an anonymous struct/union that's a static member of - // the base object's class. However, under the current standard, - // static data members cannot be anonymous structs or unions. - // Supporting this is as easy as building a MemberExpr here. - assert(!baseObjectExpr && "anonymous struct/union is static data member?"); - - DeclarationNameInfo baseNameInfo(DeclarationName(), loc); - - ExprResult result = - BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); - if (result.isInvalid()) return ExprError(); - - baseObjectExpr = result.take(); - baseObjectIsPointer = false; - baseQuals = baseObjectExpr->getType().getQualifiers(); - - // Case 2: the base of the indirect field is a field and the user - // wrote a member expression. - } else if (baseObjectExpr) { - // The caller provided the base object expression. Determine - // whether its a pointer and whether it adds any qualifiers to the - // anonymous struct/union fields we're looking into. - QualType objectType = baseObjectExpr->getType(); - - if (const PointerType *ptr = objectType->getAs<PointerType>()) { - baseObjectIsPointer = true; - objectType = ptr->getPointeeType(); - } else { - baseObjectIsPointer = false; - } - baseQuals = objectType.getQualifiers(); - - // Case 3: the base of the indirect field is a field and we should - // build an implicit member access. - } else { - // We've found a member of an anonymous struct/union that is - // inside a non-anonymous struct/union, so in a well-formed - // program our base object expression is "this". - QualType ThisTy = getAndCaptureCurrentThisType(); - if (ThisTy.isNull()) { - Diag(loc, diag::err_invalid_member_use_in_static_method) - << indirectField->getDeclName(); - return ExprError(); - } - - // Our base object expression is "this". - baseObjectExpr = - new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); - baseObjectIsPointer = true; - baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); - } - - // Build the implicit member references to the field of the - // anonymous struct/union. - Expr *result = baseObjectExpr; - IndirectFieldDecl::chain_iterator - FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); - - // Build the first member access in the chain with full information. - if (!baseVariable) { - FieldDecl *field = cast<FieldDecl>(*FI); - - // FIXME: use the real found-decl info! - DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); - - // Make a nameInfo that properly uses the anonymous name. - DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - - result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, - EmptySS, field, foundDecl, - memberNameInfo).take(); - baseObjectIsPointer = false; - - // FIXME: check qualified member access - } - - // In all cases, we should now skip the first declaration in the chain. - ++FI; - - while (FI != FEnd) { - FieldDecl *field = cast<FieldDecl>(*FI++); - - // FIXME: these are somewhat meaningless - DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); - - result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, - (FI == FEnd? SS : EmptySS), field, - foundDecl, memberNameInfo) - .take(); - } - - return Owned(result); -} - /// Decomposes the given name into a DeclarationNameInfo, its location, and /// possibly a list of template arguments. /// @@ -1399,215 +1291,30 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, /// This actually loses a lot of source location information for /// non-standard name kinds; we should consider preserving that in /// some way. -static void DecomposeUnqualifiedId(Sema &SemaRef, - const UnqualifiedId &Id, - TemplateArgumentListInfo &Buffer, - DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *&TemplateArgs) { +void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedId::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(SemaRef, + ASTTemplateArgsPtr TemplateArgsPtr(*this, Id.TemplateId->getTemplateArgs(), Id.TemplateId->NumArgs); - SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer); + translateTemplateArguments(TemplateArgsPtr, Buffer); TemplateArgsPtr.release(); TemplateName TName = Id.TemplateId->Template.get(); SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; - NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc); + NameInfo = Context.getNameForTemplate(TName, TNameLoc); TemplateArgs = &Buffer; } else { - NameInfo = SemaRef.GetNameFromUnqualifiedId(Id); + NameInfo = GetNameFromUnqualifiedId(Id); TemplateArgs = 0; } } -/// Determines if the given class is provably not derived from all of -/// the prospective base classes. -static bool IsProvablyNotDerivedFrom(Sema &SemaRef, - CXXRecordDecl *Record, - const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) { - if (Bases.count(Record->getCanonicalDecl())) - return false; - - RecordDecl *RD = Record->getDefinition(); - if (!RD) return false; - Record = cast<CXXRecordDecl>(RD); - - for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), - E = Record->bases_end(); I != E; ++I) { - CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); - CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>(); - if (!BaseRT) return false; - - CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); - if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) - return false; - } - - return true; -} - -enum IMAKind { - /// The reference is definitely not an instance member access. - IMA_Static, - - /// The reference may be an implicit instance member access. - IMA_Mixed, - - /// The reference may be to an instance member, but it is invalid if - /// so, because the context is not an instance method. - IMA_Mixed_StaticContext, - - /// The reference may be to an instance member, but it is invalid if - /// so, because the context is from an unrelated class. - IMA_Mixed_Unrelated, - - /// The reference is definitely an implicit instance member access. - IMA_Instance, - - /// The reference may be to an unresolved using declaration. - IMA_Unresolved, - - /// The reference may be to an unresolved using declaration and the - /// context is not an instance method. - IMA_Unresolved_StaticContext, - - /// All possible referrents are instance members and the current - /// context is not an instance method. - IMA_Error_StaticContext, - - /// All possible referrents are instance members of an unrelated - /// class. - IMA_Error_Unrelated -}; - -/// The given lookup names class member(s) and is not being used for -/// an address-of-member expression. Classify the type of access -/// according to whether it's possible that this reference names an -/// instance member. This is best-effort; it is okay to -/// conservatively answer "yes", in which case some errors will simply -/// not be caught until template-instantiation. -static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, - Scope *CurScope, - const LookupResult &R) { - assert(!R.empty() && (*R.begin())->isCXXClassMember()); - - DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - - bool isStaticContext = - (!isa<CXXMethodDecl>(DC) || - cast<CXXMethodDecl>(DC)->isStatic()); - - // C++0x [expr.prim]p4: - // Otherwise, if a member-declarator declares a non-static data member - // of a class X, the expression this is a prvalue of type "pointer to X" - // within the optional brace-or-equal-initializer. - if (CurScope->getFlags() & Scope::ThisScope) - isStaticContext = false; - - if (R.isUnresolvableResult()) - return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; - - // Collect all the declaring classes of instance members we find. - bool hasNonInstance = false; - bool hasField = false; - llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = *I; - - if (D->isCXXInstanceMember()) { - if (dyn_cast<FieldDecl>(D)) - hasField = true; - - CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); - Classes.insert(R->getCanonicalDecl()); - } - else - hasNonInstance = true; - } - - // If we didn't find any instance members, it can't be an implicit - // member reference. - if (Classes.empty()) - return IMA_Static; - - // If the current context is not an instance method, it can't be - // an implicit member reference. - if (isStaticContext) { - if (hasNonInstance) - return IMA_Mixed_StaticContext; - - if (SemaRef.getLangOptions().CPlusPlus0x && hasField) { - // C++0x [expr.prim.general]p10: - // An id-expression that denotes a non-static data member or non-static - // member function of a class can only be used: - // (...) - // - if that id-expression denotes a non-static data member and it appears in an unevaluated operand. - const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back(); - bool isUnevaluatedExpression = record.Context == Sema::Unevaluated; - if (isUnevaluatedExpression) - return IMA_Mixed_StaticContext; - } - - return IMA_Error_StaticContext; - } - - CXXRecordDecl *contextClass; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) - contextClass = MD->getParent()->getCanonicalDecl(); - else - contextClass = cast<CXXRecordDecl>(DC); - - // [class.mfct.non-static]p3: - // ...is used in the body of a non-static member function of class X, - // if name lookup (3.4.1) resolves the name in the id-expression to a - // non-static non-type member of some class C [...] - // ...if C is not X or a base class of X, the class member access expression - // is ill-formed. - if (R.getNamingClass() && - contextClass != R.getNamingClass()->getCanonicalDecl() && - contextClass->isProvablyNotDerivedFrom(R.getNamingClass())) - return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); - - // If we can prove that the current context is unrelated to all the - // declaring classes, it can't be an implicit member reference (in - // which case it's an error if any of those members are selected). - if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) - return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); - - return (hasNonInstance ? IMA_Mixed : IMA_Instance); -} - -/// Diagnose a reference to a field with no object available. -static void DiagnoseInstanceReference(Sema &SemaRef, - const CXXScopeSpec &SS, - NamedDecl *rep, - const DeclarationNameInfo &nameInfo) { - SourceLocation Loc = nameInfo.getLoc(); - SourceRange Range(Loc); - if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - - if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) - << Range << nameInfo.getName(); - return; - } - } - - SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) - << nameInfo.getName() << Range; - return; - } - - SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; -} - /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found @@ -1690,39 +1397,43 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, } // We didn't find anything, so try to correct for a typo. - DeclarationName Corrected; - if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) { - if (!R.empty()) { - if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { + TypoCorrection Corrected; + if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), + S, &SS, NULL, false, CTC))) { + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); + R.setLookupName(Corrected.getCorrection()); + + if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + R.addDecl(ND); + if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) { if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); + if (ND) Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); + << CorrectedQuotedStr; // Tell the callee to try to recover. return false; } - if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { + if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) { // FIXME: If we ended up with a typo for a type name or // Objective-C class name, we're in trouble because the parser // is in the wrong place to recover. Suggest the typo // correction, but don't make it a fix-it since we're not going // to recover well anyway. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange(); // Don't try to recover; it won't work. @@ -1732,15 +1443,15 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // FIXME: We found a keyword. Suggest it, but don't provide a fix-it // because we aren't able to recover. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected; + Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << Corrected + << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange(); return true; } - R.clear(); } + R.clear(); // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) @@ -1856,7 +1567,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // Decompose the UnqualifiedId into the following data. DeclarationNameInfo NameInfo; const TemplateArgumentListInfo *TemplateArgs; - DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs); + DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); DeclarationName Name = NameInfo.getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); @@ -1892,7 +1603,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool IvarLookupFollowUp = false; // Perform the required lookup. - LookupResult R(*this, NameInfo, LookupOrdinaryName); + LookupResult R(*this, NameInfo, + (Id.getKind() == UnqualifiedId::IK_ImplicitSelfParam) + ? LookupObjCImplicitSelfParam : LookupOrdinaryName); if (TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the @@ -2032,38 +1745,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, return BuildDeclarationNameExpr(SS, R, ADL); } -/// Builds an expression which might be an implicit member expression. -ExprResult -Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { - case IMA_Instance: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); - - case IMA_Mixed: - case IMA_Mixed_Unrelated: - case IMA_Unresolved: - return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); - - case IMA_Static: - case IMA_Mixed_StaticContext: - case IMA_Unresolved_StaticContext: - if (TemplateArgs) - return BuildTemplateIdExpr(SS, R, false, *TemplateArgs); - return BuildDeclarationNameExpr(SS, R, false); - - case IMA_Error_StaticContext: - case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), - R.getLookupNameInfo()); - return ExprError(); - } - - llvm_unreachable("unexpected instance member access kind"); - return ExprError(); -} - /// BuildQualifiedDeclarationNameExpr - Build a C++ qualified /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along @@ -2155,6 +1836,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo &II = Context.Idents.get("self"); UnqualifiedId SelfName; SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setKind(UnqualifiedId::IK_ImplicitSelfParam); CXXScopeSpec SelfScopeSpec; ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, SelfName, false, false); @@ -2166,27 +1848,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return ExprError(); MarkDeclarationReferenced(Loc, IV); - Expr *base = SelfExpr.take(); - base = base->IgnoreParenImpCasts(); - if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) { - const NamedDecl *ND = DE->getDecl(); - if (!isa<ImplicitParamDecl>(ND)) { - // relax the rule such that it is allowed to have a shadow 'self' - // where stand-alone ivar can be found in this 'self' object. - // This is to match gcc's behavior. - ObjCInterfaceDecl *selfIFace = 0; - if (const ObjCObjectPointerType *OPT = - base->getType()->getAsObjCInterfacePointerType()) - selfIFace = OPT->getInterfaceDecl(); - if (!selfIFace || - !selfIFace->lookupInstanceVariable(IV->getIdentifier())) { - Diag(Loc, diag::error_implicit_ivar_access) - << IV->getDeclName(); - Diag(ND->getLocation(), diag::note_declared_at); - return ExprError(); - } - } - } return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, SelfExpr.take(), true, true)); @@ -2385,120 +2046,6 @@ Sema::PerformObjectMemberConversion(Expr *From, VK, &BasePath); } -/// \brief Build a MemberExpr AST node. -static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec &SS, ValueDecl *Member, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo, - QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = 0) { - return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C), - Member, FoundDecl, MemberNameInfo, - TemplateArgs, Ty, VK, OK); -} - -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - const CXXScopeSpec &SS, FieldDecl *Field, - DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { - // x.a is an l-value if 'a' has a reference type. Otherwise: - // x.a is an l-value/x-value/pr-value if the base is (and note - // that *x is always an l-value), except that if the base isn't - // an ordinary object then we must have an rvalue. - ExprValueKind VK = VK_LValue; - ExprObjectKind OK = OK_Ordinary; - if (!IsArrow) { - if (BaseExpr->getObjectKind() == OK_Ordinary) - VK = BaseExpr->getValueKind(); - else - VK = VK_RValue; - } - if (VK != VK_RValue && Field->isBitField()) - OK = OK_BitField; - - // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = Field->getType(); - if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) { - MemberType = Ref->getPointeeType(); - VK = VK_LValue; - } else { - QualType BaseType = BaseExpr->getType(); - if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType(); - - Qualifiers BaseQuals = BaseType.getQualifiers(); - - // GC attributes are never picked up by members. - BaseQuals.removeObjCGCAttr(); - - // CVR attributes from the base are picked up by members, - // except that 'mutable' members don't pick up 'const'. - if (Field->isMutable()) BaseQuals.removeConst(); - - Qualifiers MemberQuals - = S.Context.getCanonicalType(MemberType).getQualifiers(); - - // TR 18037 does not allow fields to be declared with address spaces. - assert(!MemberQuals.hasAddressSpace()); - - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = S.Context.getQualifiedType(MemberType, Combined); - } - - S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); - ExprResult Base = - S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); - if (Base.isInvalid()) - return ExprError(); - return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS, - Field, FoundDecl, MemberNameInfo, - MemberType, VK, OK)); -} - -/// Builds an implicit member access expression. The current context -/// is known to be an instance method, and the given unqualified lookup -/// set is known to contain only instance members, at least one of which -/// is from an appropriate type. -ExprResult -Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool IsKnownInstance) { - assert(!R.empty() && !R.isAmbiguous()); - - SourceLocation loc = R.getNameLoc(); - - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - // FIXME: template-ids inside anonymous structs? - if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) - return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); - - // If this is known to be an instance access, go ahead and build an - // implicit 'this' expression now. - // 'this' expression now. - QualType ThisTy = getAndCaptureCurrentThisType(); - assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); - - Expr *baseExpr = 0; // null signifies implicit access - if (IsKnownInstance) { - SourceLocation Loc = R.getNameLoc(); - if (SS.getRange().isValid()) - Loc = SS.getRange().getBegin(); - baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); - } - - return BuildMemberReferenceExpr(baseExpr, ThisTy, - /*OpLoc*/ SourceLocation(), - /*IsArrow*/ true, - SS, - /*FirstQualifierInScope*/ 0, - R, TemplateArgs); -} - bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen) { @@ -3160,6 +2707,20 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, Op->getSourceRange(), ExprKind)) return true; + if (ExprKind == UETT_SizeOf) { + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) { + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { + QualType OType = PVD->getOriginalType(); + QualType Type = PVD->getType(); + if (Type->isPointerType() && OType->isArrayType()) { + Diag(Op->getExprLoc(), diag::warn_sizeof_array_param) + << Type << OType; + Diag(PVD->getLocation(), diag::note_declared_at); + } + } + } + } + return false; } @@ -3274,6 +2835,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind) { + ExprResult PE = CheckPlaceholderExpr(E); + if (PE.isInvalid()) + return ExprError(); + + E = PE.get(); + // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { @@ -3285,10 +2852,6 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; - } else if (E->getType()->isPlaceholderType()) { - ExprResult PE = CheckPlaceholderExpr(E); - if (PE.isInvalid()) return ExprError(); - return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind); } else { isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } @@ -3372,19 +2935,6 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, return BuildUnaryOp(S, OpLoc, Opc, Input); } -/// Expressions of certain arbitrary types are forbidden by C from -/// having l-value type. These are: -/// - 'void', but not qualified void -/// - function types -/// -/// The exact rule here is C99 6.3.2.1: -/// An lvalue is an expression with an object type or an incomplete -/// type other than void. -static bool IsCForbiddenLValueType(ASTContext &C, QualType T) { - return ((T->isVoidType() && !T.hasQualifiers()) || - T->isFunctionType()); -} - ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -3528,7 +3078,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) { // GNU extension: subscripting on pointer to void - Diag(LLoc, diag::ext_gnu_void_ptr) + Diag(LLoc, diag::ext_gnu_subscript_void_type) << BaseExpr->getSourceRange(); // C forbids expressions of unqualified void type from being l-values. @@ -3548,1109 +3098,12 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } assert(VK == VK_RValue || LangOpts.CPlusPlus || - !IsCForbiddenLValueType(Context, ResultType)); + !ResultType.isCForbiddenLValueType()); return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc)); } -/// Check an ext-vector component access expression. -/// -/// VK should be set in advance to the value kind of the base -/// expression. -static QualType -CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, - SourceLocation OpLoc, const IdentifierInfo *CompName, - SourceLocation CompLoc) { - // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, - // see FIXME there. - // - // FIXME: This logic can be greatly simplified by splitting it along - // halving/not halving and reworking the component checking. - const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); - - // The vector accessor can't exceed the number of elements. - const char *compStr = CompName->getNameStart(); - - // This flag determines whether or not the component is one of the four - // special names that indicate a subset of exactly half the elements are - // to be selected. - bool HalvingSwizzle = false; - - // This flag determines whether or not CompName has an 's' char prefix, - // indicating that it is a string of hex values to be used as vector indices. - bool HexSwizzle = *compStr == 's' || *compStr == 'S'; - - bool HasRepeated = false; - bool HasIndex[16] = {}; - - int Idx; - - // Check that we've found one of the special components, or that the component - // names must come from the same set. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || - !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { - HalvingSwizzle = true; - } else if (!HexSwizzle && - (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { - do { - if (HasIndex[Idx]) HasRepeated = true; - HasIndex[Idx] = true; - compStr++; - } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); - } else { - if (HexSwizzle) compStr++; - while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { - if (HasIndex[Idx]) HasRepeated = true; - HasIndex[Idx] = true; - compStr++; - } - } - - if (!HalvingSwizzle && *compStr) { - // We didn't get to the end of the string. This means the component names - // didn't come from the same set *or* we encountered an illegal name. - S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); - return QualType(); - } - - // Ensure no component accessor exceeds the width of the vector type it - // operates on. - if (!HalvingSwizzle) { - compStr = CompName->getNameStart(); - - if (HexSwizzle) - compStr++; - - while (*compStr) { - if (!vecType->isAccessorWithinNumElements(*compStr++)) { - S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) - << baseType << SourceRange(CompLoc); - return QualType(); - } - } - } - - // The component accessor looks fine - now we need to compute the actual type. - // The vector type is implied by the component accessor. For example, - // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. - // vec4.s0 is a float, vec4.s23 is a vec3, etc. - // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. - unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2 - : CompName->getLength(); - if (HexSwizzle) - CompSize--; - - if (CompSize == 1) - return vecType->getElementType(); - - if (HasRepeated) VK = VK_RValue; - - QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); - // Now look up the TypeDefDecl from the vector type. Without this, - // diagostics look bad. We want extended vector types to appear built-in. - for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { - if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) - return S.Context.getTypedefType(S.ExtVectorDecls[i]); - } - return VT; // should never get here (a typedef type should always be found). -} - -static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { - if (Member) - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) - return PD; - if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) - return OMD; - - for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), - E = PDecl->protocol_end(); I != E; ++I) { - if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, - Context)) - return D; - } - return 0; -} - -static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, - IdentifierInfo *Member, - const Selector &Sel, - ASTContext &Context) { - // Check protocols on qualified interfaces. - Decl *GDecl = 0; - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - if (Member) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - GDecl = PD; - break; - } - // Also must look for a getter or setter name which uses property syntax. - if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { - GDecl = OMD; - break; - } - } - if (!GDecl) { - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - // Search in the protocol-qualifier list of current protocol. - GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, - Context); - if (GDecl) - return GDecl; - } - } - return GDecl; -} - -ExprResult -Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, - bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs) { - // Even in dependent contexts, try to diagnose base expressions with - // obviously wrong types, e.g.: - // - // T* t; - // t.f; - // - // In Obj-C++, however, the above expression is valid, since it could be - // accessing the 'f' property if T is an Obj-C interface. The extra check - // allows this, while still reporting an error if T is a struct pointer. - if (!IsArrow) { - const PointerType *PT = BaseType->getAs<PointerType>(); - if (PT && (!getLangOptions().ObjC1 || - PT->getPointeeType()->isRecordType())) { - assert(BaseExpr && "cannot happen with implicit member accesses"); - Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr->getSourceRange(); - return ExprError(); - } - } - - assert(BaseType->isDependentType() || - NameInfo.getName().isDependentName() || - isDependentScopeSpecifier(SS)); - - // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr - // must have pointer type, and the accessed type is the pointee. - return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, - IsArrow, OpLoc, - SS.getWithLocInContext(Context), - FirstQualifierInScope, - NameInfo, TemplateArgs)); -} - -/// We know that the given qualified member reference points only to -/// declarations which do not belong to the static type of the base -/// expression. Diagnose the problem. -static void DiagnoseQualifiedMemberReference(Sema &SemaRef, - Expr *BaseExpr, - QualType BaseType, - const CXXScopeSpec &SS, - NamedDecl *rep, - const DeclarationNameInfo &nameInfo) { - // If this is an implicit member access, use a different set of - // diagnostics. - if (!BaseExpr) - return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); - - SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) - << SS.getRange() << rep << BaseType; -} - -// Check whether the declarations we found through a nested-name -// specifier in a member expression are actually members of the base -// type. The restriction here is: -// -// C++ [expr.ref]p2: -// ... In these cases, the id-expression shall name a -// member of the class or of one of its base classes. -// -// So it's perfectly legitimate for the nested-name specifier to name -// an unrelated class, and for us to find an overload set including -// decls from classes which are not superclasses, as long as the decl -// we actually pick through overload resolution is from a superclass. -bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, - QualType BaseType, - const CXXScopeSpec &SS, - const LookupResult &R) { - const RecordType *BaseRT = BaseType->getAs<RecordType>(); - if (!BaseRT) { - // We can't check this yet because the base type is still - // dependent. - assert(BaseType->isDependentType()); - return false; - } - CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); - - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - // If this is an implicit member reference and we find a - // non-instance member, it's not an error. - if (!BaseExpr && !(*I)->isCXXInstanceMember()) - return false; - - // Note that we use the DC of the decl, not the underlying decl. - DeclContext *DC = (*I)->getDeclContext(); - while (DC->isTransparentContext()) - DC = DC->getParent(); - - if (!DC->isRecord()) - continue; - - llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord; - MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl()); - - if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) - return false; - } - - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, - R.getRepresentativeDecl(), - R.getLookupNameInfo()); - return true; -} - -static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, CXXScopeSpec &SS, - bool HasTemplateArgs) { - RecordDecl *RDecl = RTy->getDecl(); - if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), - SemaRef.PDiag(diag::err_typecheck_incomplete_tag) - << BaseRange)) - return true; - - if (HasTemplateArgs) { - // LookupTemplateName doesn't expect these both to exist simultaneously. - QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); - - bool MOUS; - SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS); - return false; - } - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = SemaRef.computeDeclContext(SS, false); - - if (SemaRef.RequireCompleteDeclContext(SS, DC)) { - SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) - << SS.getRange() << DC; - return true; - } - - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - - if (!isa<TypeDecl>(DC)) { - SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return true; - } - } - - // The record definition is complete, now look up the member. - SemaRef.LookupQualifiedName(R, DC); - - if (!R.empty()) - return false; - - // We didn't find anything with the given name, so try to correct - // for typos. - DeclarationName Name = R.getLookupName(); - if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) && - !R.empty() && - (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { - SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << DC << R.getLookupName() << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) - SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); - return false; - } else { - R.clear(); - R.setLookupName(Name); - } - - return false; -} - -ExprResult -Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, - SourceLocation OpLoc, bool IsArrow, - CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs) { - if (BaseType->isDependentType() || - (SS.isSet() && isDependentScopeSpecifier(SS))) - return ActOnDependentMemberExpr(Base, BaseType, - IsArrow, OpLoc, - SS, FirstQualifierInScope, - NameInfo, TemplateArgs); - - LookupResult R(*this, NameInfo, LookupMemberName); - - // Implicit member accesses. - if (!Base) { - QualType RecordTy = BaseType; - if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, SourceRange(), - RecordTy->getAs<RecordType>(), - OpLoc, SS, TemplateArgs != 0)) - return ExprError(); - - // Explicit member accesses. - } else { - ExprResult BaseResult = Owned(Base); - ExprResult Result = - LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, - SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); - - if (BaseResult.isInvalid()) - return ExprError(); - Base = BaseResult.take(); - - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); - } - - if (Result.get()) - return move(Result); - - // LookupMemberExpr can modify Base, and thus change BaseType - BaseType = Base->getType(); - } - - return BuildMemberReferenceExpr(Base, BaseType, - OpLoc, IsArrow, SS, FirstQualifierInScope, - R, TemplateArgs); -} - -ExprResult -Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, - SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool SuppressQualifierCheck) { - QualType BaseType = BaseExprType; - if (IsArrow) { - assert(BaseType->isPointerType()); - BaseType = BaseType->getAs<PointerType>()->getPointeeType(); - } - R.setBaseObjectType(BaseType); - - const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); - DeclarationName MemberName = MemberNameInfo.getName(); - SourceLocation MemberLoc = MemberNameInfo.getLoc(); - - if (R.isAmbiguous()) - return ExprError(); - - if (R.empty()) { - // Rederive where we looked up. - DeclContext *DC = (SS.isSet() - ? computeDeclContext(SS, false) - : BaseType->getAs<RecordType>()->getDecl()); - - Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); - return ExprError(); - } - - // Diagnose lookups that find only declarations from a non-base - // type. This is possible for either qualified lookups (which may - // have been qualified with an unrelated type) or implicit member - // expressions (which were found with unqualified lookup and thus - // may have come from an enclosing scope). Note that it's okay for - // lookup to find declarations from a non-base type as long as those - // aren't the ones picked by overload resolution. - if ((SS.isSet() || !BaseExpr || - (isa<CXXThisExpr>(BaseExpr) && - cast<CXXThisExpr>(BaseExpr)->isImplicit())) && - !SuppressQualifierCheck && - CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) - return ExprError(); - - // Construct an unresolved result if we in fact got an unresolved - // result. - if (R.isOverloadedResult() || R.isUnresolvableResult()) { - // Suppress any lookup-related diagnostics; we'll do these when we - // pick a member. - R.suppressDiagnostics(); - - UnresolvedMemberExpr *MemExpr - = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), - BaseExpr, BaseExprType, - IsArrow, OpLoc, - SS.getWithLocInContext(Context), - MemberNameInfo, - TemplateArgs, R.begin(), R.end()); - - return Owned(MemExpr); - } - - assert(R.isSingleResult()); - DeclAccessPair FoundDecl = R.begin().getPair(); - NamedDecl *MemberDecl = R.getFoundDecl(); - - // FIXME: diagnose the presence of template arguments now. - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (MemberDecl->isInvalidDecl()) - return ExprError(); - - // Handle the implicit-member-access case. - if (!BaseExpr) { - // If this is not an instance member, convert to a non-member access. - if (!MemberDecl->isCXXInstanceMember()) - return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); - - SourceLocation Loc = R.getNameLoc(); - if (SS.getRange().isValid()) - Loc = SS.getRange().getBegin(); - BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); - } - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && !SS.isSet()) - ShouldCheckUse = false; - } - - // Check the use of this member. - if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) { - Owned(BaseExpr); - return ExprError(); - } - - // Perform a property load on the base regardless of whether we - // actually need it for the declaration. - if (BaseExpr->getObjectKind() == OK_ObjCProperty) { - ExprResult Result = ConvertPropertyForRValue(BaseExpr); - if (Result.isInvalid()) - return ExprError(); - BaseExpr = Result.take(); - } - - if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) - return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, - SS, FD, FoundDecl, MemberNameInfo); - - if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, - BaseExpr, OpLoc); - - if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, Var); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, FoundDecl, MemberNameInfo, - Var->getType().getNonReferenceType(), - VK_LValue, OK_Ordinary)); - } - - if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) { - ExprValueKind valueKind; - QualType type; - if (MemberFn->isInstance()) { - valueKind = VK_RValue; - type = Context.BoundMemberTy; - } else { - valueKind = VK_LValue; - type = MemberFn->getType(); - } - - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, FoundDecl, MemberNameInfo, - type, valueKind, OK_Ordinary)); - } - assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?"); - - if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, FoundDecl, MemberNameInfo, - Enum->getType(), VK_RValue, OK_Ordinary)); - } - - Owned(BaseExpr); - - // We found something that we didn't expect. Complain. - if (isa<TypeDecl>(MemberDecl)) - Diag(MemberLoc, diag::err_typecheck_member_reference_type) - << MemberName << BaseType << int(IsArrow); - else - Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) - << MemberName << BaseType << int(IsArrow); - - Diag(MemberDecl->getLocation(), diag::note_member_declared_here) - << MemberName; - R.suppressDiagnostics(); - return ExprError(); -} - -/// Given that normal member access failed on the given expression, -/// and given that the expression's type involves builtin-id or -/// builtin-Class, decide whether substituting in the redefinition -/// types would be profitable. The redefinition type is whatever -/// this translation unit tried to typedef to id/Class; we store -/// it to the side and then re-use it in places like this. -static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { - const ObjCObjectPointerType *opty - = base.get()->getType()->getAs<ObjCObjectPointerType>(); - if (!opty) return false; - - const ObjCObjectType *ty = opty->getObjectType(); - - QualType redef; - if (ty->isObjCId()) { - redef = S.Context.ObjCIdRedefinitionType; - } else if (ty->isObjCClass()) { - redef = S.Context.ObjCClassRedefinitionType; - } else { - return false; - } - - // Do the substitution as long as the redefinition type isn't just a - // possibly-qualified pointer to builtin-id or builtin-Class again. - opty = redef->getAs<ObjCObjectPointerType>(); - if (opty && !opty->getObjectType()->getInterface() != 0) - return false; - - base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); - return true; -} - -/// Look up the given member of the given non-type-dependent -/// expression. This can return in one of two ways: -/// * If it returns a sentinel null-but-valid result, the caller will -/// assume that lookup was performed and the results written into -/// the provided structure. It will take over from there. -/// * Otherwise, the returned expression will be produced in place of -/// an ordinary member expression. -/// -/// The ObjCImpDecl bit is a gross hack that will need to be properly -/// fixed for ObjC++. -ExprResult -Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, - bool &IsArrow, SourceLocation OpLoc, - CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs) { - assert(BaseExpr.get() && "no base expression"); - - // Perform default conversions. - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - - if (IsArrow) { - BaseExpr = DefaultLvalueConversion(BaseExpr.take()); - if (BaseExpr.isInvalid()) - return ExprError(); - } - - QualType BaseType = BaseExpr.get()->getType(); - assert(!BaseType->isDependentType()); - - DeclarationName MemberName = R.getLookupName(); - SourceLocation MemberLoc = R.getNameLoc(); - - // For later type-checking purposes, turn arrow accesses into dot - // accesses. The only access type we support that doesn't follow - // the C equivalence "a->b === (*a).b" is ObjC property accesses, - // and those never use arrows, so this is unaffected. - if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) - BaseType = Ptr->getPointeeType(); - else if (const ObjCObjectPointerType *Ptr - = BaseType->getAs<ObjCObjectPointerType>()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isRecordType()) { - // Recover from arrow accesses to records, e.g.: - // struct MyRecord foo; - // foo->bar - // This is actually well-formed in C++ if MyRecord has an - // overloaded operator->, but that should have been dealt with - // by now. - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "."); - IsArrow = false; - } else if (BaseType == Context.BoundMemberTy) { - goto fail; - } else { - Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr.get()->getSourceRange(); - return ExprError(); - } - } - - // Handle field access to simple records. - if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(), - RTy, OpLoc, SS, HasTemplateArgs)) - return ExprError(); - - // Returning valid-but-null is how we indicate to the caller that - // the lookup result was filled in. - return Owned((Expr*) 0); - } - - // Handle ivar access to Objective-C objects. - if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - // There are three cases for the base type: - // - builtin id (qualified or unqualified) - // - builtin Class (qualified or unqualified) - // - an interface - ObjCInterfaceDecl *IDecl = OTy->getInterface(); - if (!IDecl) { - // There's an implicit 'isa' ivar on all objects. - // But we only actually find it this way on objects of type 'id', - // apparently. - if (OTy->isObjCId() && Member->isStr("isa")) - return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, - Context.getObjCClassType())); - - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - goto fail; - } - - ObjCInterfaceDecl *ClassDeclared; - ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); - - if (!IV) { - // Attempt to correct for typos in ivar names. - LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), - LookupMemberName); - if (CorrectTypo(Res, 0, 0, IDecl, false, - IsArrow ? CTC_ObjCIvarLookup - : CTC_ObjCPropertyLookup) && - (IV = Res.getAsSingle<ObjCIvarDecl>())) { - Diag(R.getNameLoc(), - diag::err_typecheck_member_reference_ivar_suggest) - << IDecl->getDeclName() << MemberName << IV->getDeclName() - << FixItHint::CreateReplacement(R.getNameLoc(), - IV->getNameAsString()); - Diag(IV->getLocation(), diag::note_previous_decl) - << IV->getDeclName(); - } else { - Res.clear(); - Res.setLookupName(Member); - - Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) - << IDecl->getDeclName() << MemberName - << BaseExpr.get()->getSourceRange(); - return ExprError(); - } - } - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (IV->isInvalidDecl()) - return ExprError(); - - // Check whether we can reference this field. - if (DiagnoseUseOfDecl(IV, MemberLoc)) - return ExprError(); - if (IV->getAccessControl() != ObjCIvarDecl::Public && - IV->getAccessControl() != ObjCIvarDecl::Package) { - ObjCInterfaceDecl *ClassOfMethodDecl = 0; - if (ObjCMethodDecl *MD = getCurMethodDecl()) - ClassOfMethodDecl = MD->getClassInterface(); - else if (ObjCImpDecl && getCurFunctionDecl()) { - // Case of a c-function declared inside an objc implementation. - // FIXME: For a c-style function nested inside an objc implementation - // class, there is no implementation context available, so we pass - // down the context as argument to this routine. Ideally, this context - // need be passed down in the AST node and somehow calculated from the - // AST for a function decl. - if (ObjCImplementationDecl *IMPD = - dyn_cast<ObjCImplementationDecl>(ObjCImpDecl)) - ClassOfMethodDecl = IMPD->getClassInterface(); - else if (ObjCCategoryImplDecl* CatImplClass = - dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl)) - ClassOfMethodDecl = CatImplClass->getClassInterface(); - } - - if (IV->getAccessControl() == ObjCIvarDecl::Private) { - if (ClassDeclared != IDecl || - ClassOfMethodDecl != ClassDeclared) - Diag(MemberLoc, diag::error_private_ivar_access) - << IV->getDeclName(); - } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) - // @protected - Diag(MemberLoc, diag::error_protected_ivar_access) - << IV->getDeclName(); - } - - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr.take(), - IsArrow)); - } - - // Objective-C property access. - const ObjCObjectPointerType *OPT; - if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { - // This actually uses the base as an r-value. - BaseExpr = DefaultLvalueConversion(BaseExpr.take()); - if (BaseExpr.isInvalid()) - return ExprError(); - - assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType())); - - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - const ObjCObjectType *OT = OPT->getObjectType(); - - // id, with and without qualifiers. - if (OT->isObjCId()) { - // Check protocols on qualified interfaces. - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) { - if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { - // Check the use of this declaration - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - QualType T = PD->getType(); - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) - T = getMessageSendResultType(BaseType, Getter, false, false); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, T, - VK_LValue, - OK_ObjCProperty, - MemberLoc, - BaseExpr.take())); - } - - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { - // Check the use of this method. - if (DiagnoseUseOfDecl(OMD, MemberLoc)) - return ExprError(); - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *SMD = 0; - if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, - SetterSel, Context)) - SMD = dyn_cast<ObjCMethodDecl>(SDecl); - QualType PType = getMessageSendResultType(BaseType, OMD, false, - false); - - ExprValueKind VK = VK_LValue; - if (!getLangOptions().CPlusPlus && - IsCForbiddenLValueType(Context, PType)) - VK = VK_RValue; - ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); - - return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, - VK, OK, - MemberLoc, BaseExpr.take())); - } - } - // Use of id.member can only be for a property reference. Do not - // use the 'id' redefinition in this case. - if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); - } - - // 'Class', unqualified only. - if (OT->isObjCClass()) { - // Only works in a method declaration (??!). - ObjCMethodDecl *MD = getCurMethodDecl(); - if (!MD) { - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - goto fail; - } - - // Also must look for a getter name which uses property syntax. - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - ObjCMethodDecl *Getter; - if ((Getter = IFace->lookupClassMethod(Sel))) { - // Check the use of this method. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } else - Getter = IFace->lookupPrivateMethod(Sel, false); - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateMethod(SetterSel, false); - } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryClassMethod(SetterSel); - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - if (Getter || Setter) { - QualType PType; - - ExprValueKind VK = VK_LValue; - if (Getter) { - PType = getMessageSendResultType(QualType(OT, 0), Getter, true, - false); - if (!getLangOptions().CPlusPlus && - IsCForbiddenLValueType(Context, PType)) - VK = VK_RValue; - } else { - // Get the expression type from Setter's incoming parameter. - PType = (*(Setter->param_end() -1))->getType(); - } - ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); - - // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, - PType, VK, OK, - MemberLoc, BaseExpr.take())); - } - - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); - } - - // Normal property access. - return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc, - SourceLocation(), QualType(), false); - } - - // Handle 'field access' to vectors, such as 'V.xx'. - if (BaseType->isExtVectorType()) { - // FIXME: this expr should store IsArrow. - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); - QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, - Member, MemberLoc); - if (ret.isNull()) - return ExprError(); - - return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(), - *Member, MemberLoc)); - } - - // Adjust builtin-sel to the appropriate redefinition type if that's - // not just a pointer to builtin-sel again. - if (IsArrow && - BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && - !Context.ObjCSelRedefinitionType->isObjCSelType()) { - BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, - CK_BitCast); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - - // Failure cases. - fail: - - // Recover from dot accesses to pointers, e.g.: - // type *foo; - // foo.bar - // This is actually well-formed in two cases: - // - 'type' is an Objective C type - // - 'bar' is a pseudo-destructor name which happens to refer to - // the appropriate pointer type - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { - if (!IsArrow && Ptr->getPointeeType()->isRecordType() && - MemberName.getNameKind() != DeclarationName::CXXDestructorName) { - Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() - << FixItHint::CreateReplacement(OpLoc, "->"); - - // Recurse as an -> access. - IsArrow = true; - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - } - - // If the user is trying to apply -> or . to a function name, it's probably - // because they forgot parentheses to call that function. - QualType ZeroArgCallTy; - UnresolvedSet<4> Overloads; - if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { - if (ZeroArgCallTy.isNull()) { - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); - UnresolvedSet<2> PlausibleOverloads; - for (OverloadExpr::decls_iterator It = Overloads.begin(), - DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { - const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); - QualType OverloadResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && OverloadResultTy->isRecordType()) || - (IsArrow && OverloadResultTy->isPointerType() && - OverloadResultTy->getPointeeType()->isRecordType())) - PlausibleOverloads.addDecl(It.getDecl()); - } - NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); - return ExprError(); - } - if ((!IsArrow && ZeroArgCallTy->isRecordType()) || - (IsArrow && ZeroArgCallTy->isPointerType() && - ZeroArgCallTy->getPointeeType()->isRecordType())) { - // At this point, we know BaseExpr looks like it's potentially callable - // with 0 arguments, and that it returns something of a reasonable type, - // so we can emit a fixit and carry on pretending that BaseExpr was - // actually a CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - // FIXME: Try this before emitting the fixit, and suppress diagnostics - // while doing so. - ExprResult NewBase = - ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc.getFileLocWithOffset(1)); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } - } - - Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr.get()->getSourceRange(); - - return ExprError(); -} - -/// The main callback when the parser finds something like -/// expression . [nested-name-specifier] identifier -/// expression -> [nested-name-specifier] identifier -/// where 'identifier' encompasses a fairly broad spectrum of -/// possibilities, including destructor and operator references. -/// -/// \param OpKind either tok::arrow or tok::period -/// \param HasTrailingLParen whether the next token is '(', which -/// is used to diagnose mis-uses of special members that can -/// only be called -/// \param ObjCImpDecl the current ObjC @implementation decl; -/// this is an ugly hack around the fact that ObjC @implementations -/// aren't properly put in the context chain -ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, - UnqualifiedId &Id, - Decl *ObjCImpDecl, - bool HasTrailingLParen) { - if (SS.isSet() && SS.isInvalid()) - return ExprError(); - - // Warn about the explicit constructor calls Microsoft extension. - if (getLangOptions().Microsoft && - Id.getKind() == UnqualifiedId::IK_ConstructorName) - Diag(Id.getSourceRange().getBegin(), - diag::ext_ms_explicit_constructor_call); - - TemplateArgumentListInfo TemplateArgsBuffer; - - // Decompose the name into its component parts. - DeclarationNameInfo NameInfo; - const TemplateArgumentListInfo *TemplateArgs; - DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, - NameInfo, TemplateArgs); - - DeclarationName Name = NameInfo.getName(); - bool IsArrow = (OpKind == tok::arrow); - - NamedDecl *FirstQualifierInScope - = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, - static_cast<NestedNameSpecifier*>(SS.getScopeRep()))); - - // This is a postfix expression, so get rid of ParenListExprs. - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); - if (Result.isInvalid()) return ExprError(); - Base = Result.take(); - - if (Base->getType()->isDependentType() || Name.isDependentName() || - isDependentScopeSpecifier(SS)) { - Result = ActOnDependentMemberExpr(Base, Base->getType(), - IsArrow, OpLoc, - SS, FirstQualifierInScope, - NameInfo, TemplateArgs); - } else { - LookupResult R(*this, NameInfo, LookupMemberName); - ExprResult BaseResult = Owned(Base); - Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, - SS, ObjCImpDecl, TemplateArgs != 0); - if (BaseResult.isInvalid()) - return ExprError(); - Base = BaseResult.take(); - - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); - } - - if (Result.get()) { - // The only way a reference to a destructor can be used is to - // immediately call it, which falls into this case. If the - // next token is not a '(', produce a diagnostic and build the - // call now. - if (!HasTrailingLParen && - Id.getKind() == UnqualifiedId::IK_DestructorName) - return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); - - return move(Result); - } - - Result = BuildMemberReferenceExpr(Base, Base->getType(), - OpLoc, IsArrow, SS, FirstQualifierInScope, - R, TemplateArgs); - } - - return move(Result); -} - ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { @@ -4716,6 +3169,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), const_cast<CXXDestructorDecl*>(Temporary->getDestructor())); ExprTemporaries.push_back(Temporary); + ExprNeedsCleanups = true; } // We already type-checked the argument, so we know it works. @@ -4834,7 +3288,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Context, Param) - : InitializedEntity::InitializeParameter(Context, ProtoArgType); + : InitializedEntity::InitializeParameter(Context, ProtoArgType, + Proto->isArgConsumed(i)); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(Arg)); @@ -5157,7 +3612,8 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (Proto && i < Proto->getNumArgs()) { InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - Proto->getArgType(i)); + Proto->getArgType(i), + Proto->isArgConsumed(i)); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(Arg)); @@ -5248,8 +3704,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializedEntity Entity = InitializedEntity::InitializeTemporary(literalType); InitializationKind Kind - = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), - /*IsCStyleCast=*/true); + = InitializationKind::CreateCStyleCast(LParenLoc, + SourceRange(LParenLoc, RParenLoc)); InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, &literalExpr, 1), @@ -5267,8 +3723,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, // In C, compound literals are l-values for some reason. ExprValueKind VK = getLangOptions().CPlusPlus ? VK_RValue : VK_LValue; - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - VK, literalExpr, isFileScope)); + return MaybeBindToTemporary( + new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, + VK, literalExpr, isFileScope)); } ExprResult @@ -5426,14 +3883,15 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { } /// CheckCastTypes - Check type constraints for casting between types. -ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, - Expr *castExpr, CastKind& Kind, ExprValueKind &VK, +ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR, + QualType castType, Expr *castExpr, + CastKind& Kind, ExprValueKind &VK, CXXCastPath &BasePath, bool FunctionalStyle) { if (castExpr->getType() == Context.UnknownAnyTy) return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(SourceRange(TyR.getBegin(), + return CXXCheckCStyleCast(SourceRange(CastStartLoc, castExpr->getLocEnd()), castType, VK, castExpr, Kind, BasePath, FunctionalStyle); @@ -5551,8 +4009,8 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, // If either type is a pointer, the other type has to be either an // integer or a pointer. + QualType castExprType = castExpr->getType(); if (!castType->isArithmeticType()) { - QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType(Context) && castExprType->isArithmeticType()) { Diag(castExpr->getLocStart(), @@ -5568,6 +4026,36 @@ ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, } } + if (getLangOptions().ObjCAutoRefCount) { + // Diagnose problems with Objective-C casts involving lifetime qualifiers. + CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()), + castType, castExpr, CCK_CStyleCast); + + if (const PointerType *CastPtr = castType->getAs<PointerType>()) { + if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) { + Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); + Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); + if (CastPtr->getPointeeType()->isObjCLifetimeType() && + ExprPtr->getPointeeType()->isObjCLifetimeType() && + !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { + Diag(castExpr->getLocStart(), + diag::err_typecheck_incompatible_ownership) + << castExprType << castType << AA_Casting + << castExpr->getSourceRange(); + + return ExprError(); + } + } + } + else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) { + Diag(castExpr->getLocStart(), + diag::err_arc_convesion_of_weak_unavailable) << 1 + << castExprType << castType + << castExpr->getSourceRange(); + return ExprError(); + } + } + castExprRes = Owned(castExpr); Kind = PrepareScalarCast(*this, castExprRes, castType); if (castExprRes.isInvalid()) @@ -5638,20 +4126,57 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, } ExprResult -Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, +Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *castExpr) { - assert((Ty != 0) && (castExpr != 0) && + assert(!D.isInvalidType() && (castExpr != 0) && "ActOnCastExpr(): missing type or expr"); - TypeSourceInfo *castTInfo; - QualType castType = GetTypeFromParser(Ty, &castTInfo); - if (!castTInfo) - castTInfo = Context.getTrivialTypeSourceInfo(castType); + TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType()); + if (D.isInvalidType()) + return ExprError(); + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + QualType castType = castTInfo->getType(); + Ty = CreateParsedType(castType, castTInfo); + + bool isVectorLiteral = false; + + // Check for an altivec or OpenCL literal, + // i.e. all the elements are integer constants. + ParenExpr *PE = dyn_cast<ParenExpr>(castExpr); + ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr); + if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) { + if (PLE && PLE->getNumExprs() == 0) { + Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer); + return ExprError(); + } + if (PE || PLE->getNumExprs() == 1) { + Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0)); + if (!E->getType()->isVectorType()) + isVectorLiteral = true; + } + else + isVectorLiteral = true; + } + + // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' + // then handle it as such. + if (isVectorLiteral) + return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo); // If the Expr being casted is a ParenListExpr, handle it specially. - if (isa<ParenListExpr>(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr, - castTInfo); + // This is not an AltiVec-style cast, so turn the ParenListExpr into a + // sequence of BinOp comma operators. + if (isa<ParenListExpr>(castExpr)) { + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr); + if (Result.isInvalid()) return ExprError(); + castExpr = Result.take(); + } return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr); } @@ -5663,8 +4188,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, ExprValueKind VK = VK_RValue; CXXCastPath BasePath; ExprResult CastResult = - CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, VK, BasePath); + CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(), + castExpr, Kind, VK, BasePath); if (CastResult.isInvalid()) return ExprError(); castExpr = CastResult.take(); @@ -5675,6 +4200,80 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, LParenLoc, RParenLoc)); } +ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo) { + assert((isa<ParenListExpr>(E) || isa<ParenExpr>(E)) && + "Expected paren or paren list expression"); + + Expr **exprs; + unsigned numExprs; + Expr *subExpr; + if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) { + exprs = PE->getExprs(); + numExprs = PE->getNumExprs(); + } else { + subExpr = cast<ParenExpr>(E)->getSubExpr(); + exprs = &subExpr; + numExprs = 1; + } + + QualType Ty = TInfo->getType(); + assert(Ty->isVectorType() && "Expected vector type"); + + llvm::SmallVector<Expr *, 8> initExprs; + const VectorType *VTy = Ty->getAs<VectorType>(); + unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); + + // '(...)' form of vector initialization in AltiVec: the number of + // initializers must be one or must match the size of the vector. + // If a single value is specified in the initializer then it will be + // replicated to all the components of the vector + if (VTy->getVectorKind() == VectorType::AltiVecVector) { + // The number of initializers must be one or must match the size of the + // vector. If a single value is specified in the initializer then it will + // be replicated to all the components of the vector + if (numExprs == 1) { + QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + ExprResult Literal = Owned(exprs[0]); + Literal = ImpCastExprToType(Literal.take(), ElemTy, + PrepareScalarCast(*this, Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); + } + else if (numExprs < numElems) { + Diag(E->getExprLoc(), + diag::err_incorrect_number_of_vector_initializers); + return ExprError(); + } + else + for (unsigned i = 0, e = numExprs; i != e; ++i) + initExprs.push_back(exprs[i]); + } + else { + // For OpenCL, when the number of initializers is a single value, + // it will be replicated to all components of the vector. + if (getLangOptions().OpenCL && + VTy->getVectorKind() == VectorType::GenericVector && + numExprs == 1) { + QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + ExprResult Literal = Owned(exprs[0]); + Literal = ImpCastExprToType(Literal.take(), ElemTy, + PrepareScalarCast(*this, Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); + } + + for (unsigned i = 0, e = numExprs; i != e; ++i) + initExprs.push_back(exprs[i]); + } + // FIXME: This means that pretty-printing the final AST will produce curly + // braces instead of the original commas. + InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc, + &initExprs[0], + initExprs.size(), RParenLoc); + initE->setType(Ty); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); +} + /// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence /// of comma binary operators. ExprResult @@ -5694,91 +4293,18 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get()); } -ExprResult -Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, - SourceLocation RParenLoc, Expr *Op, - TypeSourceInfo *TInfo) { - ParenListExpr *PE = cast<ParenListExpr>(Op); - QualType Ty = TInfo->getType(); - bool isVectorLiteral = false; - - // Check for an altivec or OpenCL literal, - // i.e. all the elements are integer constants. - if (getLangOptions().AltiVec && Ty->isVectorType()) { - if (PE->getNumExprs() == 0) { - Diag(PE->getExprLoc(), diag::err_altivec_empty_initializer); - return ExprError(); - } - if (PE->getNumExprs() == 1) { - if (!PE->getExpr(0)->getType()->isVectorType()) - isVectorLiteral = true; - } - else - isVectorLiteral = true; - } - - // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' - // then handle it as such. - if (isVectorLiteral) { - llvm::SmallVector<Expr *, 8> initExprs; - // '(...)' form of vector initialization in AltiVec: the number of - // initializers must be one or must match the size of the vector. - // If a single value is specified in the initializer then it will be - // replicated to all the components of the vector - if (Ty->getAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector) { - unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); - // The number of initializers must be one or must match the size of the - // vector. If a single value is specified in the initializer then it will - // be replicated to all the components of the vector - if (PE->getNumExprs() == 1) { - QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); - ExprResult Literal = Owned(PE->getExpr(0)); - Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); - } - else if (PE->getNumExprs() < numElems) { - Diag(PE->getExprLoc(), - diag::err_incorrect_number_of_vector_initializers); - return ExprError(); - } - else - for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) - initExprs.push_back(PE->getExpr(i)); - } - else - for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) - initExprs.push_back(PE->getExpr(i)); - - // FIXME: This means that pretty-printing the final AST will produce curly - // braces instead of the original commas. - InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc, - &initExprs[0], - initExprs.size(), RParenLoc); - E->setType(Ty); - return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E); - } else { - // This is not an AltiVec-style cast, so turn the ParenListExpr into a - // sequence of BinOp comma operators. - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op); - if (Result.isInvalid()) return ExprError(); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take()); - } -} - ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, - MultiExprArg Val, - ParsedType TypeOfCast) { + MultiExprArg Val) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast<Expr**>(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); Expr *expr; - if (nexprs == 1 && TypeOfCast && !TypeIsVectorType(TypeOfCast)) + if (nexprs == 1) expr = new (Context) ParenExpr(L, R, exprs[0]); else - expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); + expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R, + exprs[nexprs-1]->getType()); return Owned(expr); } @@ -5876,7 +4402,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Now check the two expressions. if (LHSTy->isVectorType() || RHSTy->isVectorType()) - return CheckVectorOperands(QuestionLoc, LHS, RHS); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false); // OpenCL: If the condition is a vector, and both operands are scalar, // attempt to implicity convert them to the vector type to act like the @@ -6203,43 +4729,21 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, return QualType(); } -/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// SuggestParentheses - Emit a note with a fixit hint that wraps /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, - const PartialDiagnostic &PD, - const PartialDiagnostic &FirstNote, - SourceRange FirstParenRange, - const PartialDiagnostic &SecondNote, - SourceRange SecondParenRange) { - Self.Diag(Loc, PD); - - if (!FirstNote.getDiagID()) - return; - - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); - if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just return. - return; - } - - Self.Diag(Loc, FirstNote) - << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - - if (!SecondNote.getDiagID()) - return; - - EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); - if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, SecondNote); - return; + const PartialDiagnostic &Note, + SourceRange ParenRange) { + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); + if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() && + EndLoc.isValid()) { + Self.Diag(Loc, Note) + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + } else { + // We can't display the parentheses, so just show the bare note. + Self.Diag(Loc, Note) << ParenRange; } - - Self.Diag(Loc, SecondNote) - << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); } static bool IsArithmeticOp(BinaryOperatorKind Opc) { @@ -6312,13 +4816,13 @@ static bool ExprLooksBoolean(Expr *E) { /// "int x = a + someBinaryCondition ? 1 : 2". static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, - Expr *cond, - Expr *lhs, - Expr *rhs) { + Expr *Condition, + Expr *LHS, + Expr *RHS) { BinaryOperatorKind CondOpcode; Expr *CondRHS; - if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS)) + if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS)) return; if (!ExprLooksBoolean(CondRHS)) return; @@ -6326,25 +4830,18 @@ static void DiagnoseConditionalPrecedence(Sema &Self, // The condition is an arithmetic binary expression, with a right- // hand side that looks boolean, so warn. - PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional) - << cond->getSourceRange() - << BinaryOperator::getOpcodeStr(CondOpcode); - - PartialDiagnostic FirstNote = - Self.PDiag(diag::note_precedence_conditional_silence) + Self.Diag(OpLoc, diag::warn_precedence_conditional) + << Condition->getSourceRange() << BinaryOperator::getOpcodeStr(CondOpcode); - SourceRange FirstParenRange(cond->getLocStart(), - cond->getLocEnd()); - - PartialDiagnostic SecondNote = - Self.PDiag(diag::note_precedence_conditional_first); - - SourceRange SecondParenRange(CondRHS->getLocStart(), - rhs->getLocEnd()); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_conditional_silence) + << BinaryOperator::getOpcodeStr(CondOpcode), + SourceRange(Condition->getLocStart(), Condition->getLocEnd())); - SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange, - SecondNote, SecondParenRange); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_conditional_first), + SourceRange(CondRHS->getLocStart(), RHS->getLocEnd())); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null @@ -6427,17 +4924,31 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { // qualifiers of the type *pointed to* by the right; Qualifiers lq; + // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay. + if (lhq.getObjCLifetime() != rhq.getObjCLifetime() && + lhq.compatiblyIncludesObjCLifetime(rhq)) { + // Ignore lifetime for further calculation. + lhq.removeObjCLifetime(); + rhq.removeObjCLifetime(); + } + if (!lhq.compatiblyIncludes(rhq)) { // Treat address-space mismatches as fatal. TODO: address subspaces if (lhq.getAddressSpace() != rhq.getAddressSpace()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; - // It's okay to add or remove GC qualifiers when converting to + // It's okay to add or remove GC or lifetime qualifiers when converting to // and from void*. - else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr()) + else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime() + .compatiblyIncludes( + rhq.withoutObjCGCAttr().withoutObjCGLifetime()) && (lhptee->isVoidType() || rhptee->isVoidType())) ; // keep old + // Treat lifetime mismatches as fatal. + else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) + ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + // For GCC compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; @@ -6614,6 +5125,7 @@ Sema::AssignConvertType Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, CastKind &Kind) { QualType rhsType = rhs.get()->getType(); + QualType origLhsType = lhsType; // Get canonical types. We're not formatting these types, just comparing // them. @@ -6768,7 +5280,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // A* -> B* if (rhsType->isObjCObjectPointerType()) { Kind = CK_BitCast; - return checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + Sema::AssignConvertType result = + checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + if (getLangOptions().ObjCAutoRefCount && + result == Compatible && + !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType)) + result = IncompatibleObjCWeakRef; + return result; } // int or null -> A* @@ -6936,8 +5454,12 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { AA_Assigning); if (Res.isInvalid()) return Incompatible; + Sema::AssignConvertType result = Compatible; + if (getLangOptions().ObjCAutoRefCount && + !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType())) + result = IncompatibleObjCWeakRef; rExpr = move(Res); - return Compatible; + return result; } // FIXME: Currently, we fall through and treat C++ classes like C @@ -6989,7 +5511,8 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult & return QualType(); } -QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { +QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex, + SourceLocation Loc, bool isCompAssign) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = @@ -7001,42 +5524,33 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu if (lhsType == rhsType) return lhsType; - // Handle the case of a vector & extvector type of the same size and element - // type. It would be nice if we only had one vector type someday. - if (getLangOptions().LaxVectorConversions) { - if (const VectorType *LV = lhsType->getAs<VectorType>()) { - if (const VectorType *RV = rhsType->getAs<VectorType>()) { - if (LV->getElementType() == RV->getElementType() && - LV->getNumElements() == RV->getNumElements()) { - if (lhsType->isExtVectorType()) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; - } - - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); - return rhsType; - } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){ - // If we are allowing lax vector conversions, and LHS and RHS are both - // vectors, the total size only needs to be the same. This is a - // bitcast; no bits are changed but the result type is different. - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; - } - } - } - } - // Handle the case of equivalent AltiVec and GCC vector types if (lhsType->isVectorType() && rhsType->isVectorType() && Context.areCompatibleVectorTypes(lhsType, rhsType)) { - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); + if (lhsType->isExtVectorType()) { + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); + return lhsType; + } + + if (!isCompAssign) + lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); return rhsType; } + if (getLangOptions().LaxVectorConversions && + Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) { + // If we are allowing lax vector conversions, and LHS and RHS are both + // vectors, the total size only needs to be the same. This is a + // bitcast; no bits are changed but the result type is different. + // FIXME: Should we really be allowing this? + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); + return lhsType; + } + // Canonicalize the ExtVector to the LHS, remember if we swapped so we can // swap back (so that we don't reverse the inputs to a subtract, for instance. bool swapped = false; - if (rhsType->isExtVectorType()) { + if (rhsType->isExtVectorType() && !isCompAssign) { swapped = true; std::swap(rex, lex); std::swap(rhsType, lhsType); @@ -7069,6 +5583,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu } // Vectors of different size or scalar and non-ext-vector are errors. + if (swapped) std::swap(rex, lex); Diag(Loc, diag::err_typecheck_vector_not_convertable) << lex.get()->getType() << rex.get()->getType() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); @@ -7078,7 +5593,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResu QualType Sema::CheckMultiplyDivideOperands( ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); if (lex.isInvalid() || rex.isInvalid()) @@ -7102,7 +5617,7 @@ QualType Sema::CheckRemainderOperands( if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { if (lex.get()->getType()->hasIntegerRepresentation() && rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); return InvalidOperands(Loc, lex, rex); } @@ -7121,10 +5636,149 @@ QualType Sema::CheckRemainderOperands( return compType; } +/// \brief Diagnose invalid arithmetic on two void pointers. +static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_void_type + : diag::ext_gnu_void_ptr) + << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on a void pointer. +static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, + Expr *Pointer) { + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_void_type + : diag::ext_gnu_void_ptr) + << 0 /* one pointer */ << Pointer->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on two function pointers. +static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + assert(LHS->getType()->isAnyPointerType()); + assert(RHS->getType()->isAnyPointerType()); + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_function_type + : diag::ext_gnu_ptr_func_arith) + << 1 /* two pointers */ << LHS->getType()->getPointeeType() + // We only show the second type if it differs from the first. + << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(), + RHS->getType()) + << RHS->getType()->getPointeeType() + << LHS->getSourceRange() << RHS->getSourceRange(); +} + +/// \brief Diagnose invalid arithmetic on a function pointer. +static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, + Expr *Pointer) { + assert(Pointer->getType()->isAnyPointerType()); + S.Diag(Loc, S.getLangOptions().CPlusPlus + ? diag::err_typecheck_pointer_arith_function_type + : diag::ext_gnu_ptr_func_arith) + << 0 /* one pointer */ << Pointer->getType()->getPointeeType() + << 0 /* one pointer, so only one type */ + << Pointer->getSourceRange(); +} + +/// \brief Check the validity of an arithmetic pointer operand. +/// +/// If the operand has pointer type, this code will check for pointer types +/// which are invalid in arithmetic operations. These will be diagnosed +/// appropriately, including whether or not the use is supported as an +/// extension. +/// +/// \returns True when the operand is valid to use (even if as an extension). +static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, + Expr *Operand) { + if (!Operand->getType()->isAnyPointerType()) return true; + + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (PointeeTy->isVoidType()) { + diagnoseArithmeticOnVoidPointer(S, Loc, Operand); + return !S.getLangOptions().CPlusPlus; + } + if (PointeeTy->isFunctionType()) { + diagnoseArithmeticOnFunctionPointer(S, Loc, Operand); + return !S.getLangOptions().CPlusPlus; + } + + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return false; + } + + return true; +} + +/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer +/// operands. +/// +/// This routine will diagnose any invalid arithmetic on pointer operands much +/// like \see checkArithmeticOpPointerOperand. However, it has special logic +/// for emitting a single diagnostic even for operations where both LHS and RHS +/// are (potentially problematic) pointers. +/// +/// \returns True when the operand is valid to use (even if as an extension). +static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS) { + bool isLHSPointer = LHS->getType()->isAnyPointerType(); + bool isRHSPointer = RHS->getType()->isAnyPointerType(); + if (!isLHSPointer && !isRHSPointer) return true; + + QualType LHSPointeeTy, RHSPointeeTy; + if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType(); + if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType(); + + // Check for arithmetic on pointers to incomplete types. + bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); + bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); + if (isLHSVoidPtr || isRHSVoidPtr) { + if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS); + else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS); + else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS); + + return !S.getLangOptions().CPlusPlus; + } + + bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType(); + bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType(); + if (isLHSFuncPtr || isRHSFuncPtr) { + if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS); + else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS); + else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS); + + return !S.getLangOptions().CPlusPlus; + } + + Expr *Operands[] = { LHS, RHS }; + for (unsigned i = 0; i < 2; ++i) { + Expr *Operand = Operands[i]; + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return false; + } + } + return true; +} + QualType Sema::CheckAdditionOperands( // C99 6.5.6 ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(Loc, lex, rex); + QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -7146,42 +5800,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 std::swap(PExp, IExp); if (PExp->getType()->isAnyPointerType()) { - if (IExp->getType()->isIntegerType()) { - QualType PointeeTy = PExp->getType()->getPointeeType(); - - // Check for arithmetic on pointers to incomplete types. - if (PointeeTy->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) + return QualType(); - // GNU extension: arithmetic on pointer to void - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } else if (PointeeTy->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex.get()->getType() << lex.get()->getSourceRange(); - return QualType(); - } + QualType PointeeTy = PExp->getType()->getPointeeType(); - // GNU extension: arithmetic on pointer to function - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << lex.get()->getType() << lex.get()->getSourceRange(); - } else { - // Check if we require a complete type. - if (((PExp->getType()->isPointerType() && - !PExp->getType()->isDependentType()) || - PExp->getType()->isObjCObjectPointerType()) && - RequireCompleteType(Loc, PointeeTy, - PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PExp->getSourceRange() - << PExp->getType())) - return QualType(); - } // Diagnose bad cases where we step over interface counts. if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) @@ -7209,7 +5833,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(Loc, lex, rex); + QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -7231,35 +5855,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, if (lex.get()->getType()->isAnyPointerType()) { QualType lpointee = lex.get()->getType()->getPointeeType(); - // The LHS must be an completely-defined object type. - - bool ComplainAboutVoid = false; - Expr *ComplainAboutFunc = 0; - if (lpointee->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } - - // GNU C extension: arithmetic on pointer to void - ComplainAboutVoid = true; - } else if (lpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex.get()->getType() << lex.get()->getSourceRange(); - return QualType(); - } - - // GNU C extension: arithmetic on pointer to function - ComplainAboutFunc = lex.get(); - } else if (!lpointee->isDependentType() && - RequireCompleteType(Loc, lpointee, - PDiag(diag::err_typecheck_sub_ptr_object) - << lex.get()->getSourceRange() - << lex.get()->getType())) - return QualType(); - // Diagnose bad cases where we step over interface counts. if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) @@ -7269,13 +5864,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, // The result type of a pointer-int computation is the pointer type. if (rex.get()->getType()->isIntegerType()) { - if (ComplainAboutVoid) - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - if (ComplainAboutFunc) - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() - << ComplainAboutFunc->getSourceRange(); + if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get())) + return QualType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType(); return lex.get()->getType(); @@ -7285,33 +5875,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) { QualType rpointee = RHSPTy->getPointeeType(); - // RHS must be a completely-type object type. - // Handle the GNU void* extension. - if (rpointee->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); - } - - ComplainAboutVoid = true; - } else if (rpointee->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << rex.get()->getType() << rex.get()->getSourceRange(); - return QualType(); - } - - // GNU extension: arithmetic on pointer to function - if (!ComplainAboutFunc) - ComplainAboutFunc = rex.get(); - } else if (!rpointee->isDependentType() && - RequireCompleteType(Loc, rpointee, - PDiag(diag::err_typecheck_sub_ptr_object) - << rex.get()->getSourceRange() - << rex.get()->getType())) - return QualType(); - if (getLangOptions().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { @@ -7332,13 +5895,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, } } - if (ComplainAboutVoid) - Diag(Loc, diag::ext_gnu_void_ptr) - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - if (ComplainAboutFunc) - Diag(Loc, diag::ext_gnu_ptr_func_arith) - << ComplainAboutFunc->getType() - << ComplainAboutFunc->getSourceRange(); + if (!checkArithmeticBinOpPointerOperands(*this, Loc, + lex.get(), rex.get())) + return QualType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType(); return Context.getPointerDiffType(); @@ -7394,19 +5953,24 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue()); Result = Result.shl(Right); + // Print the bit representation of the signed integer as an unsigned + // hexadecimal number. + llvm::SmallString<40> HexResult; + Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true); + // If we are only missing a sign bit, this is less likely to result in actual // bugs -- if the result is cast back to an unsigned type, it will have the // expected value. Thus we place this behind a different warning that can be // turned off separately if needed. if (LeftBits == ResultBits - 1) { - S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit) - << Result.toString(10) << LHSTy + S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) + << HexResult.str() << LHSTy << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << Result.toString(10) << Result.getMinSignedBits() << LHSTy + << HexResult.str() << Result.getMinSignedBits() << LHSTy << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } @@ -7427,7 +5991,7 @@ QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocati // Vector shifts promote their scalar inputs to vector type. if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 @@ -7720,7 +6284,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // comparisons of member pointers to null pointer constants. if (RHSIsNull && ((lType->isAnyPointerType() || lType->isNullPtrType()) || - (!isRelational && lType->isMemberPointerType()))) { + (!isRelational && + (lType->isMemberPointerType() || lType->isBlockPointerType())))) { rex = ImpCastExprToType(rex.take(), lType, lType->isMemberPointerType() ? CK_NullToMemberPointer @@ -7729,7 +6294,8 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca } if (LHSIsNull && ((rType->isAnyPointerType() || rType->isNullPtrType()) || - (!isRelational && rType->isMemberPointerType()))) { + (!isRelational && + (rType->isMemberPointerType() || rType->isBlockPointerType())))) { lex = ImpCastExprToType(lex.take(), rType, rType->isMemberPointerType() ? CK_NullToMemberPointer @@ -7894,7 +6460,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, bool isRelational) { // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(Loc, lex, rex); + QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false); if (vType.isNull()) return vType; @@ -7949,7 +6515,7 @@ inline QualType Sema::CheckBitwiseOperands( if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { if (lex.get()->getType()->hasIntegerRepresentation() && rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(Loc, lex, rex); + return CheckVectorOperands(lex, rex, Loc, isCompAssign); return InvalidOperands(Loc, lex, rex); } @@ -7975,8 +6541,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // is a constant. if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() && rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() && - // Don't warn in macros. - !Loc.isMacroID()) { + // Don't warn in macros or template instantiations. + !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) { // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. @@ -8099,7 +6665,43 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { unsigned Diag = 0; bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 - case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break; + case Expr::MLV_ConstQualified: + Diag = diag::err_typecheck_assign_const; + + // In ARC, use some specialized diagnostics for occasions where we + // infer 'const'. These are always pseudo-strong variables. + if (S.getLangOptions().ObjCAutoRefCount) { + DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()); + if (declRef && isa<VarDecl>(declRef->getDecl())) { + VarDecl *var = cast<VarDecl>(declRef->getDecl()); + + // Use the normal diagnostic if it's pseudo-__strong but the + // user actually wrote 'const'. + if (var->isARCPseudoStrong() && + (!var->getTypeSourceInfo() || + !var->getTypeSourceInfo()->getType().isConstQualified())) { + // There are two pseudo-strong cases: + // - self + ObjCMethodDecl *method = S.getCurMethodDecl(); + if (method && var == method->getSelfDecl()) + Diag = diag::err_typecheck_arr_assign_self; + + // - fast enumeration variables + else + Diag = diag::err_typecheck_arr_assign_enumeration; + + SourceRange Assign; + if (Loc != OrigLoc) + Assign = SourceRange(OrigLoc, OrigLoc); + S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + // We need to preserve the AST regardless, so migration tool + // can do its job. + return false; + } + } + } + + break; case Expr::MLV_ArrayType: Diag = diag::err_typecheck_array_not_modifiable_lvalue; NeedType = true; @@ -8214,6 +6816,13 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc()); } } + + if (ConvTy == Compatible) { + if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) + checkRetainCycles(LHS, RHS.get()); + else if (getLangOptions().ObjCAutoRefCount) + checkUnsafeExprAssigns(Loc, LHS, RHS.get()); + } } else { // Compound assignment "x += y" ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType); @@ -8295,29 +6904,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, QualType PointeeTy = ResType->getPointeeType(); // C99 6.5.2.4p2, 6.5.6p2 - if (PointeeTy->isVoidType()) { - if (S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) - << Op->getSourceRange(); - return QualType(); - } - - // Pointer to void is a GNU extension in C. - S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); - } else if (PointeeTy->isFunctionType()) { - if (S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) - << Op->getType() << Op->getSourceRange(); - return QualType(); - } - - S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith) - << ResType << Op->getSourceRange(); - } else if (S.RequireCompleteType(OpLoc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << Op->getSourceRange() - << ResType)) + if (!checkArithmeticOpPointerOperand(S, OpLoc, Op)) return QualType(); + // Diagnose bad cases where we step over interface counts. else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) @@ -8400,6 +6989,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & LHS.get()->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); + bool Consumed = false; + if (PropRef->isImplicitProperty()) { // If using property-dot syntax notation for assignment, and there is a // setter, RHS expression is being passed to the setter argument. So, @@ -8407,6 +6998,8 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); LHSTy = (*P)->getType(); + Consumed = (getLangOptions().ObjCAutoRefCount && + (*P)->hasAttr<NSConsumedAttr>()); // Otherwise, if the getter returns an l-value, just call that. } else { @@ -8418,14 +7011,26 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & return; } } + } else if (getLangOptions().ObjCAutoRefCount) { + const ObjCMethodDecl *setter + = PropRef->getExplicitProperty()->getSetterMethodDecl(); + if (setter) { + ObjCMethodDecl::param_iterator P = setter->param_begin(); + LHSTy = (*P)->getType(); + Consumed = (*P)->hasAttr<NSConsumedAttr>(); + } } - if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) { + if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) || + getLangOptions().ObjCAutoRefCount) { InitializedEntity Entity = - InitializedEntity::InitializeParameter(Context, LHSTy); + InitializedEntity::InitializeParameter(Context, LHSTy, Consumed); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS); - if (!ArgE.isInvalid()) + if (!ArgE.isInvalid()) { RHS = ArgE; + if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver()) + checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get()); + } } } @@ -8682,8 +7287,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, VK = VK_LValue; // ...except that certain expressions are never l-values in C. - if (!S.getLangOptions().CPlusPlus && - IsCForbiddenLValueType(S.Context, Result)) + if (!S.getLangOptions().CPlusPlus && Result.isCForbiddenLValueType()) VK = VK_RValue; return Result; @@ -8815,6 +7419,53 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, rhs = move(resolvedRHS); } + // The canonical way to check for a GNU null is with isNullPointerConstant, + // but we use a bit of a hack here for speed; this is a relatively + // hot path, and isNullPointerConstant is slow. + bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts()); + bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts()); + + // Detect when a NULL constant is used improperly in an expression. These + // are mainly cases where the null pointer is used as an integer instead + // of a pointer. + if (LeftNull || RightNull) { + // Avoid analyzing cases where the result will either be invalid (and + // diagnosed as such) or entirely valid and not something to warn about. + QualType LeftType = lhs.get()->getType(); + QualType RightType = rhs.get()->getType(); + if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() && + !LeftType->isFunctionType() && + !RightType->isBlockPointerType() && + !RightType->isMemberPointerType() && + !RightType->isFunctionType()) { + if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || + Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || + Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || + Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || + Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || + Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { + // These are the operations that would not make sense with a null pointer + // no matter what the other expression is. + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) + << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); + } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || + Opc == BO_EQ || Opc == BO_NE) { + // These are the operations that would not make sense with a null pointer + // if the other expression the other expression is not a pointer. + if (LeftNull != RightNull && + !LeftType->isAnyPointerType() && + !LeftType->canDecayToPointerType() && + !RightType->isAnyPointerType() && + !RightType->canDecayToPointerType()) { + Diag(OpLoc, diag::warn_null_in_arithmetic_operation) + << (LeftNull ? lhs.get()->getSourceRange() + : rhs.get()->getSourceRange()); + } + } + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); @@ -8953,28 +7604,46 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) return; - if (BinOp::isComparisonOp(lhsopc)) + if (BinOp::isComparisonOp(lhsopc)) { + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(lhs->getLocStart(), OpLoc) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc); SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::warn_precedence_bitwise_rel) - << SourceRange(lhs->getLocStart(), OpLoc) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), Self.PDiag(diag::note_precedence_bitwise_silence) << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange(), + lhs->getSourceRange()); + SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); - else if (BinOp::isComparisonOp(rhsopc)) + } else if (BinOp::isComparisonOp(rhsopc)) { + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(OpLoc, rhs->getLocEnd()) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc); SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::warn_precedence_bitwise_rel) - << SourceRange(OpLoc, rhs->getLocEnd()) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), Self.PDiag(diag::note_precedence_bitwise_silence) << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange(), + rhs->getSourceRange()); + SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); + SourceRange(lhs->getLocStart(), + cast<BinOp>(rhs)->getLHS()->getLocStart())); + } +} + +/// \brief It accepts a '&' expr that is inside a '|' one. +/// Emit a diagnostic together with a fixit hint that wraps the '&' expression +/// in parentheses. +static void +EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc, + BinaryOperator *Bop) { + assert(Bop->getOpcode() == BO_And); + Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or) + << Bop->getSourceRange() << OpLoc; + SuggestParentheses(Self, Bop->getOperatorLoc(), + Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence), + Bop->getSourceRange()); } /// \brief It accepts a '&&' expr that is inside a '||' one. @@ -8984,12 +7653,11 @@ static void EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, BinaryOperator *Bop) { assert(Bop->getOpcode() == BO_LAnd); + Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) + << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), - Self.PDiag(diag::warn_logical_and_in_logical_or) - << Bop->getSourceRange() << OpLoc, Self.PDiag(diag::note_logical_and_in_logical_or_silence), - Bop->getSourceRange(), - Self.PDiag(0), SourceRange()); + Bop->getSourceRange()); } /// \brief Returns true if the given expression can be evaluated as a constant @@ -9043,13 +7711,28 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, } } +/// \brief Look for '&' in the left or right hand of a '|' expr. +static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, + Expr *OrArg) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrArg)) { + if (Bop->getOpcode() == BO_And) + return EmitDiagnosticForBitwiseAndInBitwiseOr(S, OpLoc, Bop); + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *lhs, Expr *rhs){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - return DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + + // Diagnose "arg1 & arg2 | arg3" + if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) { + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs); + } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. @@ -9274,6 +7957,29 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, Context.getPointerType(Context.VoidTy))); } +/// Given the last statement in a statement-expression, check whether +/// the result is a producing expression (like a call to an +/// ns_returns_retained function) and, if so, rebuild it to hoist the +/// release out of the full-expression. Otherwise, return null. +/// Cannot fail. +static Expr *maybeRebuildARCConsumingStmt(Stmt *s) { + // Should always be wrapped with one of these. + ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s); + if (!cleanups) return 0; + + ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr()); + if (!cast || cast->getCastKind() != CK_ObjCConsumeObject) + return 0; + + // Splice out the cast. This shouldn't modify any interesting + // features of the statement. + Expr *producer = cast->getSubExpr(); + assert(producer->getType() == cast->getType()); + assert(producer->getValueKind() == cast->getValueKind()); + cleanups->setSubExpr(producer); + return cleanups; +} + ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc) { // "({..})" @@ -9301,6 +8007,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, LastLabelStmt = Label; LastStmt = Label->getSubStmt(); } + if (Expr *LastE = dyn_cast<Expr>(LastStmt)) { // Do function/array conversion on the last expression, but not // lvalue-to-rvalue. However, initialize an unqualified type. @@ -9310,12 +8017,24 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, Ty = LastExpr.get()->getType().getUnqualifiedType(); if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) { - LastExpr = PerformCopyInitialization( + // In ARC, if the final expression ends in a consume, splice + // the consume out and bind it later. In the alternate case + // (when dealing with a retainable type), the result + // initialization will create a produce. In both cases the + // result will be +1, and we'll need to balance that out with + // a bind. + if (Expr *rebuiltLastStmt + = maybeRebuildARCConsumingStmt(LastExpr.get())) { + LastExpr = rebuiltLastStmt; + } else { + LastExpr = PerformCopyInitialization( InitializedEntity::InitializeResult(LPLoc, Ty, false), SourceLocation(), - LastExpr); + LastExpr); + } + if (LastExpr.isInvalid()) return ExprError(); if (LastExpr.get() != 0) { @@ -9757,7 +8476,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If we don't have a function type, just build one from nothing. } else { FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default); + EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); } @@ -9766,15 +8485,25 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. - if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + if (getCurFunction()->NeedsScopeChecking() && + !hasAnyUnrecoverableErrorsInThisFunction()) DiagnoseInvalidJumps(cast<CompoundStmt>(Body)); BSI->TheDecl->setBody(cast<CompoundStmt>(Body)); - BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); + for (BlockDecl::capture_const_iterator ci = BSI->TheDecl->capture_begin(), + ce = BSI->TheDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType T = variable->getType(); + QualType::DestructionKind destructKind = T.isDestructedType(); + if (destructKind != QualType::DK_none) + getCurFunction()->setHasBranchProtectedScope(); + } + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result); + return Owned(Result); } @@ -9818,8 +8547,41 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << OrigExpr->getType() << E->getSourceRange()); } - // FIXME: Check that type is complete/non-abstract - // FIXME: Warn if a non-POD type is passed in. + if (!TInfo->getType()->isDependentType()) { + if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), + PDiag(diag::err_second_parameter_to_va_arg_incomplete) + << TInfo->getTypeLoc().getSourceRange())) + return ExprError(); + + if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(), + TInfo->getType(), + PDiag(diag::err_second_parameter_to_va_arg_abstract) + << TInfo->getTypeLoc().getSourceRange())) + return ExprError(); + + if (!TInfo->getType().isPODType(Context)) + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::warn_second_parameter_to_va_arg_not_pod) + << TInfo->getType() + << TInfo->getTypeLoc().getSourceRange(); + + // Check for va_arg where arguments of the given type will be promoted + // (i.e. this va_arg is guaranteed to have undefined behavior). + QualType PromoteType; + if (TInfo->getType()->isPromotableIntegerType()) { + PromoteType = Context.getPromotedIntegerType(TInfo->getType()); + if (Context.typesAreCompatible(PromoteType, TInfo->getType())) + PromoteType = QualType(); + } + if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float)) + PromoteType = Context.DoubleTy; + if (!PromoteType.isNull()) + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::warn_second_parameter_to_va_arg_never_compatible) + << TInfo->getType() + << PromoteType + << TInfo->getTypeLoc().getSourceRange(); + } QualType T = TInfo->getType().getNonLValueExprType(Context); return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T)); @@ -9913,6 +8675,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (lhq.getAddressSpace() != rhq.getAddressSpace()) { DiagKind = diag::err_typecheck_incompatible_address_space; break; + + + } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) { + DiagKind = diag::err_typecheck_incompatible_ownership; + break; } llvm_unreachable("unknown error case for discarding qualifiers!"); @@ -9950,6 +8717,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, case IncompatibleVectors: DiagKind = diag::warn_incompatible_vectors; break; + case IncompatibleObjCWeakRef: + DiagKind = diag::err_arc_weak_unavailable_assign; + break; case Incompatible: DiagKind = diag::err_typecheck_convert_incompatible; isInvalid = true; @@ -10027,7 +8797,10 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size())); + ExpressionEvaluationContextRecord(NewContext, + ExprTemporaries.size(), + ExprNeedsCleanups)); + ExprNeedsCleanups = false; } void @@ -10062,15 +8835,27 @@ Sema::PopExpressionEvaluationContext() { // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. - if (Rec.Context == Unevaluated && - ExprTemporaries.size() > Rec.NumTemporaries) + if (Rec.Context == Unevaluated) { ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, ExprTemporaries.end()); + ExprNeedsCleanups = Rec.ParentNeedsCleanups; + + // Otherwise, merge the contexts together. + } else { + ExprNeedsCleanups |= Rec.ParentNeedsCleanups; + } // Destroy the popped expression evaluation record. Rec.Destroy(); } +void Sema::DiscardCleanupsInEvaluationContext() { + ExprTemporaries.erase( + ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries, + ExprTemporaries.end()); + ExprNeedsCleanups = false; +} + /// \brief Note that the given declaration was referenced in the source code. /// /// This routine should be invoke whenever a given declaration is referenced @@ -10364,7 +9149,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, const PartialDiagnostic &PD) { - switch (ExprEvalContexts.back().Context ) { + switch (ExprEvalContexts.back().Context) { case Unevaluated: // The argument will never be evaluated, so don't complain. break; @@ -10780,9 +9565,6 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { } ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { - ObjCMethodDecl *method = msg->getMethodDecl(); - assert(method && "__unknown_anytype message without result type?"); - // Verify that this is a legal result type of a call. if (DestType->isArrayType() || DestType->isFunctionType()) { S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function) @@ -10790,8 +9572,11 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { return ExprError(); } - assert(method->getResultType() == S.Context.UnknownAnyTy); - method->setResultType(DestType); + // Rewrite the method result type if available. + if (ObjCMethodDecl *method = msg->getMethodDecl()) { + assert(method->getResultType() == S.Context.UnknownAnyTy); + method->setResultType(DestType); + } // Change the type of the message. msg->setType(DestType.getNonReferenceType()); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 2f5a890..e804fcd 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -480,23 +480,63 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { /// ActOnCXXThrow - Parse throw expressions. ExprResult -Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) { +Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { + bool IsThrownVarInScope = false; + if (Ex) { + // C++0x [class.copymove]p31: + // When certain criteria are met, an implementation is allowed to omit the + // copy/move construction of a class object [...] + // + // - in a throw-expression, when the operand is the name of a + // non-volatile automatic object (other than a function or catch- + // clause parameter) whose scope does not extend beyond the end of the + // innermost enclosing try-block (if there is one), the copy/move + // operation from the operand to the exception object (15.1) can be + // omitted by constructing the automatic object directly into the + // exception object + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens())) + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) { + for( ; S; S = S->getParent()) { + if (S->isDeclScope(Var)) { + IsThrownVarInScope = true; + break; + } + + if (S->getFlags() & + (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | + Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | + Scope::TryScope)) + break; + } + } + } + } + + return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); +} + +ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, + bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOptions().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc)) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; - + if (Ex && !Ex->isTypeDependent()) { - ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex); + ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope); if (ExRes.isInvalid()) return ExprError(); Ex = ExRes.take(); } - return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); + + return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, + IsThrownVarInScope)); } /// CheckCXXThrowOperand - Validate the operand of a throw. -ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { +ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, + bool IsThrownVarInScope) { // C++ [except.throw]p3: // A throw-expression initializes a temporary object, called the exception // object, the type of which is determined by removing any top-level @@ -535,14 +575,28 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. - const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false); - - // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32. + + // C++0x [class.copymove]p31: + // When certain criteria are met, an implementation is allowed to omit the + // copy/move construction of a class object [...] + // + // - in a throw-expression, when the operand is the name of a + // non-volatile automatic object (other than a function or catch-clause + // parameter) whose scope does not extend beyond the end of the + // innermost enclosing try-block (if there is one), the copy/move + // operation from the operand to the exception object (15.1) can be + // omitted by constructing the automatic object directly into the + // exception object + const VarDecl *NRVOVariable = 0; + if (IsThrownVarInScope) + NRVOVariable = getCopyElisionCandidate(QualType(), E, false); + InitializedEntity Entity = InitializedEntity::InitializeException(ThrowLoc, E->getType(), - /*NRVO=*/false); + /*NRVO=*/NRVOVariable != 0); Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, - QualType(), E); + QualType(), E, + IsThrownVarInScope); if (Res.isInvalid()) return ExprError(); E = Res.take(); @@ -691,7 +745,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, ExprValueKind VK = VK_RValue; CXXCastPath BasePath; ExprResult CastExpr = - CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], + CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(), + TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], Kind, VK, BasePath, /*FunctionalStyle=*/true); if (CastExpr.isInvalid()) @@ -827,8 +882,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0, - /*AllowAuto=*/true); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); @@ -902,8 +956,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); - QualType ResultType = Context.getPointerType(AllocType); + // In ARC, infer 'retaining' for the allocated + if (getLangOptions().ObjCAutoRefCount && + AllocType.getObjCLifetime() == Qualifiers::OCL_None && + AllocType->isObjCLifetimeType()) { + AllocType = Context.getLifetimeQualifiedType(AllocType, + AllocType->getObjCARCImplicitLifetime()); + } + QualType ResultType = Context.getPointerType(AllocType); + // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { @@ -964,6 +1026,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } + // ARC: warn about ABI issues. + if (getLangOptions().ObjCAutoRefCount) { + QualType BaseAllocType = Context.getBaseElementType(AllocType); + if (BaseAllocType.hasStrongOrWeakObjCLifetime()) + Diag(StartLoc, diag::warn_err_new_delete_object_array) + << 0 << BaseAllocType; + } + // Note that we do *not* convert the argument in any way. It can // be signed, larger than size_t, whatever. } @@ -1078,7 +1148,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (OperatorDelete) MarkDeclarationReferenced(StartLoc, OperatorDelete); - // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) + // C++0x [expr.new]p17: + // If the new expression creates an array of objects of class type, + // access and ambiguity control are done for the destructor. + if (ArraySize && Constructor) { + if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) { + MarkDeclarationReferenced(StartLoc, dtor); + CheckDestructorAccess(StartLoc, dtor, + PDiag(diag::err_access_dtor) + << Context.getBaseElementType(AllocType)); + } + } PlacementArgs.release(); ConstructorArgs.release(); @@ -1122,6 +1202,15 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (unsigned AddressSpace = AllocType.getAddressSpace()) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AddressSpace; + else if (getLangOptions().ObjCAutoRefCount) { + if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { + QualType BaseAllocType = Context.getBaseElementType(AT); + if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None && + BaseAllocType->isObjCLifetimeType()) + return Diag(Loc, diag::err_arc_new_array_without_ownership) + << BaseAllocType; + } + } return false; } @@ -1774,8 +1863,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // delete-expression; it is not necessary to cast away the constness // (5.2.11) of the pointer expression before it is used as the operand // of the delete-expression. ] - Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy), - CK_NoOp); + if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy)) + Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp, + Ex.take(), 0, VK_RValue)); if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) @@ -1830,6 +1920,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (!dtor || !dtor->isVirtual()) Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; } + + } else if (getLangOptions().ObjCAutoRefCount && + PointeeElem->isObjCLifetimeType() && + (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong || + PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) && + ArrayForm) { + Diag(StartLoc, diag::warn_err_new_delete_object_array) + << 1 << PointeeElem; } if (!OperatorDelete) { @@ -1988,11 +2086,12 @@ static ExprResult BuildCXXCastArgument(Sema &S, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, bool CStyle) { + AssignmentAction Action, + CheckedConversionKind CCK) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, - Action, CStyle); + Action, CCK); if (Res.isInvalid()) return ExprError(); From = Res.take(); @@ -2027,7 +2126,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ExprResult Res = PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, - CStyle); + CCK); if (Res.isInvalid()) return ExprError(); From = Res.take(); @@ -2047,7 +2146,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From = CastArg.take(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, - AA_Converting, CStyle); + AA_Converting, CCK); } case ImplicitConversionSequence::AmbiguousConversion: @@ -2076,13 +2175,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, bool CStyle) { + AssignmentAction Action, + CheckedConversionKind CCK) { + bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); + // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); - + if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); @@ -2149,12 +2251,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take(); + From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); - From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take(); + From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, + VK_RValue, /*BasePath=*/0, CCK).take(); break; default: @@ -2178,17 +2282,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); - From = ImpCastExprToType(From, ToType, CK_NoOp).take(); + From = ImpCastExprToType(From, ToType, CK_NoOp, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: - From = ImpCastExprToType(From, ToType, CK_IntegralCast).take(); + From = ImpCastExprToType(From, ToType, CK_IntegralCast, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: - From = ImpCastExprToType(From, ToType, CK_FloatingCast).take(); + From = ImpCastExprToType(From, ToType, CK_FloatingCast, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Complex_Promotion: @@ -2206,21 +2313,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } else { CK = CK_IntegralComplexCast; } - From = ImpCastExprToType(From, ToType, CK).take(); + From = ImpCastExprToType(From, ToType, CK, + VK_RValue, /*BasePath=*/0, CCK).take(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) - From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take(); + From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, + VK_RValue, /*BasePath=*/0, CCK).take(); else - From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take(); + From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Compatible_Conversion: - From = ImpCastExprToType(From, ToType, CK_NoOp).take(); + From = ImpCastExprToType(From, ToType, CK_NoOp, + VK_RValue, /*BasePath=*/0, CCK).take(); break; + case ICK_Writeback_Conversion: case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions @@ -2234,17 +2346,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange(); - + if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); - } - + } + else if (getLangOptions().ObjCAutoRefCount && + !CheckObjCARCUnavailableWeakConversion(ToType, + From->getType())) { + if (Action == AA_Initializing) + Diag(From->getSourceRange().getBegin(), + diag::err_arc_weak_unavailable_assign); + else + Diag(From->getSourceRange().getBegin(), + diag::err_arc_convesion_of_weak_unavailable) + << (Action == AA_Casting) << From->getType() << ToType + << From->getSourceRange(); + } + CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); - From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take(); + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) + .take(); break; } @@ -2255,13 +2380,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); - From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take(); + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) + .take(); break; } case ICK_Boolean_Conversion: From = ImpCastExprToType(From, Context.BoolTy, - ScalarTypeToBooleanCastKind(FromType)).take(); + ScalarTypeToBooleanCastKind(FromType), + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Derived_To_Base: { @@ -2276,16 +2403,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_DerivedToBase, CastCategory(From), - &BasePath).take(); + &BasePath, CCK).take(); break; } case ICK_Vector_Conversion: - From = ImpCastExprToType(From, ToType, CK_BitCast).take(); + From = ImpCastExprToType(From, ToType, CK_BitCast, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Vector_Splat: - From = ImpCastExprToType(From, ToType, CK_VectorSplat).take(); + From = ImpCastExprToType(From, ToType, CK_VectorSplat, + VK_RValue, /*BasePath=*/0, CCK).take(); break; case ICK_Complex_Real: @@ -2321,27 +2450,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal - : CK_IntegralComplexToReal).take(); + : CK_IntegralComplexToReal, + VK_RValue, /*BasePath=*/0, CCK).take(); // x -> y if (Context.hasSameUnqualifiedType(ElType, ToType)) { // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take(); + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, + VK_RValue, /*BasePath=*/0, CCK).take(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take(); + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, + VK_RValue, /*BasePath=*/0, CCK).take(); } } break; case ICK_Block_Pointer_Conversion: { - From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, - VK_RValue).take(); - break; - } + From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, + VK_RValue, /*BasePath=*/0, CCK).take(); + break; + } case ICK_TransparentUnionConversion: { ExprResult FromRes = Owned(From); @@ -2376,7 +2508,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ExprValueKind VK = ToType->isReferenceType() ? CastCategory(From) : VK_RValue; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), - CK_NoOp, VK).take(); + CK_NoOp, VK, /*BasePath=*/0, CCK).take(); if (SCS.DeprecatedStringLiteralToCharPtr && !getLangOptions().WritableStrings) @@ -2553,6 +2685,23 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsObject: return T->isObjectType(); case UTT_IsScalar: + // Note: semantic analysis depends on Objective-C lifetime types to be + // considered scalar types. However, such types do not actually behave + // like scalar types at run time (since they may require retain/release + // operations), so we report them as non-scalar. + if (T->isObjCLifetimeType()) { + switch (T.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + return true; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Autoreleasing: + return false; + } + } + return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); @@ -2566,13 +2715,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsVolatile: return T.isVolatileQualified(); case UTT_IsTrivial: - return T->isTrivialType(); + return T.isTrivialType(Self.Context); case UTT_IsTriviallyCopyable: - return T->isTriviallyCopyableType(); + return T.isTriviallyCopyableType(Self.Context); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: - return T->isPODType(); + return T.isPODType(Self.Context); case UTT_IsLiteral: return T->isLiteralType(); case UTT_IsEmpty: @@ -2605,7 +2754,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default // constructor ([class.ctor]) then the trait is true, else it is false. - if (T->isPODType()) + if (T.isPODType(Self.Context)) return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) @@ -2617,7 +2766,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // the trait is true, else if type is a cv class or union type // with a trivial copy constructor ([class.copy]) then the trait // is true, else it is false. - if (T->isPODType() || T->isReferenceType()) + if (T.isPODType(Self.Context) || T->isReferenceType()) return true; if (const RecordType *RT = T->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor(); @@ -2637,7 +2786,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (C.getBaseElementType(T).isConstQualified()) return false; - if (T->isPODType()) + if (T.isPODType(Self.Context)) return true; if (const RecordType *RT = T->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment(); @@ -2649,8 +2798,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // type (or array thereof) with a trivial destructor // ([class.dtor]) then the trait is true, else it is // false. - if (T->isPODType() || T->isReferenceType()) + if (T.isPODType(Self.Context) || T->isReferenceType()) + return true; + + // Objective-C++ ARC: autorelease types don't require destruction. + if (T->isObjCLifetimeType() && + T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; + if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); @@ -2668,8 +2823,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return false; if (T->isReferenceType()) return false; - if (T->isPODType()) - return true; + if (T.isPODType(Self.Context) || T->isObjCLifetimeType()) + return true; if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->hasTrivialCopyAssignment()) @@ -2704,7 +2859,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // if type is a cv class or union type with copy constructors that are // known not to throw an exception then the trait is true, else it is // false. - if (T->isPODType() || T->isReferenceType()) + if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType()) return true; if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -2744,7 +2899,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // true, else if type is a cv class or union type (or array // thereof) with a default constructor that is known not to // throw an exception then the trait is true, else it is false. - if (T->isPODType()) + if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -3089,6 +3244,20 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { + assert(!lex.get()->getType()->isPlaceholderType() && + !rex.get()->getType()->isPlaceholderType() && + "placeholders should have been weeded out by now"); + + // The LHS undergoes lvalue conversions if this is ->*. + if (isIndirect) { + lex = DefaultLvalueConversion(lex.take()); + if (lex.isInvalid()) return QualType(); + } + + // The RHS always undergoes lvalue conversions. + rex = DefaultLvalueConversion(rex.take()); + if (rex.isInvalid()) return QualType(); + const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall @@ -3556,7 +3725,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) - return CheckVectorOperands(QuestionLoc, LHS, RHS); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a @@ -3828,17 +3997,83 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!E) return ExprError(); - if (!Context.getLangOptions().CPlusPlus) + assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?"); + + // If the result is a glvalue, we shouldn't bind it. + if (!E->isRValue()) return Owned(E); - assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?"); + // In ARC, calls that return a retainable type can return retained, + // in which case we have to insert a consuming cast. + if (getLangOptions().ObjCAutoRefCount && + E->getType()->isObjCRetainableType()) { + + bool ReturnsRetained; + + // For actual calls, we compute this by examining the type of the + // called value. + if (CallExpr *Call = dyn_cast<CallExpr>(E)) { + Expr *Callee = Call->getCallee()->IgnoreParens(); + QualType T = Callee->getType(); + + if (T == Context.BoundMemberTy) { + // Handle pointer-to-members. + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Callee)) + T = BinOp->getRHS()->getType(); + else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee)) + T = Mem->getMemberDecl()->getType(); + } + + if (const PointerType *Ptr = T->getAs<PointerType>()) + T = Ptr->getPointeeType(); + else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>()) + T = Ptr->getPointeeType(); + else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>()) + T = MemPtr->getPointeeType(); + + const FunctionType *FTy = T->getAs<FunctionType>(); + assert(FTy && "call to value not of function type?"); + ReturnsRetained = FTy->getExtInfo().getProducesResult(); + + // ActOnStmtExpr arranges things so that StmtExprs of retainable + // type always produce a +1 object. + } else if (isa<StmtExpr>(E)) { + ReturnsRetained = true; + + // For message sends and property references, we try to find an + // actual method. FIXME: we should infer retention by selector in + // cases where we don't have an actual method. + } else { + Decl *D = 0; + if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) { + D = Send->getMethodDecl(); + } else { + CastExpr *CE = cast<CastExpr>(E); + // FIXME. What other cast kinds to check for? + if (CE->getCastKind() == CK_ObjCProduceObject || + CE->getCastKind() == CK_LValueToRValue) + return MaybeBindToTemporary(CE->getSubExpr()); + assert(CE->getCastKind() == CK_GetObjCProperty); + const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty(); + D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0); + } - const RecordType *RT = E->getType()->getAs<RecordType>(); - if (!RT) + ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>()); + } + + ExprNeedsCleanups = true; + + CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject + : CK_ObjCReclaimReturnedObject); + return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0, + VK_RValue)); + } + + if (!getLangOptions().CPlusPlus) return Owned(E); - // If the result is a glvalue, we shouldn't bind it. - if (E->Classify(Context).isGLValue()) + const RecordType *RT = E->getType()->getAs<RecordType>(); + if (!RT) return Owned(E); // That should be enough to guarantee that this type is complete. @@ -3847,15 +4082,18 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (RD->isInvalidDecl() || RD->hasTrivialDestructor()) return Owned(E); - CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD)); - ExprTemporaries.push_back(Temp); - if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { + CXXDestructorDecl *Destructor = LookupDestructor(RD); + + CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); + if (Destructor) { MarkDeclarationReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); + + ExprTemporaries.push_back(Temp); + ExprNeedsCleanups = true; } - // FIXME: Add the temporary to the temporaries vector. return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } @@ -3864,14 +4102,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; assert(ExprTemporaries.size() >= FirstTemporary); - if (ExprTemporaries.size() == FirstTemporary) + assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary); + if (!ExprNeedsCleanups) return SubExpr; Expr *E = ExprWithCleanups::Create(Context, SubExpr, - &ExprTemporaries[FirstTemporary], + ExprTemporaries.begin() + FirstTemporary, ExprTemporaries.size() - FirstTemporary); ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, ExprTemporaries.end()); + ExprNeedsCleanups = false; return E; } @@ -3887,9 +4127,7 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { assert(SubStmt && "sub statement can't be null!"); - unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; - assert(ExprTemporaries.size() >= FirstTemporary); - if (ExprTemporaries.size() == FirstTemporary) + if (!ExprNeedsCleanups) return SubStmt; // FIXME: In order to attach the temporaries, wrap the statement into @@ -4047,17 +4285,35 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); - if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && - !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { - Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << Base->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - - // Recover by setting the destructed type to the object type. - DestructedType = ObjectType; - DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, + if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { + if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << Base->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, + DestructedTypeStart); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } else if (DestructedType.getObjCLifetime() != + ObjectType.getObjCLifetime()) { + + if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { + // Okay: just pretend that the user provided the correctly-qualified + // type. + } else { + Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals) + << ObjectType << DestructedType << Base->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + } + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); - Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } } } @@ -4293,7 +4549,16 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). - if (E->isRValue()) return Owned(E); + if (E->isRValue()) { + // In C, function designators (i.e. expressions of function type) + // are r-values, but we still want to do function-to-pointer decay + // on them. This is both technically correct and convenient for + // some clients. + if (!getLangOptions().CPlusPlus && E->getType()->isFunctionType()) + return DefaultFunctionArrayConversion(E); + + return Owned(E); + } // We always want to do this on ObjC property references. if (E->getObjectKind() == OK_ObjCProperty) { diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp new file mode 100644 index 0000000..2488dc8 --- /dev/null +++ b/lib/Sema/SemaExprMember.cpp @@ -0,0 +1,1594 @@ +//===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis member access expressions. +// +//===----------------------------------------------------------------------===// +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Scope.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; +using namespace sema; + +/// Determines if the given class is provably not derived from all of +/// the prospective base classes. +static bool IsProvablyNotDerivedFrom(Sema &SemaRef, + CXXRecordDecl *Record, + const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) { + if (Bases.count(Record->getCanonicalDecl())) + return false; + + RecordDecl *RD = Record->getDefinition(); + if (!RD) return false; + Record = cast<CXXRecordDecl>(RD); + + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); + if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) + return false; + } + + return true; +} + +enum IMAKind { + /// The reference is definitely not an instance member access. + IMA_Static, + + /// The reference may be an implicit instance member access. + IMA_Mixed, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is not an instance method. + IMA_Mixed_StaticContext, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is from an unrelated class. + IMA_Mixed_Unrelated, + + /// The reference is definitely an implicit instance member access. + IMA_Instance, + + /// The reference may be to an unresolved using declaration. + IMA_Unresolved, + + /// The reference may be to an unresolved using declaration and the + /// context is not an instance method. + IMA_Unresolved_StaticContext, + + /// All possible referrents are instance members and the current + /// context is not an instance method. + IMA_Error_StaticContext, + + /// All possible referrents are instance members of an unrelated + /// class. + IMA_Error_Unrelated +}; + +/// The given lookup names class member(s) and is not being used for +/// an address-of-member expression. Classify the type of access +/// according to whether it's possible that this reference names an +/// instance member. This is best-effort; it is okay to +/// conservatively answer "yes", in which case some errors will simply +/// not be caught until template-instantiation. +static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + Scope *CurScope, + const LookupResult &R) { + assert(!R.empty() && (*R.begin())->isCXXClassMember()); + + DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); + + bool isStaticContext = + (!isa<CXXMethodDecl>(DC) || + cast<CXXMethodDecl>(DC)->isStatic()); + + // C++0x [expr.prim]p4: + // Otherwise, if a member-declarator declares a non-static data member + // of a class X, the expression this is a prvalue of type "pointer to X" + // within the optional brace-or-equal-initializer. + if (CurScope->getFlags() & Scope::ThisScope) + isStaticContext = false; + + if (R.isUnresolvableResult()) + return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; + + // Collect all the declaring classes of instance members we find. + bool hasNonInstance = false; + bool hasField = false; + llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = *I; + + if (D->isCXXInstanceMember()) { + if (dyn_cast<FieldDecl>(D)) + hasField = true; + + CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); + Classes.insert(R->getCanonicalDecl()); + } + else + hasNonInstance = true; + } + + // If we didn't find any instance members, it can't be an implicit + // member reference. + if (Classes.empty()) + return IMA_Static; + + // If the current context is not an instance method, it can't be + // an implicit member reference. + if (isStaticContext) { + if (hasNonInstance) + return IMA_Mixed_StaticContext; + + if (SemaRef.getLangOptions().CPlusPlus0x && hasField) { + // C++0x [expr.prim.general]p10: + // An id-expression that denotes a non-static data member or non-static + // member function of a class can only be used: + // (...) + // - if that id-expression denotes a non-static data member and it + // appears in an unevaluated operand. + const Sema::ExpressionEvaluationContextRecord& record + = SemaRef.ExprEvalContexts.back(); + bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated); + if (isUnevaluatedExpression) + return IMA_Mixed_StaticContext; + } + + return IMA_Error_StaticContext; + } + + CXXRecordDecl *contextClass; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + contextClass = MD->getParent()->getCanonicalDecl(); + else + contextClass = cast<CXXRecordDecl>(DC); + + // [class.mfct.non-static]p3: + // ...is used in the body of a non-static member function of class X, + // if name lookup (3.4.1) resolves the name in the id-expression to a + // non-static non-type member of some class C [...] + // ...if C is not X or a base class of X, the class member access expression + // is ill-formed. + if (R.getNamingClass() && + contextClass != R.getNamingClass()->getCanonicalDecl() && + contextClass->isProvablyNotDerivedFrom(R.getNamingClass())) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + + // If we can prove that the current context is unrelated to all the + // declaring classes, it can't be an implicit member reference (in + // which case it's an error if any of those members are selected). + if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + + return (hasNonInstance ? IMA_Mixed : IMA_Instance); +} + +/// Diagnose a reference to a field with no object available. +static void DiagnoseInstanceReference(Sema &SemaRef, + const CXXScopeSpec &SS, + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { + SourceLocation Loc = nameInfo.getLoc(); + SourceRange Range(Loc); + if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + + if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) { + if (MD->isStatic()) { + // "invalid use of member 'x' in static member function" + SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + << Range << nameInfo.getName(); + return; + } + } + + SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) + << nameInfo.getName() << Range; + return; + } + + SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; +} + +/// Builds an expression which might be an implicit member expression. +ExprResult +Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { + switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { + case IMA_Instance: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); + + case IMA_Mixed: + case IMA_Mixed_Unrelated: + case IMA_Unresolved: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); + + case IMA_Static: + case IMA_Mixed_StaticContext: + case IMA_Unresolved_StaticContext: + if (TemplateArgs) + return BuildTemplateIdExpr(SS, R, false, *TemplateArgs); + return BuildDeclarationNameExpr(SS, R, false); + + case IMA_Error_StaticContext: + case IMA_Error_Unrelated: + DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), + R.getLookupNameInfo()); + return ExprError(); + } + + llvm_unreachable("unexpected instance member access kind"); + return ExprError(); +} + +/// Check an ext-vector component access expression. +/// +/// VK should be set in advance to the value kind of the base +/// expression. +static QualType +CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, + SourceLocation OpLoc, const IdentifierInfo *CompName, + SourceLocation CompLoc) { + // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, + // see FIXME there. + // + // FIXME: This logic can be greatly simplified by splitting it along + // halving/not halving and reworking the component checking. + const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); + + // The vector accessor can't exceed the number of elements. + const char *compStr = CompName->getNameStart(); + + // This flag determines whether or not the component is one of the four + // special names that indicate a subset of exactly half the elements are + // to be selected. + bool HalvingSwizzle = false; + + // This flag determines whether or not CompName has an 's' char prefix, + // indicating that it is a string of hex values to be used as vector indices. + bool HexSwizzle = *compStr == 's' || *compStr == 'S'; + + bool HasRepeated = false; + bool HasIndex[16] = {}; + + int Idx; + + // Check that we've found one of the special components, or that the component + // names must come from the same set. + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { + HalvingSwizzle = true; + } else if (!HexSwizzle && + (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { + do { + if (HasIndex[Idx]) HasRepeated = true; + HasIndex[Idx] = true; + compStr++; + } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); + } else { + if (HexSwizzle) compStr++; + while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { + if (HasIndex[Idx]) HasRepeated = true; + HasIndex[Idx] = true; + compStr++; + } + } + + if (!HalvingSwizzle && *compStr) { + // We didn't get to the end of the string. This means the component names + // didn't come from the same set *or* we encountered an illegal name. + S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) + << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); + return QualType(); + } + + // Ensure no component accessor exceeds the width of the vector type it + // operates on. + if (!HalvingSwizzle) { + compStr = CompName->getNameStart(); + + if (HexSwizzle) + compStr++; + + while (*compStr) { + if (!vecType->isAccessorWithinNumElements(*compStr++)) { + S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) + << baseType << SourceRange(CompLoc); + return QualType(); + } + } + } + + // The component accessor looks fine - now we need to compute the actual type. + // The vector type is implied by the component accessor. For example, + // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. + // vec4.s0 is a float, vec4.s23 is a vec3, etc. + // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. + unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2 + : CompName->getLength(); + if (HexSwizzle) + CompSize--; + + if (CompSize == 1) + return vecType->getElementType(); + + if (HasRepeated) VK = VK_RValue; + + QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); + // Now look up the TypeDefDecl from the vector type. Without this, + // diagostics look bad. We want extended vector types to appear built-in. + for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { + if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) + return S.Context.getTypedefType(S.ExtVectorDecls[i]); + } + return VT; // should never get here (a typedef type should always be found). +} + +static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, + IdentifierInfo *Member, + const Selector &Sel, + ASTContext &Context) { + if (Member) + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) + return PD; + if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) + return OMD; + + for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), + E = PDecl->protocol_end(); I != E; ++I) { + if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context)) + return D; + } + return 0; +} + +static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, + IdentifierInfo *Member, + const Selector &Sel, + ASTContext &Context) { + // Check protocols on qualified interfaces. + Decl *GDecl = 0; + for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + if (Member) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + GDecl = PD; + break; + } + // Also must look for a getter or setter name which uses property syntax. + if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { + GDecl = OMD; + break; + } + } + if (!GDecl) { + for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + // Search in the protocol-qualifier list of current protocol. + GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, + Context); + if (GDecl) + return GDecl; + } + } + return GDecl; +} + +ExprResult +Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs) { + // Even in dependent contexts, try to diagnose base expressions with + // obviously wrong types, e.g.: + // + // T* t; + // t.f; + // + // In Obj-C++, however, the above expression is valid, since it could be + // accessing the 'f' property if T is an Obj-C interface. The extra check + // allows this, while still reporting an error if T is a struct pointer. + if (!IsArrow) { + const PointerType *PT = BaseType->getAs<PointerType>(); + if (PT && (!getLangOptions().ObjC1 || + PT->getPointeeType()->isRecordType())) { + assert(BaseExpr && "cannot happen with implicit member accesses"); + Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union) + << BaseType << BaseExpr->getSourceRange(); + return ExprError(); + } + } + + assert(BaseType->isDependentType() || + NameInfo.getName().isDependentName() || + isDependentScopeSpecifier(SS)); + + // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr + // must have pointer type, and the accessed type is the pointee. + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, + IsArrow, OpLoc, + SS.getWithLocInContext(Context), + FirstQualifierInScope, + NameInfo, TemplateArgs)); +} + +/// We know that the given qualified member reference points only to +/// declarations which do not belong to the static type of the base +/// expression. Diagnose the problem. +static void DiagnoseQualifiedMemberReference(Sema &SemaRef, + Expr *BaseExpr, + QualType BaseType, + const CXXScopeSpec &SS, + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { + // If this is an implicit member access, use a different set of + // diagnostics. + if (!BaseExpr) + return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); + + SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) + << SS.getRange() << rep << BaseType; +} + +// Check whether the declarations we found through a nested-name +// specifier in a member expression are actually members of the base +// type. The restriction here is: +// +// C++ [expr.ref]p2: +// ... In these cases, the id-expression shall name a +// member of the class or of one of its base classes. +// +// So it's perfectly legitimate for the nested-name specifier to name +// an unrelated class, and for us to find an overload set including +// decls from classes which are not superclasses, as long as the decl +// we actually pick through overload resolution is from a superclass. +bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, + QualType BaseType, + const CXXScopeSpec &SS, + const LookupResult &R) { + const RecordType *BaseRT = BaseType->getAs<RecordType>(); + if (!BaseRT) { + // We can't check this yet because the base type is still + // dependent. + assert(BaseType->isDependentType()); + return false; + } + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); + + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + // If this is an implicit member reference and we find a + // non-instance member, it's not an error. + if (!BaseExpr && !(*I)->isCXXInstanceMember()) + return false; + + // Note that we use the DC of the decl, not the underlying decl. + DeclContext *DC = (*I)->getDeclContext(); + while (DC->isTransparentContext()) + DC = DC->getParent(); + + if (!DC->isRecord()) + continue; + + llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord; + MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl()); + + if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) + return false; + } + + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, + R.getRepresentativeDecl(), + R.getLookupNameInfo()); + return true; +} + +static bool +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + SourceRange BaseRange, const RecordType *RTy, + SourceLocation OpLoc, CXXScopeSpec &SS, + bool HasTemplateArgs) { + RecordDecl *RDecl = RTy->getDecl(); + if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + SemaRef.PDiag(diag::err_typecheck_incomplete_tag) + << BaseRange)) + return true; + + if (HasTemplateArgs) { + // LookupTemplateName doesn't expect these both to exist simultaneously. + QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); + + bool MOUS; + SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS); + return false; + } + + DeclContext *DC = RDecl; + if (SS.isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = SemaRef.computeDeclContext(SS, false); + + if (SemaRef.RequireCompleteDeclContext(SS, DC)) { + SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) + << SS.getRange() << DC; + return true; + } + + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + + if (!isa<TypeDecl>(DC)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) + << DC << SS.getRange(); + return true; + } + } + + // The record definition is complete, now look up the member. + SemaRef.LookupQualifiedName(R, DC); + + if (!R.empty()) + return false; + + // We didn't find anything with the given name, so try to correct + // for typos. + DeclarationName Name = R.getLookupName(); + TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(), + R.getLookupKind(), NULL, + &SS, DC, false, + Sema::CTC_MemberLookup); + NamedDecl *ND = Corrected.getCorrectionDecl(); + R.clear(); + if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) { + std::string CorrectedStr( + Corrected.getAsString(SemaRef.getLangOptions())); + std::string CorrectedQuotedStr( + Corrected.getQuoted(SemaRef.getLangOptions())); + R.setLookupName(Corrected.getCorrection()); + R.addDecl(ND); + SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << DC << CorrectedQuotedStr << SS.getRange() + << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); + SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + } + + return false; +} + +ExprResult +Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, + SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs) { + if (BaseType->isDependentType() || + (SS.isSet() && isDependentScopeSpecifier(SS))) + return ActOnDependentMemberExpr(Base, BaseType, + IsArrow, OpLoc, + SS, FirstQualifierInScope, + NameInfo, TemplateArgs); + + LookupResult R(*this, NameInfo, LookupMemberName); + + // Implicit member accesses. + if (!Base) { + QualType RecordTy = BaseType; + if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); + if (LookupMemberExprInRecord(*this, R, SourceRange(), + RecordTy->getAs<RecordType>(), + OpLoc, SS, TemplateArgs != 0)) + return ExprError(); + + // Explicit member accesses. + } else { + ExprResult BaseResult = Owned(Base); + ExprResult Result = + LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, + SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); + + if (BaseResult.isInvalid()) + return ExprError(); + Base = BaseResult.take(); + + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) + return move(Result); + + // LookupMemberExpr can modify Base, and thus change BaseType + BaseType = Base->getType(); + } + + return BuildMemberReferenceExpr(Base, BaseType, + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); +} + +static ExprResult +BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo); + +ExprResult +Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, + SourceLocation loc, + IndirectFieldDecl *indirectField, + Expr *baseObjectExpr, + SourceLocation opLoc) { + // First, build the expression that refers to the base object. + + bool baseObjectIsPointer = false; + Qualifiers baseQuals; + + // Case 1: the base of the indirect field is not a field. + VarDecl *baseVariable = indirectField->getVarDecl(); + CXXScopeSpec EmptySS; + if (baseVariable) { + assert(baseVariable->getType()->isRecordType()); + + // In principle we could have a member access expression that + // accesses an anonymous struct/union that's a static member of + // the base object's class. However, under the current standard, + // static data members cannot be anonymous structs or unions. + // Supporting this is as easy as building a MemberExpr here. + assert(!baseObjectExpr && "anonymous struct/union is static data member?"); + + DeclarationNameInfo baseNameInfo(DeclarationName(), loc); + + ExprResult result + = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); + if (result.isInvalid()) return ExprError(); + + baseObjectExpr = result.take(); + baseObjectIsPointer = false; + baseQuals = baseObjectExpr->getType().getQualifiers(); + + // Case 2: the base of the indirect field is a field and the user + // wrote a member expression. + } else if (baseObjectExpr) { + // The caller provided the base object expression. Determine + // whether its a pointer and whether it adds any qualifiers to the + // anonymous struct/union fields we're looking into. + QualType objectType = baseObjectExpr->getType(); + + if (const PointerType *ptr = objectType->getAs<PointerType>()) { + baseObjectIsPointer = true; + objectType = ptr->getPointeeType(); + } else { + baseObjectIsPointer = false; + } + baseQuals = objectType.getQualifiers(); + + // Case 3: the base of the indirect field is a field and we should + // build an implicit member access. + } else { + // We've found a member of an anonymous struct/union that is + // inside a non-anonymous struct/union, so in a well-formed + // program our base object expression is "this". + QualType ThisTy = getAndCaptureCurrentThisType(); + if (ThisTy.isNull()) { + Diag(loc, diag::err_invalid_member_use_in_static_method) + << indirectField->getDeclName(); + return ExprError(); + } + + // Our base object expression is "this". + baseObjectExpr + = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); + baseObjectIsPointer = true; + baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); + } + + // Build the implicit member references to the field of the + // anonymous struct/union. + Expr *result = baseObjectExpr; + IndirectFieldDecl::chain_iterator + FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); + + // Build the first member access in the chain with full information. + if (!baseVariable) { + FieldDecl *field = cast<FieldDecl>(*FI); + + // FIXME: use the real found-decl info! + DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); + + // Make a nameInfo that properly uses the anonymous name. + DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + + result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, + EmptySS, field, foundDecl, + memberNameInfo).take(); + baseObjectIsPointer = false; + + // FIXME: check qualified member access + } + + // In all cases, we should now skip the first declaration in the chain. + ++FI; + + while (FI != FEnd) { + FieldDecl *field = cast<FieldDecl>(*FI++); + + // FIXME: these are somewhat meaningless + DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); + + result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, + (FI == FEnd? SS : EmptySS), field, + foundDecl, memberNameInfo).take(); + } + + return Owned(result); +} + +/// \brief Build a MemberExpr AST node. +static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, + const CXXScopeSpec &SS, ValueDecl *Member, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo, + QualType Ty, + ExprValueKind VK, ExprObjectKind OK, + const TemplateArgumentListInfo *TemplateArgs = 0) { + return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C), + Member, FoundDecl, MemberNameInfo, + TemplateArgs, Ty, VK, OK); +} + +ExprResult +Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck) { + QualType BaseType = BaseExprType; + if (IsArrow) { + assert(BaseType->isPointerType()); + BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + } + R.setBaseObjectType(BaseType); + + const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); + DeclarationName MemberName = MemberNameInfo.getName(); + SourceLocation MemberLoc = MemberNameInfo.getLoc(); + + if (R.isAmbiguous()) + return ExprError(); + + if (R.empty()) { + // Rederive where we looked up. + DeclContext *DC = (SS.isSet() + ? computeDeclContext(SS, false) + : BaseType->getAs<RecordType>()->getDecl()); + + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); + return ExprError(); + } + + // Diagnose lookups that find only declarations from a non-base + // type. This is possible for either qualified lookups (which may + // have been qualified with an unrelated type) or implicit member + // expressions (which were found with unqualified lookup and thus + // may have come from an enclosing scope). Note that it's okay for + // lookup to find declarations from a non-base type as long as those + // aren't the ones picked by overload resolution. + if ((SS.isSet() || !BaseExpr || + (isa<CXXThisExpr>(BaseExpr) && + cast<CXXThisExpr>(BaseExpr)->isImplicit())) && + !SuppressQualifierCheck && + CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) + return ExprError(); + + // Construct an unresolved result if we in fact got an unresolved + // result. + if (R.isOverloadedResult() || R.isUnresolvableResult()) { + // Suppress any lookup-related diagnostics; we'll do these when we + // pick a member. + R.suppressDiagnostics(); + + UnresolvedMemberExpr *MemExpr + = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), + BaseExpr, BaseExprType, + IsArrow, OpLoc, + SS.getWithLocInContext(Context), + MemberNameInfo, + TemplateArgs, R.begin(), R.end()); + + return Owned(MemExpr); + } + + assert(R.isSingleResult()); + DeclAccessPair FoundDecl = R.begin().getPair(); + NamedDecl *MemberDecl = R.getFoundDecl(); + + // FIXME: diagnose the presence of template arguments now. + + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (MemberDecl->isInvalidDecl()) + return ExprError(); + + // Handle the implicit-member-access case. + if (!BaseExpr) { + // If this is not an instance member, convert to a non-member access. + if (!MemberDecl->isCXXInstanceMember()) + return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); + + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); + } + + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && !SS.isSet()) + ShouldCheckUse = false; + } + + // Check the use of this member. + if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) { + Owned(BaseExpr); + return ExprError(); + } + + // Perform a property load on the base regardless of whether we + // actually need it for the declaration. + if (BaseExpr->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(BaseExpr); + if (Result.isInvalid()) + return ExprError(); + BaseExpr = Result.take(); + } + + if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) + return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, + SS, FD, FoundDecl, MemberNameInfo); + + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, + BaseExpr, OpLoc); + + if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, Var); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Var, FoundDecl, MemberNameInfo, + Var->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary)); + } + + if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) { + ExprValueKind valueKind; + QualType type; + if (MemberFn->isInstance()) { + valueKind = VK_RValue; + type = Context.BoundMemberTy; + } else { + valueKind = VK_LValue; + type = MemberFn->getType(); + } + + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + MemberFn, FoundDecl, MemberNameInfo, + type, valueKind, OK_Ordinary)); + } + assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?"); + + if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Enum, FoundDecl, MemberNameInfo, + Enum->getType(), VK_RValue, OK_Ordinary)); + } + + Owned(BaseExpr); + + // We found something that we didn't expect. Complain. + if (isa<TypeDecl>(MemberDecl)) + Diag(MemberLoc, diag::err_typecheck_member_reference_type) + << MemberName << BaseType << int(IsArrow); + else + Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) + << MemberName << BaseType << int(IsArrow); + + Diag(MemberDecl->getLocation(), diag::note_member_declared_here) + << MemberName; + R.suppressDiagnostics(); + return ExprError(); +} + +/// Given that normal member access failed on the given expression, +/// and given that the expression's type involves builtin-id or +/// builtin-Class, decide whether substituting in the redefinition +/// types would be profitable. The redefinition type is whatever +/// this translation unit tried to typedef to id/Class; we store +/// it to the side and then re-use it in places like this. +static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { + const ObjCObjectPointerType *opty + = base.get()->getType()->getAs<ObjCObjectPointerType>(); + if (!opty) return false; + + const ObjCObjectType *ty = opty->getObjectType(); + + QualType redef; + if (ty->isObjCId()) { + redef = S.Context.ObjCIdRedefinitionType; + } else if (ty->isObjCClass()) { + redef = S.Context.ObjCClassRedefinitionType; + } else { + return false; + } + + // Do the substitution as long as the redefinition type isn't just a + // possibly-qualified pointer to builtin-id or builtin-Class again. + opty = redef->getAs<ObjCObjectPointerType>(); + if (opty && !opty->getObjectType()->getInterface() != 0) + return false; + + base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); + return true; +} + +/// Look up the given member of the given non-type-dependent +/// expression. This can return in one of two ways: +/// * If it returns a sentinel null-but-valid result, the caller will +/// assume that lookup was performed and the results written into +/// the provided structure. It will take over from there. +/// * Otherwise, the returned expression will be produced in place of +/// an ordinary member expression. +/// +/// The ObjCImpDecl bit is a gross hack that will need to be properly +/// fixed for ObjC++. +ExprResult +Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, + bool &IsArrow, SourceLocation OpLoc, + CXXScopeSpec &SS, + Decl *ObjCImpDecl, bool HasTemplateArgs) { + assert(BaseExpr.get() && "no base expression"); + + // Perform default conversions. + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + + if (IsArrow) { + BaseExpr = DefaultLvalueConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); + } + + QualType BaseType = BaseExpr.get()->getType(); + assert(!BaseType->isDependentType()); + + DeclarationName MemberName = R.getLookupName(); + SourceLocation MemberLoc = R.getNameLoc(); + + // For later type-checking purposes, turn arrow accesses into dot + // accesses. The only access type we support that doesn't follow + // the C equivalence "a->b === (*a).b" is ObjC property accesses, + // and those never use arrows, so this is unaffected. + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + else if (const ObjCObjectPointerType *Ptr + = BaseType->getAs<ObjCObjectPointerType>()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "."); + IsArrow = false; + } else if (BaseType == Context.BoundMemberTy) { + goto fail; + } else { + Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr.get()->getSourceRange(); + return ExprError(); + } + } + + // Handle field access to simple records. + if (const RecordType *RTy = BaseType->getAs<RecordType>()) { + if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(), + RTy, OpLoc, SS, HasTemplateArgs)) + return ExprError(); + + // Returning valid-but-null is how we indicate to the caller that + // the lookup result was filled in. + return Owned((Expr*) 0); + } + + // Handle ivar access to Objective-C objects. + if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + + // There are three cases for the base type: + // - builtin id (qualified or unqualified) + // - builtin Class (qualified or unqualified) + // - an interface + ObjCInterfaceDecl *IDecl = OTy->getInterface(); + if (!IDecl) { + if (getLangOptions().ObjCAutoRefCount && + (OTy->isObjCId() || OTy->isObjCClass())) + goto fail; + // There's an implicit 'isa' ivar on all objects. + // But we only actually find it this way on objects of type 'id', + // apparently. + if (OTy->isObjCId() && Member->isStr("isa")) + return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, + Context.getObjCClassType())); + + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + goto fail; + } + + ObjCInterfaceDecl *ClassDeclared; + ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); + + if (!IV) { + // Attempt to correct for typos in ivar names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupMemberName); + TypoCorrection Corrected = CorrectTypo( + R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false, + IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup); + if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) { + Diag(R.getNameLoc(), + diag::err_typecheck_member_reference_ivar_suggest) + << IDecl->getDeclName() << MemberName << IV->getDeclName() + << FixItHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); + Diag(IV->getLocation(), diag::note_previous_decl) + << IV->getDeclName(); + } else { + if (IsArrow && IDecl->FindPropertyDeclaration(Member)) { + Diag(MemberLoc, + diag::err_property_found_suggest) + << Member << BaseExpr.get()->getType() + << FixItHint::CreateReplacement(OpLoc, "."); + return ExprError(); + } + Res.clear(); + Res.setLookupName(Member); + + Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) + << IDecl->getDeclName() << MemberName + << BaseExpr.get()->getSourceRange(); + return ExprError(); + } + } + + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check whether we can reference this field. + if (DiagnoseUseOfDecl(IV, MemberLoc)) + return ExprError(); + if (IV->getAccessControl() != ObjCIvarDecl::Public && + IV->getAccessControl() != ObjCIvarDecl::Package) { + ObjCInterfaceDecl *ClassOfMethodDecl = 0; + if (ObjCMethodDecl *MD = getCurMethodDecl()) + ClassOfMethodDecl = MD->getClassInterface(); + else if (ObjCImpDecl && getCurFunctionDecl()) { + // Case of a c-function declared inside an objc implementation. + // FIXME: For a c-style function nested inside an objc implementation + // class, there is no implementation context available, so we pass + // down the context as argument to this routine. Ideally, this context + // need be passed down in the AST node and somehow calculated from the + // AST for a function decl. + if (ObjCImplementationDecl *IMPD = + dyn_cast<ObjCImplementationDecl>(ObjCImpDecl)) + ClassOfMethodDecl = IMPD->getClassInterface(); + else if (ObjCCategoryImplDecl* CatImplClass = + dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl)) + ClassOfMethodDecl = CatImplClass->getClassInterface(); + } + + if (IV->getAccessControl() == ObjCIvarDecl::Private) { + if (ClassDeclared != IDecl || + ClassOfMethodDecl != ClassDeclared) + Diag(MemberLoc, diag::error_private_ivar_access) + << IV->getDeclName(); + } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) + // @protected + Diag(MemberLoc, diag::error_protected_ivar_access) + << IV->getDeclName(); + } + if (getLangOptions().ObjCAutoRefCount) { + Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts(); + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp)) + if (UO->getOpcode() == UO_Deref) + BaseExp = UO->getSubExpr()->IgnoreParenCasts(); + + if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp)) + if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak) + Diag(DE->getLocation(), diag::error_arc_weak_ivar_access); + } + + return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, BaseExpr.take(), + IsArrow)); + } + + // Objective-C property access. + const ObjCObjectPointerType *OPT; + if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { + // This actually uses the base as an r-value. + BaseExpr = DefaultLvalueConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); + + assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType())); + + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + + const ObjCObjectType *OT = OPT->getObjectType(); + + // id, with and without qualifiers. + if (OT->isObjCId()) { + // Check protocols on qualified interfaces. + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) { + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { + // Check the use of this declaration + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + QualType T = PD->getType(); + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + T = getMessageSendResultType(BaseType, Getter, false, false); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, T, + VK_LValue, + OK_ObjCProperty, + MemberLoc, + BaseExpr.take())); + } + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { + // Check the use of this method. + if (DiagnoseUseOfDecl(OMD, MemberLoc)) + return ExprError(); + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *SMD = 0; + if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, + SetterSel, Context)) + SMD = dyn_cast<ObjCMethodDecl>(SDecl); + QualType PType = getMessageSendResultType(BaseType, OMD, false, + false); + + ExprValueKind VK = VK_LValue; + if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType()) + VK = VK_RValue; + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + + return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, + VK, OK, + MemberLoc, BaseExpr.take())); + } + } + // Use of id.member can only be for a property reference. Do not + // use the 'id' redefinition in this case. + if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType); + } + + // 'Class', unqualified only. + if (OT->isObjCClass()) { + // Only works in a method declaration (??!). + ObjCMethodDecl *MD = getCurMethodDecl(); + if (!MD) { + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + + goto fail; + } + + // Also must look for a getter name which uses property syntax. + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + ObjCMethodDecl *Getter; + if ((Getter = IFace->lookupClassMethod(Sel))) { + // Check the use of this method. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } else + Getter = IFace->lookupPrivateMethod(Sel, false); + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = IFace->lookupPrivateMethod(SetterSel, false); + } + // Look through local category implementations associated with the class. + if (!Setter) + Setter = IFace->getCategoryClassMethod(SetterSel); + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + ExprValueKind VK = VK_LValue; + if (Getter) { + PType = getMessageSendResultType(QualType(OT, 0), Getter, true, + false); + if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType()) + VK = VK_RValue; + } else { + // Get the expression type from Setter's incoming parameter. + PType = (*(Setter->param_end() -1))->getType(); + } + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + + // FIXME: we must check that the setter has property type. + return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, + PType, VK, OK, + MemberLoc, BaseExpr.take())); + } + + if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType); + } + + // Normal property access. + return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc, + MemberName, MemberLoc, + SourceLocation(), QualType(), false); + } + + // Handle 'field access' to vectors, such as 'V.xx'. + if (BaseType->isExtVectorType()) { + // FIXME: this expr should store IsArrow. + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); + ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); + QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, + Member, MemberLoc); + if (ret.isNull()) + return ExprError(); + + return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(), + *Member, MemberLoc)); + } + + // Adjust builtin-sel to the appropriate redefinition type if that's + // not just a pointer to builtin-sel again. + if (IsArrow && + BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && + !Context.ObjCSelRedefinitionType->isObjCSelType()) { + BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, + CK_BitCast); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } + + // Failure cases. + fail: + + // Recover from dot accesses to pointers, e.g.: + // type *foo; + // foo.bar + // This is actually well-formed in two cases: + // - 'type' is an Objective C type + // - 'bar' is a pseudo-destructor name which happens to refer to + // the appropriate pointer type + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { + if (!IsArrow && Ptr->getPointeeType()->isRecordType() && + MemberName.getNameKind() != DeclarationName::CXXDestructorName) { + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() + << FixItHint::CreateReplacement(OpLoc, "->"); + + // Recurse as an -> access. + IsArrow = true; + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } + } + + // If the user is trying to apply -> or . to a function name, it's probably + // because they forgot parentheses to call that function. + QualType ZeroArgCallTy; + UnresolvedSet<4> Overloads; + if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { + if (ZeroArgCallTy.isNull()) { + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) + << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); + UnresolvedSet<2> PlausibleOverloads; + for (OverloadExpr::decls_iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + QualType OverloadResultTy = OverloadDecl->getResultType(); + if ((!IsArrow && OverloadResultTy->isRecordType()) || + (IsArrow && OverloadResultTy->isPointerType() && + OverloadResultTy->getPointeeType()->isRecordType())) + PlausibleOverloads.addDecl(It.getDecl()); + } + NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); + return ExprError(); + } + if ((!IsArrow && ZeroArgCallTy->isRecordType()) || + (IsArrow && ZeroArgCallTy->isPointerType() && + ZeroArgCallTy->getPointeeType()->isRecordType())) { + // At this point, we know BaseExpr looks like it's potentially callable + // with 0 arguments, and that it returns something of a reasonable type, + // so we can emit a fixit and carry on pretending that BaseExpr was + // actually a CallExpr. + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) + << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() + << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); + // FIXME: Try this before emitting the fixit, and suppress diagnostics + // while doing so. + ExprResult NewBase = + ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, + MultiExprArg(*this, 0, 0), + ParenInsertionLoc.getFileLocWithOffset(1)); + if (NewBase.isInvalid()) + return ExprError(); + BaseExpr = NewBase; + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); + } + } + + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) + << BaseType << BaseExpr.get()->getSourceRange(); + + return ExprError(); +} + +/// The main callback when the parser finds something like +/// expression . [nested-name-specifier] identifier +/// expression -> [nested-name-specifier] identifier +/// where 'identifier' encompasses a fairly broad spectrum of +/// possibilities, including destructor and operator references. +/// +/// \param OpKind either tok::arrow or tok::period +/// \param HasTrailingLParen whether the next token is '(', which +/// is used to diagnose mis-uses of special members that can +/// only be called +/// \param ObjCImpDecl the current ObjC @implementation decl; +/// this is an ugly hack around the fact that ObjC @implementations +/// aren't properly put in the context chain +ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + UnqualifiedId &Id, + Decl *ObjCImpDecl, + bool HasTrailingLParen) { + if (SS.isSet() && SS.isInvalid()) + return ExprError(); + + // Warn about the explicit constructor calls Microsoft extension. + if (getLangOptions().Microsoft && + Id.getKind() == UnqualifiedId::IK_ConstructorName) + Diag(Id.getSourceRange().getBegin(), + diag::ext_ms_explicit_constructor_call); + + TemplateArgumentListInfo TemplateArgsBuffer; + + // Decompose the name into its component parts. + DeclarationNameInfo NameInfo; + const TemplateArgumentListInfo *TemplateArgs; + DecomposeUnqualifiedId(Id, TemplateArgsBuffer, + NameInfo, TemplateArgs); + + DeclarationName Name = NameInfo.getName(); + bool IsArrow = (OpKind == tok::arrow); + + NamedDecl *FirstQualifierInScope + = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, + static_cast<NestedNameSpecifier*>(SS.getScopeRep()))); + + // This is a postfix expression, so get rid of ParenListExprs. + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); + if (Result.isInvalid()) return ExprError(); + Base = Result.take(); + + if (Base->getType()->isDependentType() || Name.isDependentName() || + isDependentScopeSpecifier(SS)) { + Result = ActOnDependentMemberExpr(Base, Base->getType(), + IsArrow, OpLoc, + SS, FirstQualifierInScope, + NameInfo, TemplateArgs); + } else { + LookupResult R(*this, NameInfo, LookupMemberName); + ExprResult BaseResult = Owned(Base); + Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, + SS, ObjCImpDecl, TemplateArgs != 0); + if (BaseResult.isInvalid()) + return ExprError(); + Base = BaseResult.take(); + + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) { + // The only way a reference to a destructor can be used is to + // immediately call it, which falls into this case. If the + // next token is not a '(', produce a diagnostic and build the + // call now. + if (!HasTrailingLParen && + Id.getKind() == UnqualifiedId::IK_DestructorName) + return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); + + return move(Result); + } + + Result = BuildMemberReferenceExpr(Base, Base->getType(), + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); + } + + return move(Result); +} + +static ExprResult +BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo) { + // x.a is an l-value if 'a' has a reference type. Otherwise: + // x.a is an l-value/x-value/pr-value if the base is (and note + // that *x is always an l-value), except that if the base isn't + // an ordinary object then we must have an rvalue. + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_Ordinary; + if (!IsArrow) { + if (BaseExpr->getObjectKind() == OK_Ordinary) + VK = BaseExpr->getValueKind(); + else + VK = VK_RValue; + } + if (VK != VK_RValue && Field->isBitField()) + OK = OK_BitField; + + // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] + QualType MemberType = Field->getType(); + if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) { + MemberType = Ref->getPointeeType(); + VK = VK_LValue; + } else { + QualType BaseType = BaseExpr->getType(); + if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + + Qualifiers BaseQuals = BaseType.getQualifiers(); + + // GC attributes are never picked up by members. + BaseQuals.removeObjCGCAttr(); + + // CVR attributes from the base are picked up by members, + // except that 'mutable' members don't pick up 'const'. + if (Field->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = S.Context.getCanonicalType(MemberType).getQualifiers(); + + // TR 18037 does not allow fields to be declared with address spaces. + assert(!MemberQuals.hasAddressSpace()); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = S.Context.getQualifiedType(MemberType, Combined); + } + + S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); + ExprResult Base = + S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), + FoundDecl, Field); + if (Base.isInvalid()) + return ExprError(); + return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS, + Field, FoundDecl, MemberNameInfo, + MemberType, VK, OK)); +} + +/// Builds an implicit member access expression. The current context +/// is known to be an instance method, and the given unqualified lookup +/// set is known to contain only instance members, at least one of which +/// is from an appropriate type. +ExprResult +Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsKnownInstance) { + assert(!R.empty() && !R.isAmbiguous()); + + SourceLocation loc = R.getNameLoc(); + + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + // FIXME: template-ids inside anonymous structs? + if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) + return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); + + // If this is known to be an instance access, go ahead and build an + // implicit 'this' expression now. + // 'this' expression now. + QualType ThisTy = getAndCaptureCurrentThisType(); + assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); + + Expr *baseExpr = 0; // null signifies implicit access + if (IsKnownInstance) { + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); + } + + return BuildMemberReferenceExpr(baseExpr, ThisTy, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, + /*FirstQualifierInScope*/ 0, + R, TemplateArgs); +} diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index cb5c1e0..02a4682 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "llvm/ADT/SmallString.h" #include "clang/Lex/Preprocessor.h" @@ -62,7 +63,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // Create the aggregate string with the appropriate content and location // information. - S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), + S = StringLiteral::Create(Context, StrBuf, /*Wide=*/false, /*Pascal=*/false, Context.getPointerType(Context.CharTy), &StrLocs[0], StrLocs.size()); @@ -127,7 +128,8 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, if (EncodedType->isDependentType()) StrTy = Context.DependentTy; else { - if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled. + if (!EncodedType->getAsArrayTypeUnsafe() && //// Incomplete array is handled. + !EncodedType->isVoidType()) // void is handled too. if (RequireCompleteType(AtLoc, EncodedType, PDiag(diag::err_incomplete_type_objc_at_encode) << EncodedTypeInfo->getTypeLoc().getSourceRange())) @@ -176,12 +178,39 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceRange(LParenLoc, RParenLoc)); if (!Method) Diag(SelLoc, diag::warn_undeclared_selector) << Sel; + + if (!Method || + Method->getImplementationControl() != ObjCMethodDecl::Optional) { + llvm::DenseMap<Selector, SourceLocation>::iterator Pos + = ReferencedSelectors.find(Sel); + if (Pos == ReferencedSelectors.end()) + ReferencedSelectors.insert(std::make_pair(Sel, SelLoc)); + } - llvm::DenseMap<Selector, SourceLocation>::iterator Pos - = ReferencedSelectors.find(Sel); - if (Pos == ReferencedSelectors.end()) - ReferencedSelectors.insert(std::make_pair(Sel, SelLoc)); - + // In ARC, forbid the user from using @selector for + // retain/release/autorelease/dealloc/retainCount. + if (getLangOptions().ObjCAutoRefCount) { + switch (Sel.getMethodFamily()) { + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_retainCount: + case OMF_dealloc: + Diag(AtLoc, diag::err_arc_illegal_selector) << + Sel << SourceRange(LParenLoc, RParenLoc); + break; + + case OMF_None: + case OMF_alloc: + case OMF_copy: + case OMF_init: + case OMF_mutableCopy: + case OMF_new: + case OMF_self: + case OMF_performSelector: + break; + } + } QualType Ty = Context.getObjCSelType(); return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); } @@ -321,11 +350,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, Args[i] = Result.take(); } - unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : - diag::warn_inst_method_not_found; + unsigned DiagID; + if (getLangOptions().ObjCAutoRefCount) + DiagID = diag::err_arc_method_not_found; + else + DiagID = isClassMessage ? diag::warn_class_method_not_found + : diag::warn_inst_method_not_found; Diag(lbrac, DiagID) << Sel << isClassMessage << SourceRange(lbrac, rbrac); - ReturnType = Context.getObjCIdType(); + + // In debuggers, we want to use __unknown_anytype for these + // results so that clients can cast them. + if (getLangOptions().DebuggerSupport) { + ReturnType = Context.UnknownAnyTy; + } else { + ReturnType = Context.getObjCIdType(); + } VK = VK_RValue; return false; } @@ -404,17 +444,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, return IsError; } -bool Sema::isSelfExpr(Expr *RExpr) { +bool Sema::isSelfExpr(Expr *receiver) { // 'self' is objc 'self' in an objc method only. DeclContext *DC = CurContext; while (isa<BlockDecl>(DC)) DC = DC->getParent(); if (DC && !isa<ObjCMethodDecl>(DC)) return false; - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr)) - if (ICE->getCastKind() == CK_LValueToRValue) - RExpr = ICE->getSubExpr(); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr)) + receiver = receiver->IgnoreParenLValueCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver)) if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) return true; return false; @@ -489,7 +527,8 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, /// objective C interface. This is a property reference expression. ExprResult Sema:: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, - Expr *BaseExpr, DeclarationName MemberName, + Expr *BaseExpr, SourceLocation OpLoc, + DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super) { @@ -635,17 +674,19 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Attempt to correct for typos in property names. - LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName); - if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) && - Res.getAsSingle<ObjCPropertyDecl>()) { - DeclarationName TypoResult = Res.getLookupName(); + TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL, + NULL, IFace, false, CTC_NoKeywords, OPT); + if (ObjCPropertyDecl *Property = + Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) { + DeclarationName TypoResult = Corrected.getCorrection(); Diag(MemberLoc, diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0) << TypoResult << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString()); - ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); - return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc, + return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, + TypoResult, MemberLoc, SuperLoc, SuperType, Super); } ObjCInterfaceDecl *ClassDeclared; @@ -663,6 +704,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); } } + Diag(MemberLoc, + diag::err_ivar_access_using_property_syntax_suggest) + << MemberName << QualType(OPT, 0) << Ivar->getDeclName() + << FixItHint::CreateReplacement(OpLoc, "->"); + return ExprError(); } Diag(MemberLoc, diag::err_property_not_found) @@ -699,7 +745,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, T = Context.getObjCObjectPointerType(T); return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), - /*BaseExpr*/0, &propertyName, + /*BaseExpr*/0, + SourceLocation()/*OpLoc*/, + &propertyName, propertyNameLoc, receiverNameLoc, T, true); } @@ -862,29 +910,30 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, Method->getClassInterface()->getSuperClass()) CTC = CTC_ObjCMessageReceiver; - if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) { - if (Result.isSingleResult()) { + if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), + Result.getLookupKind(), S, NULL, + NULL, false, CTC)) { + if (NamedDecl *ND = Corrected.getCorrectionDecl()) { // If we found a declaration, correct when it refers to an Objective-C // class. - NamedDecl *ND = Result.getFoundDecl(); if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) { Diag(NameLoc, diag::err_unknown_receiver_suggest) - << Name << Result.getLookupName() + << Name << Corrected.getCorrection() << FixItHint::CreateReplacement(SourceRange(NameLoc), ND->getNameAsString()); Diag(ND->getLocation(), diag::note_previous_decl) - << Corrected; + << Corrected.getCorrection(); QualType T = Context.getObjCInterfaceType(Class); TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); ReceiverType = CreateParsedType(T, TSInfo); return ObjCClassMessage; } - } else if (Result.empty() && Corrected.getAsIdentifierInfo() && - Corrected.getAsIdentifierInfo()->isStr("super")) { + } else if (Corrected.isKeyword() && + Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) { // If we've found the keyword "super", this is a send to super. Diag(NameLoc, diag::err_unknown_receiver_suggest) - << Name << Corrected + << Name << Corrected.getCorrection() << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); return ObjCSuperMessage; } @@ -1013,11 +1062,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // Find the method we are messaging. if (!Method) { if (Class->isForwardDecl()) { + if (getLangOptions().ObjCAutoRefCount) { + Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType; + } else { + Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName(); + } + // A forward class used in messaging is treated as a 'Class' - Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName(); Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); - if (Method) + if (Method && !getLangOptions().ObjCAutoRefCount) Diag(Method->getLocation(), diag::note_method_sent_forward_class) << Method->getDeclName(); } @@ -1236,6 +1290,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). ClassDecl = OCIType->getInterfaceDecl(); + + if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) { + Diag(Loc, diag::err_arc_receiver_forward_instance) + << OCIType->getPointeeType() + << (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc)); + return ExprError(); + } + // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to MethodPool. @@ -1250,6 +1312,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + if (!Method && getLangOptions().ObjCAutoRefCount) { + Diag(Loc, diag::err_arc_may_not_respond) + << OCIType->getPointeeType() << Sel; + return ExprError(); + } + if (!Method && (!Receiver || !isSelfExpr(Receiver))) { // If we still haven't found a method, look in the global pool. This // behavior isn't very desirable, however we need it for GCC @@ -1267,10 +1335,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) return ExprError(); - } else if (!Context.getObjCIdType().isNull() && + } else if (!getLangOptions().ObjCAutoRefCount && + !Context.getObjCIdType().isNull() && (ReceiverType->isPointerType() || ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. + // But not in ARC. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); @@ -1332,8 +1402,84 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); + // In ARC, forbid the user from sending messages to + // retain/release/autorelease/dealloc/retainCount explicitly. + if (getLangOptions().ObjCAutoRefCount) { + ObjCMethodFamily family = + (Method ? Method->getMethodFamily() : Sel.getMethodFamily()); + switch (family) { + case OMF_init: + if (Method) + checkInitMethod(Method, ReceiverType); + + case OMF_None: + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + case OMF_self: + break; + + case OMF_dealloc: + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_retainCount: + Diag(Loc, diag::err_arc_illegal_explicit_message) + << Sel << SelectorLoc; + break; + + case OMF_performSelector: + if (Method && NumArgs >= 1) { + if (ObjCSelectorExpr *SelExp = dyn_cast<ObjCSelectorExpr>(Args[0])) { + Selector ArgSel = SelExp->getSelector(); + ObjCMethodDecl *SelMethod = + LookupInstanceMethodInGlobalPool(ArgSel, + SelExp->getSourceRange()); + if (!SelMethod) + SelMethod = + LookupFactoryMethodInGlobalPool(ArgSel, + SelExp->getSourceRange()); + if (SelMethod) { + ObjCMethodFamily SelFamily = SelMethod->getMethodFamily(); + switch (SelFamily) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + case OMF_self: + case OMF_init: + // Issue error, unless ns_returns_not_retained. + if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { + // selector names a +1 method + Diag(SelectorLoc, + diag::err_arc_perform_selector_retains); + Diag(SelMethod->getLocation(), diag::note_method_declared_at); + } + break; + default: + // +0 call. OK. unless ns_returns_retained. + if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) { + // selector names a +1 method + Diag(SelectorLoc, + diag::err_arc_perform_selector_retains); + Diag(SelMethod->getLocation(), diag::note_method_declared_at); + } + break; + } + } + } else { + // error (may leak). + Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks); + Diag(Args[0]->getExprLoc(), diag::note_used_here); + } + } + break; + } + } + // Construct the appropriate ObjCMessageExpr instance. - Expr *Result; + ObjCMessageExpr *Result; if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, @@ -1343,6 +1489,27 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLoc, Method, Args, NumArgs, RBracLoc); + + if (getLangOptions().ObjCAutoRefCount) { + // In ARC, annotate delegate init calls. + if (Result->getMethodFamily() == OMF_init && + (SuperLoc.isValid() || isSelfExpr(Receiver))) { + // Only consider init calls *directly* in init implementations, + // not within blocks. + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext); + if (method && method->getMethodFamily() == OMF_init) { + // The implicit assignment to self means we also don't want to + // consume the result. + Result->setDelegateInitCall(true); + return Owned(Result); + } + } + + // In ARC, check for message sends which are likely to introduce + // retain cycles. + checkRetainCycles(Result); + } + return MaybeBindToTemporary(Result); } @@ -1364,3 +1531,393 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, LBracLoc, SelectorLoc, RBracLoc, move(Args)); } +enum ARCConversionTypeClass { + ACTC_none, + ACTC_retainable, + ACTC_indirectRetainable +}; +static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) { + ARCConversionTypeClass ACTC = ACTC_retainable; + + // Ignore an outermost reference type. + if (const ReferenceType *ref = type->getAs<ReferenceType>()) + type = ref->getPointeeType(); + + // Drill through pointers and arrays recursively. + while (true) { + if (const PointerType *ptr = type->getAs<PointerType>()) { + type = ptr->getPointeeType(); + } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) { + type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0); + } else { + break; + } + ACTC = ACTC_indirectRetainable; + } + + if (!type->isObjCRetainableType()) return ACTC_none; + return ACTC; +} + +namespace { + /// Return true if the given expression can be reasonably converted + /// between a retainable pointer type and a C pointer type. + struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> { + ASTContext &Context; + ARCCastChecker(ASTContext &Context) : Context(Context) {} + bool VisitStmt(Stmt *s) { + return false; + } + bool VisitExpr(Expr *e) { + return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); + } + + bool VisitParenExpr(ParenExpr *e) { + return Visit(e->getSubExpr()); + } + bool VisitCastExpr(CastExpr *e) { + switch (e->getCastKind()) { + case CK_NullToPointer: + return true; + case CK_NoOp: + case CK_LValueToRValue: + case CK_BitCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + return Visit(e->getSubExpr()); + default: + return false; + } + } + bool VisitUnaryExtension(UnaryOperator *e) { + return Visit(e->getSubExpr()); + } + bool VisitBinComma(BinaryOperator *e) { + return Visit(e->getRHS()); + } + bool VisitConditionalOperator(ConditionalOperator *e) { + // Conditional operators are okay if both sides are okay. + return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr()); + } + bool VisitObjCStringLiteral(ObjCStringLiteral *e) { + // Always white-list Objective-C string literals. + return true; + } + bool VisitStmtExpr(StmtExpr *e) { + return Visit(e->getSubStmt()->body_back()); + } + bool VisitDeclRefExpr(DeclRefExpr *e) { + // White-list references to global extern strings from system + // headers. + if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl())) + if (var->getStorageClass() == SC_Extern && + var->getType().isConstQualified() && + Context.getSourceManager().isInSystemHeader(var->getLocation())) + return true; + return false; + } + }; +} + +bool +Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) { + Expr *NewExp = Exp->IgnoreParenCasts(); + + if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp) + && !isa<CallExpr>(NewExp)) + return false; + ObjCMethodDecl *method = 0; + bool MethodReturnsPlusOne = false; + + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) { + method = PRE->getExplicitProperty()->getGetterMethodDecl(); + } + else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp)) + method = ME->getMethodDecl(); + else { + CallExpr *CE = cast<CallExpr>(NewExp); + Decl *CallDecl = CE->getCalleeDecl(); + if (!CallDecl) + return false; + if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>()) + return true; + MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>(); + if (!MethodReturnsPlusOne) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl)) + if (const IdentifierInfo *Id = ND->getIdentifier()) + if (Id->isStr("__builtin___CFStringMakeConstantString")) + return true; + } + } + + if (!MethodReturnsPlusOne) { + if (!method) + return false; + if (method->hasAttr<CFReturnsNotRetainedAttr>()) + return true; + MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>(); + if (!MethodReturnsPlusOne) { + ObjCMethodFamily family = method->getSelector().getMethodFamily(); + switch (family) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + MethodReturnsPlusOne = true; + break; + default: + break; + } + } + } + + if (MethodReturnsPlusOne) { + TypeSourceInfo *TSInfo = + Context.getTrivialTypeSourceInfo(castType, SourceLocation()); + ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer, + SourceLocation(), TSInfo, Exp); + Exp = ExpRes.take(); + } + return true; +} + +void +Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, + Expr *&castExpr, CheckedConversionKind CCK) { + QualType castExprType = castExpr->getType(); + + ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); + ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); + if (exprACTC == castACTC) return; + if (exprACTC && castType->isIntegralType(Context)) return; + + // Allow casts between pointers to lifetime types (e.g., __strong id*) + // and pointers to void (e.g., cv void *). Casting from void* to lifetime* + // must be explicit. + if (const PointerType *CastPtr = castType->getAs<PointerType>()) { + if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) { + QualType CastPointee = CastPtr->getPointeeType(); + QualType CastExprPointee = CastExprPtr->getPointeeType(); + if ((CCK != CCK_ImplicitConversion && + CastPointee->isObjCIndirectLifetimeType() && + CastExprPointee->isVoidType()) || + (CastPointee->isVoidType() && + CastExprPointee->isObjCIndirectLifetimeType())) + return; + } + } + + if (ARCCastChecker(Context).Visit(castExpr)) + return; + + SourceLocation loc = + (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); + + if (makeUnavailableInSystemHeader(loc, + "converts between Objective-C and C pointers in -fobjc-arc")) + return; + + unsigned srcKind = 0; + switch (exprACTC) { + case ACTC_none: + srcKind = (castExprType->isPointerType() ? 1 : 0); + break; + case ACTC_retainable: + srcKind = (castExprType->isBlockPointerType() ? 2 : 3); + break; + case ACTC_indirectRetainable: + srcKind = 4; + break; + } + + if (CCK == CCK_CStyleCast) { + // Check whether this could be fixed with a bridge cast. + SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin()); + SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc; + + if (castType->isObjCARCBridgableType() && + castExprType->isCARCBridgableType()) { + // explicit unbridged casts are allowed if the source of the cast is a + // message sent to an objc method (or property access) + if (ValidObjCARCNoBridgeCastExpr(castExpr, castType)) + return; + Diag(loc, diag::err_arc_cast_requires_bridge) + << 2 + << castExprType + << (castType->isBlockPointerType()? 1 : 0) + << castType + << castRange + << castExpr->getSourceRange(); + Diag(NoteLoc, diag::note_arc_bridge) + << FixItHint::CreateInsertion(AfterLParen, "__bridge "); + Diag(NoteLoc, diag::note_arc_bridge_transfer) + << castExprType + << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer "); + + return; + } + + if (castType->isCARCBridgableType() && + castExprType->isObjCARCBridgableType()){ + Diag(loc, diag::err_arc_cast_requires_bridge) + << (castExprType->isBlockPointerType()? 1 : 0) + << castExprType + << 2 + << castType + << castRange + << castExpr->getSourceRange(); + + Diag(NoteLoc, diag::note_arc_bridge) + << FixItHint::CreateInsertion(AfterLParen, "__bridge "); + Diag(NoteLoc, diag::note_arc_bridge_retained) + << castType + << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained "); + return; + } + } + + Diag(loc, diag::err_arc_mismatched_cast) + << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType + << castRange << castExpr->getSourceRange(); +} + +bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType, + QualType exprType) { + QualType canCastType = + Context.getCanonicalType(castType).getUnqualifiedType(); + QualType canExprType = + Context.getCanonicalType(exprType).getUnqualifiedType(); + if (isa<ObjCObjectPointerType>(canCastType) && + castType.getObjCLifetime() == Qualifiers::OCL_Weak && + canExprType->isObjCObjectPointerType()) { + if (const ObjCObjectPointerType *ObjT = + canExprType->getAs<ObjCObjectPointerType>()) + if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) + return false; + } + return true; +} + +/// Look for an ObjCReclaimReturnedObject cast and destroy it. +static Expr *maybeUndoReclaimObject(Expr *e) { + // For now, we just undo operands that are *immediately* reclaim + // expressions, which prevents the vast majority of potential + // problems here. To catch them all, we'd need to rebuild arbitrary + // value-propagating subexpressions --- we can't reliably rebuild + // in-place because of expression sharing. + if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + if (ice->getCastKind() == CK_ObjCReclaimReturnedObject) + return ice->getSubExpr(); + + return e; +} + +ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, + Expr *SubExpr) { + QualType T = TSInfo->getType(); + QualType FromType = SubExpr->getType(); + + bool MustConsume = false; + if (T->isDependentType() || SubExpr->isTypeDependent()) { + // Okay: we'll build a dependent expression type. + } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) { + // Casting CF -> id + switch (Kind) { + case OBC_Bridge: + break; + + case OBC_BridgeRetained: + Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) + << 2 + << FromType + << (T->isBlockPointerType()? 1 : 0) + << T + << SubExpr->getSourceRange() + << Kind; + Diag(BridgeKeywordLoc, diag::note_arc_bridge) + << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge"); + Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer) + << FromType + << FixItHint::CreateReplacement(BridgeKeywordLoc, + "__bridge_transfer "); + + Kind = OBC_Bridge; + break; + + case OBC_BridgeTransfer: + // We must consume the Objective-C object produced by the cast. + MustConsume = true; + break; + } + } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) { + // Okay: id -> CF + switch (Kind) { + case OBC_Bridge: + // Reclaiming a value that's going to be __bridge-casted to CF + // is very dangerous, so we don't do it. + SubExpr = maybeUndoReclaimObject(SubExpr); + break; + + case OBC_BridgeRetained: + // Produce the object before casting it. + SubExpr = ImplicitCastExpr::Create(Context, FromType, + CK_ObjCProduceObject, + SubExpr, 0, VK_RValue); + break; + + case OBC_BridgeTransfer: + Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind) + << (FromType->isBlockPointerType()? 1 : 0) + << FromType + << 2 + << T + << SubExpr->getSourceRange() + << Kind; + + Diag(BridgeKeywordLoc, diag::note_arc_bridge) + << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge "); + Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained) + << T + << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained "); + + Kind = OBC_Bridge; + break; + } + } else { + Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible) + << FromType << T << Kind + << SubExpr->getSourceRange() + << TSInfo->getTypeLoc().getSourceRange(); + return ExprError(); + } + + Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, + BridgeKeywordLoc, + TSInfo, SubExpr); + + if (MustConsume) { + ExprNeedsCleanups = true; + Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result, + 0, VK_RValue); + } + + return Result; +} + +ExprResult Sema::ActOnObjCBridgedCast(Scope *S, + SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + ParsedType Type, + SourceLocation RParenLoc, + Expr *SubExpr) { + TypeSourceInfo *TSInfo = 0; + QualType T = GetTypeFromParser(Type, &TSInfo); + if (!TSInfo) + TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc); + return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo, + SubExpr); +} diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index a33f5d0..9fbcbab 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -769,7 +769,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // subaggregate, brace elision is assumed and the initializer is // considered for the initialization of the first member of // the subaggregate. - if (ElemType->isAggregateType() || ElemType->isVectorType()) { + if (!SemaRef.getLangOptions().OpenCL && + (ElemType->isAggregateType() || ElemType->isVectorType())) { CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); ++StructuredIndex; @@ -1184,6 +1185,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, continue; } + // Make sure we can use this declaration. + if (SemaRef.DiagnoseUseOfDecl(*Field, + IList->getInit(Index)->getLocStart())) { + ++Index; + ++Field; + hadError = true; + continue; + } + InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); CheckSubElementType(MemberEntity, IList, Field->getType(), Index, @@ -1443,19 +1453,23 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // was a typo for another field name. LookupResult R(SemaRef, FieldName, D->getFieldLoc(), Sema::LookupMemberName); - if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, - Sema::CTC_NoKeywords) && - (ReplacementField = R.getAsSingle<FieldDecl>()) && + TypoCorrection Corrected = SemaRef.CorrectTypo( + DeclarationNameInfo(FieldName, D->getFieldLoc()), + Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL, + RT->getDecl(), false, Sema::CTC_NoKeywords); + if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) && ReplacementField->getDeclContext()->getRedeclContext() ->Equals(RT->getDecl())) { + std::string CorrectedStr( + Corrected.getAsString(SemaRef.getLangOptions())); + std::string CorrectedQuotedStr( + Corrected.getQuoted(SemaRef.getLangOptions())); SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) - << FieldName << CurrentObjectType << R.getLookupName() - << FixItHint::CreateReplacement(D->getFieldLoc(), - R.getLookupName().getAsString()); + << FieldName << CurrentObjectType << CorrectedQuotedStr + << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr); SemaRef.Diag(ReplacementField->getLocation(), - diag::note_previous_decl) - << ReplacementField->getDeclName(); + diag::note_previous_decl) << CorrectedQuotedStr; } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; @@ -1499,6 +1513,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, StructuredList->setInitializedFieldInUnion(*Field); } + // Make sure we can use this declaration. + if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) { + ++Index; + return true; + } + // Update the designator with the field declaration. D->setField(*Field); @@ -2029,10 +2049,10 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, DeclarationName InitializedEntity::getName() const { switch (getKind()) { - case EK_Parameter: - if (!VariableOrMember) - return DeclarationName(); - // Fall through + case EK_Parameter: { + ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1); + return (D ? D->getDeclName() : DeclarationName()); + } case EK_Variable: case EK_Member: @@ -2057,10 +2077,12 @@ DeclarationName InitializedEntity::getName() const { DeclaratorDecl *InitializedEntity::getDecl() const { switch (getKind()) { case EK_Variable: - case EK_Parameter: case EK_Member: return VariableOrMember; + case EK_Parameter: + return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1); + case EK_Result: case EK_Exception: case EK_New: @@ -2123,6 +2145,9 @@ void InitializationSequence::Step::Destroy() { case SK_StringInit: case SK_ObjCObjectConversion: case SK_ArrayInit: + case SK_PassByIndirectCopyRestore: + case SK_PassByIndirectRestore: + case SK_ProduceObjCObject: break; case SK_ConversionSequence: @@ -2131,7 +2156,7 @@ void InitializationSequence::Step::Destroy() { } bool InitializationSequence::isDirectReferenceBinding() const { - return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference; + return !Steps.empty() && Steps.back().Kind == SK_BindReference; } bool InitializationSequence::isAmbiguous() const { @@ -2306,6 +2331,22 @@ void InitializationSequence::AddArrayInitStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type, + bool shouldCopy) { + Step s; + s.Kind = (shouldCopy ? SK_PassByIndirectCopyRestore + : SK_PassByIndirectRestore); + s.Type = type; + Steps.push_back(s); +} + +void InitializationSequence::AddProduceObjCObjectStep(QualType T) { + Step S; + S.Kind = SK_ProduceObjCObject; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { setSequenceKind(FailedSequence); @@ -2317,6 +2358,33 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure, // Attempt initialization //===----------------------------------------------------------------------===// +static void MaybeProduceObjCObject(Sema &S, + InitializationSequence &Sequence, + const InitializedEntity &Entity) { + if (!S.getLangOptions().ObjCAutoRefCount) return; + + /// When initializing a parameter, produce the value if it's marked + /// __attribute__((ns_consumed)). + if (Entity.getKind() == InitializedEntity::EK_Parameter) { + if (!Entity.isParameterConsumed()) + return; + + assert(Entity.getType()->isObjCRetainableType() && + "consuming an object of unretainable type?"); + Sequence.AddProduceObjCObjectStep(Entity.getType()); + + /// When initializing a return value, if the return type is a + /// retainable type, then returns need to immediately retain the + /// object. If an autorelease is required, it will be done at the + /// last instant. + } else if (Entity.getKind() == InitializedEntity::EK_Result) { + if (!Entity.getType()->isObjCRetainableType()) + return; + + Sequence.AddProduceObjCObjectStep(Entity.getType()); + } +} + /// \brief Attempt list initialization (C++0x [dcl.init.list]) static void TryListInitialization(Sema &S, const InitializedEntity &Entity, @@ -2380,13 +2448,16 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool DerivedToBase; bool ObjCConversion; + bool ObjCLifetimeConversion; assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), T1, T2, DerivedToBase, - ObjCConversion) && + ObjCConversion, + ObjCLifetimeConversion) && "Must have incompatible references when binding via conversion"); (void)DerivedToBase; (void)ObjCConversion; - + (void)ObjCLifetimeConversion; + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -2513,10 +2584,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, bool NewDerivedToBase = false; bool NewObjCConversion = false; + bool NewObjCLifetimeConversion = false; Sema::ReferenceCompareResult NewRefRelationship = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonLValueExprType(S.Context), - NewDerivedToBase, NewObjCConversion); + NewDerivedToBase, NewObjCConversion, + NewObjCLifetimeConversion); if (NewRefRelationship == Sema::Ref_Incompatible) { // If the type we've converted to is not reference-related to the // type we're looking for, then there is another conversion step @@ -2550,8 +2623,6 @@ static void TryReferenceInitialization(Sema &S, const InitializationKind &Kind, Expr *Initializer, InitializationSequence &Sequence) { - Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); - QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); Qualifiers T1Quals; @@ -2584,10 +2655,11 @@ static void TryReferenceInitialization(Sema &S, bool isRValueRef = !isLValueRef; bool DerivedToBase = false; bool ObjCConversion = false; + bool ObjCLifetimeConversion = false; Expr::Classification InitCategory = Initializer->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase, - ObjCConversion); + ObjCConversion, ObjCLifetimeConversion); // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression of type @@ -2746,11 +2818,15 @@ static void TryReferenceInitialization(Sema &S, InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); - if (S.TryImplicitConversion(Sequence, TempEntity, Initializer, + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, TempEntity.getType(), /*SuppressUserConversions*/ false, AllowExplicit, /*FIXME:InOverloadResolution=*/false, - /*CStyle=*/Kind.isCStyleOrFunctionalCast())) { + /*CStyle=*/Kind.isCStyleOrFunctionalCast(), + /*AllowObjCWritebackConversion=*/false); + + if (ICS.isBad()) { // FIXME: Use the conversion function set stored in ICS to turn // this into an overloading ambiguity diagnostic. However, we need // to keep that set as an OverloadCandidateSet rather than as some @@ -2764,6 +2840,8 @@ static void TryReferenceInitialization(Sema &S, else Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); return; + } else { + Sequence.AddConversionSequenceStep(ICS, TempEntity.getType()); } // [...] If T1 is reference-related to T2, cv1 must be the @@ -2953,10 +3031,8 @@ static void TryDefaultInitialization(Sema &S, // C++ [dcl.init]p6: // To default-initialize an object of type T means: // - if T is an array type, each element is default-initialized; - QualType DestType = Entity.getType(); - while (const ArrayType *Array = S.Context.getAsArrayType(DestType)) - DestType = Array->getElementType(); - + QualType DestType = S.Context.getBaseElementType(Entity.getType()); + // - if T is a (possibly cv-qualified) class type (Clause 9), the default // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); @@ -2970,8 +3046,16 @@ static void TryDefaultInitialization(Sema &S, // If a program calls for the default initialization of an object of // a const-qualified type T, T shall be a class type with a user-provided // default constructor. - if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) + if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) { Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + return; + } + + // If the destination type has a lifetime property, zero-initialize it. + if (DestType.getQualifiers().hasObjCLifetime()) { + Sequence.AddZeroInitializationStep(Entity.getType()); + return; + } } /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), @@ -3125,6 +3209,86 @@ static void TryUserDefinedConversion(Sema &S, } } +/// The non-zero enum values here are indexes into diagnostic alternatives. +enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar }; + +/// Determines whether this expression is an acceptable ICR source. +static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e, + bool isAddressOf) { + // Skip parens. + e = e->IgnoreParens(); + + // Skip address-of nodes. + if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) { + if (op->getOpcode() == UO_AddrOf) + return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true); + + // Skip certain casts. + } else if (CastExpr *ce = dyn_cast<CastExpr>(e)) { + switch (ce->getCastKind()) { + case CK_Dependent: + case CK_BitCast: + case CK_LValueBitCast: + case CK_NoOp: + return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf); + + case CK_ArrayToPointerDecay: + return IIK_nonscalar; + + case CK_NullToPointer: + return IIK_okay; + + default: + break; + } + + // If we have a declaration reference, it had better be a local variable. + } else if (isa<DeclRefExpr>(e) || isa<BlockDeclRefExpr>(e)) { + if (!isAddressOf) return IIK_nonlocal; + + VarDecl *var; + if (isa<DeclRefExpr>(e)) { + var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl()); + if (!var) return IIK_nonlocal; + } else { + var = cast<BlockDeclRefExpr>(e)->getDecl(); + } + + return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal); + + // If we have a conditional operator, check both sides. + } else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) { + if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf)) + return iik; + + return isInvalidICRSource(C, cond->getRHS(), isAddressOf); + + // These are never scalar. + } else if (isa<ArraySubscriptExpr>(e)) { + return IIK_nonscalar; + + // Otherwise, it needs to be a null pointer constant. + } else { + return (e->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull) + ? IIK_okay : IIK_nonlocal); + } + + return IIK_nonlocal; +} + +/// Check whether the given expression is a valid operand for an +/// indirect copy/restore. +static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) { + assert(src->isRValue()); + + InvalidICRKind iik = isInvalidICRSource(S.Context, src, false); + if (iik == IIK_okay) return; + + S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback) + << ((unsigned) iik - 1) // shift index into diagnostic explanations + << src->getSourceRange(); +} + /// \brief Determine whether we have compatible array types for the /// purposes of GNU by-copy array initialization. static bool hasCompatibleArrayTypes(ASTContext &Context, @@ -3144,6 +3308,53 @@ static bool hasCompatibleArrayTypes(ASTContext &Context, return Source->isConstantArrayType() && Dest->isIncompleteArrayType(); } +static bool tryObjCWritebackConversion(Sema &S, + InitializationSequence &Sequence, + const InitializedEntity &Entity, + Expr *Initializer) { + bool ArrayDecay = false; + QualType ArgType = Initializer->getType(); + QualType ArgPointee; + if (const ArrayType *ArgArrayType = S.Context.getAsArrayType(ArgType)) { + ArrayDecay = true; + ArgPointee = ArgArrayType->getElementType(); + ArgType = S.Context.getPointerType(ArgPointee); + } + + // Handle write-back conversion. + QualType ConvertedArgType; + if (!S.isObjCWritebackConversion(ArgType, Entity.getType(), + ConvertedArgType)) + return false; + + // We should copy unless we're passing to an argument explicitly + // marked 'out'. + bool ShouldCopy = true; + if (ParmVarDecl *param = cast_or_null<ParmVarDecl>(Entity.getDecl())) + ShouldCopy = (param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out); + + // Do we need an lvalue conversion? + if (ArrayDecay || Initializer->isGLValue()) { + ImplicitConversionSequence ICS; + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + + QualType ResultType; + if (ArrayDecay) { + ICS.Standard.First = ICK_Array_To_Pointer; + ResultType = S.Context.getPointerType(ArgPointee); + } else { + ICS.Standard.First = ICK_Lvalue_To_Rvalue; + ResultType = Initializer->getType().getNonLValueExprType(S.Context); + } + + Sequence.AddConversionSequenceStep(ICS, ResultType); + } + + Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); + return true; +} + InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -3255,12 +3466,28 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - // Handle initialization in C + // Determine whether we should consider writeback conversions for + // Objective-C ARC. + bool allowObjCWritebackConversion = S.getLangOptions().ObjCAutoRefCount && + Entity.getKind() == InitializedEntity::EK_Parameter; + + // We're at the end of the line for C: it's either a write-back conversion + // or it's a C assignment. There's no need to check anything else. if (!S.getLangOptions().CPlusPlus) { + // If allowed, check whether this is an Objective-C writeback conversion. + if (allowObjCWritebackConversion && + tryObjCWritebackConversion(S, *this, Entity, Initializer)) { + return; + } + + // Handle initialization in C AddCAssignmentStep(DestType); + MaybeProduceObjCObject(S, *this, Entity); return; } + assert(S.getLangOptions().CPlusPlus); + // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { // - If the initialization is direct-initialization, or if it is @@ -3294,6 +3521,7 @@ InitializationSequence::InitializationSequence(Sema &S, // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + MaybeProduceObjCObject(S, *this, Entity); return; } @@ -3302,12 +3530,38 @@ InitializationSequence::InitializationSequence(Sema &S, // conversions (Clause 4) will be used, if necessary, to convert the // initializer expression to the cv-unqualified version of the // destination type; no user-defined conversions are considered. - if (S.TryImplicitConversion(*this, Entity, Initializer, - /*SuppressUserConversions*/ true, + + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, Entity.getType(), + /*SuppressUserConversions*/true, /*AllowExplicitConversions*/ false, /*InOverloadResolution*/ false, - /*CStyle=*/Kind.isCStyleOrFunctionalCast())) - { + /*CStyle=*/Kind.isCStyleOrFunctionalCast(), + allowObjCWritebackConversion); + + if (ICS.isStandard() && + ICS.Standard.Second == ICK_Writeback_Conversion) { + // Objective-C ARC writeback conversion. + + // We should copy unless we're passing to an argument explicitly + // marked 'out'. + bool ShouldCopy = true; + if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl())) + ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out); + + // If there was an lvalue adjustment, add it as a separate conversion. + if (ICS.Standard.First == ICK_Array_To_Pointer || + ICS.Standard.First == ICK_Lvalue_To_Rvalue) { + ImplicitConversionSequence LvalueICS; + LvalueICS.setStandard(); + LvalueICS.Standard.setAsIdentityConversion(); + LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0)); + LvalueICS.Standard.First = ICS.Standard.First; + AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0)); + } + + AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy); + } else if (ICS.isBad()) { DeclAccessPair dap; if (Initializer->getType() == Context.OverloadTy && !S.ResolveAddressOfOverloadedFunction(Initializer @@ -3315,6 +3569,10 @@ InitializationSequence::InitializationSequence(Sema &S, SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else SetFailed(InitializationSequence::FK_ConversionFailed); + } else { + AddConversionSequenceStep(ICS, Entity.getType()); + + MaybeProduceObjCObject(S, *this, Entity); } } @@ -3560,7 +3818,7 @@ static ExprResult CopyObject(Sema &S, << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << Best->Function->isDeleted(); + << 1 << Best->Function->isDeleted(); return ExprError(); } @@ -3633,6 +3891,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, } } +static bool isReferenceBinding(const InitializationSequence::Step &s) { + return s.Kind == InitializationSequence::SK_BindReference || + s.Kind == InitializationSequence::SK_BindReferenceToTemporary; +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -3684,19 +3947,9 @@ InitializationSequence::Perform(Sema &S, } } - - if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast()) - return ExprResult(Args.release()[0]); - - if (Args.size() == 0) - return S.Owned((Expr *)0); - - unsigned NumArgs = Args.size(); - return S.Owned(new (S.Context) ParenListExpr(S.Context, - SourceLocation(), - (Expr **)Args.release(), - NumArgs, - SourceLocation())); + assert(Kind.getKind() == InitializationKind::IK_Copy || + Kind.isExplicitCast()); + return ExprResult(Args.release()[0]); } // No steps means no initialization. @@ -3733,7 +3986,10 @@ InitializationSequence::Perform(Sema &S, case SK_CAssignment: case SK_StringInit: case SK_ObjCObjectConversion: - case SK_ArrayInit: { + case SK_ArrayInit: + case SK_PassByIndirectCopyRestore: + case SK_PassByIndirectRestore: + case SK_ProduceObjCObject: { assert(Args.size() == 1); CurInit = Args.get()[0]; if (!CurInit.get()) return ExprError(); @@ -3841,12 +4097,22 @@ InitializationSequence::Perform(Sema &S, break; case SK_BindReferenceToTemporary: - // Reference binding does not have any corresponding ASTs. - // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + // Materialize the temporary into memory. + CurInit = new (S.Context) MaterializeTemporaryExpr( + Entity.getType().getNonReferenceType(), + CurInit.get(), + Entity.getType()->isLValueReferenceType()); + + // If we're binding to an Objective-C object that has lifetime, we + // need cleanups. + if (S.getLangOptions().ObjCAutoRefCount && + CurInit.get()->getType()->isObjCLifetimeType()) + S.ExprNeedsCleanups = true; + break; case SK_ExtraneousCopyToTemporary: @@ -3925,8 +4191,7 @@ InitializationSequence::Perform(Sema &S, CreatedObject = Conversion->getResultType()->isRecordType(); } - bool RequiresCopy = !IsCopy && - getKind() != InitializationSequence::ReferenceBinding; + bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back()); if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); else if (CreatedObject && shouldDestroyTemporary(Entity)) { @@ -3969,10 +4234,14 @@ InitializationSequence::Perform(Sema &S, } case SK_ConversionSequence: { + Sema::CheckedConversionKind CCK + = Kind.isCStyleCast()? Sema::CCK_CStyleCast + : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast + : Kind.isExplicitCast()? Sema::CCK_OtherCast + : Sema::CCK_ImplicitConversion; ExprResult CurInitExprRes = S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS, - getAssignmentAction(Entity), - Kind.isCStyleOrFunctionalCast()); + getAssignmentAction(Entity), CCK); if (CurInitExprRes.isInvalid()) return ExprError(); CurInit = move(CurInitExprRes); @@ -4182,7 +4451,20 @@ InitializationSequence::Perform(Sema &S, } } } + break; + case SK_PassByIndirectCopyRestore: + case SK_PassByIndirectRestore: + checkIndirectCopyRestoreSource(S, CurInit.get()); + CurInit = S.Owned(new (S.Context) + ObjCIndirectCopyRestoreExpr(CurInit.take(), Step->Type, + Step->Kind == SK_PassByIndirectCopyRestore)); + break; + + case SK_ProduceObjCObject: + CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type, + CK_ObjCProduceObject, + CurInit.take(), 0, VK_RValue)); break; } } @@ -4278,7 +4560,7 @@ bool InitializationSequence::Diagnose(Sema &S, true); if (Ovl == OR_Deleted) { S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << Best->Function->isDeleted(); + << 1 << Best->Function->isDeleted(); } else { llvm_unreachable("Inconsistent overload resolution?"); } @@ -4443,7 +4725,7 @@ bool InitializationSequence::Diagnose(Sema &S, = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl == OR_Deleted) { S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << Best->Function->isDeleted(); + << 1 << Best->Function->isDeleted(); } else { llvm_unreachable("Inconsistent overload resolution?"); } @@ -4587,10 +4869,6 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case NormalSequence: OS << "Normal sequence: "; break; - - case ReferenceBinding: - OS << "Reference binding: "; - break; } for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) { @@ -4674,6 +4952,18 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case SK_ArrayInit: OS << "array initialization"; break; + + case SK_PassByIndirectCopyRestore: + OS << "pass by indirect copy and restore"; + break; + + case SK_PassByIndirectRestore: + OS << "pass by indirect restore"; + break; + + case SK_ProduceObjCObject: + OS << "Objective-C object retension"; + break; } } } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 92ade1e..0e448e3 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -20,6 +20,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/TypoCorrection.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" @@ -42,6 +43,7 @@ #include <iterator> #include <utility> #include <algorithm> +#include <map> using namespace clang; using namespace sema; @@ -207,6 +209,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, bool Redeclaration) { unsigned IDNS = 0; switch (NameKind) { + case Sema::LookupObjCImplicitSelfParam: case Sema::LookupOrdinaryName: case Sema::LookupRedeclarationWithLinkage: IDNS = Decl::IDNS_Ordinary; @@ -1095,7 +1098,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { if (LeftStartingScope && !((*I)->hasLinkage())) continue; } - + else if (NameKind == LookupObjCImplicitSelfParam && + !isa<ImplicitParamDecl>(*I)) + continue; + R.addDecl(*I); if ((*I)->getAttr<OverloadableAttr>()) { @@ -1379,6 +1385,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Look for this member in our base classes CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0; switch (R.getLookupKind()) { + case LookupObjCImplicitSelfParam: case LookupOrdinaryName: case LookupMemberName: case LookupRedeclarationWithLinkage: @@ -2137,15 +2144,15 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, } } -Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, +Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis) { - D = D->getDefinition(); - assert((D && !D->isBeingDefined()) && + RD = RD->getDefinition(); + assert((RD && !RD->isBeingDefined()) && "doing special member lookup into record that isn't fully complete"); if (RValueThis || ConstThis || VolatileThis) assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && @@ -2155,7 +2162,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, "parameter-less special members can't have qualified arguments"); llvm::FoldingSetNodeID ID; - ID.AddPointer(D); + ID.AddPointer(RD); ID.AddInteger(SM); ID.AddInteger(ConstArg); ID.AddInteger(VolatileArg); @@ -2176,9 +2183,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { - if (!D->hasDeclaredDestructor()) - DeclareImplicitDestructor(D); - CXXDestructorDecl *DD = D->getDestructor(); + if (!RD->hasDeclaredDestructor()) + DeclareImplicitDestructor(RD); + CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); Result->setSuccess(DD->isDeleted()); @@ -2188,7 +2195,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, // Prepare for overload resolution. Here we construct a synthetic argument // if necessary and make sure that implicit functions are declared. - CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D)); + CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD)); DeclarationName Name; Expr *Arg = 0; unsigned NumArgs; @@ -2196,18 +2203,18 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, if (SM == CXXDefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; - if (D->needsImplicitDefaultConstructor()) - DeclareImplicitDefaultConstructor(D); + if (RD->needsImplicitDefaultConstructor()) + DeclareImplicitDefaultConstructor(RD); } else { if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); - if (!D->hasDeclaredCopyConstructor()) - DeclareImplicitCopyConstructor(D); + if (!RD->hasDeclaredCopyConstructor()) + DeclareImplicitCopyConstructor(RD); // TODO: Move constructors } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - if (!D->hasDeclaredCopyAssignment()) - DeclareImplicitCopyAssignment(D); + if (!RD->hasDeclaredCopyAssignment()) + DeclareImplicitCopyAssignment(RD); // TODO: Move assignment } @@ -2225,7 +2232,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, // there is no semantic difference for class types in this restricted // case. ExprValueKind VK; - if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + if (SM == CXXCopyConstructor || SM == CXXCopyAssignment) VK = VK_LValue; else VK = VK_RValue; @@ -2240,7 +2247,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, ThisTy.addConst(); if (VolatileThis) ThisTy.addVolatile(); - Expr::Classification ObjectClassification = + Expr::Classification Classification = (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy, RValueThis ? VK_RValue : VK_LValue))-> Classify(Context); @@ -2252,16 +2259,33 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, DeclContext::lookup_iterator I, E; Result->setConstParamMatch(false); - llvm::tie(I, E) = D->lookup(Name); + llvm::tie(I, E) = RD->lookup(Name); assert((I != E) && "lookup for a constructor or assignment operator was empty"); for ( ; I != E; ++I) { - if ((*I)->isInvalidDecl()) + Decl *Cand = *I; + + if (Cand->isInvalidDecl()) continue; - if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) { - AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs, - OCS, true); + if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) { + // FIXME: [namespace.udecl]p15 says that we should only consider a + // using declaration here if it does not match a declaration in the + // derived class. We do not implement this correctly in other cases + // either. + Cand = U->getTargetDecl(); + + if (Cand->isInvalidDecl()) + continue; + } + + if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) { + if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy, + Classification, &Arg, NumArgs, OCS, true); + else + AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, + NumArgs, OCS, true); // Here we're looking for a const parameter to speed up creation of // implicit copy methods. @@ -2269,13 +2293,21 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D, (SM == CXXCopyConstructor && cast<CXXConstructorDecl>(M)->isCopyConstructor())) { QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0); - if (ArgType->getPointeeType().isConstQualified()) + if (!ArgType->isReferenceType() || + ArgType->getPointeeType().isConstQualified()) Result->setConstParamMatch(true); } + } else if (FunctionTemplateDecl *Tmpl = + dyn_cast<FunctionTemplateDecl>(Cand)) { + if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), + RD, 0, ThisTy, Classification, &Arg, NumArgs, + OCS, true); + else + AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), + 0, &Arg, NumArgs, OCS, true); } else { - FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I); - AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), - 0, &Arg, NumArgs, OCS, true); + assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl"); } } @@ -2310,10 +2342,10 @@ CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { return cast_or_null<CXXConstructorDecl>(Result->getMethod()); } -/// \brief Look up the copy constructor for the given class. -CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class, - unsigned Quals, - bool *ConstParamMatch) { +/// \brief Look up the copying constructor for the given class. +CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, + unsigned Quals, + bool *ConstParamMatch) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy ctor arg"); SpecialMemberOverloadResult *Result = @@ -2341,6 +2373,27 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { return Class->lookup(Name); } +/// \brief Look up the copying assignment operator for the given class. +CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, + unsigned Quals, bool RValueThis, + unsigned ThisQuals, + bool *ConstParamMatch) { + assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy assignment arg"); + assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy assignment this"); + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, RValueThis, + ThisQuals & Qualifiers::Const, + ThisQuals & Qualifiers::Volatile); + + if (ConstParamMatch) + *ConstParamMatch = Result->hasConstParamMatch(); + + return Result->getMethod(); +} + /// \brief Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of @@ -2995,6 +3048,12 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, //===----------------------------------------------------------------------===// namespace { + +typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap; +typedef std::map<unsigned, TypoResultsMap *> TypoEditDistanceMap; + +static const unsigned MaxTypoDistanceResultSets = 5; + class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The name written that is a typo in the source. llvm::StringRef Typo; @@ -3002,33 +3061,55 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. /// - /// The boolean value indicates whether there is a keyword with this name. - llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults; + /// The pointer value being set to the current DeclContext indicates + /// whether there is a keyword with this name. + TypoEditDistanceMap BestResults; + + /// \brief The worst of the best N edit distances found so far. + unsigned MaxEditDistance; - /// \brief The best edit distance found so far. - unsigned BestEditDistance; + Sema &SemaRef; public: - explicit TypoCorrectionConsumer(IdentifierInfo *Typo) + explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo) : Typo(Typo->getName()), - BestEditDistance((std::numeric_limits<unsigned>::max)()) { } + MaxEditDistance((std::numeric_limits<unsigned>::max)()), + SemaRef(SemaRef) { } + ~TypoCorrectionConsumer() { + for (TypoEditDistanceMap::iterator I = BestResults.begin(), + IEnd = BestResults.end(); + I != IEnd; + ++I) + delete I->second; + } + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); void FoundName(llvm::StringRef Name); - void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword); - - typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator; - iterator begin() { return BestResults.begin(); } - iterator end() { return BestResults.end(); } - void erase(iterator I) { BestResults.erase(I); } + void addKeywordResult(llvm::StringRef Keyword); + void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance, + NestedNameSpecifier *NNS=NULL); + void addCorrection(TypoCorrection Correction); + + typedef TypoResultsMap::iterator result_iterator; + typedef TypoEditDistanceMap::iterator distance_iterator; + distance_iterator begin() { return BestResults.begin(); } + distance_iterator end() { return BestResults.end(); } + void erase(distance_iterator I) { BestResults.erase(I); } unsigned size() const { return BestResults.size(); } bool empty() const { return BestResults.empty(); } - bool &operator[](llvm::StringRef Name) { - return BestResults[Name]; + TypoCorrection &operator[](llvm::StringRef Name) { + return (*BestResults.begin()->second)[Name]; + } + + unsigned getMaxEditDistance() const { + return MaxEditDistance; } - unsigned getBestEditDistance() const { return BestEditDistance; } + unsigned getBestEditDistance() { + return (BestResults.empty()) ? MaxEditDistance : BestResults.begin()->first; + } }; } @@ -3053,55 +3134,181 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); - if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3)) + if (MinED > MaxEditDistance || (MinED && Typo.size() / MinED < 3)) return; // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. unsigned UpperBound = - std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance); + std::min(unsigned((Typo.size() + 2) / 3), MaxEditDistance); // Compute the edit distance between the typo and the name of this // entity. If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Name, true, UpperBound); - if (ED == 0) - return; - if (ED < BestEditDistance) { - // This result is better than any we've seen before; clear out - // the previous results. - BestResults.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { + if (ED > MaxEditDistance) { // This result is worse than the best results we've seen so far; // ignore it. return; } - // Add this name to the list of results. By not assigning a value, we - // keep the current value if we've seen this name before (either as a - // keyword or as a declaration), or get the default value (not a keyword) - // if we haven't seen it before. - (void)BestResults[Name]; + addName(Name, NULL, ED); } -void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, - llvm::StringRef Keyword) { +void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Keyword); - if (ED < BestEditDistance) { - BestResults.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { + if (ED > MaxEditDistance) { // This result is worse than the best results we've seen so far; // ignore it. return; } - BestResults[Keyword] = true; + addName(Keyword, TypoCorrection::KeywordDecl(), ED); +} + +void TypoCorrectionConsumer::addName(llvm::StringRef Name, + NamedDecl *ND, + unsigned Distance, + NestedNameSpecifier *NNS) { + addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name), + ND, NNS, Distance)); +} + +void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { + llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); + TypoResultsMap *& Map = BestResults[Correction.getEditDistance()]; + if (!Map) + Map = new TypoResultsMap; + + TypoCorrection &CurrentCorrection = (*Map)[Name]; + if (!CurrentCorrection || + // FIXME: The following should be rolled up into an operator< on + // TypoCorrection with a more principled definition. + CurrentCorrection.isKeyword() < Correction.isKeyword() || + Correction.getAsString(SemaRef.getLangOptions()) < + CurrentCorrection.getAsString(SemaRef.getLangOptions())) + CurrentCorrection = Correction; + + while (BestResults.size() > MaxTypoDistanceResultSets) { + TypoEditDistanceMap::iterator Last = BestResults.end(); + --Last; + delete Last->second; + BestResults.erase(Last); + } +} + +namespace { + +class SpecifierInfo { + public: + DeclContext* DeclCtx; + NestedNameSpecifier* NameSpecifier; + unsigned EditDistance; + + SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED) + : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {} +}; + +typedef llvm::SmallVector<DeclContext*, 4> DeclContextList; +typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList; + +class NamespaceSpecifierSet { + ASTContext &Context; + DeclContextList CurContextChain; + bool isSorted; + + SpecifierInfoList Specifiers; + llvm::SmallSetVector<unsigned, 4> Distances; + llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap; + + /// \brief Helper for building the list of DeclContexts between the current + /// context and the top of the translation unit + static DeclContextList BuildContextChain(DeclContext *Start); + + void SortNamespaces(); + + public: + explicit NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext) + : Context(Context), CurContextChain(BuildContextChain(CurContext)), + isSorted(true) {} + + /// \brief Add the namespace to the set, computing the corresponding + /// NestedNameSpecifier and its distance in the process. + void AddNamespace(NamespaceDecl *ND); + + typedef SpecifierInfoList::iterator iterator; + iterator begin() { + if (!isSorted) SortNamespaces(); + return Specifiers.begin(); + } + iterator end() { return Specifiers.end(); } +}; + +} + +DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { + assert(Start && "Bulding a context chain from a null context"); + DeclContextList Chain; + for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL; + DC = DC->getLookupParent()) { + NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC); + if (!DC->isInlineNamespace() && !DC->isTransparentContext() && + !(ND && ND->isAnonymousNamespace())) + Chain.push_back(DC->getPrimaryContext()); + } + return Chain; +} + +void NamespaceSpecifierSet::SortNamespaces() { + llvm::SmallVector<unsigned, 4> sortedDistances; + sortedDistances.append(Distances.begin(), Distances.end()); + + if (sortedDistances.size() > 1) + std::sort(sortedDistances.begin(), sortedDistances.end()); + + Specifiers.clear(); + for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(), + DIEnd = sortedDistances.end(); + DI != DIEnd; ++DI) { + SpecifierInfoList &SpecList = DistanceMap[*DI]; + Specifiers.append(SpecList.begin(), SpecList.end()); + } + + isSorted = true; +} + +void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) { + DeclContext *Ctx = cast<DeclContext>(ND); + NestedNameSpecifier *NNS = NULL; + unsigned NumSpecifiers = 0; + DeclContextList NamespaceDeclChain(BuildContextChain(Ctx)); + + // Eliminate common elements from the two DeclContext chains + for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), + CEnd = CurContextChain.rend(); + C != CEnd && !NamespaceDeclChain.empty() && + NamespaceDeclChain.back() == *C; ++C) { + NamespaceDeclChain.pop_back(); + } + + // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain + for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(), + CEnd = NamespaceDeclChain.rend(); + C != CEnd; ++C) { + NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C); + if (ND) { + NNS = NestedNameSpecifier::Create(Context, NNS, ND); + ++NumSpecifiers; + } + } + + isSorted = false; + Distances.insert(NumSpecifiers); + DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); } /// \brief Perform name lookup for a possible result for typo correction. @@ -3155,14 +3362,193 @@ static void LookupPotentialTypoResult(Sema &SemaRef, } } +/// \brief Add keywords to the consumer as possible typo corrections. +static void AddKeywordsToConsumer(Sema &SemaRef, + TypoCorrectionConsumer &Consumer, + Scope *S, Sema::CorrectTypoContext CTC) { + // Add context-dependent keywords. + bool WantTypeSpecifiers = false; + bool WantExpressionKeywords = false; + bool WantCXXNamedCasts = false; + bool WantRemainingKeywords = false; + switch (CTC) { + case Sema::CTC_Unknown: + WantTypeSpecifiers = true; + WantExpressionKeywords = true; + WantCXXNamedCasts = true; + WantRemainingKeywords = true; + + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) + if (Method->getClassInterface() && + Method->getClassInterface()->getSuperClass()) + Consumer.addKeywordResult("super"); + + break; + + case Sema::CTC_NoKeywords: + break; + + case Sema::CTC_Type: + WantTypeSpecifiers = true; + break; + + case Sema::CTC_ObjCMessageReceiver: + Consumer.addKeywordResult("super"); + // Fall through to handle message receivers like expressions. + + case Sema::CTC_Expression: + if (SemaRef.getLangOptions().CPlusPlus) + WantTypeSpecifiers = true; + WantExpressionKeywords = true; + // Fall through to get C++ named casts. + + case Sema::CTC_CXXCasts: + WantCXXNamedCasts = true; + break; + + case Sema::CTC_ObjCPropertyLookup: + // FIXME: Add "isa"? + break; + + case Sema::CTC_MemberLookup: + if (SemaRef.getLangOptions().CPlusPlus) + Consumer.addKeywordResult("template"); + break; + + case Sema::CTC_ObjCIvarLookup: + break; + } + + if (WantTypeSpecifiers) { + // Add type-specifier keywords to the set of results. + const char *CTypeSpecs[] = { + "char", "const", "double", "enum", "float", "int", "long", "short", + "signed", "struct", "union", "unsigned", "void", "volatile", + "_Complex", "_Imaginary", + // storage-specifiers as well + "extern", "inline", "static", "typedef" + }; + + const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); + for (unsigned I = 0; I != NumCTypeSpecs; ++I) + Consumer.addKeywordResult(CTypeSpecs[I]); + + if (SemaRef.getLangOptions().C99) + Consumer.addKeywordResult("restrict"); + if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) + Consumer.addKeywordResult("bool"); + else if (SemaRef.getLangOptions().C99) + Consumer.addKeywordResult("_Bool"); + + if (SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("class"); + Consumer.addKeywordResult("typename"); + Consumer.addKeywordResult("wchar_t"); + + if (SemaRef.getLangOptions().CPlusPlus0x) { + Consumer.addKeywordResult("char16_t"); + Consumer.addKeywordResult("char32_t"); + Consumer.addKeywordResult("constexpr"); + Consumer.addKeywordResult("decltype"); + Consumer.addKeywordResult("thread_local"); + } + } + + if (SemaRef.getLangOptions().GNUMode) + Consumer.addKeywordResult("typeof"); + } + + if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("const_cast"); + Consumer.addKeywordResult("dynamic_cast"); + Consumer.addKeywordResult("reinterpret_cast"); + Consumer.addKeywordResult("static_cast"); + } + + if (WantExpressionKeywords) { + Consumer.addKeywordResult("sizeof"); + if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("false"); + Consumer.addKeywordResult("true"); + } + + if (SemaRef.getLangOptions().CPlusPlus) { + const char *CXXExprs[] = { + "delete", "new", "operator", "throw", "typeid" + }; + const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); + for (unsigned I = 0; I != NumCXXExprs; ++I) + Consumer.addKeywordResult(CXXExprs[I]); + + if (isa<CXXMethodDecl>(SemaRef.CurContext) && + cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance()) + Consumer.addKeywordResult("this"); + + if (SemaRef.getLangOptions().CPlusPlus0x) { + Consumer.addKeywordResult("alignof"); + Consumer.addKeywordResult("nullptr"); + } + } + } + + if (WantRemainingKeywords) { + if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) { + // Statements. + const char *CStmts[] = { + "do", "else", "for", "goto", "if", "return", "switch", "while" }; + const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); + for (unsigned I = 0; I != NumCStmts; ++I) + Consumer.addKeywordResult(CStmts[I]); + + if (SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("catch"); + Consumer.addKeywordResult("try"); + } + + if (S && S->getBreakParent()) + Consumer.addKeywordResult("break"); + + if (S && S->getContinueParent()) + Consumer.addKeywordResult("continue"); + + if (!SemaRef.getCurFunction()->SwitchStack.empty()) { + Consumer.addKeywordResult("case"); + Consumer.addKeywordResult("default"); + } + } else { + if (SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("namespace"); + Consumer.addKeywordResult("template"); + } + + if (S && S->isClassScope()) { + Consumer.addKeywordResult("explicit"); + Consumer.addKeywordResult("friend"); + Consumer.addKeywordResult("mutable"); + Consumer.addKeywordResult("private"); + Consumer.addKeywordResult("protected"); + Consumer.addKeywordResult("public"); + Consumer.addKeywordResult("virtual"); + } + } + + if (SemaRef.getLangOptions().CPlusPlus) { + Consumer.addKeywordResult("using"); + + if (SemaRef.getLangOptions().CPlusPlus0x) + Consumer.addKeywordResult("static_assert"); + } + } +} + /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. /// -/// \param Res the \c LookupResult structure that contains the name -/// that was present in the source code along with the name-lookup -/// criteria used to search for the name. On success, this structure -/// will contain the results of name lookup. +/// \param TypoName the \c DeclarationNameInfo structure that contains +/// the name that was present in the source code along with its location. +/// +/// \param LookupKind the name-lookup criteria used to search for the name. /// /// \param S the scope in which name lookup occurs. /// @@ -3181,60 +3567,64 @@ static void LookupPotentialTypoResult(Sema &SemaRef, /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// -/// \returns the corrected name if the typo was corrected, otherwise returns an -/// empty \c DeclarationName. When a typo was corrected, the result structure -/// may contain the results of name lookup for the correct name or it may be -/// empty. -DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext, - bool EnteringContext, - CorrectTypoContext CTC, - const ObjCObjectPointerType *OPT) { +/// \returns a \c TypoCorrection containing the corrected name if the typo +/// along with information such as the \c NamedDecl where the corrected name +/// was declared, and any additional \c NestedNameSpecifier needed to access +/// it (C++ only). The \c TypoCorrection is empty if there is no correction. +TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext, + bool EnteringContext, + CorrectTypoContext CTC, + const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking) - return DeclarationName(); + return TypoCorrection(); // We only attempt to correct typos for identifiers. - IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); + IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) - return DeclarationName(); + return TypoCorrection(); // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) - return DeclarationName(); + return TypoCorrection(); // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) - return DeclarationName(); + return TypoCorrection(); - TypoCorrectionConsumer Consumer(Typo); + NamespaceSpecifierSet Namespaces(Context, CurContext); + + TypoCorrectionConsumer Consumer(*this, Typo); // Perform name lookup to find visible, similarly-named entities. bool IsUnqualifiedLookup = false; if (MemberContext) { - LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); + LookupVisibleDecls(MemberContext, LookupKind, Consumer); // Look in qualified interfaces. if (OPT) { for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) - LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); + LookupVisibleDecls(*I, LookupKind, Consumer); } } else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) - return DeclarationName(); + return TypoCorrection(); // Provide a stop gap for files that are just seriously broken. Trying // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) - return DeclarationName(); + return TypoCorrection(); ++TyposCorrected; - LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); + LookupVisibleDecls(DC, LookupKind, Consumer); } else { IsUnqualifiedLookup = true; UnqualifiedTyposCorrectedMap::iterator Cached @@ -3244,7 +3634,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) - return DeclarationName(); + return TypoCorrection(); // For unqualified lookup, look through all of the names that we have // seen in this translation unit. @@ -3268,313 +3658,225 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, } else { // Use the cached value, unless it's a keyword. In the keyword case, we'll // end up adding the keyword below. - if (Cached->second.first.empty()) - return DeclarationName(); + if (!Cached->second) + return TypoCorrection(); - if (!Cached->second.second) - Consumer.FoundName(Cached->second.first); + if (!Cached->second.isKeyword()) + Consumer.addCorrection(Cached->second); } } - // Add context-dependent keywords. - bool WantTypeSpecifiers = false; - bool WantExpressionKeywords = false; - bool WantCXXNamedCasts = false; - bool WantRemainingKeywords = false; - switch (CTC) { - case CTC_Unknown: - WantTypeSpecifiers = true; - WantExpressionKeywords = true; - WantCXXNamedCasts = true; - WantRemainingKeywords = true; - - if (ObjCMethodDecl *Method = getCurMethodDecl()) - if (Method->getClassInterface() && - Method->getClassInterface()->getSuperClass()) - Consumer.addKeywordResult(Context, "super"); - - break; - - case CTC_NoKeywords: - break; - - case CTC_Type: - WantTypeSpecifiers = true; - break; - - case CTC_ObjCMessageReceiver: - Consumer.addKeywordResult(Context, "super"); - // Fall through to handle message receivers like expressions. - - case CTC_Expression: - if (getLangOptions().CPlusPlus) - WantTypeSpecifiers = true; - WantExpressionKeywords = true; - // Fall through to get C++ named casts. - - case CTC_CXXCasts: - WantCXXNamedCasts = true; - break; - - case CTC_ObjCPropertyLookup: - // FIXME: Add "isa"? - break; + AddKeywordsToConsumer(*this, Consumer, S, CTC); - case CTC_MemberLookup: - if (getLangOptions().CPlusPlus) - Consumer.addKeywordResult(Context, "template"); - break; + // If we haven't found anything, we're done. + if (Consumer.empty()) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; - case CTC_ObjCIvarLookup: - break; + return TypoCorrection(); } - if (WantTypeSpecifiers) { - // Add type-specifier keywords to the set of results. - const char *CTypeSpecs[] = { - "char", "const", "double", "enum", "float", "int", "long", "short", - "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool", - "_Complex", "_Imaginary", - // storage-specifiers as well - "extern", "inline", "static", "typedef" - }; - - const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); - for (unsigned I = 0; I != NumCTypeSpecs; ++I) - Consumer.addKeywordResult(Context, CTypeSpecs[I]); - - if (getLangOptions().C99) - Consumer.addKeywordResult(Context, "restrict"); - if (getLangOptions().Bool || getLangOptions().CPlusPlus) - Consumer.addKeywordResult(Context, "bool"); - - if (getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "class"); - Consumer.addKeywordResult(Context, "typename"); - Consumer.addKeywordResult(Context, "wchar_t"); - - if (getLangOptions().CPlusPlus0x) { - Consumer.addKeywordResult(Context, "char16_t"); - Consumer.addKeywordResult(Context, "char32_t"); - Consumer.addKeywordResult(Context, "constexpr"); - Consumer.addKeywordResult(Context, "decltype"); - Consumer.addKeywordResult(Context, "thread_local"); - } - } + // Make sure that the user typed at least 3 characters for each correction + // made. Otherwise, we don't even both looking at the results. + unsigned ED = Consumer.getBestEditDistance(); + if (ED > 0 && Typo->getName().size() / ED < 3) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; - if (getLangOptions().GNUMode) - Consumer.addKeywordResult(Context, "typeof"); + return TypoCorrection(); } - if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "const_cast"); - Consumer.addKeywordResult(Context, "dynamic_cast"); - Consumer.addKeywordResult(Context, "reinterpret_cast"); - Consumer.addKeywordResult(Context, "static_cast"); + // Build the NestedNameSpecifiers for the KnownNamespaces + if (getLangOptions().CPlusPlus) { + // Load any externally-known namespaces. + if (ExternalSource && !LoadedExternalKnownNamespaces) { + llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; + LoadedExternalKnownNamespaces = true; + ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); + for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) + KnownNamespaces[ExternalKnownNamespaces[I]] = true; + } + + for (llvm::DenseMap<NamespaceDecl*, bool>::iterator + KNI = KnownNamespaces.begin(), + KNIEnd = KnownNamespaces.end(); + KNI != KNIEnd; ++KNI) + Namespaces.AddNamespace(KNI->first); } - if (WantExpressionKeywords) { - Consumer.addKeywordResult(Context, "sizeof"); - if (getLangOptions().Bool || getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "false"); - Consumer.addKeywordResult(Context, "true"); - } + // Weed out any names that could not be found by name lookup. + llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults; + LookupResult TmpRes(*this, TypoName, LookupKind); + TmpRes.suppressDiagnostics(); + while (!Consumer.empty()) { + TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); + unsigned ED = DI->first; + for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(), + IEnd = DI->second->end(); + I != IEnd; /* Increment in loop. */) { + // If the item already has been looked up or is a keyword, keep it + if (I->second.isResolved()) { + ++I; + continue; + } - if (getLangOptions().CPlusPlus) { - const char *CXXExprs[] = { - "delete", "new", "operator", "throw", "typeid" - }; - const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); - for (unsigned I = 0; I != NumCXXExprs; ++I) - Consumer.addKeywordResult(Context, CXXExprs[I]); + // Perform name lookup on this name. + IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo(); + LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext, + EnteringContext, CTC); - if (isa<CXXMethodDecl>(CurContext) && - cast<CXXMethodDecl>(CurContext)->isInstance()) - Consumer.addKeywordResult(Context, "this"); + switch (TmpRes.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + QualifiedResults.insert(Name); + // We didn't find this name in our scope, or didn't like what we found; + // ignore it. + { + TypoCorrectionConsumer::result_iterator Next = I; + ++Next; + DI->second->erase(I); + I = Next; + } + break; - if (getLangOptions().CPlusPlus0x) { - Consumer.addKeywordResult(Context, "alignof"); - Consumer.addKeywordResult(Context, "nullptr"); + case LookupResult::Ambiguous: + // We don't deal with ambiguities. + return TypoCorrection(); + + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>()); + // FIXME: This sets the CorrectionDecl to NULL for overloaded functions. + // It would be nice to find the right one with overload resolution. + ++I; + break; } } - } - - if (WantRemainingKeywords) { - if (getCurFunctionOrMethodDecl() || getCurBlock()) { - // Statements. - const char *CStmts[] = { - "do", "else", "for", "goto", "if", "return", "switch", "while" }; - const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); - for (unsigned I = 0; I != NumCStmts; ++I) - Consumer.addKeywordResult(Context, CStmts[I]); - - if (getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "catch"); - Consumer.addKeywordResult(Context, "try"); - } - if (S && S->getBreakParent()) - Consumer.addKeywordResult(Context, "break"); - - if (S && S->getContinueParent()) - Consumer.addKeywordResult(Context, "continue"); - - if (!getCurFunction()->SwitchStack.empty()) { - Consumer.addKeywordResult(Context, "case"); - Consumer.addKeywordResult(Context, "default"); - } - } else { - if (getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "namespace"); - Consumer.addKeywordResult(Context, "template"); - } + if (DI->second->empty()) + Consumer.erase(DI); + else if (!getLangOptions().CPlusPlus || QualifiedResults.empty() || !ED) + // If there are results in the closest possible bucket, stop + break; - if (S && S->isClassScope()) { - Consumer.addKeywordResult(Context, "explicit"); - Consumer.addKeywordResult(Context, "friend"); - Consumer.addKeywordResult(Context, "mutable"); - Consumer.addKeywordResult(Context, "private"); - Consumer.addKeywordResult(Context, "protected"); - Consumer.addKeywordResult(Context, "public"); - Consumer.addKeywordResult(Context, "virtual"); + // Only perform the qualified lookups for C++ + if (getLangOptions().CPlusPlus) { + TmpRes.suppressDiagnostics(); + for (llvm::SmallPtrSet<IdentifierInfo*, + 16>::iterator QRI = QualifiedResults.begin(), + QRIEnd = QualifiedResults.end(); + QRI != QRIEnd; ++QRI) { + for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(), + NIEnd = Namespaces.end(); + NI != NIEnd; ++NI) { + DeclContext *Ctx = NI->DeclCtx; + unsigned QualifiedED = ED + NI->EditDistance; + + // Stop searching once the namespaces are too far away to create + // acceptable corrections for this identifier (since the namespaces + // are sorted in ascending order by edit distance) + if (QualifiedED > Consumer.getMaxEditDistance()) break; + + TmpRes.clear(); + TmpRes.setLookupName(*QRI); + if (!LookupQualifiedName(TmpRes, Ctx)) continue; + + switch (TmpRes.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(), + QualifiedED, NI->NameSpecifier); + break; + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + break; + } + } } } - if (getLangOptions().CPlusPlus) { - Consumer.addKeywordResult(Context, "using"); - - if (getLangOptions().CPlusPlus0x) - Consumer.addKeywordResult(Context, "static_assert"); - } + QualifiedResults.clear(); } - // If we haven't found anything, we're done. - if (Consumer.empty()) { - // If this was an unqualified lookup, note that no correction was found. - if (IsUnqualifiedLookup) - (void)UnqualifiedTyposCorrected[Typo]; + // No corrections remain... + if (Consumer.empty()) return TypoCorrection(); - return DeclarationName(); - } + TypoResultsMap &BestResults = *Consumer.begin()->second; + ED = Consumer.begin()->first; - // Make sure that the user typed at least 3 characters for each correction - // made. Otherwise, we don't even both looking at the results. - - // We also suppress exact matches; those should be handled by a - // different mechanism (e.g., one that introduces qualification in - // C++). - unsigned ED = Consumer.getBestEditDistance(); if (ED > 0 && Typo->getName().size() / ED < 3) { // If this was an unqualified lookup, note that no correction was found. if (IsUnqualifiedLookup) (void)UnqualifiedTyposCorrected[Typo]; - return DeclarationName(); + return TypoCorrection(); } - // Weed out any names that could not be found by name lookup. - bool LastLookupWasAccepted = false; - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), - IEnd = Consumer.end(); - I != IEnd; /* Increment in loop. */) { - // Keywords are always found. - if (I->second) { - ++I; - continue; - } - - // Perform name lookup on this name. - IdentifierInfo *Name = &Context.Idents.get(I->getKey()); - LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, - EnteringContext, CTC); - - switch (Res.getResultKind()) { - case LookupResult::NotFound: - case LookupResult::NotFoundInCurrentInstantiation: - case LookupResult::Ambiguous: - // We didn't find this name in our scope, or didn't like what we found; - // ignore it. - Res.suppressDiagnostics(); - { - TypoCorrectionConsumer::iterator Next = I; - ++Next; - Consumer.erase(I); - I = Next; - } - LastLookupWasAccepted = false; - break; - - case LookupResult::Found: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: - ++I; - LastLookupWasAccepted = true; - break; - } - - if (Res.isAmbiguous()) { - // We don't deal with ambiguities. - Res.suppressDiagnostics(); - Res.clear(); - return DeclarationName(); + // If we have multiple possible corrections, eliminate the ones where we + // added namespace qualifiers to try to resolve the ambiguity (and to favor + // corrections without additional namespace qualifiers) + if (getLangOptions().CPlusPlus && BestResults.size() > 1) { + TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); + for (TypoCorrectionConsumer::result_iterator I = DI->second->begin(), + IEnd = DI->second->end(); + I != IEnd; /* Increment in loop. */) { + if (I->second.getCorrectionSpecifier() != NULL) { + TypoCorrectionConsumer::result_iterator Cur = I; + ++I; + DI->second->erase(Cur); + } else ++I; } } // If only a single name remains, return that result. - if (Consumer.size() == 1) { - IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey()); - if (Consumer.begin()->second) { - Res.suppressDiagnostics(); - Res.clear(); - - // Don't correct to a keyword that's the same as the typo; the keyword - // wasn't actually in scope. - if (ED == 0) { - Res.setLookupName(Typo); - return DeclarationName(); - } + if (BestResults.size() == 1) { + const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin()); + const TypoCorrection &Result = Correction.second; - } else if (!LastLookupWasAccepted) { - // Perform name lookup on this name. - LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, - EnteringContext, CTC); - } + // Don't correct to a keyword that's the same as the typo; the keyword + // wasn't actually in scope. + if (ED == 0 && Result.isKeyword()) return TypoCorrection(); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] - = std::make_pair(Name->getName(), Consumer.begin()->second); + UnqualifiedTyposCorrected[Typo] = Result; - return &Context.Idents.get(Consumer.begin()->getKey()); + return Result; } - else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver - && Consumer["super"]) { - // Prefix 'super' when we're completing in a message-receiver + else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver + && BestResults["super"].isKeyword()) { + // Prefer 'super' when we're completing in a message-receiver // context. - Res.suppressDiagnostics(); - Res.clear(); // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. - if (ED == 0) { - Res.setLookupName(Typo); - return DeclarationName(); - } + if (ED == 0) return TypoCorrection(); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] - = std::make_pair("super", Consumer.begin()->second); + UnqualifiedTyposCorrected[Typo] = BestResults["super"]; - return &Context.Idents.get("super"); + return BestResults["super"]; } - Res.suppressDiagnostics(); - Res.setLookupName(Typo); - Res.clear(); - // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) (void)UnqualifiedTyposCorrected[Typo]; - return DeclarationName(); + return TypoCorrection(); +} + +std::string TypoCorrection::getAsString(const LangOptions &LO) const { + if (CorrectionNameSpec) { + std::string tmpBuffer; + llvm::raw_string_ostream PrefixOStream(tmpBuffer); + CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); + return PrefixOStream.str() + CorrectionName.getAsString(); + } + + return CorrectionName.getAsString(); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 6c4469c..d826ea8 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -24,6 +24,51 @@ using namespace clang; // Grammar actions. //===----------------------------------------------------------------------===// +/// Check the internal consistency of a property declaration. +static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { + if (property->isInvalidDecl()) return; + + ObjCPropertyDecl::PropertyAttributeKind propertyKind + = property->getPropertyAttributes(); + Qualifiers::ObjCLifetime propertyLifetime + = property->getType().getObjCLifetime(); + + // Nothing to do if we don't have a lifetime. + if (propertyLifetime == Qualifiers::OCL_None) return; + + Qualifiers::ObjCLifetime expectedLifetime; + unsigned selector; + + // Strong properties should have either strong or no lifetime. + if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy)) { + expectedLifetime = Qualifiers::OCL_Strong; + selector = 0; + } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) { + expectedLifetime = Qualifiers::OCL_Weak; + selector = 1; + } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_unsafe_unretained) && + property->getType()->isObjCRetainableType()) { + expectedLifetime = Qualifiers::OCL_ExplicitNone; + selector = 2; + } else { + // We have a lifetime qualifier but no dominating property + // attribute. That's okay. + return; + } + + if (propertyLifetime == expectedLifetime) return; + + property->setInvalidDecl(); + S.Diag(property->getLocation(), + diag::err_arc_inconsistent_property_ownership) + << property->getDeclName() + << selector + << propertyLifetime; +} + Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, @@ -34,6 +79,14 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); + TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); + QualType T = TSI->getType(); + if ((getLangOptions().getGCMode() != LangOptions::NonGC && + T.isObjCGCWeak()) || + (getLangOptions().ObjCAutoRefCount && + T.getObjCLifetime() == Qualifiers::OCL_Weak)) + Attributes |= ObjCDeclSpec::DQ_PR_weak; + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); @@ -42,9 +95,10 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || (isReadWrite && !(Attributes & ObjCDeclSpec::DQ_PR_retain) && - !(Attributes & ObjCDeclSpec::DQ_PR_copy))); - - TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); + !(Attributes & ObjCDeclSpec::DQ_PR_strong) && + !(Attributes & ObjCDeclSpec::DQ_PR_copy) && + !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) && + !(Attributes & ObjCDeclSpec::DQ_PR_weak))); // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = @@ -58,20 +112,27 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Attributes, isOverridingProperty, TSI, MethodImplKind); - if (Res) + if (Res) { CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + if (getLangOptions().ObjCAutoRefCount) + checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res)); + } return Res; } - Decl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD, - GetterSel, SetterSel, - isAssign, isReadWrite, - Attributes, TSI, MethodImplKind); + ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, TSI, MethodImplKind); if (lexicalDC) Res->setLexicalDeclContext(lexicalDC); // Validate the attributes on the @property. CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + + if (getLangOptions().ObjCAutoRefCount) + checkARCPropertyDecl(*this, Res); + return Res; } @@ -118,6 +179,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, // Set setter/getter selector name. Needed later. PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); + ProcessDeclAttributes(S, PDecl, FD.D); DC->addDecl(PDecl); // We need to look in the @interface to see if the @property was @@ -139,10 +201,6 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, CreatePropertyDecl(S, CCPrimary, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, T, MethodImplKind, DC); - // Mark written attribute as having no attribute because - // this is not a user-written property declaration in primary - // class. - PDecl->setPropertyAttributesAsWritten(ObjCPropertyDecl::OBJC_PR_noattr); // A case of continuation class adding a new property in the class. This // is not what it was meant for. However, gcc supports it and so should we. @@ -158,6 +216,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { unsigned retainCopyNonatomic = (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | ObjCPropertyDecl::OBJC_PR_copy | ObjCPropertyDecl::OBJC_PR_nonatomic); if ((Attributes & retainCopyNonatomic) != @@ -189,6 +248,8 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_strong) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); if (Attributes & ObjCDeclSpec::DQ_PR_copy) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); @@ -272,6 +333,35 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PDecl->setGetterName(GetterSel); PDecl->setSetterName(SetterSel); + unsigned attributesAsWritten = 0; + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly; + if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite; + if (Attributes & ObjCDeclSpec::DQ_PR_getter) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter; + if (Attributes & ObjCDeclSpec::DQ_PR_setter) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter; + if (Attributes & ObjCDeclSpec::DQ_PR_assign) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign; + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain; + if (Attributes & ObjCDeclSpec::DQ_PR_strong) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong; + if (Attributes & ObjCDeclSpec::DQ_PR_weak) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak; + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy; + if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic; + if (Attributes & ObjCDeclSpec::DQ_PR_atomic) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; + + PDecl->setPropertyAttributesAsWritten( + (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten); + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); @@ -287,9 +377,18 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (Attributes & ObjCDeclSpec::DQ_PR_retain) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_strong) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + + if (Attributes & ObjCDeclSpec::DQ_PR_weak) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak); + if (Attributes & ObjCDeclSpec::DQ_PR_copy) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + if (isAssign) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); @@ -298,8 +397,12 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, else if (Attributes & ObjCDeclSpec::DQ_PR_atomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); - PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes()); - + // 'unsafe_unretained' is alias for 'assign'. + if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + if (isAssign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + if (MethodImplKind == tok::objc_required) PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); else if (MethodImplKind == tok::objc_optional) @@ -308,6 +411,93 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, return PDecl; } +static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, + ObjCPropertyDecl *property, + ObjCIvarDecl *ivar) { + if (property->isInvalidDecl() || ivar->isInvalidDecl()) return; + + QualType propertyType = property->getType(); + Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime(); + ObjCPropertyDecl::PropertyAttributeKind propertyKind + = property->getPropertyAttributes(); + + QualType ivarType = ivar->getType(); + Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime(); + + // Case 1: strong properties. + if (propertyLifetime == Qualifiers::OCL_Strong || + (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy))) { + switch (ivarLifetime) { + case Qualifiers::OCL_Strong: + // Okay. + return; + + case Qualifiers::OCL_None: + case Qualifiers::OCL_Autoreleasing: + // These aren't valid lifetimes for object ivars; don't diagnose twice. + return; + + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Weak: + S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) + << property->getDeclName() + << ivar->getDeclName() + << ivarLifetime; + break; + } + + // Case 2: weak properties. + } else if (propertyLifetime == Qualifiers::OCL_Weak || + (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) { + switch (ivarLifetime) { + case Qualifiers::OCL_Weak: + // Okay. + return; + + case Qualifiers::OCL_None: + case Qualifiers::OCL_Autoreleasing: + // These aren't valid lifetimes for object ivars; don't diagnose twice. + return; + + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Strong: + S.Diag(propertyImplLoc, diag::error_weak_property) + << property->getDeclName() + << ivar->getDeclName(); + break; + } + + // Case 3: assign properties. + } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) && + propertyType->isObjCRetainableType()) { + switch (ivarLifetime) { + case Qualifiers::OCL_ExplicitNone: + // Okay. + return; + + case Qualifiers::OCL_None: + case Qualifiers::OCL_Autoreleasing: + // These aren't valid lifetimes for object ivars; don't diagnose twice. + return; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) + << property->getDeclName() + << ivar->getDeclName(); + break; + } + + // Any other property should be ignored. + } else { + return; + } + + S.Diag(property->getLocation(), diag::note_property_declare); +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared @@ -396,9 +586,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCIvarDecl *Ivar = 0; // Check that we have a valid, previously declared ivar for @synthesize if (Synthesize) { + if (getLangOptions().ObjCAutoRefCount && + !property->hasWrittenStorageAttribute() && + property->getType()->isObjCRetainableType()) { + Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object); + Diag(property->getLocation(), diag::note_property_declare); + } + // @synthesize if (!PropertyIvar) PropertyIvar = PropertyId; + ObjCPropertyDecl::PropertyAttributeKind kind + = property->getPropertyAttributes(); QualType PropType = Context.getCanonicalType(property->getType()); QualType PropertyIvarType = PropType; if (PropType->isReferenceType()) @@ -407,6 +606,45 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCInterfaceDecl *ClassDeclared; Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { + // In ARC, give the ivar a lifetime qualifier based on its + // property attributes. + if (getLangOptions().ObjCAutoRefCount && + !PropertyIvarType.getObjCLifetime()) { + + // retain/copy have retaining lifetime. + if (kind & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy)) { + Qualifiers qs; + qs.addObjCLifetime(Qualifiers::OCL_Strong); + PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); + } + else if (kind & ObjCPropertyDecl::OBJC_PR_weak) { + if (!getLangOptions().ObjCRuntimeHasWeak) { + Diag(PropertyLoc, diag::err_arc_weak_no_runtime); + Diag(property->getLocation(), diag::note_property_declare); + } + Qualifiers qs; + qs.addObjCLifetime(Qualifiers::OCL_Weak); + PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); + } + else if (kind & ObjCPropertyDecl::OBJC_PR_assign && + PropertyIvarType->isObjCRetainableType()) { + // assume that an 'assign' property synthesizes __unsafe_unretained + // ivar + Qualifiers qs; + qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); + PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); + } + } + + if (kind & ObjCPropertyDecl::OBJC_PR_weak && + !getLangOptions().ObjCAutoRefCount && + getLangOptions().getGCMode() == LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc); + Diag(property->getLocation(), diag::note_property_declare); + } + Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyLoc, PropertyIvar, PropertyIvarType, /*Dinfo=*/0, @@ -435,7 +673,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (PropertyIvarType != IvarType) { bool compat = false; if (isa<ObjCObjectPointerType>(PropertyIvarType) - && isa<ObjCObjectPointerType>(IvarType)) + && isa<ObjCObjectPointerType>(IvarType)) compat = Context.canAssignObjCInterfaces( PropertyIvarType->getAs<ObjCObjectPointerType>(), @@ -470,12 +708,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Fall thru - see previous comment } // __weak is explicit. So it works on Canonical type. - if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { + if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC)) { Diag(PropertyLoc, diag::error_weak_property) << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment } + // Fall thru - see previous comment if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && getLangOptions().getGCMode() != LangOptions::NonGC) { @@ -484,9 +723,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Fall thru - see previous comment } } + if (getLangOptions().ObjCAutoRefCount) + checkARCPropertyImpl(*this, PropertyLoc, property, Ivar); } else if (PropertyIvar) // @dynamic Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); + assert (property && "ActOnPropertyImplDecl - property declaration missing"); ObjCPropertyImplDecl *PIDecl = ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, @@ -523,6 +765,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, PIDecl->setGetterCXXConstructor(ResExpr); } } + if (property->hasAttr<NSReturnsNotRetainedAttr>() && + !getterMethod->hasAttr<NSReturnsNotRetainedAttr>()) { + Diag(getterMethod->getLocation(), + diag::warn_property_getter_owning_mismatch); + Diag(property->getLocation(), diag::note_property_declare); + } } if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); @@ -632,10 +880,19 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "copy" << inheritedName; - else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) - != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "retain" << inheritedName; + else { + unsigned CAttrRetain = + (CAttr & + (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); + unsigned SAttrRetain = + (SAttr & + (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); + bool CStrong = (CAttrRetain != 0); + bool SStrong = (SAttrRetain != 0); + if (CStrong != SStrong) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "retain (or strong)" << inheritedName; + } if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) @@ -653,13 +910,16 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, QualType RHSType = Context.getCanonicalType(Property->getType()); - if (!Context.typesAreCompatible(LHSType, RHSType)) { - // FIXME: Incorporate this test with typesAreCompatible. - if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) - if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) - return; - Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) - << Property->getType() << SuperProperty->getType() << inheritedName; + if (!Context.propertyTypesAreCompatible(LHSType, RHSType)) { + // Do cases not handled in above. + // FIXME. For future support of covariant property types, revisit this. + bool IncompatibleObjC = false; + QualType ConvertedType; + if (!isObjCPointerConversion(RHSType, LHSType, + ConvertedType, IncompatibleObjC) || + IncompatibleObjC) + Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) + << Property->getType() << SuperProperty->getType() << inheritedName; } } @@ -1050,7 +1310,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // Is there a matching propery synthesize/dynamic? if (Prop->isInvalidDecl() || Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - PropImplMap.count(Prop)) + PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>()) continue; if (!InsMap.count(Prop->getGetterName())) { Diag(Prop->getLocation(), @@ -1135,6 +1395,35 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } } +void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) { + if (getLangOptions().getGCMode() == LangOptions::GCOnly) + return; + + for (ObjCImplementationDecl::propimpl_iterator + i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) { + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) + continue; + + const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() && + !D->getInstanceMethod(PD->getGetterName())) { + ObjCMethodDecl *method = PD->getGetterMethodDecl(); + if (!method) + continue; + ObjCMethodFamily family = method->getMethodFamily(); + if (family == OMF_alloc || family == OMF_copy || + family == OMF_mutableCopy || family == OMF_new) { + if (getLangOptions().ObjCAutoRefCount) + Diag(PID->getLocation(), diag::err_ownin_getter_rule); + else + Diag(PID->getLocation(), diag::warn_ownin_getter_rule); + Diag(PD->getLocation(), diag::note_property_declare); + } + } + } +} + /// AddPropertyAttrs - Propagates attributes from a property to the /// implicitly-declared getter or setter for that property. static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod, @@ -1214,6 +1503,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // and the real context should be the same. if (lexicalDC) GetterMethod->setLexicalDeclContext(lexicalDC); + if (property->hasAttr<NSReturnsNotRetainedAttr>()) + GetterMethod->addAttr( + ::new (Context) NSReturnsNotRetainedAttr(Loc, Context)); } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation @@ -1245,7 +1537,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, Loc, Loc, property->getIdentifier(), - property->getType(), + property->getType().getUnqualifiedType(), /*TInfo=*/0, SC_None, SC_None, @@ -1287,7 +1579,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, SourceLocation Loc, unsigned &Attributes) { // FIXME: Improve the reported location. - if (!PDecl) + if (!PDecl || PDecl->isInvalidDecl()) return; ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl); @@ -1297,12 +1589,16 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain))) { + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong))) { const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? "readwrite" : (Attributes & ObjCDeclSpec::DQ_PR_assign) ? "assign" : + (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ? + "unsafe_unretained" : (Attributes & ObjCDeclSpec::DQ_PR_copy) ? "copy" : "retain"; @@ -1313,14 +1609,15 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, } // Check for copy or retain on non-object types. - if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && - !PropertyTy->isObjCObjectPointerType() && - !PropertyTy->isBlockPointerType() && - !Context.isObjCNSObjectType(PropertyTy) && + if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) && + !PropertyTy->isObjCRetainableType() && !PropertyDecl->getAttr<ObjCNSObjectAttr>()) { Diag(Loc, diag::err_objc_property_requires_object) - << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); - Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); + << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" : + Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)"); + Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong); } // Check for more than one of { assign, copy, retain }. @@ -1335,18 +1632,75 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, << "assign" << "retain"; Attributes &= ~ObjCDeclSpec::DQ_PR_retain; } + if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "strong"; + Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + } + if (getLangOptions().ObjCAutoRefCount && + (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "weak"; + Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + } + } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) { + if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "unsafe_unretained" << "copy"; + Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + } + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "unsafe_unretained" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "unsafe_unretained" << "strong"; + Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + } + if (getLangOptions().ObjCAutoRefCount && + (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "unsafe_unretained" << "weak"; + Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + } } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { if (Attributes & ObjCDeclSpec::DQ_PR_retain) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "copy" << "retain"; Attributes &= ~ObjCDeclSpec::DQ_PR_retain; } + if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "copy" << "strong"; + Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + } + if (Attributes & ObjCDeclSpec::DQ_PR_weak) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "copy" << "weak"; + Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + } + } + else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) && + (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "retain" << "weak"; + Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + } + else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) && + (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "strong" << "weak"; + Attributes &= ~ObjCDeclSpec::DQ_PR_weak; } // Warn if user supplied no assignment attribute, property is // readwrite, and this is an object type. if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain)) && + ObjCDeclSpec::DQ_PR_unsafe_unretained | + ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong | + ObjCDeclSpec::DQ_PR_weak)) && !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && PropertyTy->isObjCObjectPointerType()) { // Skip this warning in gc-only mode. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 4bba6f8..437b2b5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -38,8 +38,10 @@ using namespace sema; /// function. static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, - SourceLocation Loc = SourceLocation()) { - ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc)); + SourceLocation Loc = SourceLocation(), + const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ + ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), + VK_LValue, Loc, LocInfo)); E = S.DefaultFunctionArrayConversion(E.take()); if (E.isInvalid()) return ExprError(); @@ -49,7 +51,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, StandardConversionSequence &SCS, - bool CStyle); + bool CStyle, + bool AllowObjCWritebackConversion); static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, QualType &ToType, @@ -106,6 +109,7 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Conversion, ICC_Conversion, ICC_Conversion, + ICC_Conversion, ICC_Conversion }; return Category[(int)Kind]; @@ -138,7 +142,8 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Complex_Real_Conversion, ICR_Conversion, - ICR_Conversion + ICR_Conversion, + ICR_Writeback_Conversion }; return Rank[(int)Kind]; } @@ -170,6 +175,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Complex-real conversion", "Block Pointer conversion", "Transparent Union Conversion" + "Writeback conversion" }; return Name[Kind]; } @@ -181,12 +187,14 @@ void StandardConversionSequence::setAsIdentityConversion() { Second = ICK_Identity; Third = ICK_Identity; DeprecatedStringLiteralToCharPtr = false; + QualificationIncludesObjCLifetime = false; ReferenceBinding = false; DirectBinding = false; IsLvalueReference = true; BindsToFunctionLvalue = false; BindsToRvalue = false; BindsImplicitObjectArgumentWithoutRefQualifier = false; + ObjCLifetimeConversionBinding = false; CopyConstructor = 0; } @@ -730,6 +738,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return false; } +/// \brief Checks availability of the function depending on the current +/// function context. Inside an unavailable function, unavailability is ignored. +/// +/// \returns true if \arg FD is unavailable and current context is inside +/// an available function, false otherwise. +bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) { + return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable(); +} + /// TryImplicitConversion - Attempt to perform an implicit conversion /// from the given expression (Expr) to the given type (ToType). This /// function returns an implicit conversion sequence that can be used @@ -753,15 +770,20 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, /// not permitted. /// If @p AllowExplicit, then explicit user-defined conversions are /// permitted. +/// +/// \param AllowObjCWritebackConversion Whether we allow the Objective-C +/// writeback conversion, which allows __autoreleasing id* parameters to +/// be initialized with __strong id* or __weak id* arguments. static ImplicitConversionSequence TryImplicitConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, bool InOverloadResolution, - bool CStyle) { + bool CStyle, + bool AllowObjCWritebackConversion) { ImplicitConversionSequence ICS; if (IsStandardConversion(S, From, ToType, InOverloadResolution, - ICS.Standard, CStyle)) { + ICS.Standard, CStyle, AllowObjCWritebackConversion)){ ICS.setStandard(); return ICS; } @@ -867,24 +889,17 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, return ICS; } -bool Sema::TryImplicitConversion(InitializationSequence &Sequence, - const InitializedEntity &Entity, - Expr *Initializer, - bool SuppressUserConversions, - bool AllowExplicitConversions, - bool InOverloadResolution, - bool CStyle) { - ImplicitConversionSequence ICS - = clang::TryImplicitConversion(*this, Initializer, Entity.getType(), - SuppressUserConversions, - AllowExplicitConversions, - InOverloadResolution, - CStyle); - if (ICS.isBad()) return true; - - // Perform the actual conversion. - Sequence.AddConversionSequenceStep(ICS, Entity.getType()); - return false; +ImplicitConversionSequence +Sema::TryImplicitConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion) { + return clang::TryImplicitConversion(*this, From, ToType, + SuppressUserConversions, AllowExplicit, + InOverloadResolution, CStyle, + AllowObjCWritebackConversion); } /// PerformImplicitConversion - Perform an implicit conversion of the @@ -903,18 +918,25 @@ ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS) { + // Objective-C ARC: Determine whether we will allow the writeback conversion. + bool AllowObjCWritebackConversion + = getLangOptions().ObjCAutoRefCount && + (Action == AA_Passing || Action == AA_Sending); + + ICS = clang::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, /*InOverloadResolution=*/false, - /*CStyle=*/false); + /*CStyle=*/false, + AllowObjCWritebackConversion); return PerformImplicitConversion(From, ToType, ICS, Action); } /// \brief Determine whether the conversion from FromType to ToType is a valid /// conversion that strips "noreturn" off the nested function type. -static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, - QualType ToType, QualType &ResultTy) { +bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType, + QualType &ResultTy) { if (Context.hasSameUnqualifiedType(FromType, ToType)) return false; @@ -1016,7 +1038,8 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, StandardConversionSequence &SCS, - bool CStyle) { + bool CStyle, + bool AllowObjCWritebackConversion) { QualType FromType = From->getType(); // Standard conversions (C++ [conv]) @@ -1054,7 +1077,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, S.ExtractUnqualifiedFunctionType(ToType), FromType)) { QualType resultTy; // if the function type matches except for [[noreturn]], it's ok - if (!IsNoReturnConversion(S.Context, FromType, + if (!S.IsNoReturnConversion(FromType, S.ExtractUnqualifiedFunctionType(ToType), resultTy)) // otherwise, only a boolean conversion is standard if (!ToType->isBooleanType()) @@ -1123,6 +1146,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // conversion (4.4). (C++ 4.2p2) SCS.Second = ICK_Identity; SCS.Third = ICK_Qualification; + SCS.QualificationIncludesObjCLifetime = false; SCS.setAllToTypes(FromType); return true; } @@ -1199,7 +1223,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); } else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) { - SCS.Second = ICK_Block_Pointer_Conversion; + SCS.Second = ICK_Block_Pointer_Conversion; + } else if (AllowObjCWritebackConversion && + S.isObjCWritebackConversion(FromType, ToType, FromType)) { + SCS.Second = ICK_Writeback_Conversion; } else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution, FromType, IncompatibleObjC)) { // Pointer conversions (C++ 4.10). @@ -1218,7 +1245,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) { + } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) { // Treat a conversion that strips "noreturn" as an identity conversion. SCS.Second = ICK_NoReturn_Adjustment; } else if (IsTransparentUnionStandardConversion(S, From, ToType, @@ -1235,8 +1262,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, QualType CanonFrom; QualType CanonTo; // The third conversion can be a qualification conversion (C++ 4p1). - if (S.IsQualificationConversion(FromType, ToType, CStyle)) { + bool ObjCLifetimeConversion; + if (S.IsQualificationConversion(FromType, ToType, CStyle, + ObjCLifetimeConversion)) { SCS.Third = ICK_Qualification; + SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion; FromType = ToType; CanonFrom = S.Context.getCanonicalType(FromType); CanonTo = S.Context.getCanonicalType(ToType); @@ -1253,7 +1283,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() - || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) { + || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr() + || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) { FromType = ToType; CanonFrom = CanonTo; } @@ -1284,7 +1315,8 @@ IsTransparentUnionStandardConversion(Sema &S, Expr* From, for (RecordDecl::field_iterator it = UD->field_begin(), itend = UD->field_end(); it != itend; ++it) { - if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) { + if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, + CStyle, /*ObjCWritebackConversion=*/false)) { ToType = it->getType(); return true; } @@ -1479,16 +1511,18 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) { /// same type qualifiers as FromPtr has on its pointee type. ToType, /// if non-empty, will be a pointer to ToType that may or may not have /// the right set of qualifiers on its pointee. +/// static QualType BuildSimilarlyQualifiedPointerType(const Type *FromPtr, QualType ToPointee, QualType ToType, - ASTContext &Context) { + ASTContext &Context, + bool StripObjCLifetime = false) { assert((FromPtr->getTypeClass() == Type::Pointer || FromPtr->getTypeClass() == Type::ObjCObjectPointer) && "Invalid similarly-qualified pointer type"); - /// \brief Conversions to 'id' subsume cv-qualifier conversions. - if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) + /// Conversions to 'id' subsume cv-qualifier conversions. + if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) return ToType.getUnqualifiedType(); QualType CanonFromPointee @@ -1496,6 +1530,9 @@ BuildSimilarlyQualifiedPointerType(const Type *FromPtr, QualType CanonToPointee = Context.getCanonicalType(ToPointee); Qualifiers Quals = CanonFromPointee.getQualifiers(); + if (StripObjCLifetime) + Quals.removeObjCLifetime(); + // Exact qualifier match -> return the pointer type we're converting to. if (CanonToPointee.getLocalQualifiers() == Quals) { // ToType is exactly what we need. Return it. @@ -1599,7 +1636,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // Beyond this point, both types need to be pointers // , including objective-c pointers. QualType ToPointeeType = ToTypePtr->getPointeeType(); - if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) { + if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() && + !getLangOptions().ObjCAutoRefCount) { ConvertedType = BuildSimilarlyQualifiedPointerType( FromType->getAs<ObjCObjectPointerType>(), ToPointeeType, @@ -1624,7 +1662,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, ToPointeeType->isVoidType()) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, - ToType, Context); + ToType, Context, + /*StripObjCLifetime=*/true); return true; } @@ -1814,6 +1853,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToPointeeType->getAs<ObjCObjectPointerType>() && isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, IncompatibleObjC)) { + ConvertedType = Context.getPointerType(ConvertedType); ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; @@ -1885,6 +1925,73 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, return false; } +/// \brief Determine whether this is an Objective-C writeback conversion, +/// used for parameter passing when performing automatic reference counting. +/// +/// \param FromType The type we're converting form. +/// +/// \param ToType The type we're converting to. +/// +/// \param ConvertedType The type that will be produced after applying +/// this conversion. +bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType, + QualType &ConvertedType) { + if (!getLangOptions().ObjCAutoRefCount || + Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + // Parameter must be a pointer to __autoreleasing (with no other qualifiers). + QualType ToPointee; + if (const PointerType *ToPointer = ToType->getAs<PointerType>()) + ToPointee = ToPointer->getPointeeType(); + else + return false; + + Qualifiers ToQuals = ToPointee.getQualifiers(); + if (!ToPointee->isObjCLifetimeType() || + ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing || + !ToQuals.withoutObjCGLifetime().empty()) + return false; + + // Argument must be a pointer to __strong to __weak. + QualType FromPointee; + if (const PointerType *FromPointer = FromType->getAs<PointerType>()) + FromPointee = FromPointer->getPointeeType(); + else + return false; + + Qualifiers FromQuals = FromPointee.getQualifiers(); + if (!FromPointee->isObjCLifetimeType() || + (FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong && + FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak)) + return false; + + // Make sure that we have compatible qualifiers. + FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing); + if (!ToQuals.compatiblyIncludes(FromQuals)) + return false; + + // Remove qualifiers from the pointee type we're converting from; they + // aren't used in the compatibility check belong, and we'll be adding back + // qualifiers (with __autoreleasing) if the compatibility check succeeds. + FromPointee = FromPointee.getUnqualifiedType(); + + // The unqualified form of the pointee types must be compatible. + ToPointee = ToPointee.getUnqualifiedType(); + bool IncompatibleObjC; + if (Context.typesAreCompatible(FromPointee, ToPointee)) + FromPointee = ToPointee; + else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee, + IncompatibleObjC)) + return false; + + /// \brief Construct the type we're converting to, which is a pointer to + /// __autoreleasing pointee. + FromPointee = Context.getQualifiedType(FromPointee, FromQuals); + ConvertedType = Context.getPointerType(FromPointee); + return true; +} + bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType) { QualType ToPointeeType; @@ -2178,12 +2285,17 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, /// IsQualificationConversion - Determines whether the conversion from /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). +/// +/// \param ObjCLifetimeConversion Output parameter that will be set to indicate +/// when the qualification conversion involves a change in the Objective-C +/// object lifetime. bool Sema::IsQualificationConversion(QualType FromType, QualType ToType, - bool CStyle) { + bool CStyle, bool &ObjCLifetimeConversion) { FromType = Context.getCanonicalType(FromType); ToType = Context.getCanonicalType(ToType); - + ObjCLifetimeConversion = false; + // If FromType and ToType are the same type, this is not a // qualification conversion. if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType()) @@ -2206,6 +2318,21 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); + // Objective-C ARC: + // Check Objective-C lifetime conversions. + if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() && + UnwrappedAnyPointer) { + if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) { + ObjCLifetimeConversion = true; + FromQuals.removeObjCLifetime(); + ToQuals.removeObjCLifetime(); + } else { + // Qualification conversions cannot cast between different + // Objective-C lifetime qualifiers. + return false; + } + } + // Allow addition/removal of GC attributes but not changing GC attributes. if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { @@ -2713,6 +2840,15 @@ CompareStandardConversionSequences(Sema &S, QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); if (UnqualT1 == UnqualT2) { + // Objective-C++ ARC: If the references refer to objects with different + // lifetimes, prefer bindings that don't change lifetime. + if (SCS1.ObjCLifetimeConversionBinding != + SCS2.ObjCLifetimeConversionBinding) { + return SCS1.ObjCLifetimeConversionBinding + ? ImplicitConversionSequence::Worse + : ImplicitConversionSequence::Better; + } + // If the type is an array type, promote the element qualifiers to the // type for comparison. if (isa<ArrayType>(T1) && T1Quals) @@ -2722,7 +2858,7 @@ CompareStandardConversionSequences(Sema &S, if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; else if (T1.isMoreQualifiedThan(T2)) - return ImplicitConversionSequence::Worse; + return ImplicitConversionSequence::Worse; } } @@ -2770,6 +2906,17 @@ CompareQualificationConversions(Sema &S, ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; + + // Objective-C++ ARC: + // Prefer qualification conversions not involving a change in lifetime + // to qualification conversions that do not change lifetime. + if (SCS1.QualificationIncludesObjCLifetime != + SCS2.QualificationIncludesObjCLifetime) { + Result = SCS1.QualificationIncludesObjCLifetime + ? ImplicitConversionSequence::Worse + : ImplicitConversionSequence::Better; + } + while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) { // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification @@ -3039,7 +3186,8 @@ Sema::ReferenceCompareResult Sema::CompareReferenceRelationship(SourceLocation Loc, QualType OrigT1, QualType OrigT2, bool &DerivedToBase, - bool &ObjCConversion) { + bool &ObjCConversion, + bool &ObjCLifetimeConversion) { assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); @@ -3056,6 +3204,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // T1 is a base class of T2. DerivedToBase = false; ObjCConversion = false; + ObjCLifetimeConversion = false; if (UnqualT1 == UnqualT2) { // Nothing to do. } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && @@ -3090,9 +3239,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // qualifiers when performing these computations, so that e.g., an int in // address space 1 is not reference-compatible with an int in address // space 2. + if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() && + T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) { + T1Quals.removeObjCLifetime(); + T2Quals.removeObjCLifetime(); + ObjCLifetimeConversion = true; + } + if (T1Quals == T2Quals) return Ref_Compatible; - else if (T1.isMoreQualifiedThan(T2)) + else if (T1Quals.compatiblyIncludes(T2Quals)) return Ref_Compatible_With_Added_Qualification; else return Ref_Related; @@ -3135,13 +3291,14 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, if (AllowRvalues) { bool DerivedToBase = false; bool ObjCConversion = false; + bool ObjCLifetimeConversion = false; if (!ConvTemplate && S.CompareReferenceRelationship( DeclLoc, Conv->getConversionType().getNonReferenceType() .getUnqualifiedType(), DeclType.getNonReferenceType().getUnqualifiedType(), - DerivedToBase, ObjCConversion) == + DerivedToBase, ObjCConversion, ObjCLifetimeConversion) == Sema::Ref_Incompatible) continue; } else { @@ -3242,10 +3399,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, bool isRValRef = DeclType->isRValueReferenceType(); bool DerivedToBase = false; bool ObjCConversion = false; + bool ObjCLifetimeConversion = false; Expr::Classification InitCategory = Init->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase, - ObjCConversion); + ObjCConversion, ObjCLifetimeConversion); // C++0x [dcl.init.ref]p5: @@ -3283,6 +3441,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = false; ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion; ICS.Standard.CopyConstructor = 0; // Nothing more to do: the inaccessibility/ambiguity check for @@ -3328,7 +3487,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // -- If the initializer expression // // -- is an xvalue, class prvalue, array prvalue or function - // lvalue and "cv1T1" is reference-compatible with "cv2 T2", or + // lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && (InitCategory.isXValue() || (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || @@ -3356,6 +3515,7 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = InitCategory.isRValue(); ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion; ICS.Standard.CopyConstructor = 0; return ICS; } @@ -3398,7 +3558,17 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // we would be reference-compatible or reference-compatible with // added qualification. But that wasn't the case, so the reference // initialization fails. - return ICS; + // + // Note that we only want to check address spaces and cvr-qualifiers here. + // ObjC GC and lifetime qualifiers aren't important. + Qualifiers T1Quals = T1.getQualifiers(); + Qualifiers T2Quals = T2.getQualifiers(); + T1Quals.removeObjCGCAttr(); + T1Quals.removeObjCLifetime(); + T2Quals.removeObjCGCAttr(); + T2Quals.removeObjCLifetime(); + if (!T1Quals.compatiblyIncludes(T2Quals)) + return ICS; } // If at least one of the types is a class type, the types are not @@ -3429,7 +3599,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, /*AllowExplicit=*/false, /*InOverloadResolution=*/false, - /*CStyle=*/false); + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); // Of course, that's still a reference binding. if (ICS.isStandard()) { @@ -3438,12 +3609,14 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = true; ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.ObjCLifetimeConversionBinding = false; } else if (ICS.isUserDefined()) { ICS.UserDefined.After.ReferenceBinding = true; ICS.Standard.IsLvalueReference = !isRValRef; ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); ICS.Standard.BindsToRvalue = true; ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.ObjCLifetimeConversionBinding = false; } return ICS; @@ -3458,7 +3631,8 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, static ImplicitConversionSequence TryCopyInitialization(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, - bool InOverloadResolution) { + bool InOverloadResolution, + bool AllowObjCWritebackConversion) { if (ToType->isReferenceType()) return TryReferenceInit(S, From, ToType, /*FIXME:*/From->getLocStart(), @@ -3469,7 +3643,8 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, SuppressUserConversions, /*AllowExplicit=*/false, InOverloadResolution, - /*CStyle=*/false); + /*CStyle=*/false, + AllowObjCWritebackConversion); } /// TryObjectArgumentInitialization - Try to initialize the object @@ -3659,7 +3834,8 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) { /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, /*InOverloadResolution=*/false, - /*CStyle=*/false); + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); } /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -3686,7 +3862,8 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) { /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, /*InOverloadResolution=*/false, - /*CStyle=*/false); + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); } /// PerformContextuallyConvertToObjCId - Perform a contextual conversion @@ -3980,7 +4157,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, SuppressUserConversions, - /*InOverloadResolution=*/true); + /*InOverloadResolution=*/true, + /*AllowObjCWritebackConversion=*/ + getLangOptions().ObjCAutoRefCount); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -4153,7 +4332,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, Candidate.Conversions[ArgIdx + 1] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, SuppressUserConversions, - /*InOverloadResolution=*/true); + /*InOverloadResolution=*/true, + /*AllowObjCWritebackConversion=*/ + getLangOptions().ObjCAutoRefCount); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -4356,25 +4537,26 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, CK_FunctionToPointerDecay, &ConversionRef, VK_RValue); - QualType CallResultType - = Conversion->getConversionType().getNonLValueExprType(Context); - if (RequireCompleteType(From->getLocStart(), CallResultType, 0)) { + QualType ConversionType = Conversion->getConversionType(); + if (RequireCompleteType(From->getLocStart(), ConversionType, 0)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_final_conversion; return; } - ExprValueKind VK = Expr::getValueKindForType(Conversion->getConversionType()); + ExprValueKind VK = Expr::getValueKindForType(ConversionType); // Note that it is safe to allocate CallExpr on the stack here because // there are 0 arguments (i.e., nothing is allocated using ASTContext's // allocator). + QualType CallResultType = ConversionType.getNonLValueExprType(Context); CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK, From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, /*SuppressUserConversions=*/true, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*AllowObjCWritebackConversion=*/false); switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: @@ -4544,7 +4726,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[ArgIdx + 1] = TryCopyInitialization(*this, Args[ArgIdx], ParamType, /*SuppressUserConversions=*/false, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*AllowObjCWritebackConversion=*/ + getLangOptions().ObjCAutoRefCount); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -4662,7 +4846,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx], ArgIdx == 0 && IsAssignmentOperator, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*AllowObjCWritebackConversion=*/ + getLangOptions().ObjCAutoRefCount); } if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; @@ -6417,7 +6603,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Best is the best viable function. if (Best->Function && - (Best->Function->isDeleted() || Best->Function->isUnavailable())) + (Best->Function->isDeleted() || + S.isFunctionConsideredUnavailable(Best->Function))) return OR_Deleted; return OR_Success; @@ -6619,6 +6806,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy + << FromQs.getObjCLifetime() << ToQs.getObjCLifetime() + << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc) << (unsigned) FnKind << FnDesc @@ -6901,7 +7099,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, FunctionDecl *Fn = Cand->Function; // Note deleted candidates, but only if they're viable. - if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) { + if (Cand->Viable && (Fn->isDeleted() || + S.isFunctionConsideredUnavailable(Fn))) { std::string FnDesc; OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); @@ -7152,7 +7351,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, = TryCopyInitialization(S, Args[ConvIdx], Cand->BuiltinTypes.ParamTypes[ConvIdx], SuppressUserConversions, - /*InOverloadResolution*/ true); + /*InOverloadResolution*/ true, + /*AllowObjCWritebackConversion=*/ + S.getLangOptions().ObjCAutoRefCount); return; } @@ -7163,7 +7364,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), SuppressUserConversions, - /*InOverloadResolution=*/true); + /*InOverloadResolution=*/true, + /*AllowObjCWritebackConversion=*/ + S.getLangOptions().ObjCAutoRefCount); else Cand->Conversions[ConvIdx].setEllipsis(); } @@ -7407,8 +7610,8 @@ private: QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || - IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType, - ResultTy)) { + S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType, + ResultTy)) { Matches.push_back(std::make_pair(CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; @@ -7742,13 +7945,17 @@ static void AddOverloadedCallCandidate(Sema &S, TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, - bool PartialOverloading) { + bool PartialOverloading, + bool KnownValid) { NamedDecl *Callee = FoundDecl.getDecl(); if (isa<UsingShadowDecl>(Callee)) Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl(); if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { - assert(!ExplicitTemplateArgs && "Explicit template arguments?"); + if (ExplicitTemplateArgs) { + assert(!KnownValid && "Explicit template arguments?"); + return; + } S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet, false, PartialOverloading); return; @@ -7762,9 +7969,7 @@ static void AddOverloadedCallCandidate(Sema &S, return; } - assert(false && "unhandled case in overloaded call candidate"); - - // do nothing? + assert(!KnownValid && "unhandled case in overloaded call candidate"); } /// \brief Add the overload candidates named by callee and/or found by argument @@ -7815,7 +8020,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, E = ULE->decls_end(); I != E; ++I) AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args, NumArgs, CandidateSet, - PartialOverloading); + PartialOverloading, /*KnownValid*/ true); if (ULE->requiresADL()) AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false, @@ -7857,13 +8062,15 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) AddOverloadedCallCandidate(SemaRef, I.getPair(), ExplicitTemplateArgs, Args, NumArgs, - Candidates, false); + Candidates, false, /*KnownValid*/ false); OverloadCandidateSet::iterator Best; - if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) + if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success) { // No viable functions. Don't bother the user with notes for functions // which don't work and shouldn't be found anyway. + R.clear(); return false; + } // Find the namespaces where ADL would have looked, and suggest // declaring the function there instead. @@ -8673,7 +8880,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc); + DeclarationNameLoc LocInfo; + LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding(); + LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding(); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo); if (FnExpr.isInvalid()) return ExprError(); @@ -8963,13 +9173,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, TheCall->getMethodDecl()->isPure()) { const CXXMethodDecl *MD = TheCall->getMethodDecl(); - if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) + if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts())) { Diag(MemExpr->getLocStart(), diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor) << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext) << MD->getParent()->getDeclName(); Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName(); + } } return MaybeBindToTemporary(TheCall); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d7c0a54..65f431d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -66,8 +66,30 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { // If we have an invalid decl, just return. if (DG.isNull() || !DG.isSingleDecl()) return; + VarDecl *var = cast<VarDecl>(DG.getSingleDecl()); + // suppress any potential 'unused variable' warning. - DG.getSingleDecl()->setUsed(); + var->setUsed(); + + // foreach variables are never actually initialized in the way that + // the parser came up with. + var->setInit(0); + + // In ARC, we don't need to retain the iteration variable of a fast + // enumeration loop. Rather than actually trying to catch that + // during declaration processing, we remove the consequences here. + if (getLangOptions().ObjCAutoRefCount) { + QualType type = var->getType(); + + // Only do this if we inferred the lifetime. Inferred lifetime + // will show up as a local qualifier because explicit lifetime + // should have shown up as an AttributedType instead. + if (type.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong) { + // Add 'const' and mark the variable as pseudo-strong. + var->setType(type.withConst()); + var->setARCPseudoStrong(true); + } + } } void Sema::DiagnoseUnusedExprResult(const Stmt *S) { @@ -114,6 +136,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) { + if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) { + Diag(Loc, diag::err_arc_unused_init_message) << R1; + return; + } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr<WarnUnusedResultAttr>()) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; @@ -951,14 +977,13 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag((*DS->decl_begin())->getLocation(), diag::err_toomany_element_decls)); - Decl *D = DS->getSingleDecl(); - FirstType = cast<ValueDecl>(D)->getType(); + VarDecl *D = cast<VarDecl>(DS->getSingleDecl()); + FirstType = D->getType(); // C99 6.8.5p3: The declaration part of a 'for' statement shall only // declare identifiers for objects having storage class 'auto' or // 'register'. - VarDecl *VD = cast<VarDecl>(D); - if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) - return StmtError(Diag(VD->getLocation(), + if (!D->hasLocalStorage()) + return StmtError(Diag(D->getLocation(), diag::err_non_variable_decl_in_for)); } else { Expr *FirstE = cast<Expr>(First); @@ -1047,6 +1072,13 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, Decl->setTypeSourceInfo(InitTSI); Decl->setType(InitTSI->getType()); + // In ARC, infer lifetime. + // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if + // we're doing the equivalent of fast iteration. + if (SemaRef.getLangOptions().ObjCAutoRefCount && + SemaRef.inferObjCARCLifetime(Decl)) + Decl->setInvalidDecl(); + SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false, /*TypeMayContainAuto=*/false); SemaRef.FinalizeDeclaration(Decl); @@ -1374,6 +1406,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (LoopVar->isInvalidDecl()) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } + } else { + // The range is implicitly used as a placeholder when it is dependent. + RangeVar->setUsed(); } return Owned(new (Context) CXXForRangeStmt(RangeDS, @@ -1508,7 +1543,8 @@ ExprResult Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, - Expr *Value) { + Expr *Value, + bool AllowNRVO) { // C++0x [class.copy]p33: // When the criteria for elision of a copy operation are met or would // be met save for the fact that the source object is a function @@ -1516,7 +1552,8 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // overload resolution to select the constructor for the copy is first // performed as if the object were designated by an rvalue. ExprResult Res = ExprError(); - if (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true)) { + if (AllowNRVO && + (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_LValueToRValue, Value, VK_XValue); @@ -1726,8 +1763,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (D != diag::ext_return_has_void_expr || !getLangOptions().CPlusPlus) { NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + + int FunctionKind = 0; + if (isa<ObjCMethodDecl>(CurDecl)) + FunctionKind = 1; + else if (isa<CXXConstructorDecl>(CurDecl)) + FunctionKind = 2; + else if (isa<CXXDestructorDecl>(CurDecl)) + FunctionKind = 3; + Diag(ReturnLoc, D) - << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) + << CurDecl->getDeclName() << FunctionKind << RetValExp->getSourceRange(); } } @@ -1756,7 +1802,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // overlap restriction of subclause 6.5.16.1 does not apply to the case of // function return. - // In C++ the return statement is handled via a copy initialization. + // In C++ the return statement is handled via a copy initialization, // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, @@ -1797,7 +1843,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (getLangOptions().CPlusPlus && FnRetType->isRecordType() && !CurContext->isDependentContext()) FunctionScopes.back()->Returns.push_back(Result); - + return Owned(Result); } @@ -1955,7 +2001,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, llvm::StringRef Clobber = Literal->getString(); - if (!Context.Target.isValidGCCRegisterName(Clobber)) + if (!Context.Target.isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } @@ -2179,6 +2225,12 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, HandlerBlock)); } +StmtResult +Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) { + getCurFunction()->setHasBranchProtectedScope(); + return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body)); +} + namespace { class TypeWithHandler { @@ -2309,4 +2361,3 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc, assert(Block); return Owned(SEHFinallyStmt::Create(Context,Loc,Block)); } - diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 5d4caac..3ac190e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -294,26 +294,31 @@ void Sema::LookupTemplateName(LookupResult &Found, if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, - false, CTC_CXXCasts)) { + Found.clear(); + if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(), + Found.getLookupKind(), S, &SS, + LookupCtx, false, + CTC_CXXCasts)) { + Found.setLookupName(Corrected.getCorrection()); + if (Corrected.getCorrectionDecl()) + Found.addDecl(Corrected.getCorrectionDecl()); FilterAcceptableTemplateNames(Found); if (!Found.empty()) { + std::string CorrectedStr(Corrected.getAsString(getLangOptions())); + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) - << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << FixItHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << Name << LookupCtx << CorrectedQuotedStr << SS.getRange() + << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); else Diag(Found.getNameLoc(), diag::err_no_template_suggest) - << Name << Found.getLookupName() - << FixItHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << Name << CorrectedQuotedStr + << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>()) Diag(Template->getLocation(), diag::note_previous_decl) - << Template->getDeclName(); + << CorrectedQuotedStr; } } else { - Found.clear(); Found.setLookupName(Name); } } @@ -1856,7 +1861,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { - DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + DependentTemplateName *DTN + = Name.getUnderlying().getAsDependentTemplateName(); if (DTN && DTN->isIdentifier()) // When building a template-id where the template-name is dependent, // assume the template is a type template. Either our assumption is @@ -1892,6 +1898,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; + bool InstantiationDependent = false; if (TypeAliasTemplateDecl *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template)) { // Find the canonical type for this type alias template specialization. @@ -1917,7 +1924,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return QualType(); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs)) { + TemplateArgs, InstantiationDependent)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -2357,8 +2364,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; // Add the converted template type argument. - Converted.push_back( - TemplateArgument(Context.getCanonicalType(Arg.getAsType()))); + QualType ArgType = Context.getCanonicalType(Arg.getAsType()); + + // Objective-C ARC: + // If an explicitly-specified template argument type is a lifetime type + // with no lifetime qualifier, the __strong lifetime qualifier is inferred. + if (getLangOptions().ObjCAutoRefCount && + ArgType->isObjCLifetimeType() && + !ArgType.getObjCLifetime()) { + Qualifiers Qs; + Qs.setObjCLifetime(Qualifiers::OCL_Strong); + ArgType = Context.getQualifiedType(ArgType, Qs); + } + + Converted.push_back(TemplateArgument(ArgType)); return false; } @@ -2912,16 +2931,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // arguments, just break out now and we'll fill in the argument pack below. if ((*Param)->isTemplateParameterPack()) break; - - // If our template is a template template parameter that hasn't acquired - // its proper context yet (e.g., because we're using the template template - // parameter in the signature of a function template, before we've built - // the function template itself), don't attempt substitution of default - // template arguments at this point: we don't have enough context to - // do it properly. - if (isTemplateTemplateParameter && - Template->getDeclContext()->isTranslationUnit()) - break; // We have a default template argument that we will use. TemplateArgumentLoc Arg; @@ -3307,8 +3316,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, QualType ArgType = Arg->getType(); // See through any implicit casts we added to fix the type. - while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = Cast->getSubExpr(); + Arg = Arg->IgnoreImpCasts(); // C++ [temp.arg.nontype]p1: // @@ -3321,7 +3329,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // expressed as & id-expression where the & is optional if // the name refers to a function or array, or if the // corresponding template-parameter is a reference; or - DeclRefExpr *DRE = 0; // In C++98/03 mode, give an extension warning on any extra parentheses. // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773 @@ -3337,29 +3344,30 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, Arg = Parens->getSubExpr(); } + while (SubstNonTypeTemplateParmExpr *subst = + dyn_cast<SubstNonTypeTemplateParmExpr>(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + bool AddressTaken = false; SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { if (UnOp->getOpcode() == UO_AddrOf) { - // Support &__uuidof(class_with_uuid) as a non-type template argument. - // Very common in Microsoft COM headers. - if (S.getLangOptions().Microsoft && - isa<CXXUuidofExpr>(UnOp->getSubExpr())) { - Converted = TemplateArgument(ArgIn); - return false; - } - - DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); + Arg = UnOp->getSubExpr(); AddressTaken = true; AddrOpLoc = UnOp->getOperatorLoc(); } - } else { - if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) { - Converted = TemplateArgument(ArgIn); - return false; - } - DRE = dyn_cast<DeclRefExpr>(Arg); } + + if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) { + Converted = TemplateArgument(ArgIn); + return false; + } + + while (SubstNonTypeTemplateParmExpr *subst = + dyn_cast<SubstNonTypeTemplateParmExpr>(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg); if (!DRE) { S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); @@ -3513,9 +3521,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; } + bool ObjCLifetimeConversion; if (ParamType->isPointerType() && !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() && - S.IsQualificationConversion(ArgType, ParamType, false)) { + S.IsQualificationConversion(ArgType, ParamType, false, + ObjCLifetimeConversion)) { // For pointer-to-object types, qualification conversions are // permitted. } else { @@ -3552,10 +3562,10 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // We can't perform this conversion or binding. if (ParamType->isReferenceType()) S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind) - << ParamType << Arg->getType() << Arg->getSourceRange(); + << ParamType << ArgIn->getType() << Arg->getSourceRange(); else S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) - << Arg->getType() << ParamType << Arg->getSourceRange(); + << ArgIn->getType() << ParamType << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -3599,6 +3609,10 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, Arg = Parens->getSubExpr(); } + while (SubstNonTypeTemplateParmExpr *subst = + dyn_cast<SubstNonTypeTemplateParmExpr>(Arg)) + Arg = subst->getReplacement()->IgnoreImpCasts(); + // A pointer-to-member constant written &Class::member. if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { if (UnOp->getOpcode() == UO_AddrOf) { @@ -3875,8 +3889,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return Owned(Arg); } + bool ObjCLifetimeConversion; if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), - false)) { + false, ObjCLifetimeConversion)) { Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { @@ -3943,9 +3958,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // member, qualification conversions (4.4) are applied. assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); + bool ObjCLifetimeConversion; if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. - } else if (IsQualificationConversion(ArgType, ParamType, false)) { + } else if (IsQualificationConversion(ArgType, ParamType, false, + ObjCLifetimeConversion)) { Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); } else { // We can't perform this conversion. @@ -4053,8 +4070,10 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, // We might need to perform a trailing qualification conversion, since // the element type on the parameter could be more qualified than the // element type in the expression we constructed. + bool ObjCLifetimeConversion; if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType(), false)) + ParamType.getUnqualifiedType(), false, + ObjCLifetimeConversion)) RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp); assert(!RefExpr.isInvalid() && @@ -4818,10 +4837,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted)) return true; + bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs.getArgumentArray(), - TemplateArgs.size())) { + TemplateArgs.size(), + InstantiationDependent)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); isPartialSpecialization = false; @@ -5346,7 +5367,7 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, /// explicitly provided as in, e.g., \c void sort<>(char*, char*); /// as it anyway contains info on the angle brackets locations. /// -/// \param PrevDecl the set of declarations that may be specialized by +/// \param Previous the set of declarations that may be specialized by /// this function specialization. bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, @@ -5410,13 +5431,12 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); assert(SpecInfo && "Function template specialization info missing?"); - { - // Note: do not overwrite location info if previous template - // specialization kind was explicit. - TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind(); - if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) - Specialization->setLocation(FD->getLocation()); - } + + // Note: do not overwrite location info if previous template + // specialization kind was explicit. + TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind(); + if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) + Specialization->setLocation(FD->getLocation()); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7d0ce8b..dcb4ff2 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -12,7 +12,6 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/DeclSpec.h" -#include "clang/Sema/SemaDiagnostic.h" // FIXME: temporary! #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" @@ -820,6 +819,11 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, ParamQs.hasAddressSpace()) return true; + // Mismatched (but not missing) Objective-C lifetime qualifiers. + if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() && + ParamQs.hasObjCLifetime()) + return true; + // CVR qualifier superset. return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) @@ -1010,6 +1014,17 @@ DeduceTemplateArguments(Sema &S, DeducedQs.removeObjCGCAttr(); if (ParamQs.hasAddressSpace()) DeducedQs.removeAddressSpace(); + if (ParamQs.hasObjCLifetime()) + DeducedQs.removeObjCLifetime(); + + // Objective-C ARC: + // If template deduction would produce an argument type with lifetime type + // but no lifetime qualifier, the __strong lifetime qualifier is inferred. + if (S.getLangOptions().ObjCAutoRefCount && + DeducedType->isObjCLifetimeType() && + !DeducedQs.hasObjCLifetime()) + DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); @@ -1054,10 +1069,39 @@ DeduceTemplateArguments(Sema &S, } switch (Param->getTypeClass()) { - // No deduction possible for these types + // Non-canonical types cannot appear here. +#define NON_CANONICAL_TYPE(Class, Base) \ + case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); +#define TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + llvm_unreachable("Type nodes handled above"); + + // These types cannot be used in templates or cannot be dependent, so + // deduction always fails. case Type::Builtin: + case Type::VariableArray: + case Type::Vector: + case Type::FunctionNoProto: + case Type::Record: + case Type::Enum: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: return Sema::TDK_NonDeducedMismatch; + // _Complex T [placeholder extension] + case Type::Complex: + if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>()) + return DeduceTemplateArguments(S, TemplateParams, + cast<ComplexType>(Param)->getElementType(), + ComplexArg->getElementType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; + // T * case Type::Pointer: { QualType PointeeType; @@ -1361,17 +1405,107 @@ DeduceTemplateArguments(Sema &S, Deduced, 0); } + // (clang extension) + // + // T __attribute__(((ext_vector_type(<integral constant>)))) + case Type::ExtVector: { + const ExtVectorType *VectorParam = cast<ExtVectorType>(Param); + if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) { + // Make sure that the vectors have the same number of elements. + if (VectorParam->getNumElements() != VectorArg->getNumElements()) + return Sema::TDK_NonDeducedMismatch; + + // Perform deduction on the element types. + return DeduceTemplateArguments(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, + TDF); + } + + if (const DependentSizedExtVectorType *VectorArg + = dyn_cast<DependentSizedExtVectorType>(Arg)) { + // We can't check the number of elements, since the argument has a + // dependent number of elements. This can only occur during partial + // ordering. + + // Perform deduction on the element types. + return DeduceTemplateArguments(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, + TDF); + } + + return Sema::TDK_NonDeducedMismatch; + } + + // (clang extension) + // + // T __attribute__(((ext_vector_type(N)))) + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *VectorParam + = cast<DependentSizedExtVectorType>(Param); + + if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) { + // Perform deduction on the element types. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, + TDF)) + return Result; + + // Perform deduction on the vector size, if we can. + NonTypeTemplateParmDecl *NTTP + = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + if (!NTTP) + return Sema::TDK_Success; + + llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); + ArgSize = VectorArg->getNumElements(); + return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy, + false, Info, Deduced); + } + + if (const DependentSizedExtVectorType *VectorArg + = dyn_cast<DependentSizedExtVectorType>(Arg)) { + // Perform deduction on the element types. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, + TDF)) + return Result; + + // Perform deduction on the vector size, if we can. + NonTypeTemplateParmDecl *NTTP + = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(), + Info, Deduced); + } + + return Sema::TDK_NonDeducedMismatch; + } + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: + case Type::UnresolvedUsing: + case Type::Decltype: + case Type::UnaryTransform: + case Type::Auto: + case Type::DependentTemplateSpecialization: + case Type::PackExpansion: // No template argument deduction for these types return Sema::TDK_Success; - - default: - break; } - // FIXME: Many more cases to go (to go). return Sema::TDK_Success; } @@ -2189,15 +2323,108 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } +/// \brief Check whether the deduced argument type for a call to a function +/// template matches the actual argument type per C++ [temp.deduct.call]p4. +static bool +CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, + QualType DeducedA) { + ASTContext &Context = S.Context; + + QualType A = OriginalArg.OriginalArgType; + QualType OriginalParamType = OriginalArg.OriginalParamType; + + // Check for type equality (top-level cv-qualifiers are ignored). + if (Context.hasSameUnqualifiedType(A, DeducedA)) + return false; + + // Strip off references on the argument types; they aren't needed for + // the following checks. + if (const ReferenceType *DeducedARef = DeducedA->getAs<ReferenceType>()) + DeducedA = DeducedARef->getPointeeType(); + if (const ReferenceType *ARef = A->getAs<ReferenceType>()) + A = ARef->getPointeeType(); + + // C++ [temp.deduct.call]p4: + // [...] However, there are three cases that allow a difference: + // - If the original P is a reference type, the deduced A (i.e., the + // type referred to by the reference) can be more cv-qualified than + // the transformed A. + if (const ReferenceType *OriginalParamRef + = OriginalParamType->getAs<ReferenceType>()) { + // We don't want to keep the reference around any more. + OriginalParamType = OriginalParamRef->getPointeeType(); + + Qualifiers AQuals = A.getQualifiers(); + Qualifiers DeducedAQuals = DeducedA.getQualifiers(); + if (AQuals == DeducedAQuals) { + // Qualifiers match; there's nothing to do. + } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { + return true; + } else { + // Qualifiers are compatible, so have the argument type adopt the + // deduced argument type's qualifiers as if we had performed the + // qualification conversion. + A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals); + } + } + + // - The transformed A can be another pointer or pointer to member + // type that can be converted to the deduced A via a qualification + // conversion. + // + // Also allow conversions which merely strip [[noreturn]] from function types + // (recursively) as an extension. + // FIXME: Currently, this doesn't place nicely with qualfication conversions. + bool ObjCLifetimeConversion = false; + QualType ResultTy; + if ((A->isAnyPointerType() || A->isMemberPointerType()) && + (S.IsQualificationConversion(A, DeducedA, false, + ObjCLifetimeConversion) || + S.IsNoReturnConversion(A, DeducedA, ResultTy))) + return false; + + + // - If P is a class and P has the form simple-template-id, then the + // transformed A can be a derived class of the deduced A. [...] + // [...] Likewise, if P is a pointer to a class of the form + // simple-template-id, the transformed A can be a pointer to a + // derived class pointed to by the deduced A. + if (const PointerType *OriginalParamPtr + = OriginalParamType->getAs<PointerType>()) { + if (const PointerType *DeducedAPtr = DeducedA->getAs<PointerType>()) { + if (const PointerType *APtr = A->getAs<PointerType>()) { + if (A->getPointeeType()->isRecordType()) { + OriginalParamType = OriginalParamPtr->getPointeeType(); + DeducedA = DeducedAPtr->getPointeeType(); + A = APtr->getPointeeType(); + } + } + } + } + + if (Context.hasSameUnqualifiedType(A, DeducedA)) + return false; + + if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && + S.IsDerivedFrom(A, DeducedA)) + return false; + + return true; +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. +/// +/// \param OriginalCallArgs If non-NULL, the original call arguments against +/// which the deduced argument types should be compared. Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -2351,6 +2578,24 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, !Trap.hasErrorOccurred()) Info.take(); + if (OriginalCallArgs) { + // C++ [temp.deduct.call]p4: + // In general, the deduction process attempts to find template argument + // values that will make the deduced A identical to A (after the type A + // is transformed as described above). [...] + for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) { + OriginalCallArg OriginalArg = (*OriginalCallArgs)[I]; + unsigned ParamIdx = OriginalArg.ArgIdx; + + if (ParamIdx >= Specialization->getNumParams()) + continue; + + QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); + if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) + return Sema::TDK_SubstitutionFailure; + } + } + // There may have been an error that did not prevent us from constructing a // declaration. Mark the declaration invalid and return with a substitution // failure. @@ -2594,6 +2839,10 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, return false; } +static bool hasDeducibleTemplateParameters(Sema &S, + FunctionTemplateDecl *FunctionTemplate, + QualType T); + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// @@ -2675,10 +2924,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); unsigned ArgIdx = 0; + llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs; for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); ParamIdx != NumParams; ++ParamIdx) { - QualType ParamType = ParamTypes[ParamIdx]; - + QualType OrigParamType = ParamTypes[ParamIdx]; + QualType ParamType = OrigParamType; + const PackExpansionType *ParamExpansion = dyn_cast<PackExpansionType>(ParamType); if (!ParamExpansion) { @@ -2688,20 +2939,25 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Expr *Arg = Args[ArgIdx++]; QualType ArgType = Arg->getType(); + unsigned TDF = 0; if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, ParamType, ArgType, Arg, TDF)) continue; + // Keep track of the argument type and corresponding parameter index, + // so we can check for compatibility between the deduced A and A. + if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, + ArgType)); + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, ParamType, ArgType, Info, Deduced, TDF)) return Result; - // FIXME: we need to check that the deduced A is the same as A, - // modulo the various allowed differences. continue; } @@ -2747,9 +3003,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, for (; ArgIdx < NumArgs; ++ArgIdx) { HasAnyArguments = true; - ParamType = ParamPattern; + QualType OrigParamType = ParamPattern; + ParamType = OrigParamType; Expr *Arg = Args[ArgIdx]; QualType ArgType = Arg->getType(); + unsigned TDF = 0; if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, ParamType, ArgType, Arg, @@ -2760,6 +3018,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, break; } + // Keep track of the argument type and corresponding argument index, + // so we can check for compatibility between the deduced A and A. + if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, + ArgType)); + if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, ParamType, ArgType, Info, Deduced, @@ -2792,7 +3056,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, NumExplicitlySpecified, - Specialization, Info); + Specialization, Info, &OriginalCallArgs); } /// \brief Deduce template arguments when taking the address of a function @@ -2969,9 +3233,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, P, A, Info, Deduced, TDF)) return Result; - // FIXME: we need to check that the deduced A is the same as A, - // modulo the various allowed differences. - // Finish template argument deduction. LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; @@ -3099,8 +3360,19 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init, QualType DeducedType = Deduced[0].getAsType(); if (DeducedType.isNull()) return false; - + Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type); + + // Check that the deduced argument type is compatible with the original + // argument type per C++ [temp.deduct.call]p4. + if (Result && + CheckOriginalCallArgDeduction(*this, + Sema::OriginalCallArg(FuncParam,0,InitType), + Result->getType())) { + Result = 0; + return false; + } + return true; } @@ -3227,8 +3499,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Other: // - In other contexts (14.6.6.2) the function template's function type // is used. - // FIXME: Don't we actually want to perform the adjustments on the parameter - // types? if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced, TDF_None, /*PartialOrdering=*/true, RefParamComparisons)) @@ -4010,3 +4280,23 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), true, TemplateParams->getDepth(), Deduced); } + +bool hasDeducibleTemplateParameters(Sema &S, + FunctionTemplateDecl *FunctionTemplate, + QualType T) { + if (!T->isDependentType()) + return false; + + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + llvm::SmallVector<bool, 4> Deduced; + Deduced.resize(TemplateParams->size()); + ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(), + Deduced); + + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) + if (Deduced[I]) + return true; + + return false; +} diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 3c19641..1988f14 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -62,8 +62,20 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (!Ctx) { Ctx = D->getDeclContext(); - assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) && - "Template parameter doesn't have its context yet!"); + // If we have a template template parameter with translation unit context, + // then we're performing substitution into a default template argument of + // this template template parameter before we've constructed the template + // that will own this template template parameter. In this case, we + // use empty template parameter lists for all of the outer templates + // to avoid performing any substitutions. + if (Ctx->isTranslationUnit()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(D)) { + for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) + Result.addOuterTemplateArguments(0, 0); + return Result; + } + } } while (!Ctx->isFileContext()) { @@ -788,6 +800,11 @@ namespace { getSema().CallsUndergoingInstantiation.pop_back(); return move(Result); } + + private: + ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, + SourceLocation loc, + const TemplateArgument &arg); }; } @@ -795,7 +812,7 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) { if (T.isNull()) return true; - if (T->isDependentType() || T->isVariablyModifiedType()) + if (T->isInstantiationDependentType() || T->isVariablyModifiedType()) return false; getSema().MarkDeclarationsReferencedInType(Loc, T); @@ -980,13 +997,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - + // We don't ever want to substitute for a qualified template name, since // the qualifier is handled separately. So, look through the qualified // template name to its underlying declaration. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); - + + Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); return Template; } } @@ -1065,46 +1083,65 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; } + return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg); +} + +ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( + NonTypeTemplateParmDecl *parm, + SourceLocation loc, + const TemplateArgument &arg) { + ExprResult result; + QualType type; + // The template argument itself might be an expression, in which // case we just return that expression. - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()); + if (arg.getKind() == TemplateArgument::Expression) { + Expr *argExpr = arg.getAsExpr(); + result = SemaRef.Owned(argExpr); + type = argExpr->getType(); - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + } else if (arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(arg.getAsDecl()); // Find the instantiation of the template argument. This is // required for nested templates. VD = cast_or_null<ValueDecl>( - getSema().FindInstantiatedDecl(E->getLocation(), - VD, TemplateArgs)); + getSema().FindInstantiatedDecl(loc, VD, TemplateArgs)); if (!VD) return ExprError(); // Derive the type we want the substituted decl to have. This had // better be non-dependent, or these checks will have serious problems. - QualType TargetType; - if (NTTP->isExpandedParameterPack()) - TargetType = NTTP->getExpansionType( - getSema().ArgumentPackSubstitutionIndex); - else if (NTTP->isParameterPack() && - isa<PackExpansionType>(NTTP->getType())) { - TargetType = SemaRef.SubstType( - cast<PackExpansionType>(NTTP->getType())->getPattern(), - TemplateArgs, E->getLocation(), - NTTP->getDeclName()); - } else - TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, - E->getLocation(), NTTP->getDeclName()); - assert(!TargetType.isNull() && "type substitution failed for param type"); - assert(!TargetType->isDependentType() && "param type still dependent"); - return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, - TargetType, - E->getLocation()); + if (parm->isExpandedParameterPack()) { + type = parm->getExpansionType(SemaRef.ArgumentPackSubstitutionIndex); + } else if (parm->isParameterPack() && + isa<PackExpansionType>(parm->getType())) { + type = SemaRef.SubstType( + cast<PackExpansionType>(parm->getType())->getPattern(), + TemplateArgs, loc, parm->getDeclName()); + } else { + type = SemaRef.SubstType(parm->getType(), TemplateArgs, + loc, parm->getDeclName()); + } + assert(!type.isNull() && "type substitution failed for param type"); + assert(!type->isDependentType() && "param type still dependent"); + result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, type, loc); + + if (!result.isInvalid()) type = result.get()->getType(); + } else { + result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc); + + // Note that this type can be different from the type of 'result', + // e.g. if it's an enum type. + type = arg.getIntegralType(); } + if (result.isInvalid()) return ExprError(); - return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, - E->getSourceRange().getBegin()); + Expr *resultExpr = result.take(); + return SemaRef.Owned(new (SemaRef.Context) + SubstNonTypeTemplateParmExpr(type, + resultExpr->getValueKind(), + loc, parm, resultExpr)); } ExprResult @@ -1120,36 +1157,9 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); const TemplateArgument &Arg = ArgPack.pack_begin()[Index]; - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()); - - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - - // Find the instantiation of the template argument. This is - // required for nested templates. - VD = cast_or_null<ValueDecl>( - getSema().FindInstantiatedDecl(E->getParameterPackLocation(), - VD, TemplateArgs)); - if (!VD) - return ExprError(); - - QualType T; - NonTypeTemplateParmDecl *NTTP = E->getParameterPack(); - if (NTTP->isExpandedParameterPack()) - T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex); - else if (const PackExpansionType *Expansion - = dyn_cast<PackExpansionType>(NTTP->getType())) - T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs, - E->getParameterPackLocation(), NTTP->getDeclName()); - else - T = E->getType(); - return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T, - E->getParameterPackLocation()); - } - - return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, - E->getParameterPackLocation()); + return transformNonTypeTemplateParmRef(E->getParameterPack(), + E->getParameterPackLocation(), + Arg); } ExprResult @@ -1327,7 +1337,7 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, "Cannot perform an instantiation without some context on the " "instantiation stack"); - if (!T->getType()->isDependentType() && + if (!T->getType()->isInstantiationDependentType() && !T->getType()->isVariablyModifiedType()) return T; @@ -1346,7 +1356,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL, if (TL.getType().isNull()) return 0; - if (!TL.getType()->isDependentType() && + if (!TL.getType()->isInstantiationDependentType() && !TL.getType()->isVariablyModifiedType()) { // FIXME: Make a copy of the TypeLoc data here, so that we can // return a new TypeSourceInfo. Inefficient! @@ -1375,7 +1385,7 @@ QualType Sema::SubstType(QualType T, // If T is not a dependent type or a variably-modified type, there // is nothing to do. - if (!T->isDependentType() && !T->isVariablyModifiedType()) + if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType()) return T; TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); @@ -1383,7 +1393,8 @@ QualType Sema::SubstType(QualType T, } static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { - if (T->getType()->isDependentType() || T->getType()->isVariablyModifiedType()) + if (T->getType()->isInstantiationDependentType() || + T->getType()->isVariablyModifiedType()) return true; TypeLoc TL = T->getTypeLoc().IgnoreParens(); @@ -1397,7 +1408,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { // The parameter's type as written might be dependent even if the // decayed type was not dependent. if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo()) - if (TSInfo->getType()->isDependentType()) + if (TSInfo->getType()->isInstantiationDependentType()) return true; // TODO: currently we always rebuild expressions. When we @@ -1798,9 +1809,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ExprResult NewInit = SubstExpr(OldInit, TemplateArgs); // If the initialization is no longer dependent, check it now. - if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent()) - && !NewField->getType()->isDependentType() - && !NewInit.get()->isTypeDependent()) { + if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() || + OldInit->isValueDependent()) && + !NewField->getType()->isDependentType() && + !NewInit.get()->isTypeDependent() && + !NewInit.get()->isValueDependent()) { // FIXME: handle list-initialization SourceLocation EqualLoc = NewField->getLocation(); NewInit = PerformCopyInitialization( diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e78aa29..29385e5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -59,7 +59,7 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, // FIXME: Is this still too simple? void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, - Decl *Tmpl, Decl *New) { + const Decl *Tmpl, Decl *New) { for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end(); i != e; ++i) { const Attr *TmplAttr = *i; @@ -132,7 +132,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType() || + if (DI->getType()->isInstantiationDependentType() || DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -415,8 +415,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { !Var->isCXXForRangeDecl()) SemaRef.ActOnUninitializedDecl(Var, false); - // Diagnose unused local variables. - if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed()) + // Diagnose unused local variables with dependent types, where the diagnostic + // will have been deferred. + if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() && + D->getType()->isDependentType()) SemaRef.DiagnoseUnusedDecl(Var); return Var; @@ -433,7 +435,7 @@ Decl *TemplateDeclInstantiator::VisitAccessSpecDecl(AccessSpecDecl *D) { Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI->getType()->isDependentType() || + if (DI->getType()->isInstantiationDependentType() || DI->getType()->isVariablyModifiedType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -1088,9 +1090,26 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function->setLexicalDeclContext(LexicalDC); // Attach the parameters - for (unsigned P = 0; P < Params.size(); ++P) - if (Params[P]) - Params[P]->setOwningFunction(Function); + if (isa<FunctionProtoType>(Function->getType().IgnoreParens())) { + // Adopt the already-instantiated parameters into our own context. + for (unsigned P = 0; P < Params.size(); ++P) + if (Params[P]) + Params[P]->setOwningFunction(Function); + } else { + // Since we were instantiated via a typedef of a function type, create + // new parameters. + const FunctionProtoType *Proto + = Function->getType()->getAs<FunctionProtoType>(); + assert(Proto && "No function prototype in template instantiation?"); + for (FunctionProtoType::arg_type_iterator AI = Proto->arg_type_begin(), + AE = Proto->arg_type_end(); AI != AE; ++AI) { + ParmVarDecl *Param + = SemaRef.BuildParmVarDeclForTypedef(Function, Function->getLocation(), + *AI); + Param->setScopeInfo(0, Params.size()); + Params.push_back(Param); + } + } Function->setParams(Params.data(), Params.size()); SourceLocation InstantiateAtPOI; @@ -2264,7 +2283,12 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI)); } - SemaRef.InstantiateAttrs(TemplateArgs, Tmpl, New); + const FunctionDecl* Definition = Tmpl; + + // Get the definition. Leaves the variable unchanged if undefined. + Tmpl->isDefined(Definition); + + SemaRef.InstantiateAttrs(TemplateArgs, Definition, New); return false; } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 86d3bc1..daa1523 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -716,17 +716,19 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: - if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false, - CTC_NoKeywords)) { - if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>()) + if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(), + R.getLookupKind(), S, 0, 0, + false, CTC_NoKeywords)) { + if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl()) if (CorrectedResult->isParameterPack()) { + std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); ParameterPack = CorrectedResult; Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest) - << &Name << CorrectedName - << FixItHint::CreateReplacement(NameLoc, - CorrectedName.getAsString()); + << &Name << CorrectedQuotedStr + << FixItHint::CreateReplacement( + NameLoc, Corrected.getAsString(getLangOptions())); Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here) - << CorrectedName; + << CorrectedQuotedStr; } } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 5fd8afa..f3e73ec 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -26,36 +26,11 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; -/// \brief Perform adjustment on the parameter type of a function. -/// -/// This routine adjusts the given parameter type @p T to the actual -/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], -/// C++ [dcl.fct]p3). The adjusted parameter type is returned. -QualType Sema::adjustParameterType(QualType T) { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - if (T->isArrayType()) - return Context.getArrayDecayedType(T); - - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. - if (T->isFunctionType()) - return Context.getPointerType(T); - - return T; -} - - - /// isOmittedBlockReturnType - Return true if this declarator is missing a /// return type because this is a omitted return type on a block literal. static bool isOmittedBlockReturnType(const Declarator &D) { @@ -86,6 +61,11 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, useInstantiationLoc = true; break; + case AttributeList::AT_objc_ownership: + diagID = diag::warn_objc_object_attribute_wrong_type; + useInstantiationLoc = true; + break; + default: // Assume everything else was a function attribute. diagID = diag::warn_function_attribute_wrong_type; @@ -110,7 +90,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, // objc_gc applies to Objective-C pointers or, otherwise, to the // smallest available pointer type (i.e. 'void*' in 'void**'). #define OBJC_POINTER_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_objc_gc + case AttributeList::AT_objc_gc: \ + case AttributeList::AT_objc_ownership // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -295,11 +276,15 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, static bool handleObjCGCTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); +static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, + AttributeList &attr, QualType &type); + static bool handleObjCPointerTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { - // Right now, we have exactly one of these attributes: objc_gc. - assert(attr.getKind() == AttributeList::AT_objc_gc); - return handleObjCGCTypeAttr(state, attr, type); + if (attr.getKind() == AttributeList::AT_objc_gc) + return handleObjCGCTypeAttr(state, attr, type); + assert(attr.getKind() == AttributeList::AT_objc_ownership); + return handleObjCOwnershipTypeAttr(state, attr, type); } /// Given that an objc_gc attribute was written somewhere on a @@ -447,7 +432,12 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, return true; } - return handleFunctionTypeAttr(state, attr, declSpecType); + if (handleFunctionTypeAttr(state, attr, declSpecType)) { + spliceAttrOutOfList(attr, attrList); + return true; + } + + return false; } /// A function type attribute was written in the decl spec. Try to @@ -512,6 +502,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); break; + case AttributeList::AT_ns_returns_retained: + if (!state.getSema().getLangOptions().ObjCAutoRefCount) + break; + // fallthrough + FUNCTION_TYPE_ATTRS_CASELIST: distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); break; @@ -560,6 +555,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*args*/ 0, 0, /*type quals*/ 0, /*ref-qualifier*/true, SourceLocation(), + /*mutable qualifier*/SourceLocation(), /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); @@ -575,10 +571,11 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { +static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. + Sema &S = state.getSema(); Declarator &declarator = state.getDeclarator(); const DeclSpec &DS = declarator.getDeclSpec(); SourceLocation DeclLoc = declarator.getIdentifierLoc(); @@ -1017,6 +1014,51 @@ QualType Sema::BuildParenType(QualType T) { return Context.getParenType(T); } +/// Given that we're building a pointer or reference to the given +static QualType inferARCLifetimeForPointee(Sema &S, QualType type, + SourceLocation loc, + bool isReference) { + // Bail out if retention is unrequired or already specified. + if (!type->isObjCLifetimeType() || + type.getObjCLifetime() != Qualifiers::OCL_None) + return type; + + Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None; + + // If the object type is const-qualified, we can safely use + // __unsafe_unretained. This is safe (because there are no read + // barriers), and it'll be safe to coerce anything but __weak* to + // the resulting type. + if (type.isConstQualified()) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + + // Otherwise, check whether the static type does not require + // retaining. This currently only triggers for Class (possibly + // protocol-qualifed, and arrays thereof). + } else if (type->isObjCARCImplicitlyUnretainedType()) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + + // If that failed, give an error and recover using __autoreleasing. + } else { + // These types can show up in private ivars in system headers, so + // we need this to not be an error in those cases. Instead we + // want to delay. + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType(loc, + diag::err_arc_indirect_no_ownership, type, isReference)); + } else { + S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference; + } + implicitLifetime = Qualifiers::OCL_Autoreleasing; + } + assert(implicitLifetime && "didn't infer any lifetime!"); + + Qualifiers qs; + qs.addObjCLifetime(implicitLifetime); + return S.Context.getQualifiedType(type, qs); +} + /// \brief Build a pointer type. /// /// \param T The type to which we'll be building a pointer. @@ -1041,6 +1083,10 @@ QualType Sema::BuildPointerType(QualType T, assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); + // In ARC, it is forbidden to build pointers to unqualified pointers. + if (getLangOptions().ObjCAutoRefCount) + T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); + // Build the pointer type. return Context.getPointerType(T); } @@ -1094,12 +1140,38 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } + // In ARC, it is forbidden to build references to unqualified pointers. + if (getLangOptions().ObjCAutoRefCount) + T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); + // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); return Context.getRValueReferenceType(T); } +/// Check whether the specified array size makes the array type a VLA. If so, +/// return true, if not, return the size of the array in SizeVal. +static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) { + // If the size is an ICE, it certainly isn't a VLA. + if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context)) + return false; + + // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable + // value as an extension. + Expr::EvalResult Result; + if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) { + if (!Result.hasSideEffects() && Result.Val.isInt()) { + SizeVal = Result.Val.getInt(); + S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant); + return false; + } + } + + return true; +} + + /// \brief Build an array type. /// /// \param T The type of each element in the array. @@ -1200,11 +1272,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); - } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || - (!T->isDependentType() && !T->isIncompleteType() && - !T->isConstantSizeType())) { - // Per C99, a variable array is an array with either a non-constant - // size or an element type that has a non-constant-size + } else if (!T->isDependentType() && !T->isIncompleteType() && + !T->isConstantSizeType()) { + // C99: an array with an element type that has a non-constant-size is a VLA. + T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); + } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) { + // C99: an array with a non-ICE size is a VLA. We accept any expression + // that we can fold to a non-zero positive value as an extension. T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall @@ -1242,10 +1316,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (!getLangOptions().C99) { if (T->isVariableArrayType()) { // Prohibit the use of non-POD types in VLAs. + QualType BaseT = Context.getBaseElementType(T); if (!T->isDependentType() && - !Context.getBaseElementType(T)->isPODType()) { + !BaseT.isPODType(Context) && + !BaseT->isObjCLifetimeType()) { Diag(Loc, diag::err_vla_non_pod) - << Context.getBaseElementType(T); + << BaseT; return QualType(); } // Prohibit the use of VLAs during template argument deduction. @@ -1296,8 +1372,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } - if (!T->isDependentType()) - return Context.getExtVectorType(T, vectorSize); + return Context.getExtVectorType(T, vectorSize); } return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); @@ -1347,7 +1422,7 @@ QualType Sema::BuildFunctionType(QualType T, bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { - QualType ParamType = adjustParameterType(ParamTypes[Idx]); + QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; @@ -1467,6 +1542,109 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { return QT; } +static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, + Qualifiers::ObjCLifetime ownership, + unsigned chunkIndex); + +/// Given that this is the declaration of a parameter under ARC, +/// attempt to infer attributes and such for pointer-to-whatever +/// types. +static void inferARCWriteback(TypeProcessingState &state, + QualType &declSpecType) { + Sema &S = state.getSema(); + Declarator &declarator = state.getDeclarator(); + + // TODO: should we care about decl qualifiers? + + // Check whether the declarator has the expected form. We walk + // from the inside out in order to make the block logic work. + unsigned outermostPointerIndex = 0; + bool isBlockPointer = false; + unsigned numPointers = 0; + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + unsigned chunkIndex = i; + DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex); + switch (chunk.Kind) { + case DeclaratorChunk::Paren: + // Ignore parens. + break; + + case DeclaratorChunk::Reference: + case DeclaratorChunk::Pointer: + // Count the number of pointers. Treat references + // interchangeably as pointers; if they're mis-ordered, normal + // type building will discover that. + outermostPointerIndex = chunkIndex; + numPointers++; + break; + + case DeclaratorChunk::BlockPointer: + // If we have a pointer to block pointer, that's an acceptable + // indirect reference; anything else is not an application of + // the rules. + if (numPointers != 1) return; + numPointers++; + outermostPointerIndex = chunkIndex; + isBlockPointer = true; + + // We don't care about pointer structure in return values here. + goto done; + + case DeclaratorChunk::Array: // suppress if written (id[])? + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + return; + } + } + done: + + // If we have *one* pointer, then we want to throw the qualifier on + // the declaration-specifiers, which means that it needs to be a + // retainable object type. + if (numPointers == 1) { + // If it's not a retainable object type, the rule doesn't apply. + if (!declSpecType->isObjCRetainableType()) return; + + // If it already has lifetime, don't do anything. + if (declSpecType.getObjCLifetime()) return; + + // Otherwise, modify the type in-place. + Qualifiers qs; + + if (declSpecType->isObjCARCImplicitlyUnretainedType()) + qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); + else + qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing); + declSpecType = S.Context.getQualifiedType(declSpecType, qs); + + // If we have *two* pointers, then we want to throw the qualifier on + // the outermost pointer. + } else if (numPointers == 2) { + // If we don't have a block pointer, we need to check whether the + // declaration-specifiers gave us something that will turn into a + // retainable object pointer after we slap the first pointer on it. + if (!isBlockPointer && !declSpecType->isObjCObjectType()) + return; + + // Look for an explicit lifetime attribute there. + DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex); + if (chunk.Kind != DeclaratorChunk::Pointer && + chunk.Kind != DeclaratorChunk::BlockPointer) + return; + for (const AttributeList *attr = chunk.getAttrs(); attr; + attr = attr->getNext()) + if (attr->getKind() == AttributeList::AT_objc_ownership) + return; + + transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing, + outermostPointerIndex); + + // Any other number of pointers/references does not trigger the rule. + } else return; + + // TODO: mark whether we did this inference? +} + static void DiagnoseIgnoredQualifiers(unsigned Quals, SourceLocation ConstQualLoc, SourceLocation VolatileQualLoc, @@ -1513,47 +1691,28 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals, << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; } -/// GetTypeForDeclarator - Convert the type for the specified -/// declarator to Type instances. -/// -/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq -/// owns the declaration of a type (e.g., the definition of a struct -/// type), then *OwnedDecl will receive the owned declaration. -/// -/// The result of this call will never be null, but the associated -/// type may be a null type if there's an unrecoverable error. -TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl, - bool AutoAllowedInTypeName) { - // Determine the type of the declarator. Not all forms of declarator - // have a type. +static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, + TypeSourceInfo *&ReturnTypeInfo) { + Sema &SemaRef = state.getSema(); + Declarator &D = state.getDeclarator(); QualType T; - TypeSourceInfo *ReturnTypeInfo = 0; - - TypeProcessingState state(*this, D); + ReturnTypeInfo = 0; - // In C++0x, deallocation functions (normal and array operator delete) - // are implicitly noexcept. - bool ImplicitlyNoexcept = false; + // The TagDecl owned by the DeclSpec. + TagDecl *OwnedTagDecl = 0; switch (D.getName().getKind()) { + case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: - if (getLangOptions().CPlusPlus0x) { - OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; - if (OO == OO_Delete || OO == OO_Array_Delete) - ImplicitlyNoexcept = true; - } - // Intentional fall-through. case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(*this, state); + T = ConvertDeclSpecToType(state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { - TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); + OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); // Owned declaration is embedded in declarator. - Owned->setEmbeddedInDeclarator(true); - if (OwnedDecl) *OwnedDecl = Owned; + OwnedTagDecl->setEmbeddedInDeclarator(true); } break; @@ -1562,14 +1721,14 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case UnqualifiedId::IK_DestructorName: // Constructors and destructors don't have return types. Use // "void" instead. - T = Context.VoidTy; + T = SemaRef.Context.VoidTy; break; case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. - T = GetTypeFromParser(D.getName().ConversionFunctionId, - &ReturnTypeInfo); + T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, + &ReturnTypeInfo); break; } @@ -1581,7 +1740,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - (!getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) { + (!SemaRef.getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) { int Error = -1; switch (D.getContext()) { @@ -1595,7 +1754,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::MemberContext: if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; - switch (cast<TagDecl>(CurContext)->getTagKind()) { + switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { case TTK_Enum: assert(0 && "unhandled tag kind"); break; case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; @@ -1603,6 +1762,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } break; case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: Error = 4; // Exception declaration break; case Declarator::TemplateParamContext: @@ -1619,13 +1779,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 9; // Type alias break; case Declarator::TypeNameContext: - if (!AutoAllowedInTypeName) - Error = 11; // Generic + Error = 11; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: + case Declarator::CXXNewContext: break; } @@ -1640,7 +1800,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // contains a trailing return type. That is only legal at the outermost // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. - if (getLangOptions().CPlusPlus0x && Error != -1) { + if (SemaRef.getLangOptions().CPlusPlus0x && Error != -1) { for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -1656,15 +1816,86 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (Error != -1) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed) + SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_auto_not_allowed) << Error; - T = Context.IntTy; + T = SemaRef.Context.IntTy; D.setInvalidType(true); } } - - if (T.isNull()) - return Context.getNullTypeSourceInfo(); + + if (SemaRef.getLangOptions().CPlusPlus && + OwnedTagDecl && OwnedTagDecl->isDefinition()) { + // Check the contexts where C++ forbids the declaration of a new class + // or enumeration in a type-specifier-seq. + switch (D.getContext()) { + case Declarator::FileContext: + case Declarator::MemberContext: + case Declarator::BlockContext: + case Declarator::ForContext: + case Declarator::BlockLiteralContext: + // C++0x [dcl.type]p3: + // A type-specifier-seq shall not define a class or enumeration unless + // it appears in the type-id of an alias-declaration (7.1.3) that is not + // the declaration of a template-declaration. + case Declarator::AliasDeclContext: + break; + case Declarator::AliasTemplateContext: + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_alias_template) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::TypeNameContext: + case Declarator::TemplateParamContext: + case Declarator::CXXNewContext: + case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: + case Declarator::TemplateTypeArgContext: + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_type_specifier) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::PrototypeContext: + case Declarator::ObjCPrototypeContext: + case Declarator::KNRTypeListContext: + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_param_type) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::ConditionContext: + // C++ 6.4p2: + // The type-specifier-seq shall not contain typedef and shall not declare + // a new class or enumeration. + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_condition); + break; + } + } + + return T; +} + +static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, + QualType declSpecType, + TypeSourceInfo *TInfo) { + + QualType T = declSpecType; + Declarator &D = state.getDeclarator(); + Sema &S = state.getSema(); + ASTContext &Context = S.Context; + const LangOptions &LangOpts = S.getLangOptions(); + + bool ImplicitlyNoexcept = false; + if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId && + LangOpts.CPlusPlus0x) { + OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; + /// In C++0x, deallocation functions (normal and array operator delete) + /// are implicitly noexcept. + if (OO == OO_Delete || OO == OO_Array_Delete) + ImplicitlyNoexcept = true; + } // The name we're declaring, if any. DeclarationName Name; @@ -1687,56 +1918,56 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::Paren: - T = BuildParenType(T); + T = S.BuildParenType(T); break; case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) - Diag(DeclType.Loc, diag::err_blocks_disable); + S.Diag(DeclType.Loc, diag::err_blocks_disable); - T = BuildBlockPointerType(T, D.getIdentifierLoc(), Name); + T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); break; case DeclaratorChunk::Pointer: // Verify that we're not building a pointer to pointer to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } - if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) { + if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); if (DeclType.Ptr.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; } - T = BuildPointerType(T, DeclType.Loc, Name); + T = S.BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } - T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name); + T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name); Qualifiers Quals; if (DeclType.Ref.HasRestrict) - T = BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict); + T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict); break; } case DeclaratorChunk::Array: { // Verify that we're not building an array of pointers to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } @@ -1753,13 +1984,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // FIXME: This check isn't quite right: it allows star in prototypes // for function definitions, and disallows some edge cases detailed // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html - Diag(DeclType.Loc, diag::err_array_star_outside_prototype); + S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype); ASM = ArrayType::Normal; D.setInvalidType(true); } - T = BuildArrayType(T, ASM, ArraySize, - Qualifiers::fromCVRMask(ATI.TypeQuals), - SourceRange(DeclType.Loc, DeclType.EndLoc), Name); + T = S.BuildArrayType(T, ASM, ArraySize, + Qualifiers::fromCVRMask(ATI.TypeQuals), + SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; } case DeclaratorChunk::Function: { @@ -1775,27 +2006,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // and not, for instance, a pointer to a function. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && !FTI.TrailingReturnType && chunkIndex == 0) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_missing_trailing_return); T = Context.IntTy; D.setInvalidType(true); } else if (FTI.TrailingReturnType) { // T must be exactly 'auto' at this point. See CWG issue 681. if (isa<ParenType>(T)) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_in_parens) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (T.hasQualifiers() || !isa<AutoType>(T)) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } - T = GetTypeFromParser( + T = S.GetTypeFromParser( ParsedType::getFromOpaquePtr(FTI.TrailingReturnType), - &ReturnTypeInfo); + &TInfo); } } @@ -1809,7 +2040,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (chunkIndex == 0 && D.getContext() == Declarator::BlockLiteralContext) diagID = diag::err_block_returning_array_function; - Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; + S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } @@ -1818,7 +2049,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // class type in C++. if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) && - (!getLangOptions().CPlusPlus || !T->isDependentType())) { + (!LangOpts.CPlusPlus || !T->isDependentType())) { assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?"); DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer); @@ -1829,43 +2060,43 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), - *this); + S); } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() && - (!getLangOptions().CPlusPlus || + (!LangOpts.CPlusPlus || (!T->isDependentType() && !T->isRecordType()))) { DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(), D.getDeclSpec().getConstSpecLoc(), D.getDeclSpec().getVolatileSpecLoc(), D.getDeclSpec().getRestrictSpecLoc(), - *this); + S); } - if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { + if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); if (Tag->isDefinition()) - Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) + S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) << Context.getTypeDeclType(Tag); } // Exception specs are not allowed in typedefs. Complain, but add it // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) - Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) + S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) << (D.getContext() == Declarator::AliasDeclContext || D.getContext() == Declarator::AliasTemplateContext); - if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { + if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan // for this attribute now. - if (!FTI.NumArgs && FTI.isVariadic && !getLangOptions().CPlusPlus) { + if (!FTI.NumArgs && FTI.isVariadic && !LangOpts.CPlusPlus) { bool Overloadable = false; for (const AttributeList *Attrs = D.getAttributes(); Attrs; Attrs = Attrs->getNext()) { @@ -1876,13 +2107,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (!Overloadable) - Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); + S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); } if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function // definition. - Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); D.setInvalidType(true); break; } @@ -1899,13 +2130,18 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, llvm::SmallVector<QualType, 16> ArgTys; ArgTys.reserve(FTI.NumArgs); + llvm::SmallVector<bool, 16> ConsumedArguments; + ConsumedArguments.reserve(FTI.NumArgs); + bool HasAnyConsumedArguments = false; + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // Adjust the parameter type. - assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?"); + assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) && + "Unadjusted type?"); // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record @@ -1915,19 +2151,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // is an incomplete type (C99 6.2.5p19) and function decls cannot // have arguments of incomplete type. if (FTI.NumArgs != 1 || FTI.isVariadic) { - Diag(DeclType.Loc, diag::err_void_only_param); + S.Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; Param->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. - Diag(FTI.ArgInfo[i].IdentLoc, + S.Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.hasQualifiers()) - Diag(DeclType.Loc, diag::err_void_param_qualified); + S.Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. break; @@ -1944,19 +2180,28 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } + if (LangOpts.ObjCAutoRefCount) { + bool Consumed = Param->hasAttr<NSConsumedAttr>(); + ConsumedArguments.push_back(Consumed); + HasAnyConsumedArguments |= Consumed; + } + ArgTys.push_back(ArgTy); } + if (HasAnyConsumedArguments) + EPI.ConsumedArguments = ConsumedArguments.data(); + llvm::SmallVector<QualType, 4> Exceptions; EPI.ExceptionSpecType = FTI.getExceptionSpecType(); if (FTI.getExceptionSpecType() == EST_Dynamic) { Exceptions.reserve(FTI.NumExceptions); for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { // FIXME: Preserve type source info. - QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); + QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty); // Check that the type is valid for an exception spec, and // drop it if not. - if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) + if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) Exceptions.push_back(ET); } EPI.NumExceptions = Exceptions.size(); @@ -1973,7 +2218,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (!NoexceptExpr->isValueDependent() && !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc, /*evaluated*/false)) - Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) + S.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) << NoexceptExpr->getSourceRange(); else EPI.NoexceptExpr = NoexceptExpr; @@ -1996,8 +2241,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); - } else if (isDependentScopeSpecifier(SS) || - dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS))) { + } else if (S.isDependentScopeSpecifier(SS) || + dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) { NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); @@ -2026,7 +2271,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } } else { - Diag(DeclType.Mem.Scope().getBeginLoc(), + S.Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") << DeclType.Mem.Scope().getRange(); @@ -2034,12 +2279,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (!ClsType.isNull()) - T = BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); + T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); } else if (DeclType.Mem.TypeQuals) { - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); } break; } @@ -2054,7 +2299,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, processTypeAttrs(state, T, false, attrs); } - if (getLangOptions().CPlusPlus && T->isFunctionType()) { + if (LangOpts.CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); @@ -2071,7 +2316,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FreeFunction = (D.getContext() != Declarator::MemberContext || D.getDeclSpec().isFriendSpecified()); } else { - DeclContext *DC = computeDeclContext(D.getCXXScopeSpec()); + DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec()); FreeFunction = (DC && !DC->isRecord()); } @@ -2109,16 +2354,16 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::ext_qualified_function_type_template_arg) << Quals; } else { if (FnTy->getTypeQuals() != 0) { if (D.isFunctionDeclarator()) - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); else - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_typedef_function_type_use) << FreeFunction; } @@ -2135,11 +2380,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - Diag(Loc, diag::err_invalid_ref_qualifier_function_type) + S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type) << (FnTy->getRefQualifier() == RQ_LValue) << FixItHint::CreateRemoval(Loc); } else { - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_ref_qualifier_typedef_function_type_use) << FreeFunction << (FnTy->getRefQualifier() == RQ_LValue); @@ -2192,7 +2437,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // We represent function parameter packs as function parameters whose // type is a pack expansion. if (!T->containsUnexpandedParameterPack()) { - Diag(D.getEllipsisLoc(), + S.Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_without_parameter_packs) << T << D.getSourceRange(); D.setEllipsisLoc(SourceLocation()); @@ -2212,14 +2457,15 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); - else if (!getLangOptions().CPlusPlus0x) - Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); + else if (!LangOpts.CPlusPlus0x) + S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); break; case Declarator::FileContext: case Declarator::KNRTypeListContext: case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: + case Declarator::CXXNewContext: case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: case Declarator::MemberContext: @@ -2227,11 +2473,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::ForContext: case Declarator::ConditionContext: case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: case Declarator::BlockLiteralContext: case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. - Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); + S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); D.setEllipsisLoc(SourceLocation()); break; } @@ -2241,7 +2488,138 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, return Context.getNullTypeSourceInfo(); else if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); - return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo); + + return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); +} + +/// GetTypeForDeclarator - Convert the type for the specified +/// declarator to Type instances. +/// +/// The result of this call will never be null, but the associated +/// type may be a null type if there's an unrecoverable error. +TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { + // Determine the type of the declarator. Not all forms of declarator + // have a type. + + TypeProcessingState state(*this, D); + + TypeSourceInfo *ReturnTypeInfo = 0; + QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); + if (T.isNull()) + return Context.getNullTypeSourceInfo(); + + if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount) + inferARCWriteback(state, T); + + return GetFullTypeForDeclarator(state, T, ReturnTypeInfo); +} + +static void transferARCOwnershipToDeclSpec(Sema &S, + QualType &declSpecTy, + Qualifiers::ObjCLifetime ownership) { + if (declSpecTy->isObjCRetainableType() && + declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) { + Qualifiers qs; + qs.addObjCLifetime(ownership); + declSpecTy = S.Context.getQualifiedType(declSpecTy, qs); + } +} + +static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, + Qualifiers::ObjCLifetime ownership, + unsigned chunkIndex) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + // Look for an explicit lifetime attribute. + DeclaratorChunk &chunk = D.getTypeObject(chunkIndex); + for (const AttributeList *attr = chunk.getAttrs(); attr; + attr = attr->getNext()) + if (attr->getKind() == AttributeList::AT_objc_ownership) + return; + + const char *attrStr = 0; + switch (ownership) { + case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break; + case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break; + case Qualifiers::OCL_Strong: attrStr = "strong"; break; + case Qualifiers::OCL_Weak: attrStr = "weak"; break; + case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break; + } + + // If there wasn't one, add one (with an invalid source location + // so that we don't make an AttributedType for it). + AttributeList *attr = D.getAttributePool() + .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(), + /*scope*/ 0, SourceLocation(), + &S.Context.Idents.get(attrStr), SourceLocation(), + /*args*/ 0, 0, + /*declspec*/ false, /*C++0x*/ false); + spliceAttrIntoList(*attr, chunk.getAttrListRef()); + + // TODO: mark whether we did this inference? +} + +static void transferARCOwnership(TypeProcessingState &state, + QualType &declSpecTy, + Qualifiers::ObjCLifetime ownership) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + int inner = -1; + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = D.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Paren: + // Ignore parens. + break; + + case DeclaratorChunk::Array: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Pointer: + inner = i; + break; + + case DeclaratorChunk::BlockPointer: + return transferARCOwnershipToDeclaratorChunk(state, ownership, i); + + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + return; + } + } + + if (inner == -1) + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + + DeclaratorChunk &chunk = D.getTypeObject(inner); + if (chunk.Kind == DeclaratorChunk::Pointer) { + if (declSpecTy->isObjCRetainableType()) + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + if (declSpecTy->isObjCObjectType()) + return transferARCOwnershipToDeclaratorChunk(state, ownership, inner); + } else { + assert(chunk.Kind == DeclaratorChunk::Array || + chunk.Kind == DeclaratorChunk::Reference); + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + } +} + +TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { + TypeProcessingState state(*this, D); + + TypeSourceInfo *ReturnTypeInfo = 0; + QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); + if (declSpecTy.isNull()) + return Context.getNullTypeSourceInfo(); + + if (getLangOptions().ObjCAutoRefCount) { + Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy); + if (ownership != Qualifiers::OCL_None) + transferARCOwnership(state, declSpecTy, ownership); + } + + return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); } /// Map an AttributedType::Kind to an AttributeList::Kind. @@ -2259,6 +2637,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_neon_polyvector_type; case AttributedType::attr_objc_gc: return AttributeList::AT_objc_gc; + case AttributedType::attr_objc_ownership: + return AttributeList::AT_objc_ownership; case AttributedType::attr_noreturn: return AttributeList::AT_noreturn; case AttributedType::attr_cdecl: @@ -2489,6 +2869,9 @@ namespace { llvm_unreachable("qualified type locs not expected here!"); } + void VisitAttributedTypeLoc(AttributedTypeLoc TL) { + fillAttributedTypeLoc(TL, Chunk.getAttrs()); + } void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::BlockPointer); TL.setCaretLoc(Chunk.Loc); @@ -2657,8 +3040,7 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - TagDecl *OwnedTag = 0; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (D.isInvalidType()) return true; @@ -2666,26 +3048,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); - - // C++0x [dcl.type]p3: - // A type-specifier-seq shall not define a class or enumeration unless - // it appears in the type-id of an alias-declaration (7.1.3) that is not - // the declaration of a template-declaration. - if (OwnedTag && OwnedTag->isDefinition()) { - if (D.getContext() == Declarator::AliasTemplateContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template) - << Context.getTypeDeclType(OwnedTag); - else if (D.getContext() != Declarator::AliasDeclContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) - << Context.getTypeDeclType(OwnedTag); - } } return CreateParsedType(T, TInfo); } - - //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// @@ -2744,6 +3111,99 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } +/// handleObjCOwnershipTypeAttr - Process an objc_ownership +/// attribute on the specified type. +/// +/// Returns 'true' if the attribute was handled. +static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type) { + if (!type->isObjCRetainableType() && !type->isDependentType()) + return false; + + Sema &S = state.getSema(); + + if (type.getQualifiers().getObjCLifetime()) { + S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant) + << type; + return true; + } + + if (!attr.getParameterName()) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "objc_ownership" << 1; + attr.setInvalid(); + return true; + } + + Qualifiers::ObjCLifetime lifetime; + if (attr.getParameterName()->isStr("none")) + lifetime = Qualifiers::OCL_ExplicitNone; + else if (attr.getParameterName()->isStr("strong")) + lifetime = Qualifiers::OCL_Strong; + else if (attr.getParameterName()->isStr("weak")) + lifetime = Qualifiers::OCL_Weak; + else if (attr.getParameterName()->isStr("autoreleasing")) + lifetime = Qualifiers::OCL_Autoreleasing; + else { + S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) + << "objc_ownership" << attr.getParameterName(); + attr.setInvalid(); + return true; + } + + // Consume lifetime attributes without further comment outside of + // ARC mode. + if (!S.getLangOptions().ObjCAutoRefCount) + return true; + + Qualifiers qs; + qs.setObjCLifetime(lifetime); + QualType origType = type; + type = S.Context.getQualifiedType(type, qs); + + // If we have a valid source location for the attribute, use an + // AttributedType instead. + if (attr.getLoc().isValid()) + type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, + origType, type); + + // Forbid __weak if the runtime doesn't support it. + if (lifetime == Qualifiers::OCL_Weak && + !S.getLangOptions().ObjCRuntimeHasWeak) { + + // Actually, delay this until we know what we're parsing. + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(), + diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); + } else { + S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime); + } + + attr.setInvalid(); + return true; + } + + // Forbid __weak for class objects marked as + // objc_arc_weak_reference_unavailable + if (lifetime == Qualifiers::OCL_Weak) { + QualType T = type; + while (const PointerType *ptr = T->getAs<PointerType>()) + T = ptr->getPointeeType(); + if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { + ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); + if (Class->isArcWeakrefUnavailable()) { + S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class); + S.Diag(ObjT->getInterfaceDecl()->getLocation(), + diag::note_class_declared); + } + } + } + + return true; +} + /// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type /// attribute on the specified type. Returns true to indicate that /// the attribute was handled, false to indicate that the type does @@ -2954,6 +3414,23 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } + // ns_returns_retained is not always a type attribute, but if we got + // here, we're treating it as one right now. + if (attr.getKind() == AttributeList::AT_ns_returns_retained) { + assert(S.getLangOptions().ObjCAutoRefCount && + "ns_returns_retained treated as type attribute in non-ARC"); + if (attr.getNumArgs()) return true; + + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + + FunctionType::ExtInfo EI + = unwrapped.get()->getExtInfo().withProducesResult(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + if (attr.getKind() == AttributeList::AT_regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) @@ -3127,6 +3604,40 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, VectorType::GenericVector); } +/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on +/// a type. +static void HandleExtVectorTypeAttr(QualType &CurType, + const AttributeList &Attr, + Sema &S) { + Expr *sizeExpr; + + // Special case where the argument is a template id. + if (Attr.getParameterName()) { + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(Attr.getParameterName(), Attr.getLoc()); + + ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false, + false); + if (Size.isInvalid()) + return; + + sizeExpr = Size.get(); + } else { + // check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + sizeExpr = Attr.getArg(0); + } + + // Create the vector type. + QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc()); + if (!T.isNull()) + CurType = T; +} + /// HandleNeonVectorTypeAttr - The "neon_vector_type" and /// "neon_polyvector_type" attributes are used to create vector types that /// are mangled according to ARM's ABI. Otherwise, these types are identical @@ -3217,6 +3728,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_vector_size: HandleVectorSizeAttr(type, attr, state.getSema()); break; + case AttributeList::AT_ext_vector_type: + if (state.getDeclarator().getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) + HandleExtVectorTypeAttr(type, attr, state.getSema()); + break; case AttributeList::AT_neon_vector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector, "neon_vector_type"); @@ -3226,11 +3742,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, VectorType::NeonPolyVector, "neon_polyvector_type"); break; - case AttributeList::AT_opencl_image_access: HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); break; + case AttributeList::AT_ns_returns_retained: + if (!state.getSema().getLangOptions().ObjCAutoRefCount) + break; + // fallthrough into the function attrs + FUNCTION_TYPE_ATTRS_CASELIST: // Never process function type attributes as part of the // declaration-specifiers. diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ff2e46a..fa87217 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1192,6 +1192,16 @@ public: Body); } + /// \brief Build a new Objective-C @autoreleasepool statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildObjCAutoreleasePoolStmt(SourceLocation AtLoc, + Stmt *Body) { + return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); + } + + /// \brief Build a new Objective-C fast enumeration statement. /// /// By default, performs semantic analysis to build the new statement. @@ -1537,9 +1547,9 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildInitList(SourceLocation LBraceLoc, - MultiExprArg Inits, - SourceLocation RBraceLoc, - QualType ResultTy) { + MultiExprArg Inits, + SourceLocation RBraceLoc, + QualType ResultTy) { ExprResult Result = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc); if (Result.isInvalid() || ResultTy->isDependentType()) @@ -1856,8 +1866,9 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub) { - return getSema().ActOnCXXThrow(ThrowLoc, Sub); + ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub, + bool IsThrownVariableInScope) { + return getSema().BuildCXXThrow(ThrowLoc, Sub, IsThrownVariableInScope); } /// \brief Build a new C++ default-argument expression. @@ -2466,6 +2477,10 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, Outputs.push_back(Out.get()); continue; } + + // Record right away that the argument was changed. This needs + // to happen even if the array expands to nothing. + if (ArgChanged) *ArgChanged = true; // The transform has determined that we should perform an elementwise // expansion of the pattern. Do so. @@ -2482,8 +2497,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, return true; } - if (ArgChanged) - *ArgChanged = true; Outputs.push_back(Out.get()); } @@ -3162,6 +3175,38 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, if (Result->isFunctionType() || Result->isReferenceType()) return Result; + // Suppress Objective-C lifetime qualifiers if they don't make sense for the + // resulting type. + if (Quals.hasObjCLifetime()) { + if (!Result->isObjCLifetimeType() && !Result->isDependentType()) + Quals.removeObjCLifetime(); + else if (Result.getObjCLifetime()) { + // Objective-C ARC: + // A lifetime qualifier applied to a substituted template parameter + // overrides the lifetime qualifier from the template argument. + if (const SubstTemplateTypeParmType *SubstTypeParam + = dyn_cast<SubstTemplateTypeParmType>(Result)) { + QualType Replacement = SubstTypeParam->getReplacementType(); + Qualifiers Qs = Replacement.getQualifiers(); + Qs.removeObjCLifetime(); + Replacement + = SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), + Qs); + Result = SemaRef.Context.getSubstTemplateTypeParmType( + SubstTypeParam->getReplacedParameter(), + Replacement); + TLB.TypeWasModifiedSafely(Result); + } else { + // Otherwise, complain about the addition of a qualifier to an + // already-qualified type. + SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange(); + SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant) + << Result << R; + + Quals.removeObjCLifetime(); + } + } + } if (!Quals.empty()) { Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals); TLB.push<QualifiedTypeLoc>(Result); @@ -3333,7 +3378,11 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, if (Result.isNull()) return QualType(); } - + + // Objective-C ARC can add lifetime qualifiers to the type that we're + // pointing to. + TLB.TypeWasModifiedSafely(Result->getPointeeType()); + PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result); NewT.setSigilLoc(TL.getSigilLoc()); return Result; @@ -3387,6 +3436,11 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, return QualType(); } + // Objective-C ARC can add lifetime qualifiers to the type that we're + // referring to. + TLB.TypeWasModifiedSafely( + Result->getAs<ReferenceType>()->getPointeeTypeAsWritten()); + // r-value references can be rebuilt as l-value references. ReferenceTypeLoc NewTL; if (isa<LValueReferenceType>(Result)) @@ -5435,6 +5489,25 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( template<typename Derived> StmtResult +TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt( + ObjCAutoreleasePoolStmt *S) { + // Transform the body. + StmtResult Body = getDerived().TransformStmt(S->getSubStmt()); + if (Body.isInvalid()) + return StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Body.get() == S->getSubStmt()) + return SemaRef.Owned(S); + + // Build a new statement. + return getDerived().RebuildObjCAutoreleasePoolStmt( + S->getAtLoc(), Body.get()); +} + +template<typename Derived> +StmtResult TreeTransform<Derived>::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { // Transform the element statement. @@ -6721,7 +6794,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E); - return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get()); + return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get(), + E->isThrownVariableInScope()); } template<typename Derived> @@ -6867,9 +6941,13 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { AllocType, AllocTypeInfo, ArraySize.get(), - /*FIXME:*/E->getLocStart(), + /*FIXME:*/E->hasInitializer() + ? E->getLocStart() + : SourceLocation(), move_arg(ConstructorArgs), - E->getLocEnd()); + /*FIXME:*/E->hasInitializer() + ? E->getLocEnd() + : SourceLocation()); } template<typename Derived> @@ -7587,6 +7665,21 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformMaterializeTemporaryExpr( + MaterializeTemporaryExpr *E) { + return getDerived().TransformExpr(E->GetTemporaryExpr()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { return SemaRef.Owned(E); } @@ -7609,6 +7702,43 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { } template<typename Derived> +ExprResult TreeTransform<Derived>:: +TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { + ExprResult result = getDerived().TransformExpr(E->getSubExpr()); + if (result.isInvalid()) return ExprError(); + Expr *subExpr = result.take(); + + if (!getDerived().AlwaysRebuild() && + subExpr == E->getSubExpr()) + return SemaRef.Owned(E); + + return SemaRef.Owned(new(SemaRef.Context) + ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy())); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>:: +TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { + TypeSourceInfo *TSInfo + = getDerived().TransformType(E->getTypeInfoAsWritten()); + if (!TSInfo) + return ExprError(); + + ExprResult Result = getDerived().TransformExpr(E->getSubExpr()); + if (Result.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + TSInfo == E->getTypeInfoAsWritten() && + Result.get() == E->getSubExpr()) + return SemaRef.Owned(E); + + return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(), + E->getBridgeKeywordLoc(), TSInfo, + Result.get()); +} + +template<typename Derived> ExprResult TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // Transform arguments. @@ -8227,11 +8357,24 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First); } - if (Op == OO_Subscript) - return SemaRef.CreateOverloadedArraySubscriptExpr(Callee->getLocStart(), - OpLoc, - First, - Second); + if (Op == OO_Subscript) { + SourceLocation LBrace; + SourceLocation RBrace; + + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) { + DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo(); + LBrace = SourceLocation::getFromRawEncoding( + NameLoc.CXXOperatorName.BeginOpNameLoc); + RBrace = SourceLocation::getFromRawEncoding( + NameLoc.CXXOperatorName.EndOpNameLoc); + } else { + LBrace = Callee->getLocStart(); + RBrace = OpLoc; + } + + return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace, + First, Second); + } // Create the overloaded operator invocation for binary operators. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index 3570737..7a5e43e 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -16,7 +16,6 @@ #define LLVM_CLANG_SEMA_TYPELOCBUILDER_H #include "clang/AST/TypeLoc.h" -#include "llvm/ADT/SmallVector.h" #include "clang/AST/ASTContext.h" namespace clang { @@ -87,6 +86,14 @@ class TypeLocBuilder { Index = Capacity; } + /// \brief Tell the TypeLocBuilder that the type it is storing has been + /// modified in some safe way that doesn't affect type-location information. + void TypeWasModifiedSafely(QualType T) { +#ifndef NDEBUG + LastTy = T; +#endif + } + /// Pushes space for a new TypeLoc of the given type. Invalidates /// any TypeLocs previously retrieved from this builder. template <class TyLocType> TyLocType push(QualType T) { @@ -139,7 +146,7 @@ private: Index -= LocalSize; - return getTypeLoc(T); + return getTemporaryTypeLoc(T); } /// Grow to the given capacity. @@ -171,15 +178,17 @@ private: reserve(Size); Index -= Size; - return getTypeLoc(T); + return getTemporaryTypeLoc(T); } - - // This is private because, when we kill off TypeSourceInfo in favor - // of TypeLoc, we'll want an interface that creates a TypeLoc given - // an ASTContext, and we don't want people to think they can just - // use this as an equivalent. - TypeLoc getTypeLoc(QualType T) { +public: + /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder + /// object. + /// + /// The resulting \c TypeLoc should only be used so long as the + /// \c TypeLocBuilder is active and has not had more type information + /// pushed into it. + TypeLoc getTemporaryTypeLoc(QualType T) { #ifndef NDEBUG assert(LastTy == T && "type doesn't match last type pushed!"); #endif |