diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
commit | 8aaf5818a64e9f7687798852af5945b053c68a54 (patch) | |
tree | d6a70c3518b8dea8be7062438d7e8676820ed17f /lib/Sema | |
parent | 71438373cd57f0d5d8c93bb5cf690844a0fbc9d0 (diff) | |
download | FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.zip FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.tar.gz |
Update clang to r103004.
Diffstat (limited to 'lib/Sema')
33 files changed, 8218 insertions, 4469 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index d1f00ca..6ded0a3 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -25,7 +25,6 @@ #include "clang/Analysis/Analyses/ReachableCode.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Casting.h" -#include <queue> using namespace clang; @@ -75,7 +74,6 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; llvm::BitVector live(cfg->getNumBlockIDs()); unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), live); @@ -149,7 +147,8 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (B.succ_begin()[0] != &cfg->getExit()) { + if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) + == B.succ_end()) { HasAbnormalEdge = true; continue; } @@ -190,7 +189,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_NeverFallThroughOrReturn; bool funMode; - static CheckFallThroughDiagnostics MakeForFunction() { + static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = diag::warn_falloff_noreturn_function; @@ -200,8 +199,19 @@ struct CheckFallThroughDiagnostics { diag::warn_falloff_noreturn_function; D.diag_AlwaysFallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid_function; - D.diag_NeverFallThroughOrReturn = - diag::warn_suggest_noreturn_function; + + // Don't suggest that virtual functions be marked "noreturn", since they + // might be overridden by non-noreturn functions. + bool isVirtualMethod = false; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) + isVirtualMethod = Method->isVirtual(); + + if (!isVirtualMethod) + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_function; + else + D.diag_NeverFallThroughOrReturn = 0; + D.funMode = true; return D; } @@ -297,7 +307,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); break; @@ -325,8 +335,7 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { void clang::sema:: AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, - const Decl *D, QualType BlockTy, - const bool analyzeStaticInline) { + const Decl *D, QualType BlockTy) { assert(BlockTy.isNull() || isa<BlockDecl>(D)); @@ -336,12 +345,14 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // don't bother trying. // (2) The code already has problems; running the analysis just takes more // time. - if (S.getDiagnostics().hasErrorOccurred()) + Diagnostic &Diags = S.getDiagnostics(); + + if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; // Do not do any analysis for declarations in system headers if we are // going to just ignore them. - if (S.getDiagnostics().getSuppressSystemWarnings() && + if (Diags.getSuppressSystemWarnings() && S.SourceMgr.isInSystemHeader(D->getLocation())) return; @@ -350,17 +361,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; - - // Only analyze 'static inline' functions when explicitly asked. - if (!analyzeStaticInline && FD->isInlineSpecified() && - FD->getStorageClass() == FunctionDecl::Static) { - FD = FD->getCanonicalDecl(); - VisitFlag &visitFlag = VisitedFD[FD]; - if (visitFlag == Pending) - visitFlag = Visited; - else - return; - } } const Stmt *Body = D->getBody(); @@ -369,61 +369,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. AnalysisContext AC(D, false); - bool performedCheck = false; // Warning: check missing 'return' if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() - : CheckFallThroughDiagnostics::MakeForFunction()); + : CheckFallThroughDiagnostics::MakeForFunction(D)); CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); - performedCheck = true; } // Warning: check for unreachable code - if (P.enableCheckUnreachable) { + if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - performedCheck = true; - } - - // If this block or function calls a 'static inline' function, - // we should analyze those functions as well. - if (performedCheck) { - // The CFG should already be constructed, so this should not - // incur any extra cost. We might not have a CFG, however, for - // invalid code. - if (const CFG *cfg = AC.getCFG()) { - // All CallExprs are block-level expressions in the CFG. This means - // that walking the basic blocks in the CFG is more efficient - // than walking the entire AST to find all calls. - for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) { - const CFGBlock *B = *I; - for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI) - if (const CallExpr *CE = dyn_cast<CallExpr>(*BI)) - if (const DeclRefExpr *DR = - dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts())) - if (const FunctionDecl *calleeD = - dyn_cast<FunctionDecl>(DR->getDecl())) { - calleeD = calleeD->getCanonicalDecl(); - if (calleeD->isInlineSpecified() && - calleeD->getStorageClass() == FunctionDecl::Static) { - // Have we analyzed this static inline function before? - VisitFlag &visitFlag = VisitedFD[calleeD]; - if (visitFlag == NotVisited) { - // Mark the callee visited prior to analyzing it - // so we terminate in case of recursion. - if (calleeD->getBody()) { - visitFlag = Visited; - IssueWarnings(DefaultPolicy, calleeD, QualType(), true); - } - else { - // Delay warnings until we encounter the definition. - visitFlag = Pending; - } - } - } - } - } - } - } } diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h index b5db8af..dea19ba 100644 --- a/lib/Sema/AnalysisBasedWarnings.h +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -47,9 +47,7 @@ public: Policy getDefaultPolicy() { return DefaultPolicy; } - void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(), - const bool analyzeStaticInline = false); - + void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType()); }; }} // end namespace clang::sema diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 5483a29..0ef9a15 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -86,7 +86,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) break; case CK_Colon: - this->Text = ": "; + this->Text = ":"; break; case CK_SemiColon: @@ -425,7 +425,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case Result::RK_Declaration: - OS << Results[I].Declaration->getNameAsString() ; + OS << Results[I].Declaration; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 1c761b9..0694294 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -155,8 +155,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { BuildScopeInformation(TryPart, Scopes.size()-1); // Jump from the catch to the finally or try is not valid. - for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC; - AC = AC->getNextCatchStmt()) { + for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *AC = AT->getCatchStmt(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, AC->getAtCatchLoc())); diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index f310c25..0961299 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -124,7 +124,6 @@ public: }; typedef UnresolvedSetImpl::iterator iterator; - typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, Sema::LookupNameKind LookupKind, @@ -136,7 +135,6 @@ public: Name(Name), NameLoc(NameLoc), LookupKind(LookupKind), - IsAcceptableFn(0), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), HideTags(true), @@ -156,7 +154,6 @@ public: Name(Other.Name), NameLoc(Other.NameLoc), LookupKind(Other.LookupKind), - IsAcceptableFn(Other.IsAcceptableFn), IDNS(Other.IDNS), Redecl(Other.Redecl), HideTags(Other.HideTags), @@ -242,8 +239,7 @@ public: /// \brief Tests whether the given declaration is acceptable. bool isAcceptableDecl(NamedDecl *D) const { - assert(IsAcceptableFn); - return IsAcceptableFn(D, IDNS); + return D->isInIdentifierNamespace(IDNS); } /// \brief Returns the identifier namespace mask for this lookup. @@ -282,6 +278,18 @@ public: NamingClass = Record; } + /// \brief Returns the base object type associated with this lookup; + /// important for [class.protected]. Most lookups do not have an + /// associated base object. + QualType getBaseObjectType() const { + return BaseObjectType; + } + + /// \brief Sets the base object type for this lookup. + void setBaseObjectType(QualType T) { + BaseObjectType = T; + } + /// \brief Add a declaration to these results with its natural access. /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { @@ -331,6 +339,11 @@ public: } else { ResultKind = Found; resolveKind(); + + if (Paths && (ResultKind != Ambiguous)) { + deletePaths(Paths); + Paths = 0; + } } } @@ -550,6 +563,7 @@ private: UnresolvedSet<8> Decls; CXXBasePaths *Paths; CXXRecordDecl *NamingClass; + QualType BaseObjectType; // Parameters. Sema &SemaRef; @@ -557,7 +571,6 @@ private: SourceLocation NameLoc; SourceRange NameContextRange; Sema::LookupNameKind LookupKind; - ResultFilter IsAcceptableFn; // set by configure() unsigned IDNS; // set by configure() bool Redecl; diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 7cd3989..bb0bd9e 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -24,6 +24,26 @@ using namespace clang; +static void DumpRecordLayouts(ASTContext &C) { + for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); + I != E; ++I) { + const RecordType *RT = dyn_cast<RecordType>(*I); + if (!RT) + continue; + + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD || RD->isImplicit() || RD->isDependentType() || + RD->isInvalidDecl() || !RD->getDefinition()) + continue; + + // FIXME: Do we really need to hard code this? + if (RD->getQualifiedNameAsString() == "__va_list_tag") + continue; + + C.DumpRecordLayout(RD, llvm::errs()); + } +} + //===----------------------------------------------------------------------===// // Public interface to the file //===----------------------------------------------------------------------===// @@ -44,8 +64,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); // Initialize the parser. P.Initialize(); @@ -82,6 +101,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, E = S.WeakTopLevelDecls().end(); I != E; ++I) Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); + // Dump record layouts, if requested. + if (PP.getLangOptions().DumpRecordLayouts) + DumpRecordLayouts(Ctx); + Consumer->HandleTranslationUnit(Ctx); if (ExternalSemaSource *ESS = diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index ccfbe1e..755af84 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -158,7 +158,8 @@ Sema::~Sema() { /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, - CastExpr::CastKind Kind, bool isLvalue) { + CastExpr::CastKind Kind, + bool isLvalue, CXXBaseSpecifierArray BasePath) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); @@ -177,14 +178,14 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { - if (ImpCast->getCastKind() == Kind) { + if (ImpCast->getCastKind() == Kind && BasePath.empty()) { ImpCast->setType(Ty); ImpCast->setLvalueCast(isLvalue); return; } } - Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); + Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, BasePath, isLvalue); } void Sema::DeleteExpr(ExprTy *E) { @@ -197,14 +198,7 @@ void Sema::DeleteStmt(StmtTy *S) { /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. -void Sema::ActOnEndOfTranslationUnit() { - - // Remove functions that turned out to be used. - UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), - UnusedStaticFuncs.end(), - std::mem_fun(&FunctionDecl::isUsed)), - UnusedStaticFuncs.end()); - +void Sema::ActOnEndOfTranslationUnit() { while (1) { // C++: Perform implicit template instantiations. // @@ -225,6 +219,12 @@ void Sema::ActOnEndOfTranslationUnit() { break; } + // Remove functions that turned out to be used. + UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), + UnusedStaticFuncs.end(), + std::mem_fun(&FunctionDecl::isUsed)), + UnusedStaticFuncs.end()); + // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0766b1e..f146c85 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -25,6 +25,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/FullExpr.h" #include "clang/Parse/Action.h" #include "clang/Sema/SemaDiagnostic.h" @@ -108,33 +109,33 @@ namespace clang { class TargetAttributesSema; class ADLResult; -/// \brief Retains information about a function, method, or block that is +/// \brief Retains information about a function, method, or block that is /// currently being parsed. struct FunctionScopeInfo { /// \brief Whether this scope information structure defined information for /// a block. bool IsBlockInfo; - - /// \brief Set true when a function, method contains a VLA or ObjC try block, + + /// \brief Set true when a function, method contains a VLA or ObjC try block, /// which introduce scopes that need to be checked for goto conditions. If a /// function does not contain this, then it need not have the jump checker run on it. bool NeedsScopeChecking; - + /// \brief The number of errors that had occurred before starting this /// function or block. unsigned NumErrorsAtStartOfFunction; - + /// LabelMap - This is a mapping from label identifiers to the LabelStmt for /// it (which acts like the label decl in some ways). Forward referenced /// labels have a LabelStmt created for them with a null location & SubStmt. llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; - + /// SwitchStack - This is the current set of active switch statements in the /// block. - llvm::SmallVector<SwitchStmt*, 8> SwitchStack; - - FunctionScopeInfo(unsigned NumErrors) - : IsBlockInfo(false), NeedsScopeChecking(false), + llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + + FunctionScopeInfo(unsigned NumErrors) + : IsBlockInfo(false), NeedsScopeChecking(false), NumErrorsAtStartOfFunction(NumErrors) { } virtual ~FunctionScopeInfo(); @@ -142,11 +143,11 @@ struct FunctionScopeInfo { /// \brief Clear out the information in this function scope, making it /// suitable for reuse. void Clear(unsigned NumErrors); - - static bool classof(const FunctionScopeInfo *FSI) { return true; } + + static bool classof(const FunctionScopeInfo *FSI) { return true; } }; - - + + /// \brief Retains information about a block that is currently being parsed. struct BlockScopeInfo : FunctionScopeInfo { llvm::SmallVector<ParmVarDecl*, 8> Params; @@ -164,11 +165,11 @@ struct BlockScopeInfo : FunctionScopeInfo { /// return types, if any, in the block body. QualType ReturnType; - BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), - hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) + BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) + : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), + hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) { - IsBlockInfo = true; + IsBlockInfo = true; } virtual ~BlockScopeInfo(); @@ -233,6 +234,30 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush) + : S(S), SavedContext(S.CurContext) { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + SavedContext = 0; + } + + ~ContextRAII() { + pop(); + } + }; + /// PackContext - Manages the stack for #pragma pack. An alignment /// of 0 indicates default alignment. void *PackContext; // Really a "PragmaPackStack*" @@ -240,14 +265,14 @@ public: /// \brief Stack containing information about each of the nested function, /// block, and method scopes that are currently active. llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes; - + /// \brief Cached function scope object used for the top function scope /// and when there is no function scope (in error cases). /// - /// This should never be accessed directly; rather, it's address will be + /// This should never be accessed directly; rather, it's address will be /// pushed into \c FunctionScopes when we want to re-use it. FunctionScopeInfo TopFunctionScope; - + /// ExprTemporaries - This is the stack of temporaries that are created by /// the current full expression. llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries; @@ -312,26 +337,17 @@ public: bool isMemberAccess() const { return IsMember; } - AccessedEntity(ASTContext &Context, - MemberNonce _, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - NamedDecl *Target) - : Access(Access), IsMember(true), - Target(Target), NamingClass(NamingClass), - Diag(0, Context.getDiagAllocator()) { - } - - AccessedEntity(ASTContext &Context, + AccessedEntity(ASTContext &Context, MemberNonce _, CXXRecordDecl *NamingClass, - DeclAccessPair FoundDecl) - : Access(FoundDecl.getAccess()), IsMember(true), + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : Access(FoundDecl.getAccess()), IsMember(true), Target(FoundDecl.getDecl()), NamingClass(NamingClass), - Diag(0, Context.getDiagAllocator()) { + BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(ASTContext &Context, + AccessedEntity(ASTContext &Context, BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, @@ -353,6 +369,10 @@ public: CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); } CXXRecordDecl *getDerivedClass() const { return NamingClass; } + /// Retrieves the base object type, important when accessing + /// an instance member. + QualType getBaseObjectType() const { return BaseObjectType; } + /// Sets a diagnostic to be performed. The diagnostic is given /// four (additional) arguments: /// %0 - 0 if the entity was private, 1 if protected @@ -377,7 +397,8 @@ public: unsigned Access : 2; bool IsMember; NamedDecl *Target; - CXXRecordDecl *NamingClass; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; PartialDiagnostic Diag; }; @@ -484,14 +505,14 @@ public: /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. CXXRecordDecl *StdBadAlloc; - + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// \brief The set of declarations that have been referenced within /// a potentially evaluated expression. - typedef std::vector<std::pair<SourceLocation, Decl *> > + typedef std::vector<std::pair<SourceLocation, Decl *> > PotentiallyReferencedDecls; /// \brief A set of diagnostics that may be emitted. @@ -522,8 +543,8 @@ public: PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, - unsigned NumTemporaries) - : Context(Context), NumTemporaries(NumTemporaries), + unsigned NumTemporaries) + : Context(Context), NumTemporaries(NumTemporaries), PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { @@ -618,11 +639,11 @@ public: /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); - /// \brief Build a partial diagnostic. + /// \brief Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0) { return PartialDiagnostic(DiagID, Context.getDiagAllocator()); } - + virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); @@ -646,13 +667,13 @@ public: void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); void PopFunctionOrBlockScope(); - + /// getLabelMap() - Return the current label map. If we're in a block, we /// return it. llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() { if (FunctionScopes.empty()) return TopFunctionScope.LabelMap; - + return FunctionScopes.back()->LabelMap; } @@ -661,24 +682,24 @@ public: llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() { if (FunctionScopes.empty()) return TopFunctionScope.SwitchStack; - + return FunctionScopes.back()->SwitchStack; } - /// \brief Determine whether the current function or block needs scope + /// \brief Determine whether the current function or block needs scope /// checking. bool &FunctionNeedsScopeChecking() { if (FunctionScopes.empty()) return TopFunctionScope.NeedsScopeChecking; - + return FunctionScopes.back()->NeedsScopeChecking; } - + bool hasAnyErrorsInThisFunction() const; - + /// \brief Retrieve the current block, if any. BlockScopeInfo *getCurBlock(); - + /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } @@ -708,7 +729,8 @@ public: QualType GetTypeForDeclarator(Declarator &D, Scope *S, TypeSourceInfo **TInfo = 0, TagDecl **OwnedDecl = 0); - TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo); /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo); DeclarationName GetNameForDeclarator(Declarator &D); @@ -745,7 +767,7 @@ public: const PartialDiagnostic &PD); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); - + QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); @@ -762,16 +784,16 @@ public: DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr); virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName = false, TypeTy *ObjectType = 0); virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); - virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, - const CXXScopeSpec *SS, + CXXScopeSpec *SS, TypeTy *&SuggestedType); - + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); } @@ -809,7 +831,12 @@ public: bool &OverloadableAttrRequired); void CheckMain(FunctionDecl *FD); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); - virtual void ActOnObjCCatchParam(DeclPtrTy D); + ParmVarDecl *CheckParameter(DeclContext *DC, + TypeSourceInfo *TSInfo, QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + VarDecl::StorageClass StorageClass, + VarDecl::StorageClass StorageClassAsWritten); virtual void ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg); @@ -847,11 +874,21 @@ public: /// ParmVarDecl pointers. template<typename InputIterator> void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) { + if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == + Diagnostic::Ignored) + return; + + // Don't diagnose unused-parameter errors in template instantiations; we + // will already have done so in the template itself. + if (!ActiveTemplateInstantiations.empty()) + return; + for (; Param != ParamEnd; ++Param) { if (!(*Param)->isUsed() && (*Param)->getDeclName() && - !(*Param)->template hasAttr<UnusedAttr>()) + !(*Param)->template hasAttr<UnusedAttr>()) { Diag((*Param)->getLocation(), diag::warn_unused_parameter) << (*Param)->getDeclName(); + } } } @@ -877,7 +914,7 @@ public: const IdentifierInfo &Name); virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -911,12 +948,14 @@ public: Declarator *D = 0); enum CXXSpecialMember { - CXXDefaultConstructor = 0, + CXXInvalid = -1, + CXXConstructor = 0, CXXCopyConstructor = 1, CXXCopyAssignment = 2, CXXDestructor = 3 }; void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, DeclPtrTy IntfDecl, @@ -1034,7 +1073,7 @@ public: AA_Sending, AA_Casting }; - + /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are @@ -1058,9 +1097,7 @@ public: TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, - bool ForceRValue, - bool InOverloadResolution, - bool UserCast = false); + bool InOverloadResolution); bool IsStandardConversion(Expr *From, QualType ToType, bool InOverloadResolution, StandardConversionSequence& SCS); @@ -1072,24 +1109,27 @@ public: QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); + bool FunctionArgTypesAreEqual (FunctionProtoType* OldType, + FunctionProtoType* NewType); + bool CheckPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray& BasePath, bool IgnoreBaseAccess); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType); OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, OverloadCandidateSet& Conversions, - bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue, - bool UserCast = false); + bool AllowExplicit); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - + ImplicitConversionSequence::CompareKind CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, @@ -1107,18 +1147,13 @@ public: CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); - ImplicitConversionSequence - TryCopyInitialization(Expr* From, QualType ToType, - bool SuppressUserConversions, bool ForceRValue, - bool InOverloadResolution); - OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, OwningExprResult Init); ImplicitConversionSequence TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext); - bool PerformObjectArgumentInitialization(Expr *&From, + bool PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); @@ -1126,7 +1161,7 @@ public: ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); bool PerformContextuallyConvertToBool(Expr *&From); - bool PerformObjectMemberConversion(Expr *&From, + bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); @@ -1146,7 +1181,6 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, - bool ForceRValue = false, bool PartialOverloading = false); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, Expr **Args, unsigned NumArgs, @@ -1156,15 +1190,13 @@ public: QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversion = false, - bool ForceRValue = false); + bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -1172,15 +1204,13 @@ public: QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddConversionCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -1197,11 +1227,6 @@ public: const FunctionProtoType *Proto, QualType ObjectTy, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); - void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange = SourceRange()); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr **Args, unsigned NumArgs, @@ -1254,18 +1279,18 @@ public: FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); Expr *FixOverloadedFunctionReference(Expr *E, - NamedDecl *FoundDecl, + DeclAccessPair FoundDecl, FunctionDecl *Fn); - OwningExprResult FixOverloadedFunctionReference(OwningExprResult, - NamedDecl *FoundDecl, + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); - - OwningExprResult BuildOverloadedCallExpr(Expr *Fn, + + OwningExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -1305,7 +1330,7 @@ public: /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); - + /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); @@ -1374,9 +1399,7 @@ public: /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up the name of an Objective-C protocol. - LookupObjCProtocolName, - /// Look up the name of an Objective-C implementation - LookupObjCImplementationName + LookupObjCProtocolName }; /// \brief Specifies whether (or how) name lookup is being performed for a @@ -1400,6 +1423,7 @@ public: /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); @@ -1407,15 +1431,15 @@ public: bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); - bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); - ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); - + void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, ADLResult &Functions); @@ -1425,10 +1449,34 @@ public: void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer); - bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext = 0, - bool EnteringContext = false, - const ObjCObjectPointerType *OPT = 0); + /// \brief The context in which typo-correction occurs. + /// + /// The typo-correction context affects which keywords (if any) are + /// considered when trying to correct for typos. + enum CorrectTypoContext { + /// \brief An unknown context, where any keyword might be valid. + CTC_Unknown, + /// \brief A context where no keywords are used (e.g. we expect an actual + /// name). + CTC_NoKeywords, + /// \brief A context where we're correcting a type name. + CTC_Type, + /// \brief An expression context. + CTC_Expression, + /// \brief A type cast, or anything else that can be followed by a '<'. + CTC_CXXCasts, + /// \brief A member lookup context. + CTC_MemberLookup, + /// \brief The receiver of an Objective-C message send within an + /// Objective-C method where 'super' is a valid keyword. + CTC_ObjCMessageReceiver + }; + + DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext = 0, + bool EnteringContext = false, + CorrectTypoContext CTC = CTC_Unknown, + const ObjCObjectPointerType *OPT = 0); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1438,7 +1486,8 @@ public: //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, - SourceLocation RecoverLoc = SourceLocation()); + SourceLocation IdLoc, + bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); @@ -1482,7 +1531,7 @@ public: void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); - + /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, @@ -1494,13 +1543,19 @@ public: void CollectImmediateProperties(ObjCContainerDecl *CDecl, llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// ProtocolConformsToSuperClass - Returns true if class has a super class + /// and it, or its nested super class conforms to the protocol. + bool ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl); + /// ProtocolConformsToProtocol - Returns true if 2nd Protocol (PDecl) is + /// qualified by the 1st. + bool ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl); + /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. - ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, + ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, IdentifierInfo *II); - - ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII); /// Called by ActOnProperty to handle @property declarations in //// class extensions. @@ -1572,6 +1627,11 @@ public: /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); + + /// CollectIvarsToConstructOrDestruct - Collect those ivars which require + /// initialization. + void CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: @@ -1601,7 +1661,7 @@ public: FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, DeclPtrTy CondVar); virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); @@ -1619,7 +1679,7 @@ public: SourceLocation LParenLoc, StmtArg First, FullExprArg Second, DeclPtrTy SecondVar, - FullExprArg Third, + FullExprArg Third, SourceLocation RParenLoc, StmtArg Body); virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, @@ -1656,18 +1716,27 @@ public: SourceLocation RParenLoc, bool MSAsm = false); + + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, + IdentifierInfo *Name, SourceLocation NameLoc, + bool Invalid = false); + + virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D); + virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, - DeclPtrTy Parm, StmtArg Body, - StmtArg CatchList); + DeclPtrTy Parm, StmtArg Body); virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body); virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, - StmtArg Catch, StmtArg Finally); + MultiStmtArg Catch, + StmtArg Finally); + virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw); virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, Scope *CurScope); @@ -1717,17 +1786,17 @@ public: void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); - + // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; virtual OwningExprResult ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, bool HasTrailingLParen, bool IsAddressOfOperand); - bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R); + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R); OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, @@ -1739,7 +1808,7 @@ public: SourceLocation NameLoc, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); - + OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS = 0); @@ -1761,7 +1830,7 @@ public: const LookupResult &R, bool HasTrailingLParen); - OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, + OwningExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc); OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, @@ -1831,7 +1900,7 @@ public: QualType BaseType, SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, @@ -1843,11 +1912,12 @@ public: const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck = false); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, bool &IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -1867,11 +1937,11 @@ public: virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Member, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen); - + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, @@ -1954,6 +2024,11 @@ public: SourceLocation RPLoc); // "({..})" /// __builtin_offsetof(type, a.b[123][456].c) + OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, @@ -2011,7 +2086,7 @@ public: virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); @@ -2022,7 +2097,7 @@ public: SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); @@ -2043,7 +2118,7 @@ public: NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, @@ -2055,7 +2130,7 @@ public: AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -2078,28 +2153,21 @@ public: /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. - OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, - QualType DeclInitType, - CXXConstructorDecl *Constructor, - MultiExprArg Exprs, - bool RequiresZeroInit = false, - bool BaseInitialization = false); + OwningExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, MultiExprArg Exprs, + bool RequiresZeroInit = false, + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? - OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, - QualType DeclInitType, - CXXConstructorDecl *Constructor, - bool Elidable, - MultiExprArg Exprs, - bool RequiresZeroInit = false, - bool BaseInitialization = false); - - OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc, - QualType Ty, - CastExpr::CastKind Kind, - CXXMethodDecl *Method, - ExprArg Arg); + OwningExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, bool RequiresZeroInit = false, + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. @@ -2127,36 +2195,23 @@ public: CXXConstructorDecl *Constructor, unsigned TypeQuals); - /// DefineImplicitOverloadedAssign - Checks for feasibility of - /// defining implicit this overloaded assignment operator. - void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl); - - /// getAssignOperatorMethod - Returns the default copy assignmment operator - /// for the class. - CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation, - ParmVarDecl *Decl, - CXXRecordDecl *ClassDecl); + /// \brief Defined and implicitly-declared copy assignment operator. + void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - CXXConstructorDecl * - TryInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, - InitializationKind Kind); - bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, - SourceLocation Loc, + SourceLocation Loc, ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); - + virtual TypeTy *getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, TypeTy *ObjectType, bool EnteringContext); @@ -2177,6 +2232,15 @@ public: SourceRange AngleBrackets, SourceRange Parens); + OwningExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + OwningExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + ExprArg Operand, + SourceLocation RParenLoc); + /// ActOnCXXTypeid - Parse typeid( something ). virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, @@ -2247,7 +2311,7 @@ public: QualType Argument, bool addMallocAttr = false); - bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator); /// ActOnCXXDelete - Parsed a C++ 'delete' expression @@ -2258,7 +2322,7 @@ public: virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); OwningExprResult CheckConditionVariable(VarDecl *ConditionVar); - + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, @@ -2276,7 +2340,7 @@ public: OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, ExprArg MemExpr); - + OwningExprResult BuildPseudoDestructorExpr(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -2286,27 +2350,28 @@ public: SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType, bool HasTrailingLParen); - + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName, bool HasTrailingLParen); - + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr); OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr); FullExpr CreateFullExpr(Expr *SubExpr); - + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); - bool RequireCompleteDeclContext(const CXXScopeSpec &SS); + // Marks SS invalid if it represents an incomplete type. + bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, @@ -2323,13 +2388,13 @@ public: bool isAcceptableNestedNameSpecifier(NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, TypeTy *ObjectType); - + CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -2339,7 +2404,7 @@ public: bool ErrorRecoveryLookup); virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -2347,11 +2412,11 @@ public: bool EnteringContext); virtual bool IsInvalidUnlessNestedName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext); - + /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., /// "foo::bar<int, float>::", and now we need to build a scope @@ -2374,7 +2439,7 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same @@ -2400,7 +2465,7 @@ public: unsigned NumStrings); Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, - QualType EncodedType, + TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, @@ -2432,8 +2497,7 @@ public: virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc); virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S, DeclPtrTy LinkageSpec, @@ -2455,7 +2519,7 @@ public: virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -2479,6 +2543,9 @@ public: bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors); + + void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as @@ -2494,28 +2561,28 @@ public: ClassesWithUnmarkedVirtualMembers; /// MaybeMarkVirtualMembersReferenced - If the passed in method is the - /// key function of the record decl, will mark virtual member functions as + /// key function of the record decl, will mark virtual member functions as /// referenced. void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); - + /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); - /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes + /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes /// that might need to have their virtual members marked as referenced. /// Returns false if no work was done. bool ProcessPendingClassesWithUnmarkedVirtualMembers(); - - void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl); virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits, bool AnyErrors); - void CheckCompletedCXXClass(CXXRecordDecl *Record); + void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -2537,6 +2604,8 @@ public: ExprArg AssertExpr, ExprArg AssertMessageExpr); + FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc, + TypeSourceInfo *TSInfo); DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, @@ -2551,7 +2620,7 @@ public: void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - + //===--------------------------------------------------------------------===// // C++ Derived Classes // @@ -2562,14 +2631,14 @@ public: bool Virtual, AccessSpecifier Access, QualType BaseType, SourceLocation BaseLoc); - - /// SetClassDeclAttributesFromBase - Copies class decl traits - /// (such as whether the class has a trivial constructor, + + /// SetClassDeclAttributesFromBase - Copies class decl traits + /// (such as whether the class has a trivial constructor, /// trivial destructor etc) from the given base class. void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, const CXXRecordDecl *BaseClass, bool BaseIsVirtual); - + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, @@ -2583,15 +2652,21 @@ public: bool IsDerivedFrom(QualType Derived, QualType Base); bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); - + + // FIXME: I don't like this name. + void BuildBasePathArray(const CXXBasePaths &Paths, + CXXBaseSpecifierArray &BasePath); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, + CXXBaseSpecifierArray *BasePath = 0, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, - DeclarationName Name); + DeclarationName Name, + CXXBaseSpecifierArray *BasePath); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); @@ -2636,6 +2711,7 @@ public: DeclAccessPair FoundDecl); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, + const InitializedEntity &Entity, AccessSpecifier Access); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, @@ -2691,23 +2767,23 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS, + void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext); virtual TemplateNameKind isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); - - virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + + virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); - + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); @@ -2765,10 +2841,11 @@ public: const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, @@ -2776,7 +2853,7 @@ public: void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); - + QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs); @@ -2796,13 +2873,13 @@ public: LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo &TemplateArgs); - OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, + OwningExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &TemplateArgs); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext); @@ -2815,7 +2892,7 @@ public: virtual DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -2839,12 +2916,16 @@ public: TemplateSpecializationKind PrevTSK, SourceLocation PrevPointOfInstantiation, bool &SuppressNew); - + + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); - + virtual DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -2865,7 +2946,7 @@ public: SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); @@ -2874,8 +2955,8 @@ public: SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); - - TemplateArgumentLoc + + TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, @@ -2905,7 +2986,7 @@ public: SourceLocation RAngleLoc, TemplateArgumentListBuilder &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs, @@ -2918,23 +2999,23 @@ public: bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); - bool CheckTemplateArgumentPointerToMember(Expr *Arg, + bool CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, const TemplateArgumentLoc &Arg); - OwningExprResult + OwningExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); - OwningExprResult + OwningExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); - + /// \brief Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { @@ -2946,7 +3027,7 @@ public: /// template<typename T> struct X; /// \endcode TPL_TemplateMatch, - + /// \brief We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. @@ -2956,7 +3037,7 @@ public: /// template<template<int Value> class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, - + /// \brief We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. @@ -2968,7 +3049,7 @@ public: /// \endcode TPL_TemplateTemplateArgumentMatch }; - + bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, @@ -3001,12 +3082,15 @@ public: ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TypeTy *Ty); - QualType CheckTypenameType(NestedNameSpecifier *NNS, + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range); - QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, - DeclarationName Name); + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name); + bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, @@ -3016,7 +3100,7 @@ public: getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); - + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of @@ -3205,27 +3289,28 @@ public: const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag); - + ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); - + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used); void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced); - + //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = 0, - bool RelativeToPrimary = false); + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = 0); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { @@ -3257,12 +3342,12 @@ public: /// Entity is either a ClassTemplatePartialSpecializationDecl or /// a FunctionTemplateDecl. DeducedTemplateArgumentSubstitution, - + /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, - + /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking @@ -3274,7 +3359,7 @@ public: /// \brief The template in which we are performing the instantiation, /// for substitutions of prior template arguments. TemplateDecl *Template; - + /// \brief The entity that is being instantiated. uintptr_t Entity; @@ -3291,13 +3376,13 @@ public: SourceRange InstantiationRange; ActiveTemplateInstantiation() - : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), + : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), NumTemplateArgs(0) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; - + friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) @@ -3314,9 +3399,9 @@ public: case DefaultTemplateArgumentChecking: if (X.Template != Y.Template) return false; - + // Fall through - + case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: @@ -3347,7 +3432,7 @@ public: /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. unsigned NonInstantiationEntries; - + /// \brief The last template from which a template instantiation /// error or warning was produced. /// @@ -3422,7 +3507,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); - + /// \brief Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -3431,8 +3516,8 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); - - + + /// \brief Note that we have finished instantiating this template. void Clear(); @@ -3510,7 +3595,7 @@ public: /// instantiated ParmVarDecl for 'x'. llvm::DenseMap<const Decl *, Decl *> LocalDecls; - /// \brief The outer scope, in which contains local variable + /// \brief The outer scope, which contains local variable /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; @@ -3518,54 +3603,36 @@ public: /// \brief Whether we have already exited this scope. bool Exited; - /// \brief Whether this scope is temporary, meaning that we should - /// remove any additions we make once we exit this - /// scope. Temporary scopes are always combined with their outer - /// scopes. - bool Temporary; - - /// \brief List of the declarations that we have added into this - /// temporary scope. They will be removed when we exit the - /// temporary scope. - llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls; - + /// \brief Whether to combine this scope with the outer scope, such that + /// lookup will search our outer scope. + bool CombineWithOuterScope; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, - bool Temporary = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false), Temporary(Temporary) { - if (!CombineWithOuterScope && !Temporary) - SemaRef.CurrentInstantiationScope = this; - else - assert(SemaRef.CurrentInstantiationScope && - "No outer instantiation scope?"); + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false), CombineWithOuterScope(CombineWithOuterScope) + { + SemaRef.CurrentInstantiationScope = this; } ~LocalInstantiationScope() { - if (!Exited) { - SemaRef.CurrentInstantiationScope = Outer; - for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I) - LocalDecls.erase(AddedTemporaryDecls[I]); - } + Exit(); } /// \brief Exit this local instantiation scope early. void Exit() { + if (Exited) + return; + SemaRef.CurrentInstantiationScope = Outer; - LocalDecls.clear(); Exited = true; } - Decl *getInstantiationOf(const Decl *D) { - Decl *Result = LocalDecls[D]; - assert((Result || D->isInvalidDecl()) && - "declaration was not instantiated in this scope!"); - return Result; - } + Decl *getInstantiationOf(const Decl *D); VarDecl *getInstantiationOf(const VarDecl *Var) { return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var))); @@ -3579,16 +3646,8 @@ public: const NonTypeTemplateParmDecl *Var) { return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); } - - void InstantiatedLocal(const Decl *D, Decl *Inst) { - Decl *&Stored = LocalDecls[D]; - assert((!Stored || Stored == Inst) && "Already instantiated this local"); - if (Temporary && !Stored) - AddedTemporaryDecls.push_back(D); - - Stored = Inst; - } + void InstantiatedLocal(const Decl *D, Decl *Inst); }; /// \brief The current instantiation scope used to store local @@ -3634,6 +3693,12 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity); + ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs); OwningExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -3701,8 +3766,6 @@ public: DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); - bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params); - // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, @@ -3823,7 +3886,7 @@ public: // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, - llvm::SmallVectorImpl<Declarator> &Cdecls, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic = false); @@ -3836,28 +3899,66 @@ public: ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, ObjCInterfaceDecl *ClassDecl); - virtual OwningExprResult ActOnClassPropertyRefExpr( - IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation &receiverNameLoc, - SourceLocation &propertyNameLoc); - - // ActOnClassMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnClassMessage( - Scope *S, - IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, - SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); - - // ActOnInstanceMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); + OwningExprResult + HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, + DeclarationName MemberName, + SourceLocation MemberLoc); + + virtual OwningExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc); + + virtual ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType); + + virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + OwningExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + virtual OwningExprResult ActOnClassMessage(Scope *S, + TypeTy *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + OwningExprResult BuildInstanceMessage(ExprArg Receiver, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + virtual OwningExprResult ActOnInstanceMessage(Scope *S, + ExprArg Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, @@ -3900,7 +4001,9 @@ public: /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind, - bool isLvalue = false); + bool isLvalue = false, + CXXBaseSpecifierArray BasePath = + CXXBaseSpecifierArray()); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). @@ -3985,11 +4088,11 @@ public: /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, - + /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two - /// levels differ e.g. char ** -> const char **, but we accept them as an - /// extension. + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that @@ -4013,14 +4116,15 @@ public: /// represent it in the AST. Incompatible }; - + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, AssignmentAction Action); + Expr *SrcExpr, AssignmentAction Action, + bool *Complained = 0); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. @@ -4056,12 +4160,10 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, - bool AllowExplicit = false, - bool Elidable = false); + bool AllowExplicit = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - bool Elidable, ImplicitConversionSequence& ICS); bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, @@ -4106,12 +4208,12 @@ public: Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType FindCompositePointerType(Expr *&E1, Expr *&E2, + QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType = 0); QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation questionLoc); - + /// type checking for vector binary operators. inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, @@ -4120,7 +4222,7 @@ public: /// type checking unary operators (subroutines of ActOnUnaryOp). /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, - bool isInc); + bool isInc, bool isPrefix); QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); @@ -4162,19 +4264,10 @@ public: QualType T1, QualType T2, bool& DerivedToBase); - bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, - SourceLocation DeclLoc, - bool SuppressUserConversions, - bool AllowExplicit, - bool ForceRValue, - ImplicitConversionSequence *ICS = 0, - bool IgnoreBaseAccess = false); - /// CheckCastTypes - Check type constraints for casting between types under /// C semantics, or forward to CXXCheckCStyleCast in C++. bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, - CXXMethodDecl *& ConversionDecl, + CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath, bool FunctionalStyle = false); // CheckVectorCast - check type constraints for vectors. @@ -4195,8 +4288,9 @@ public: /// CXXCheckCStyleCast - Check constraints of a C-style or function-style /// cast under C++ semantics. bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, bool FunctionalStyle, - CXXMethodDecl *&ConversionDecl); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, + bool FunctionalStyle); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. @@ -4253,7 +4347,7 @@ public: /// \name Code completion //@{ - virtual void CodeCompleteOrdinaryName(Scope *S, + virtual void CodeCompleteOrdinaryName(Scope *S, CodeCompletionContext CompletionContext); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, @@ -4262,14 +4356,14 @@ public: virtual void CodeCompleteCase(Scope *S); virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, ExprTy **Args, unsigned NumArgs); - virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext); virtual void CodeCompleteUsing(Scope *S); virtual void CodeCompleteUsingDirective(Scope *S); virtual void CodeCompleteNamespaceDecl(Scope *S); virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); - + virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface); virtual void CodeCompleteObjCAtVisibility(Scope *S); @@ -4283,9 +4377,11 @@ public: DeclPtrTy *Methods, unsigned NumMethods); - virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc, - IdentifierInfo **SelIdents, + virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); + virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, + IdentifierInfo **SelIdents, unsigned NumSelIdents); virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, @@ -4294,20 +4390,27 @@ public: unsigned NumProtocols); virtual void CodeCompleteObjCProtocolDecl(Scope *S); virtual void CodeCompleteObjCInterfaceDecl(Scope *S); - virtual void CodeCompleteObjCSuperclass(Scope *S, - IdentifierInfo *ClassName); + virtual void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); virtual void CodeCompleteObjCImplementationDecl(Scope *S); - virtual void CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName); - virtual void CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName); - virtual void CodeCompleteObjCPropertyDefinition(Scope *S, + virtual void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + virtual void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + virtual void CodeCompleteObjCPropertyDefinition(Scope *S, DeclPtrTy ObjCImpDecl); - virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName, DeclPtrTy ObjCImpDecl); + virtual void CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnType, + DeclPtrTy IDecl); //@} - + //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system @@ -4327,7 +4430,6 @@ private: bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); - bool SemaBuiltinStackAddress(CallExpr *TheCall); public: // Used by C++ template instantiation. @@ -4338,7 +4440,8 @@ private: bool SemaBuiltinObjectSize(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall); - bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall); + bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result); bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index f628884..444ee79 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -22,6 +23,13 @@ using namespace clang; +/// A copy of Sema's enum without AR_delayed. +enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent +}; + /// SetMemberAccessSpecifier - Set the access specifier of a member. /// Returns true on error (when the previous member decl access specifier /// is different from the new member decl access specifier). @@ -51,6 +59,20 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, return false; } +static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { + DeclContext *DC = D->getDeclContext(); + + // This can only happen at top: enum decls only "publish" their + // immediate members. + if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); + while (DeclaringClass->isAnonymousStructOrUnion()) + DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); + return DeclaringClass; +} + namespace { struct EffectiveContext { EffectiveContext() : Inner(0), Dependent(false) {} @@ -109,22 +131,168 @@ struct EffectiveContext { llvm::SmallVector<CXXRecordDecl*, 4> Records; bool Dependent; }; + +/// Like Sema's AccessedEntity, but kindly lets us scribble all over +/// it. +struct AccessTarget : public Sema::AccessedEntity { + AccessTarget(const Sema::AccessedEntity &Entity) + : AccessedEntity(Entity) { + initialize(); + } + + AccessTarget(ASTContext &Context, + MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { + initialize(); + } + + AccessTarget(ASTContext &Context, + BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) { + initialize(); + } + + bool hasInstanceContext() const { + return HasInstanceContext; + } + + class SavedInstanceContext { + public: + ~SavedInstanceContext() { + Target.HasInstanceContext = Has; + } + + private: + friend struct AccessTarget; + explicit SavedInstanceContext(AccessTarget &Target) + : Target(Target), Has(Target.HasInstanceContext) {} + AccessTarget &Target; + bool Has; + }; + + SavedInstanceContext saveInstanceContext() { + return SavedInstanceContext(*this); + } + + void suppressInstanceContext() { + HasInstanceContext = false; + } + + const CXXRecordDecl *resolveInstanceContext(Sema &S) const { + assert(HasInstanceContext); + if (CalculatedInstanceContext) + return InstanceContext; + + CalculatedInstanceContext = true; + DeclContext *IC = S.computeDeclContext(getBaseObjectType()); + InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); + return InstanceContext; + } + + const CXXRecordDecl *getDeclaringClass() const { + return DeclaringClass; + } + +private: + void initialize() { + HasInstanceContext = (isMemberAccess() && + !getBaseObjectType().isNull() && + getTargetDecl()->isCXXInstanceMember()); + CalculatedInstanceContext = false; + InstanceContext = 0; + + if (isMemberAccess()) + DeclaringClass = FindDeclaringClass(getTargetDecl()); + else + DeclaringClass = getBaseClass(); + DeclaringClass = DeclaringClass->getCanonicalDecl(); + } + + bool HasInstanceContext : 1; + mutable bool CalculatedInstanceContext : 1; + mutable const CXXRecordDecl *InstanceContext; + const CXXRecordDecl *DeclaringClass; +}; + } -static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { - DeclContext *DC = D->getDeclContext(); +/// Checks whether one class might instantiate to the other. +static bool MightInstantiateTo(const CXXRecordDecl *From, + const CXXRecordDecl *To) { + // Declaration names are always preserved by instantiation. + if (From->getDeclName() != To->getDeclName()) + return false; - // This can only happen at top: enum decls only "publish" their - // immediate members. - if (isa<EnumDecl>(DC)) - DC = cast<EnumDecl>(DC)->getDeclContext(); + const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); + const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); + if (FromDC == ToDC) return true; + if (FromDC->isFileContext() || ToDC->isFileContext()) return false; - CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); - while (DeclaringClass->isAnonymousStructOrUnion()) - DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); - return DeclaringClass; + // Be conservative. + return true; } +/// Checks whether one class is derived from another, inclusively. +/// Properly indicates when it couldn't be determined due to +/// dependence. +/// +/// This should probably be donated to AST or at least Sema. +static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, + const CXXRecordDecl *Target) { + assert(Derived->getCanonicalDecl() == Derived); + assert(Target->getCanonicalDecl() == Target); + + if (Derived == Target) return AR_accessible; + + bool CheckDependent = Derived->isDependentContext(); + if (CheckDependent && MightInstantiateTo(Derived, Target)) + return AR_dependent; + + AccessResult OnFailure = AR_inaccessible; + llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack + + while (true) { + for (CXXRecordDecl::base_class_const_iterator + I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { + + const CXXRecordDecl *RD; + + QualType T = I->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + RD = cast<CXXRecordDecl>(RT->getDecl()); + } else if (const InjectedClassNameType *IT + = T->getAs<InjectedClassNameType>()) { + RD = IT->getDecl(); + } else { + assert(T->isDependentType() && "non-dependent base wasn't a record?"); + OnFailure = AR_dependent; + continue; + } + + RD = RD->getCanonicalDecl(); + if (RD == Target) return AR_accessible; + if (CheckDependent && MightInstantiateTo(RD, Target)) + OnFailure = AR_dependent; + + Queue.push_back(RD); + } + + if (Queue.empty()) break; + + Derived = Queue.back(); + Queue.pop_back(); + } + + return OnFailure; +} + + static bool MightInstantiateTo(Sema &S, DeclContext *Context, DeclContext *Friend) { if (Friend == Context) @@ -204,11 +372,11 @@ static bool MightInstantiateTo(Sema &S, Friend->getTemplatedDecl()); } -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *Friend) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Friend) { if (EC.includesClass(Friend)) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent()) { CanQualType FriendTy @@ -219,32 +387,32 @@ static Sema::AccessResult MatchesFriend(Sema &S, CanQualType ContextTy = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); if (MightInstantiateTo(S, ContextTy, FriendTy)) - return Sema::AR_dependent; + return AR_dependent; } } - return Sema::AR_inaccessible; + return AR_inaccessible; } -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - CanQualType Friend) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + CanQualType Friend) { if (const RecordType *RT = Friend->getAs<RecordType>()) return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); // TODO: we can do better than this if (Friend->isDependentType()) - return Sema::AR_dependent; + return AR_dependent; - return Sema::AR_inaccessible; + return AR_inaccessible; } /// Determines whether the given friend class template matches /// anything in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - ClassTemplateDecl *Friend) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + ClassTemplateDecl *Friend) { + AccessResult OnFailure = AR_inaccessible; // Check whether the friend is the template of a class in the // context chain. @@ -268,7 +436,7 @@ static Sema::AccessResult MatchesFriend(Sema &S, // It's a match. if (Friend == CTD->getCanonicalDecl()) - return Sema::AR_accessible; + return AR_accessible; // If the context isn't dependent, it can't be a dependent match. if (!EC.isDependent()) @@ -286,7 +454,7 @@ static Sema::AccessResult MatchesFriend(Sema &S, continue; // Otherwise, it's a dependent match. - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -294,18 +462,18 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend function matches anything in /// the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FunctionDecl *Friend) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionDecl *Friend) { + AccessResult OnFailure = AR_inaccessible; for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { if (Friend == *I) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -313,12 +481,12 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend function template matches /// anything in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FunctionTemplateDecl *Friend) { - if (EC.Functions.empty()) return Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionTemplateDecl *Friend) { + if (EC.Functions.empty()) return AR_inaccessible; - Sema::AccessResult OnFailure = Sema::AR_inaccessible; + AccessResult OnFailure = AR_inaccessible; for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { @@ -332,10 +500,10 @@ static Sema::AccessResult MatchesFriend(Sema &S, FTD = FTD->getCanonicalDecl(); if (Friend == FTD) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -343,9 +511,9 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend declaration matches anything /// in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FriendDecl *FriendD) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *FriendD) { if (TypeSourceInfo *T = FriendD->getFriendType()) return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); @@ -367,10 +535,10 @@ static Sema::AccessResult MatchesFriend(Sema &S, return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); } -static Sema::AccessResult GetFriendKind(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *Class) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult GetFriendKind(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Class) { + AccessResult OnFailure = AR_inaccessible; // Okay, check friends. for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), @@ -378,18 +546,15 @@ static Sema::AccessResult GetFriendKind(Sema &S, FriendDecl *Friend = *I; switch (MatchesFriend(S, EC, Friend)) { - case Sema::AR_accessible: - return Sema::AR_accessible; + case AR_accessible: + return AR_accessible; - case Sema::AR_inaccessible: - break; + case AR_inaccessible: + continue; - case Sema::AR_dependent: - OnFailure = Sema::AR_dependent; + case AR_dependent: + OnFailure = AR_dependent; break; - - case Sema::AR_delayed: - llvm_unreachable("cannot get delayed answer from MatchesFriend"); } } @@ -397,16 +562,19 @@ static Sema::AccessResult GetFriendKind(Sema &S, return OnFailure; } -static Sema::AccessResult HasAccess(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *NamingClass, - AccessSpecifier Access) { +static AccessResult HasAccess(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *NamingClass, + AccessSpecifier Access, + const AccessTarget &Target) { assert(NamingClass->getCanonicalDecl() == NamingClass && "declaration should be canonicalized before being passed here"); - if (Access == AS_public) return Sema::AR_accessible; + if (Access == AS_public) return AR_accessible; assert(Access == AS_private || Access == AS_protected); + AccessResult OnFailure = AR_inaccessible; + for (EffectiveContext::record_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { // All the declarations in EC have been canonicalized, so pointer @@ -414,16 +582,78 @@ static Sema::AccessResult HasAccess(Sema &S, const CXXRecordDecl *ECRecord = *I; // [B2] and [M2] - if (ECRecord == NamingClass) - return Sema::AR_accessible; + if (Access == AS_private) { + if (ECRecord == NamingClass) + return AR_accessible; + + if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) + OnFailure = AR_dependent; // [B3] and [M3] - if (Access == AS_protected && - ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass))) - return Sema::AR_accessible; + } else { + assert(Access == AS_protected); + switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { + case AR_accessible: break; + case AR_inaccessible: continue; + case AR_dependent: OnFailure = AR_dependent; continue; + } + + if (!Target.hasInstanceContext()) + return AR_accessible; + + const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); + if (!InstanceContext) { + OnFailure = AR_dependent; + continue; + } + + // C++ [class.protected]p1: + // An additional access check beyond those described earlier in + // [class.access] is applied when a non-static data member or + // non-static member function is a protected member of its naming + // class. As described earlier, access to a protected member is + // granted because the reference occurs in a friend or member of + // some class C. If the access is to form a pointer to member, + // the nested-name-specifier shall name C or a class derived from + // C. All other accesses involve a (possibly implicit) object + // expression. In this case, the class of the object expression + // shall be C or a class derived from C. + // + // We interpret this as a restriction on [M3]. Most of the + // conditions are encoded by not having any instance context. + switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { + case AR_accessible: return AR_accessible; + case AR_inaccessible: continue; + case AR_dependent: OnFailure = AR_dependent; continue; + } + } } - return GetFriendKind(S, EC, NamingClass); + if (!NamingClass->hasFriends()) + return OnFailure; + + // Don't consider friends if we're under the [class.protected] + // restriction, above. + if (Access == AS_protected && Target.hasInstanceContext()) { + const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); + if (!InstanceContext) return AR_dependent; + + switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) { + case AR_accessible: break; + case AR_inaccessible: return OnFailure; + case AR_dependent: return AR_dependent; + } + } + + switch (GetFriendKind(S, EC, NamingClass)) { + case AR_accessible: return AR_accessible; + case AR_inaccessible: return OnFailure; + case AR_dependent: return AR_dependent; + } + + // Silence bogus warnings + llvm_unreachable("impossible friendship kind"); + return OnFailure; } /// Finds the best path from the naming class to the declaring class, @@ -479,17 +709,21 @@ static Sema::AccessResult HasAccess(Sema &S, /// /// B is an accessible base of N at R iff ACAB(1) = public. /// -/// \param FinalAccess the access of the "final step", or AS_none if +/// \param FinalAccess the access of the "final step", or AS_public if /// there is no final step. /// \return null if friendship is dependent static CXXBasePath *FindBestPath(Sema &S, const EffectiveContext &EC, - CXXRecordDecl *Derived, - CXXRecordDecl *Base, + AccessTarget &Target, AccessSpecifier FinalAccess, CXXBasePaths &Paths) { // Derive the paths to the desired base. - bool isDerived = Derived->isDerivedFrom(Base, Paths); + const CXXRecordDecl *Derived = Target.getNamingClass(); + const CXXRecordDecl *Base = Target.getDeclaringClass(); + + // FIXME: fail correctly when there are dependent paths. + bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), + Paths); assert(isDerived && "derived class not actually derived from base"); (void) isDerived; @@ -502,6 +736,7 @@ static CXXBasePath *FindBestPath(Sema &S, // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { + AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); // Walk through the path backwards. AccessSpecifier PathAccess = FinalAccess; @@ -519,16 +754,23 @@ static CXXBasePath *FindBestPath(Sema &S, break; } + const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); + AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); PathAccess = std::max(PathAccess, BaseAccess); - switch (HasAccess(S, EC, I->Class, PathAccess)) { - case Sema::AR_inaccessible: break; - case Sema::AR_accessible: PathAccess = AS_public; break; - case Sema::AR_dependent: + + switch (HasAccess(S, EC, NC, PathAccess, Target)) { + case AR_inaccessible: break; + case AR_accessible: + PathAccess = AS_public; + + // Future tests are not against members and so do not have + // instance context. + Target.suppressInstanceContext(); + break; + case AR_dependent: AnyDependent = true; goto Next; - case Sema::AR_delayed: - llvm_unreachable("friend resolution is never delayed"); break; } } @@ -561,46 +803,36 @@ static CXXBasePath *FindBestPath(Sema &S, /// to become inaccessible. static void DiagnoseAccessPath(Sema &S, const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { AccessSpecifier Access = Entity.getAccess(); - CXXRecordDecl *NamingClass = Entity.getNamingClass(); + const CXXRecordDecl *NamingClass = Entity.getNamingClass(); NamingClass = NamingClass->getCanonicalDecl(); - NamedDecl *D; - CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - D = Entity.getTargetDecl(); - DeclaringClass = FindDeclaringClass(D); - } else { - D = 0; - DeclaringClass = Entity.getBaseClass(); - } - DeclaringClass = DeclaringClass->getCanonicalDecl(); + NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); // Easy case: the decl's natural access determined its path access. // We have to check against AS_private here in case Access is AS_none, // indicating a non-public member of a private base class. if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { - switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) { - case Sema::AR_inaccessible: { + switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) { + case AR_inaccessible: { S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) << /*FIXME: not implicitly*/ 0; return; } - case Sema::AR_accessible: break; + case AR_accessible: break; - case Sema::AR_dependent: - case Sema::AR_delayed: - llvm_unreachable("dependent/delayed not allowed"); + case AR_dependent: + llvm_unreachable("can't diagnose dependent access failures"); return; } } CXXBasePaths Paths; - CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, - AS_public, Paths); + CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths); CXXBasePath::iterator I = Path.end(), E = Path.begin(); while (I != E) { @@ -615,12 +847,10 @@ static void DiagnoseAccessPath(Sema &S, continue; switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_accessible: continue; - case Sema::AR_inaccessible: break; - - case Sema::AR_dependent: - case Sema::AR_delayed: - llvm_unreachable("dependent friendship, should not be diagnosing"); + case AR_accessible: continue; + case AR_inaccessible: break; + case AR_dependent: + llvm_unreachable("can't diagnose dependent access failures"); } // Check whether this base specifier is the tighest point @@ -649,17 +879,10 @@ static void DiagnoseAccessPath(Sema &S, static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { const CXXRecordDecl *NamingClass = Entity.getNamingClass(); - NamedDecl *D; - const CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - D = Entity.getTargetDecl(); - DeclaringClass = FindDeclaringClass(D); - } else { - D = 0; - DeclaringClass = Entity.getBaseClass(); - } + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); + NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); S.Diag(Loc, Entity.getDiag()) << (Entity.getAccess() == AS_protected) @@ -671,9 +894,9 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, /// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. -static Sema::AccessResult IsAccessible(Sema &S, - const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { +static AccessResult IsAccessible(Sema &S, + const EffectiveContext &EC, + AccessTarget &Entity) { // Determine the actual naming class. CXXRecordDecl *NamingClass = Entity.getNamingClass(); while (NamingClass->isAnonymousStructOrUnion()) @@ -686,10 +909,10 @@ static Sema::AccessResult IsAccessible(Sema &S, // Before we try to recalculate access paths, try to white-list // accesses which just trade in on the final step, i.e. accesses // which don't require [M4] or [B4]. These are by far the most - // common forms of access. + // common forms of privileged access. if (UnprivilegedAccess != AS_none) { - switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) { - case Sema::AR_dependent: + switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { + case AR_dependent: // This is actually an interesting policy decision. We don't // *have* to delay immediately here: we can do the full access // calculation in the hope that friendship on some intermediate @@ -697,23 +920,14 @@ static Sema::AccessResult IsAccessible(Sema &S, // But that's not cheap, and odds are very good (note: assertion // made without data) that the friend declaration will determine // access. - return Sema::AR_dependent; + return AR_dependent; - case Sema::AR_accessible: return Sema::AR_accessible; - case Sema::AR_inaccessible: break; - case Sema::AR_delayed: - llvm_unreachable("friendship never subject to contextual delay"); + case AR_accessible: return AR_accessible; + case AR_inaccessible: break; } } - // Determine the declaring class. - CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); - } else { - DeclaringClass = Entity.getBaseClass(); - } - DeclaringClass = DeclaringClass->getCanonicalDecl(); + AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); // We lower member accesses to base accesses by pretending that the // member is a base class of its declaring class. @@ -723,43 +937,44 @@ static Sema::AccessResult IsAccessible(Sema &S, // Determine if the declaration is accessible from EC when named // in its declaring class. NamedDecl *Target = Entity.getTargetDecl(); + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); FinalAccess = Target->getAccess(); - switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) { - case Sema::AR_accessible: FinalAccess = AS_public; break; - case Sema::AR_inaccessible: break; - case Sema::AR_dependent: return Sema::AR_dependent; // see above - case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); + switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { + case AR_accessible: + FinalAccess = AS_public; + break; + case AR_inaccessible: break; + case AR_dependent: return AR_dependent; // see above } if (DeclaringClass == NamingClass) - return (FinalAccess == AS_public - ? Sema::AR_accessible - : Sema::AR_inaccessible); + return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); + + Entity.suppressInstanceContext(); } else { FinalAccess = AS_public; } - assert(DeclaringClass != NamingClass); + assert(Entity.getDeclaringClass() != NamingClass); // Append the declaration's access if applicable. CXXBasePaths Paths; - CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass, - FinalAccess, Paths); + CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); if (!Path) - return Sema::AR_dependent; + return AR_dependent; assert(Path->Access <= UnprivilegedAccess && "access along best path worse than direct?"); if (Path->Access == AS_public) - return Sema::AR_accessible; - return Sema::AR_inaccessible; + return AR_accessible; + return AR_inaccessible; } -static void DelayAccess(Sema &S, - const EffectiveContext &EC, - SourceLocation Loc, - const Sema::AccessedEntity &Entity) { +static void DelayDependentAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + const AccessTarget &Entity) { assert(EC.isDependent() && "delaying non-dependent access"); DeclContext *DC = EC.getInnerContext(); assert(DC->isDependentContext() && "delaying non-dependent access"); @@ -769,48 +984,38 @@ static void DelayAccess(Sema &S, Entity.getAccess(), Entity.getTargetDecl(), Entity.getNamingClass(), + Entity.getBaseObjectType(), Entity.getDiag()); } /// Checks access to an entity from the given effective context. -static Sema::AccessResult CheckEffectiveAccess(Sema &S, - const EffectiveContext &EC, - SourceLocation Loc, - const Sema::AccessedEntity &Entity) { +static AccessResult CheckEffectiveAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); switch (IsAccessible(S, EC, Entity)) { - case Sema::AR_dependent: - DelayAccess(S, EC, Loc, Entity); - return Sema::AR_dependent; - - case Sema::AR_delayed: - llvm_unreachable("IsAccessible cannot contextually delay"); + case AR_dependent: + DelayDependentAccess(S, EC, Loc, Entity); + return AR_dependent; - case Sema::AR_inaccessible: + case AR_inaccessible: if (!Entity.isQuiet()) DiagnoseBadAccess(S, Loc, EC, Entity); - return Sema::AR_inaccessible; - - case Sema::AR_accessible: - break; - } + return AR_inaccessible; - // We only consider the natural access of the declaration when - // deciding whether to do the protected check. - if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) { - NamedDecl *D = Entity.getTargetDecl(); - if (isa<FieldDecl>(D) || - (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) { - // FIXME: implement [class.protected] - } + case AR_accessible: + return AR_accessible; } - return Sema::AR_accessible; + // silence unnecessary warning + llvm_unreachable("invalid access result"); + return AR_accessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { // If the access path is public, it's accessible everywhere. if (Entity.getAccess() == AS_public) return Sema::AR_accessible; @@ -825,16 +1030,31 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, return Sema::AR_delayed; } - return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), - Loc, Entity); + EffectiveContext EC(S.CurContext); + switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { + case AR_accessible: return Sema::AR_accessible; + case AR_inaccessible: return Sema::AR_inaccessible; + case AR_dependent: return Sema::AR_dependent; + } + llvm_unreachable("falling off end"); + return Sema::AR_accessible; } void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { // Pretend we did this from the context of the newly-parsed - // declaration. - EffectiveContext EC(Ctx->getDeclContext()); - - if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) + // declaration. If that declaration itself forms a declaration context, + // include it in the effective context so that parameters and return types of + // befriended functions have that function's access priveledges. + DeclContext *DC = Ctx->getDeclContext(); + if (isa<FunctionDecl>(Ctx)) + DC = cast<DeclContext>(Ctx); + else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx)) + DC = cast<DeclContext>(FnTpl->getTemplatedDecl()); + EffectiveContext EC(DC); + + AccessTarget Target(DD.getAccessData()); + + if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) DD.Triggered = true; } @@ -851,19 +1071,28 @@ void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, if (!TargetD) return; if (DD.isAccessToMember()) { - AccessedEntity Entity(Context, - AccessedEntity::Member, - cast<CXXRecordDecl>(NamingD), - Access, - cast<NamedDecl>(TargetD)); + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); + NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); + QualType BaseObjectType = DD.getAccessBaseObjectType(); + if (!BaseObjectType.isNull()) { + BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, + DeclarationName()); + if (BaseObjectType.isNull()) return; + } + + AccessTarget Entity(Context, + AccessTarget::Member, + NamingClass, + DeclAccessPair::make(TargetDecl, Access), + BaseObjectType); Entity.setDiag(DD.getDiagnostic()); CheckAccess(*this, Loc, Entity); } else { - AccessedEntity Entity(Context, - AccessedEntity::Base, - cast<CXXRecordDecl>(TargetD), - cast<CXXRecordDecl>(NamingD), - Access); + AccessTarget Entity(Context, + AccessTarget::Base, + cast<CXXRecordDecl>(TargetD), + cast<CXXRecordDecl>(NamingD), + Access); Entity.setDiag(DD.getDiagnostic()); CheckAccess(*this, Loc, Entity); } @@ -876,8 +1105,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), - Found); + AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), + Found, QualType()); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -891,8 +1120,12 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), - Found); + QualType BaseType = E->getBaseType(); + if (E->isArrow()) + BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + + AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), + Found, BaseType); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -910,8 +1143,9 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Dtor, Access)); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Dtor, Access), + QualType()); Entity.setDiag(PDiag); // TODO: avoid copy return CheckAccess(*this, Loc, Entity); @@ -920,17 +1154,39 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, + const InitializedEntity &Entity, AccessSpecifier Access) { if (!getLangOptions().AccessControl || Access == AS_public) return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Constructor, Access)); - Entity.setDiag(diag::err_access_ctor); + AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Constructor, Access), + QualType()); + switch (Entity.getKind()) { + default: + AccessEntity.setDiag(diag::err_access_ctor); + break; - return CheckAccess(*this, UseLoc, Entity); + case InitializedEntity::EK_Base: + AccessEntity.setDiag(PDiag(diag::err_access_base) + << Entity.isInheritedVirtualBase() + << Entity.getBaseSpecifier()->getType() + << getSpecialMember(Constructor)); + break; + + case InitializedEntity::EK_Member: { + const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); + AccessEntity.setDiag(PDiag(diag::err_access_field) + << Field->getType() + << getSpecialMember(Constructor)); + break; + } + + } + + return CheckAccess(*this, UseLoc, AccessEntity); } /// Checks direct (i.e. non-inherited) access to an arbitrary class @@ -944,8 +1200,9 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Target, Access)); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Target, Access), + QualType()); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); } @@ -961,7 +1218,8 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + QualType()); Entity.setDiag(diag::err_access) << PlacementRange; @@ -982,7 +1240,8 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + ObjectExpr->getType()); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -998,24 +1257,16 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, return AR_accessible; OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); - NestedNameSpecifier *Qualifier = Ovl->getQualifier(); - assert(Qualifier && "address of overloaded member without qualifier"); + CXXRecordDecl *NamingClass = Ovl->getNamingClass(); - CXXScopeSpec SS; - SS.setScopeRep(Qualifier); - SS.setRange(Ovl->getQualifierRange()); - DeclContext *DC = computeDeclContext(SS); - assert(DC && DC->isRecord() && "scope did not resolve to record"); - CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC); - - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + Context.getTypeDeclType(NamingClass)); Entity.setDiag(diag::err_access) << Ovl->getSourceRange(); return CheckAccess(*this, Ovl->getNameLoc(), Entity); } - /// Checks access for a hierarchy conversion. /// /// \param IsBaseToDerived whether this is a base-to-derived conversion (true) @@ -1042,13 +1293,20 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); - AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD, - Path.Access); + AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, + Path.Access); if (DiagID) Entity.setDiag(DiagID) << Derived << Base; - if (ForceUnprivileged) - return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); + if (ForceUnprivileged) { + switch (CheckEffectiveAccess(*this, EffectiveContext(), + AccessLoc, Entity)) { + case ::AR_accessible: return Sema::AR_accessible; + case ::AR_inaccessible: return Sema::AR_inaccessible; + case ::AR_dependent: return Sema::AR_dependent; + } + llvm_unreachable("unexpected result from CheckEffectiveAccess"); + } return CheckAccess(*this, AccessLoc, Entity); } @@ -1060,9 +1318,9 @@ void Sema::CheckLookupAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { - AccessedEntity Entity(Context, AccessedEntity::Member, - R.getNamingClass(), - I.getPair()); + AccessTarget Entity(Context, AccessedEntity::Member, + R.getNamingClass(), I.getPair(), + R.getBaseObjectType()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 11c8e6d..ba7e1ff 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -47,11 +47,12 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CXXBaseSpecifierArray &BasePath); static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); @@ -69,39 +70,43 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, - QualType DestType, bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastExpr::CastKind &Kind); + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, - QualType SrcType, - QualType DestType,bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastExpr::CastKind &Kind); + QualType SrcType, + QualType DestType,bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); + static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CastExpr::CastKind &Kind); static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CXXBaseSpecifierArray &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, @@ -153,10 +158,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXBaseSpecifierArray BasePath; if (!TypeDependent) - CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); + CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, BasePath, DestTInfo, + OpLoc)); } case tok::kw_reinterpret_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -164,28 +171,18 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, CXXBaseSpecifierArray(), + DestTInfo, OpLoc)); } case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (!TypeDependent) { - CXXMethodDecl *Method = 0; - - CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method); - - if (Method) { - OwningExprResult CastArg - = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(), - Kind, Method, Owned(Ex)); - if (CastArg.isInvalid()) - return ExprError(); - - Ex = CastArg.takeAs<Expr>(); - } - } + CXXBaseSpecifierArray BasePath; + if (!TypeDependent) + CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath); return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, BasePath, + DestTInfo, OpLoc)); } } @@ -290,7 +287,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, - const SourceRange &DestRange, CastExpr::CastKind &Kind) { + const SourceRange &DestRange, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); @@ -384,10 +382,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { - Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, - OpRange.getBegin(), OpRange); + if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, + OpRange.getBegin(), OpRange, + &BasePath)) + return; + Kind = CastExpr::CK_DerivedToBase; - // Diagnostic already emitted on error. return; } @@ -448,7 +448,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CXXBaseSpecifierArray &BasePath) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". @@ -462,8 +462,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, - Kind, ConversionDecl) - != TC_Success && msg != 0) + Kind, BasePath) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static << SrcExpr->getType() << DestType << OpRange; } @@ -475,7 +474,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CXXBaseSpecifierArray &BasePath) { // The order the tests is not entirely arbitrary. There is one conversion // that can be handled in two different ways. Given: // struct A {}; @@ -497,7 +496,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // See the function for details. // DR 427 specifies that this is to be applied before paragraph 2. tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange, - msg, Kind); + msg, Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -512,7 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&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, - Kind, ConversionDecl); + Kind); if (tcr != TC_NotApplicable) return tcr; @@ -548,7 +547,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg, - Kind); + Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -556,7 +555,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // conversion. C++ 5.2.9p9 has additional information. // DR54's access restrictions apply here also. tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle, - OpRange, msg, Kind); + OpRange, msg, Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -630,7 +629,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be // cast to type "reference to cv2 D", where D is a class derived from B, // if a valid standard conversion from "pointer to D" to "pointer to B" @@ -656,14 +656,16 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, return TryStaticDowncast(Self, Self.Context.getCanonicalType(SrcExpr->getType()), Self.Context.getCanonicalType(DestPointee), CStyle, - OpRange, SrcExpr->getType(), DestType, msg, Kind); + OpRange, SrcExpr->getType(), DestType, msg, Kind, + BasePath); } /// Tests whether a conversion according to C++ 5.2.9p8 is valid. TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class // type, can be converted to an rvalue of type "pointer to cv2 D", where D // is a class derived from B, if a valid standard conversion from "pointer @@ -686,7 +688,8 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, return TryStaticDowncast(Self, Self.Context.getCanonicalType(SrcPointer->getPointeeType()), Self.Context.getCanonicalType(DestPointer->getPointeeType()), - CStyle, OpRange, SrcType, DestType, msg, Kind); + CStyle, OpRange, SrcType, DestType, msg, Kind, + BasePath); } /// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and @@ -696,7 +699,7 @@ TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind) { + CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath) { // We can only work with complete types. But don't complain if it doesn't work if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) || Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0))) @@ -707,7 +710,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_NotApplicable; } - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) { return TC_NotApplicable; @@ -787,6 +790,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_Failed; } + Self.BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_BaseToDerived; return TC_Success; } @@ -802,22 +806,25 @@ TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); if (!DestMemPtr) return TC_NotApplicable; bool WasOverloadedFunction = false; DeclAccessPair FoundOverload; - if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, - FoundOverload)) { - CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); - SrcType = Self.Context.getMemberPointerType(Fn->getType(), - Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); - WasOverloadedFunction = true; + if (SrcExpr->getType() == Self.Context.OverloadTy) { + if (FunctionDecl *Fn + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + FoundOverload)) { + CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); + SrcType = Self.Context.getMemberPointerType(Fn->getType(), + Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); + WasOverloadedFunction = true; + } } - + const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>(); if (!SrcMemPtr) { msg = diag::err_bad_static_cast_member_pointer_nonmp; @@ -832,7 +839,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TC_NotApplicable; @@ -886,6 +893,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } } + Self.BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_DerivedToBaseMemberPointer; return TC_Success; } @@ -898,8 +906,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CastExpr::CastKind &Kind) { if (DestType->isRecordType()) { if (Self.RequireCompleteType(OpRange.getBegin(), DestType, diag::err_bad_dynamic_cast_incomplete)) { @@ -907,71 +914,35 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return TC_Failed; } } - - if (DestType->isReferenceType()) { - // All reference bindings insert implicit casts above that do the actual - // casting. - Kind = CastExpr::CK_NoOp; - - // At this point of CheckStaticCast, if the destination is a reference, - // this has to work. 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. - InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); - InitializationKind InitKind = InitializationKind::CreateCast(OpRange, - CStyle); - InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); - if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle) - return TC_NotApplicable; - - Sema::OwningExprResult Result - = InitSeq.Perform(Self, Entity, InitKind, - Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); - if (Result.isInvalid()) { - msg = 0; - return TC_Failed; - } - - SrcExpr = Result.takeAs<Expr>(); - return TC_Success; - } - - if (DestType->isRecordType()) { - if (CXXConstructorDecl *Constructor - = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, - OpRange.getBegin(), - InitializationKind::CreateDirect(OpRange.getBegin(), - OpRange.getBegin(), - OpRange.getEnd()))) { - ConversionDecl = Constructor; - Kind = CastExpr::CK_ConstructorConversion; - return TC_Success; - } - + + // At this point of CheckStaticCast, if the destination is a reference, + // this has to work. 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. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); + InitializationKind InitKind + = InitializationKind::CreateCast(/*FIXME:*/OpRange, + CStyle); + InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + if (InitSeq.getKind() == InitializationSequence::FailedSequence && + (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; + + Sema::OwningExprResult Result + = InitSeq.Perform(Self, Entity, InitKind, + Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); + if (Result.isInvalid()) { + msg = 0; + return TC_Failed; } - - // FIXME: To get a proper error from invalid conversions here, we need to - // reimplement more of this. - // FIXME: This does not actually perform the conversion, and thus does not - // check for ambiguity or access. - ImplicitConversionSequence ICS = - Self.TryImplicitConversion(SrcExpr, DestType, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false, - /*one of user provided casts*/true); - - if (ICS.isBad()) - return TC_NotApplicable; - - // The conversion is possible, so commit to it. - Kind = CastExpr::CK_NoOp; - msg = 0; - return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting, - /*IgnoreBaseAccess*/CStyle) ? - TC_Failed : TC_Success; + + if (InitSeq.isConstructorInitialization()) + Kind = CastExpr::CK_ConstructorConversion; + else + Kind = CastExpr::CK_NoOp; + + SrcExpr = Result.takeAs<Expr>(); + return TC_Success; } /// TryConstCast - See if a const_cast from source to destination is allowed, @@ -1234,9 +1205,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Success; } -bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, bool FunctionalStyle, - CXXMethodDecl *&ConversionDecl) { +bool +Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, + bool FunctionalStyle) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". @@ -1271,8 +1244,8 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, - Kind, ConversionDecl); + tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind, + BasePath); if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index c90f75e..c0ec9e9 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -24,61 +24,17 @@ using namespace clang; /// \brief Find the current instantiation that associated with the given type. -static CXXRecordDecl * -getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, - QualType T) { +static CXXRecordDecl *getCurrentInstantiationOf(QualType T) { if (T.isNull()) return 0; - - T = Context.getCanonicalType(T).getUnqualifiedType(); - - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { - // If we've hit a namespace or the global scope, then the - // nested-name-specifier can't refer to the current instantiation. - if (Ctx->isFileContext()) - return 0; - - // Skip non-class contexts. - CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); - if (!Record) - continue; - - // If this record type is not dependent, - if (!Record->isDependentType()) - return 0; - - // C++ [temp.dep.type]p1: - // - // In the definition of a class template, a nested class of a - // class template, a member of a class template, or a member of a - // nested class of a class template, a name refers to the current - // instantiation if it is - // -- the injected-class-name (9) of the class template or - // nested class, - // -- in the definition of a primary class template, the name - // of the class template followed by the template argument - // list of the primary template (as described below) - // enclosed in <>, - // -- in the definition of a nested class of a class template, - // the name of the nested class referenced as a member of - // the current instantiation, or - // -- in the definition of a partial specialization, the name - // of the class template followed by the template argument - // list of the partial specialization enclosed in <>. If - // the nth template parameter is a parameter pack, the nth - // template argument is a pack expansion (14.6.3) whose - // pattern is the name of the parameter pack. - // (FIXME: parameter packs) - // - // All of these options come down to having the - // nested-name-specifier type that is equivalent to the - // injected-class-name of one of the types that is currently in - // our context. - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) - return Record; - } - - return 0; + + const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); + if (isa<RecordType>(Ty)) + return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); + else if (isa<InjectedClassNameType>(Ty)) + return cast<InjectedClassNameType>(Ty)->getDecl(); + else + return 0; } /// \brief Compute the DeclContext that is associated with the given type. @@ -92,7 +48,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { if (const TagType *Tag = T->getAs<TagType>()) return Tag->getDecl(); - return ::getCurrentInstantiationOf(Context, CurContext, T); + return ::getCurrentInstantiationOf(T); } /// \brief Compute the DeclContext that is associated with the given @@ -218,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return 0; QualType T = QualType(NNS->getAsType(), 0); - return ::getCurrentInstantiationOf(Context, CurContext, T); + return ::getCurrentInstantiationOf(T); } /// \brief Require that the context specified by SS be complete. @@ -230,11 +186,10 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { /// that is currently being defined. Or, if we have a type that names /// a class template specialization that is not a complete type, we /// will attempt to instantiate that class template. -bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { - if (!SS.isSet() || SS.isInvalid()) - return false; +bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, + DeclContext *DC) { + assert(DC != 0 && "given null context"); - DeclContext *DC = computeDeclContext(SS, true); if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { // If this is a dependent type, then we consider it complete. if (Tag->isDependentContext()) @@ -247,10 +202,13 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { return false; // The type must be complete. - return RequireCompleteType(SS.getRange().getBegin(), - Context.getTypeDeclType(Tag), - PDiag(diag::err_incomplete_nested_name_spec) - << SS.getRange()); + if (RequireCompleteType(SS.getRange().getBegin(), + Context.getTypeDeclType(Tag), + PDiag(diag::err_incomplete_nested_name_spec) + << SS.getRange())) { + SS.setScopeRep(0); // Mark the ScopeSpec invalid. + return true; + } } return false; @@ -322,7 +280,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return 0; } -bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, +bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, TypeTy *ObjectTypePtr) { @@ -353,7 +311,8 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(SS, LookupCtx)) return false; LookupQualifiedName(Found, LookupCtx); @@ -384,7 +343,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -423,7 +382,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(SS, LookupCtx)) return 0; LookupQualifiedName(Found, LookupCtx); @@ -480,7 +440,8 @@ Sema::CXXScopeTy *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) && + if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext, + CTC_NoKeywords) && Found.isSingleResult() && isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { if (LookupCtx) @@ -593,7 +554,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. /// Returns a CXXScopeTy* object representing the C++ scope. Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -611,7 +572,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// conservatively correct to always return false from this method. /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. -bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, +bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), @@ -676,7 +637,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. -bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { +bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); if (SS.isInvalid()) return true; @@ -686,10 +647,15 @@ bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { // Before we enter a declarator's context, we need to make sure that // it is a complete declaration context. - if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC)) return true; EnterDeclaratorContext(S, DC); + + // Rebuild the nested name specifier for the new scope. + if (DC->isDependentContext()) + RebuildNestedNameSpecifierInCurrentInstantiation(SS); + return false; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f2520fc..7029711 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -26,6 +26,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" +#include "clang/Basic/TargetBuiltins.h" #include <limits> using namespace clang; @@ -155,14 +156,18 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return ExprError(); break; case Builtin::BI__builtin_return_address: - case Builtin::BI__builtin_frame_address: - if (SemaBuiltinStackAddress(TheCall)) + case Builtin::BI__builtin_frame_address: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 0, Result)) return ExprError(); break; - case Builtin::BI__builtin_eh_return_data_regno: - if (SemaBuiltinEHReturnDataRegNo(TheCall)) + } + case Builtin::BI__builtin_eh_return_data_regno: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 0, Result)) return ExprError(); break; + } case Builtin::BI__builtin_shufflevector: return SemaBuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since @@ -196,6 +201,15 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinAtomicOverloaded(TheCall)) return ExprError(); break; + + // Target specific builtins start here. + case X86::BI__builtin_ia32_palignr128: + case X86::BI__builtin_ia32_palignr: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 2, Result)) + return ExprError(); + break; + } } return move(TheCallResult); @@ -270,8 +284,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Ensure that we have at least one argument to do type inference from. if (TheCall->getNumArgs() < 1) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << TheCall->getCallee()->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); // Inspect the first argument of the atomic builtin. This should always be // a pointer type, whose element is an integral scalar or pointer type. @@ -367,8 +383,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Now that we know how many fixed arguments we expect, first check that we // have at least that many. if (TheCall->getNumArgs() < 1+NumFixed) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << TheCall->getCallee()->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1+NumFixed << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); // Get the decl for the concrete builtin from this, we can tell what the @@ -405,9 +423,8 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXMethodDecl *ConversionDecl = 0; - if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, - ConversionDecl)) + CXXBaseSpecifierArray BasePath; + if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath)) return true; // Okay, we have something that *can* be converted to the right type. Check @@ -416,7 +433,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false); + ImpCastExprToType(Arg, ValType, Kind); TheCall->setArg(i+1, Arg); } @@ -476,15 +493,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { if (TheCall->getNumArgs() > 2) { Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << Fn->getSourceRange() + << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << Fn->getSourceRange() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); return true; } if (TheCall->getNumArgs() < 2) { - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } // Determine whether the current function is variadic or not. @@ -492,15 +511,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { bool isVariadic; if (CurBlock) isVariadic = CurBlock->isVariadic; - else if (getCurFunctionDecl()) { - if (FunctionProtoType* FTP = - dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType())) - isVariadic = FTP->isVariadic(); - else - isVariadic = false; - } else { + else if (FunctionDecl *FD = getCurFunctionDecl()) + isVariadic = FD->isVariadic(); + else isVariadic = getCurMethodDecl()->isVariadic(); - } if (!isVariadic) { Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); @@ -538,11 +552,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + << 0 << 2 << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > 2) return Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ + << 0 /*function call*/ << 2 << TheCall->getNumArgs() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); @@ -580,11 +594,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (TheCall->getNumArgs() < NumArgs) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + << 0 << NumArgs << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > NumArgs) return Diag(TheCall->getArg(NumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ + << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); @@ -602,25 +616,14 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { return false; } -bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) { - // The signature for these builtins is exact; the only thing we need - // to check is that the argument is a constant. - SourceLocation Loc; - if (!TheCall->getArg(0)->isTypeDependent() && - !TheCall->getArg(0)->isValueDependent() && - !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc)) - return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange(); - - return false; -} - /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 3) return ExprError(Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 3 << TheCall->getNumArgs() + << TheCall->getSourceRange()); unsigned numElements = std::numeric_limits<unsigned>::max(); if (!TheCall->getArg(0)->isTypeDependent() && @@ -647,10 +650,14 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < numElements+2) return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + << 0 /*function call*/ + << numElements+2 << TheCall->getNumArgs() + << TheCall->getSourceRange()); return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + << 0 /*function call*/ + << numElements+2 << TheCall->getNumArgs() + << TheCall->getSourceRange()); } } @@ -659,11 +666,9 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->getArg(i)->isValueDependent()) continue; - llvm::APSInt Result(32); - if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_nonconstant_argument) - << TheCall->getArg(i)->getSourceRange()); + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, i, Result)) + return ExprError(); if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) return ExprError(Diag(TheCall->getLocStart(), @@ -691,30 +696,19 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << TheCall->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 3 << NumArgs + << TheCall->getSourceRange(); // Argument 0 is checked for us and the remaining arguments must be // constant integers. for (unsigned i = 1; i != NumArgs; ++i) { Expr *Arg = TheCall->getArg(i); - if (Arg->isTypeDependent()) - continue; - - if (!Arg->getType()->isIntegralType()) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type) - << Arg->getSourceRange(); - - ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast); - TheCall->setArg(i, Arg); - - if (Arg->isValueDependent()) - continue; - + llvm::APSInt Result; - if (!Arg->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + if (SemaBuiltinConstantArg(TheCall, i, Result)) + return true; // FIXME: gcc issues a warning and rewrites these to 0. These // seems especially odd for the third argument since the default @@ -733,42 +727,35 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { return false; } -/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the -/// operand must be an integer constant. -bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) { - llvm::APSInt Result; - if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_expr_not_ice) - << TheCall->getArg(0)->getSourceRange(); - +/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr +/// TheCall is a constant expression. +bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result) { + Expr *Arg = TheCall->getArg(ArgNum); + DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); + + if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; + + if (!Arg->isIntegerConstantExpr(Result, Context)) + return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type) + << FDecl->getDeclName() << Arg->getSourceRange(); + return false; } - /// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, /// int type). This simply type checks that type is one of the defined /// constants (0-3). // For compatability check 0-3, llvm only handles 0 and 2. bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { - Expr *Arg = TheCall->getArg(1); - if (Arg->isTypeDependent()) - return false; - - QualType ArgType = Arg->getType(); - const BuiltinType *BT = ArgType->getAs<BuiltinType>(); - llvm::APSInt Result(32); - if (!BT || BT->getKind() != BuiltinType::Int) - return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); - - if (Arg->isValueDependent()) - return false; - - if (!Arg->isIntegerConstantExpr(Result, Context)) { - return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); - } + llvm::APSInt Result; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + Expr *Arg = TheCall->getArg(1); if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) { return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -781,11 +768,13 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { /// This checks that val is a constant 1. bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(1); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; + llvm::APSInt Result; - llvm::APSInt Result(32); - if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1) + // TODO: This is less than ideal. Overload this to take a value. + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + + if (Result != 1) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -1885,6 +1874,17 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // Left shift gets black-listed based on a judgement call. case BinaryOperator::Shl: + // ...except that we want to treat '1 << (blah)' as logically + // positive. It's an important idiom. + if (IntegerLiteral *I + = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) { + if (I->getValue() == 1) { + IntRange R = IntRange::forType(C, E->getType()); + return IntRange(R.Width, /*NonNegative*/ true); + } + } + // fallthrough + case BinaryOperator::ShlAssign: return IntRange::forType(C, E->getType()); @@ -1945,6 +1945,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return GetExprRange(C, UO->getSubExpr(), MaxWidth); } } + + if (dyn_cast<OffsetOfExpr>(E)) { + IntRange::forType(C, E->getType()); + } FieldDecl *BitField = E->getBitField(); if (BitField) { diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index df14aa7..c075d16 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,12 +13,14 @@ #include "Sema.h" #include "Lookup.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include <list> #include <map> #include <vector> @@ -413,6 +415,9 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, return false; } + + if (Filter == &ResultBuilder::IsNestedNameSpecifier) + AsNestedNameSpecifier = true; // ... then it must be interesting! return true; @@ -502,7 +507,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { } for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag && + if (I->first->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -627,7 +632,7 @@ void ResultBuilder::ExitScope() { bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) - IDNS |= Decl::IDNS_Tag; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND)) return true; @@ -639,7 +644,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) - IDNS |= Decl::IDNS_Tag; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; return (ND->getIdentifierNamespace() & IDNS) && !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND); @@ -882,7 +887,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddPlaceholderChunk("identifier"); Pattern->AddChunk(CodeCompletionString::CK_Equal); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Using directives @@ -892,7 +896,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("namespace"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // asm(string-literal) @@ -901,7 +904,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("string-literal"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Explicit template instantiation @@ -909,7 +911,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("template"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("declaration"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -926,7 +927,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("using"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("qualified-id"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // using typename qualified-id; (only in a dependent context) @@ -937,7 +937,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("typename"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("qualified-id"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1090,7 +1089,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("expression"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // for ( for-init-statement ; condition ; expression ) { statements } @@ -1116,7 +1114,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // continue ; Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("continue"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1124,7 +1121,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // break ; Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("break"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1145,7 +1141,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); } - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // goto identifier ; @@ -1153,7 +1148,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("goto"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Using directives @@ -1163,7 +1157,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("namespace"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -2075,10 +2068,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, Results.ExitScope(); - // Add macros - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); - // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2108,13 +2097,17 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { return; } - ResultBuilder Results(*this, Filter); - Results.allowNestedNameSpecifiers(); + ResultBuilder Results(*this); CodeCompletionDeclConsumer Consumer(Results, CurContext); + + // First pass: look for tags. + Results.setFilter(Filter); LookupVisibleDecls(S, LookupTagName, Consumer); + + // Second pass: look for nested name specifiers. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2192,7 +2185,7 @@ void Sema::CodeCompleteCase(Scope *S) { CurContext, 0, false); } Results.ExitScope(); - + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2258,7 +2251,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: access? AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none), Args, NumArgs, CandidateSet, - false, false, /*PartialOverloading*/ true); + false, /*PartialOverloading*/true); } } @@ -2276,14 +2269,13 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } } - if (Results.empty()) - CodeCompleteOrdinaryName(S, CCC_Expression); - else + CodeCompleteOrdinaryName(S, CCC_Expression); + if (!Results.empty()) CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); } -void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, +void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { if (!SS.getScopeRep() || !CodeCompleter) return; @@ -2294,7 +2286,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, // Try to instantiate any non-dependent declaration contexts before // we look in them. - if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS)) + if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) return; ResultBuilder Results(*this); @@ -2307,8 +2299,6 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2329,8 +2319,6 @@ void Sema::CodeCompleteUsing(Scope *S) { LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2345,8 +2333,6 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2381,8 +2367,6 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2394,8 +2378,6 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2422,8 +2404,6 @@ void Sema::CodeCompleteOperatorName(Scope *S) { AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2484,7 +2464,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // @interface name @@ -2593,7 +2572,6 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // @synchronized ( expression ) { statements } @@ -2908,70 +2886,198 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc, +/// \brief When we have an expression with type "id", we may assume +/// that it has some more-specific class type based on knowledge of +/// common uses of Objective-C. This routine returns that class type, +/// or NULL if no better result could be determined. +static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { + ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E); + if (!Msg) + return 0; + + Selector Sel = Msg->getSelector(); + if (Sel.isNull()) + return 0; + + IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); + if (!Id) + return 0; + + ObjCMethodDecl *Method = Msg->getMethodDecl(); + if (!Method) + return 0; + + // Determine the class that we're sending the message to. + ObjCInterfaceDecl *IFace = 0; + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Class: + if (const ObjCInterfaceType *IFaceType + = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()) + IFace = IFaceType->getDecl(); + break; + + case ObjCMessageExpr::Instance: { + QualType T = Msg->getInstanceReceiver()->getType(); + if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>()) + IFace = Ptr->getInterfaceDecl(); + break; + } + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + break; + } + + if (!IFace) + return 0; + + ObjCInterfaceDecl *Super = IFace->getSuperClass(); + if (Method->isInstanceMethod()) + return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName()) + .Case("retain", IFace) + .Case("autorelease", IFace) + .Case("copy", IFace) + .Case("copyWithZone", IFace) + .Case("mutableCopy", IFace) + .Case("mutableCopyWithZone", IFace) + .Case("awakeFromCoder", IFace) + .Case("replacementObjectFromCoder", IFace) + .Case("class", IFace) + .Case("classForCoder", IFace) + .Case("superclass", Super) + .Default(0); + + return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName()) + .Case("new", IFace) + .Case("alloc", IFace) + .Case("allocWithZone", IFace) + .Case("class", IFace) + .Case("superclass", Super) + .Default(0); +} + +void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, IdentifierInfo **SelIdents, unsigned NumSelIdents) { - typedef CodeCompleteConsumer::Result Result; ObjCInterfaceDecl *CDecl = 0; + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { + // Figure out which interface we're in. + CDecl = CurMethod->getClassInterface(); + if (!CDecl) + return; + + // Find the superclass of this class. + CDecl = CDecl->getSuperClass(); + if (!CDecl) + return; - if (FName->isStr("super")) { - // We're sending a message to "super". - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { - // Figure out which interface we're in. - CDecl = CurMethod->getClassInterface(); - if (!CDecl) - return; - - // Find the superclass of this class. - CDecl = CDecl->getSuperClass(); - if (!CDecl) - return; + if (CurMethod->isInstanceMethod()) { + // We are inside an instance method, which means that the message + // send [super ...] is actually calling an instance method on the + // current object. Build the super expression and handle this like + // an instance method. + QualType SuperTy = Context.getObjCInterfaceType(CDecl); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + OwningExprResult Super + = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy)); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), + SelIdents, NumSelIdents); + } - if (CurMethod->isInstanceMethod()) { - // We are inside an instance method, which means that the message - // send [super ...] is actually calling an instance method on the - // current object. Build the super expression and handle this like - // an instance method. - QualType SuperTy = Context.getObjCInterfaceType(CDecl); - SuperTy = Context.getObjCObjectPointerType(SuperTy); - OwningExprResult Super - = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy)); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), - SelIdents, NumSelIdents); - } + // Fall through to send to the superclass in CDecl. + } else { + // "super" may be the name of a type or variable. Figure out which + // it is. + IdentifierInfo *Super = &Context.Idents.get("super"); + NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, + LookupOrdinaryName); + if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { + // "super" names an interface. Use it. + } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) { + if (const ObjCInterfaceType *Iface + = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>()) + CDecl = Iface->getDecl(); + } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) { + // "super" names an unresolved type; we can't be more specific. + } else { + // Assume that "super" names some kind of value and parse that way. + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(Super, SuperLoc); + OwningExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false); + return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), + SelIdents, NumSelIdents); + } - // Okay, we're calling a factory method in our superclass. - } + // Fall through } + TypeTy *Receiver = 0; + if (CDecl) + Receiver = Context.getObjCInterfaceType(CDecl).getAsOpaquePtr(); + return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, + NumSelIdents); +} + +void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + typedef CodeCompleteConsumer::Result Result; + ObjCInterfaceDecl *CDecl = 0; + // If the given name refers to an interface type, retrieve the // corresponding declaration. - if (!CDecl) - if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) { - QualType T = GetTypeFromParser(Ty, 0); - if (!T.isNull()) - if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) - CDecl = Interface->getDecl(); - } - - if (!CDecl && FName->isStr("super")) { - // "super" may be the name of a variable, in which case we are - // probably calling an instance method. - CXXScopeSpec SS; - UnqualifiedId id; - id.setIdentifier(FName, FNameLoc); - OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), - SelIdents, NumSelIdents); + if (Receiver) { + QualType T = GetTypeFromParser(Receiver, 0); + if (!T.isNull()) + if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) + CDecl = Interface->getDecl(); } // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + + if (CDecl) + AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); + else { + // We're messaging "id" as a type; provide all class/factory methods. + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || FactoryMethodPool.count(Sel) || + InstanceMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/false); + } + } + + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + M = FactoryMethodPool.begin(), + MEnd = FactoryMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); // This also suppresses remaining diagnostics. @@ -2990,15 +3096,17 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, DefaultFunctionArrayLvalueConversion(RecExpr); QualType ReceiverType = RecExpr->getType(); - if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) { - // FIXME: We're messaging 'id'. Do we actually want to look up every method - // in the universe? - return; - } - // Build the set of methods we can see. ResultBuilder Results(*this); Results.EnterNewScope(); + + // If we're messaging an expression with type "id" or "Class", check + // whether we know something special about the receiver that allows + // us to assume a more-specific receiver type. + if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) + if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) + ReceiverType = Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(IFace)); // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a @@ -3035,7 +3143,44 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, Results); } - + // Handle messages to "id". + else if (ReceiverType->isObjCIdType()) { + // We're messaging "id", so provide all instance methods we know + // about as code-completion results. + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || InstanceMethodPool.count(Sel) || + FactoryMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/true); + } + } + + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + M = InstanceMethodPool.begin(), + MEnd = InstanceMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -3076,7 +3221,8 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, // Tell the result set to ignore all of the protocols we have // already seen. for (unsigned I = 0; I != NumProtocols; ++I) - if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first)) + if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first, + Protocols[I].second)) Results.Ignore(Protocol); // Add all protocols. @@ -3140,13 +3286,14 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) { +void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { ResultBuilder Results(*this); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (CurClass && isa<ObjCInterfaceDecl>(CurClass)) Results.Ignore(CurClass); @@ -3171,7 +3318,8 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { } void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this); @@ -3180,7 +3328,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, // interface. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)) for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; Category = Category->getNextClassCategory()) @@ -3201,17 +3349,18 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, } void Sema::CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { typedef CodeCompleteConsumer::Result Result; // Find the corresponding interface. If we couldn't find the interface, the // program itself is ill-formed. However, we'll try to be helpful still by // providing the list of all of the categories we know about. NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass); if (!Class) - return CodeCompleteObjCInterfaceCategory(S, ClassName); + return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); ResultBuilder Results(*this); @@ -3306,3 +3455,224 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +typedef llvm::DenseMap<Selector, ObjCMethodDecl *> KnownMethodsMap; + +/// \brief Find all of the methods that reside in the given container +/// (and its superclasses, protocols, etc.) that meet the given +/// criteria. Insert those methods into the map of known methods, +/// indexed by selector so they can be easily found. +static void FindImplementableMethods(ASTContext &Context, + ObjCContainerDecl *Container, + bool WantInstanceMethods, + QualType ReturnType, + bool IsInImplementation, + KnownMethodsMap &KnownMethods) { + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = IFace->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + + // If we're not in the implementation of a class, also visit the + // superclass. + if (!IsInImplementation && IFace->getSuperClass()) + FindImplementableMethods(Context, IFace->getSuperClass(), + WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + + // Add methods from any class extensions (but not from categories; + // those should go into category implementations). + for (ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; + Cat = Cat->getNextClassCategory()) { + if (!Cat->IsClassExtension()) + continue; + + FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + } + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = Category->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = Protocol->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + + // Add methods in this container. This operation occurs last because + // we want the methods from this container to override any methods + // we've previously seen with the same selector. + for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), + MEnd = Container->meth_end(); + M != MEnd; ++M) { + if ((*M)->isInstanceMethod() == WantInstanceMethods) { + if (!ReturnType.isNull() && + !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType())) + continue; + + KnownMethods[(*M)->getSelector()] = *M; + } + } +} + +void Sema::CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnTy, + DeclPtrTy IDecl) { + // Determine the return type of the method we're declaring, if + // provided. + QualType ReturnType = GetTypeFromParser(ReturnTy); + + // Determine where we should start searching for methods, and where we + ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0; + bool IsInImplementation = false; + if (Decl *D = IDecl.getAs<Decl>()) { + if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) { + SearchDecl = Impl->getClassInterface(); + CurrentDecl = Impl; + IsInImplementation = true; + } else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(D)) { + SearchDecl = CatImpl->getCategoryDecl(); + CurrentDecl = CatImpl; + IsInImplementation = true; + } else { + SearchDecl = dyn_cast<ObjCContainerDecl>(D); + CurrentDecl = SearchDecl; + } + } + + if (!SearchDecl && S) { + if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) { + SearchDecl = dyn_cast<ObjCContainerDecl>(DC); + CurrentDecl = SearchDecl; + } + } + + if (!SearchDecl || !CurrentDecl) { + HandleCodeCompleteResults(this, CodeCompleter, 0, 0); + return; + } + + // Find all of the methods that we could declare/implement here. + KnownMethodsMap KnownMethods; + FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, + ReturnType, IsInImplementation, KnownMethods); + + // Erase any methods that have already been declared or + // implemented here. + for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(), + MEnd = CurrentDecl->meth_end(); + M != MEnd; ++M) { + if ((*M)->isInstanceMethod() != IsInstanceMethod) + continue; + + KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector()); + if (Pos != KnownMethods.end()) + KnownMethods.erase(Pos); + } + + // Add declarations or definitions for each of the known methods. + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + for (KnownMethodsMap::iterator M = KnownMethods.begin(), + MEnd = KnownMethods.end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = M->second; + CodeCompletionString *Pattern = new CodeCompletionString; + + // If the result type was not already provided, add it to the + // pattern as (type). + if (ReturnType.isNull()) { + std::string TypeStr; + Method->getResultType().getAsStringInternal(TypeStr, Policy); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddTextChunk(TypeStr); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + } + + Selector Sel = Method->getSelector(); + + // Add the first part of the selector to the pattern. + Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + + // Add parameters to the pattern. + unsigned I = 0; + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; (void)++P, ++I) { + // Add the part of the selector name. + if (I == 0) + Pattern->AddChunk(CodeCompletionString::CK_Colon); + else if (I < Sel.getNumArgs()) { + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(1)->getName()); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + } else + break; + + // Add the parameter type. + std::string TypeStr; + (*P)->getOriginalType().getAsStringInternal(TypeStr, Policy); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddTextChunk(TypeStr); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + + if (IdentifierInfo *Id = (*P)->getIdentifier()) + Pattern->AddTextChunk(Id->getName()); + } + + if (Method->isVariadic()) { + if (Method->param_size() > 0) + Pattern->AddChunk(CodeCompletionString::CK_Comma); + Pattern->AddTextChunk("..."); + } + + if (IsInImplementation) { + // We will be defining the method here, so add a compound statement. + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + if (!Method->getResultType()->isVoidType()) { + // If the result type is not void, add a return clause. + Pattern->AddTextChunk("return"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + } else + Pattern->AddPlaceholderChunk("statements"); + + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + } + + Results.AddResult(Result(Pattern)); + } + + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 541c271..0e839a9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -61,7 +61,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName, TypeTy *ObjectTypePtr) { // Determine where we will perform name lookup. @@ -70,7 +70,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); - } else if (SS && SS->isSet()) { + } else if (SS && SS->isNotEmpty()) { LookupCtx = computeDeclContext(*SS, false); if (!LookupCtx) { @@ -89,16 +89,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We know from the grammar that this name refers to a type, so build a // DependentNameType node to describe the type. - // FIXME: Record somewhere that this DependentNameType node has no "typename" - // keyword associated with it. - return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), + return CheckTypenameType(ETK_None, + (NestedNameSpecifier *)SS->getScopeRep(), II, SS->getRange()).getAsOpaquePtr(); } return 0; } - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(*SS, LookupCtx)) return 0; } @@ -236,7 +236,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, - const CXXScopeSpec *SS, + CXXScopeSpec *SS, TypeTy *&SuggestedType) { // We don't have anything to suggest (yet). SuggestedType = 0; @@ -246,31 +246,53 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName, NotForRedeclaration); - // FIXME: It would be nice if we could correct for typos in built-in - // names, such as "itn" for "int". - - if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) { - NamedDecl *Result = Lookup.getAsSingle<NamedDecl>(); - 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()); - 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()); - else - llvm_unreachable("could not have corrected a typo here"); + if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) { + if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) { + 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()); + 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()); + else + llvm_unreachable("could not have corrected a typo here"); - Diag(Result->getLocation(), diag::note_previous_decl) - << Result->getDeclName(); - - SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + Diag(Result->getLocation(), diag::note_previous_decl) + << Result->getDeclName(); + + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + 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; + } + } + + if (getLangOptions().CPlusPlus) { + // See if II is a class template that the user forgot to pass arguments to. + UnqualifiedId Name; + Name.setIdentifier(&II, IILoc); + CXXScopeSpec EmptySS; + TemplateTy TemplateResult; + if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult) + == TNK_Type_template) { + TemplateName TplName = TemplateResult.getAsVal<TemplateName>(); + Diag(IILoc, diag::err_template_missing_args) << TplName; + if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { + Diag(TplDecl->getLocation(), diag::note_template_decl_here) + << TplDecl->getTemplateParameters()->getSourceRange(); + } return true; } } @@ -522,6 +544,11 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; } + // If we failed to complete the type for some reason, don't + // diagnose the variable. + if (Ty->isIncompleteType()) + return false; + if (const TagType *TT = Ty->getAs<TagType>()) { const TagDecl *Tag = TT->getDecl(); if (Tag->hasAttr<UnusedAttr>()) @@ -558,40 +585,48 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // Diagnose unused variables in this scope. if (ShouldDiagnoseUnusedDecl(D) && - S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) - Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); - + S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) { + if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) + Diag(D->getLocation(), diag::warn_unused_exception_param) + << D->getDeclName(); + else + Diag(D->getLocation(), diag::warn_unused_variable) + << D->getDeclName(); + } // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } } -/// getObjCInterfaceDecl - Look up a for a class declaration in the scope. -/// return 0 if one not found. +/// \brief Look for an Objective-C class in the translation unit. /// -/// \param Id the name of the Objective-C class we're looking for. If +/// \param Id The name of the Objective-C class we're looking for. If /// typo-correction fixes this name, the Id will be updated /// to the fixed name. /// -/// \param RecoverLoc if provided, this routine will attempt to -/// recover from a typo in the name of an existing Objective-C class -/// and, if successful, will return the lookup that results from -/// typo-correction. +/// \param IdLoc The location of the name in the translation unit. +/// +/// \param TypoCorrection If true, this routine will attempt typo correction +/// if there is no class with the given name. +/// +/// \returns The declaration of the named Objective-C class, or NULL if the +/// class could not be found. ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, - SourceLocation RecoverLoc) { + SourceLocation IdLoc, + bool TypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. - NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName); + NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName); - if (!IDecl && !RecoverLoc.isInvalid()) { + if (!IDecl && TypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0) && + LookupResult R(*this, Id, IdLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { - Diag(RecoverLoc, diag::err_undef_interface_suggest) + Diag(IdLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() - << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString()); + << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString()); Diag(IDecl->getLocation(), diag::note_previous_decl) << IDecl->getDeclName(); @@ -639,7 +674,8 @@ void Sema::InitBuiltinVaListType() { return; IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName); + NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(), + LookupOrdinaryName, ForRedeclaration); TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); } @@ -691,7 +727,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), Loc, II, R, /*TInfo=*/0, - FunctionDecl::Extern, false, + FunctionDecl::Extern, + FunctionDecl::None, false, /*hasPrototype=*/true); New->setImplicit(); @@ -702,7 +739,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, - VarDecl::None, 0)); + VarDecl::None, VarDecl::None, 0)); New->setParams(Params.data(), Params.size()); } @@ -897,13 +934,12 @@ struct GNUCompatibleParamWarning { /// getSpecialMember - get the special member enum for a method. -static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, - const CXXMethodDecl *MD) { +Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { - if (Ctor->isDefaultConstructor()) - return Sema::CXXDefaultConstructor; if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; + + return Sema::CXXConstructor; } if (isa<CXXDestructorDecl>(MD)) @@ -1040,10 +1076,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); - const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); if (OldMethod && NewMethod) { - if (!NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { + // Preserve triviality. + NewMethod->setTrivial(OldMethod->isTrivial()); + + bool isFriend = NewMethod->getFriendObjectKind(); + + if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. @@ -1069,14 +1109,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - } else { - if (OldMethod->isImplicit()) { + + // Complain if this is an explicit declaration of a special + // member that was initially declared implicitly. + // + // As an exception, it's okay to befriend such methods in order + // to permit the implicit constructor/destructor/operator calls. + } else if (OldMethod->isImplicit()) { + if (isFriend) { + NewMethod->setImplicit(); + } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) - << New << getSpecialMember(Context, OldMethod); - - Diag(OldMethod->getLocation(), - diag::note_previous_implicit_declaration); + << New << getSpecialMember(OldMethod); return true; } } @@ -1125,7 +1170,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, *ParamType, /*TInfo=*/0, - VarDecl::None, 0); + VarDecl::None, VarDecl::None, + 0); Param->setImplicit(); Params.push_back(Param); } @@ -1441,7 +1487,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { Record->getDeclContext()->isRecord()) return BuildAnonymousStructOrUnion(S, DS, Record); - Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); } @@ -1463,9 +1509,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return DeclPtrTy::make(Tag); } - Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); - return DeclPtrTy(); } return DeclPtrTy::make(Tag); @@ -1558,6 +1603,64 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, return Invalid; } +/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to +/// a VarDecl::StorageClass. Any error reporting is up to the caller: +/// illegal input values are mapped to VarDecl::None. +/// If the input declaration context is a linkage specification +/// with no braces, then Extern is mapped to None. +static VarDecl::StorageClass +StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec, + DeclContext *DC) { + switch (StorageClassSpec) { + case DeclSpec::SCS_unspecified: return VarDecl::None; + case DeclSpec::SCS_extern: + // If the current context is a C++ linkage specification + // having no braces, then the keyword "extern" is properly part + // of the linkage specification itself, rather than being + // the written storage class specifier. + return (DC && isa<LinkageSpecDecl>(DC) && + !cast<LinkageSpecDecl>(DC)->hasBraces()) + ? VarDecl::None : VarDecl::Extern; + case DeclSpec::SCS_static: return VarDecl::Static; + case DeclSpec::SCS_auto: return VarDecl::Auto; + case DeclSpec::SCS_register: return VarDecl::Register; + case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern; + // Illegal SCSs map to None: error reporting is up to the caller. + case DeclSpec::SCS_mutable: // Fall through. + case DeclSpec::SCS_typedef: return VarDecl::None; + } + llvm_unreachable("unknown storage class specifier"); +} + +/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to +/// a FunctionDecl::StorageClass. Any error reporting is up to the caller: +/// illegal input values are mapped to FunctionDecl::None. +/// If the input declaration context is a linkage specification +/// with no braces, then Extern is mapped to None. +static FunctionDecl::StorageClass +StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, + DeclContext *DC) { + switch (StorageClassSpec) { + case DeclSpec::SCS_unspecified: return FunctionDecl::None; + case DeclSpec::SCS_extern: + // If the current context is a C++ linkage specification + // having no braces, then the keyword "extern" is properly part + // of the linkage specification itself, rather than being + // the written storage class specifier. + return (DC && isa<LinkageSpecDecl>(DC) && + !cast<LinkageSpecDecl>(DC)->hasBraces()) + ? FunctionDecl::None : FunctionDecl::Extern; + case DeclSpec::SCS_static: return FunctionDecl::Static; + case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern; + // Illegal SCSs map to None: error reporting is up to the caller. + case DeclSpec::SCS_auto: // Fall through. + case DeclSpec::SCS_mutable: // Fall through. + case DeclSpec::SCS_register: // Fall through. + case DeclSpec::SCS_typedef: return FunctionDecl::None; + } + llvm_unreachable("unknown storage class specifier"); +} + /// ActOnAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a GNU C extension; anonymous structures @@ -1675,32 +1778,31 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus) { FieldCollector->Add(cast<FieldDecl>(Anon)); + if (!cast<CXXRecordDecl>(Record)->isEmpty()) + cast<CXXRecordDecl>(OwningClass)->setEmpty(false); + } } else { - VarDecl::StorageClass SC; - switch (DS.getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; - case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; - case DeclSpec::SCS_static: SC = VarDecl::Static; break; - case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; - case DeclSpec::SCS_register: SC = VarDecl::Register; break; - case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; - case DeclSpec::SCS_mutable: + DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); + assert(SCSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(Record->getLocation(), diag::err_mutable_nonmember); Invalid = true; SC = VarDecl::None; - break; } + SCSpec = DS.getStorageClassSpecAsWritten(); + VarDecl::StorageClass SCAsWritten + = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - TInfo, - SC); + TInfo, SC, SCAsWritten); } Anon->setImplicit(); @@ -1708,7 +1810,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // context. We'll be referencing this object when we refer to one of // its members. Owner->addDecl(Anon); - + // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. @@ -1829,6 +1931,71 @@ static bool isNearlyMatchingFunction(ASTContext &Context, return true; } +/// NeedsRebuildingInCurrentInstantiation - Checks whether the given +/// declarator needs to be rebuilt in the current instantiation. +/// Any bits of declarator which appear before the name are valid for +/// consideration here. That's specifically the type in the decl spec +/// and the base type in any member-pointer chunks. +static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, + DeclarationName Name) { + // The types we specifically need to rebuild are: + // - typenames, typeofs, and decltypes + // - types which will become injected class names + // Of course, we also need to rebuild any type referencing such a + // type. It's safest to just say "dependent", but we call out a + // few cases here. + + DeclSpec &DS = D.getMutableDeclSpec(); + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_typename: + case DeclSpec::TST_typeofType: + case DeclSpec::TST_typeofExpr: + case DeclSpec::TST_decltype: { + // Grab the type from the parser. + TypeSourceInfo *TSI = 0; + QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI); + if (T.isNull() || !T->isDependentType()) break; + + // Make sure there's a type source info. This isn't really much + // of a waste; most dependent types should have type source info + // attached already. + if (!TSI) + TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc()); + + // Rebuild the type in the current instantiation. + TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name); + if (!TSI) return true; + + // Store the new type back in the decl spec. + QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI); + DS.UpdateTypeRep(LocType.getAsOpaquePtr()); + break; + } + + default: + // Nothing to do for these decl specs. + break; + } + + // It doesn't matter what order we do this in. + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + DeclaratorChunk &Chunk = D.getTypeObject(I); + + // The only type information in the declarator which can come + // before the declaration name is the base type of a member + // pointer. + if (Chunk.Kind != DeclaratorChunk::MemberPointer) + continue; + + // Rebuild the scope specifier in-place. + CXXScopeSpec &SS = Chunk.Mem.Scope(); + if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS)) + return true; + } + + return false; +} + Sema::DeclPtrTy Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, @@ -1851,35 +2018,47 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); - // If this is an out-of-line definition of a member of a class template - // or class template partial specialization, we may need to rebuild the - // type specifier in the declarator. See RebuildTypeInCurrentInstantiation() - // for more information. - // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can - // handle expressions properly. - DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec()); - if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() && - isDependentScopeSpecifier(D.getCXXScopeSpec()) && - (DS.getTypeSpecType() == DeclSpec::TST_typename || - DS.getTypeSpecType() == DeclSpec::TST_typeofType || - DS.getTypeSpecType() == DeclSpec::TST_typeofExpr || - DS.getTypeSpecType() == DeclSpec::TST_decltype)) { - if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) { - // FIXME: Preserve type source info. - QualType T = GetTypeFromParser(DS.getTypeRep()); - - DeclContext *SavedContext = CurContext; - CurContext = DC; - T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name); - CurContext = SavedContext; - - if (T.isNull()) - return DeclPtrTy(); - DS.UpdateTypeRep(T.getAsOpaquePtr()); + DeclContext *DC = CurContext; + if (D.getCXXScopeSpec().isInvalid()) + D.setInvalidType(); + else if (D.getCXXScopeSpec().isSet()) { + bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); + DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); + if (!DC) { + // If we could not compute the declaration context, it's because the + // declaration context is dependent but does not refer to a class, + // class template, or class template partial specialization. Complain + // and return early, to avoid the coming semantic disaster. + Diag(D.getIdentifierLoc(), + diag::err_template_qualified_declarator_no_match) + << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() + << D.getCXXScopeSpec().getRange(); + return DeclPtrTy(); + } + + bool IsDependentContext = DC->isDependentContext(); + + if (!IsDependentContext && + RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) + return DeclPtrTy(); + + if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } + + // Check whether we need to rebuild the type of the given + // declaration in the current instantiation. + if (EnteringContext && IsDependentContext && + TemplateParamLists.size() != 0) { + ContextRAII SavedContext(*this, DC); + if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name)) + D.setInvalidType(); } } - DeclContext *DC; NamedDecl *New; TypeSourceInfo *TInfo = 0; @@ -1889,10 +2068,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, ForRedeclaration); // See if this is a redefinition of a variable in the same scope. - if (D.getCXXScopeSpec().isInvalid()) { - DC = CurContext; - D.setInvalidType(); - } else if (!D.getCXXScopeSpec().isSet()) { + if (!D.getCXXScopeSpec().isSet()) { bool IsLinkageLookup = false; // If the declaration we're planning to build will be a function @@ -1913,34 +2089,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (IsLinkageLookup) Previous.clear(LookupRedeclarationWithLinkage); - DC = CurContext; LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup); } else { // Something like "int foo::x;" - DC = computeDeclContext(D.getCXXScopeSpec(), true); - - if (!DC) { - // If we could not compute the declaration context, it's because the - // declaration context is dependent but does not refer to a class, - // class template, or class template partial specialization. Complain - // and return early, to avoid the coming semantic disaster. - Diag(D.getIdentifierLoc(), - diag::err_template_qualified_declarator_no_match) - << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() - << D.getCXXScopeSpec().getRange(); - return DeclPtrTy(); - } - - if (!DC->isDependentContext() && - RequireCompleteDeclContext(D.getCXXScopeSpec())) - return DeclPtrTy(); - - if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { - Diag(D.getIdentifierLoc(), - diag::err_member_def_undefined_record) - << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); - } - LookupQualifiedName(Previous, DC); // Don't consider using declarations as previous declarations for @@ -2298,24 +2448,20 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - VarDecl *NewVD; - VarDecl::StorageClass SC; - switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; - case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; - case DeclSpec::SCS_static: SC = VarDecl::Static; break; - case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; - case DeclSpec::SCS_register: SC = VarDecl::Register; break; - case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; - case DeclSpec::SCS_mutable: + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); + assert(SCSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); D.setInvalidType(); SC = VarDecl::None; - break; } + SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + VarDecl::StorageClass SCAsWritten + = StorageClassSpecToVarDeclStorageClass(SCSpec, DC); IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { @@ -2367,6 +2513,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + /*never a friend*/ false, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // There is no such thing as a variable template. @@ -2388,8 +2535,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC); + VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -2767,6 +2914,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + FunctionDecl::StorageClass SCAsWritten + = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC); + // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. @@ -2827,7 +2978,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, isInline, + Name, R, TInfo, SC, SCAsWritten, isInline, /*hasPrototype=*/true); D.setInvalidType(); } @@ -2876,7 +3027,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getIdentifierLoc(), Name, R, TInfo, - isStatic, isInline); + isStatic, SCAsWritten, isInline); isVirtualOkay = !isStatic; } else { @@ -2893,7 +3044,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, isInline, HasPrototype); + Name, R, TInfo, SC, SCAsWritten, isInline, + HasPrototype); } if (D.isInvalidType()) @@ -2917,6 +3069,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + isFriend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a function template @@ -2935,7 +3088,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a function template specialization. isFunctionTemplateSpecialization = true; - // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);". + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend && isFunctionTemplateSpecialization) { // We want to remove the "template<>", found here. SourceRange RemoveRange = TemplateParams->getSourceRange(); @@ -3015,10 +3168,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); - } else { - NewFD->setObjectOfFriendDecl(false); } - + NewFD->setObjectOfFriendDecl(false); NewFD->setAccess(AS_public); } @@ -3072,6 +3223,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); + + if (Param->isInvalidDecl()) + NewFD->setInvalidDecl(); } } @@ -3091,6 +3245,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(), 0, *AI, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -3139,24 +3294,39 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } + } else if (isFriend && isFunctionTemplateSpecialization) { + // This combination is only possible in a recovery case; the user + // wrote something like: + // template <> friend void foo(int); + // which we're recovering from as if the user had written: + // friend void foo<>(int); + // Go ahead and fake up a template id. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); + } + + // If it's a friend (and only if it's a friend), it's possible + // that either the specialized function type or the specialized + // template is dependent, and therefore matching will fail. In + // this case, don't check the specialization yet. + if (isFunctionTemplateSpecialization && isFriend && + (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + assert(HasExplicitTemplateArgs && + "friend function specialization without template args"); + if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } else if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { + if (CheckMemberSpecialization(NewFD, Previous)) + NewFD->setInvalidDecl(); } - if (isFunctionTemplateSpecialization) { - if (isFriend && NewFD->getType()->isDependentType()) { - // FIXME: When we see a friend of a function template - // specialization with a dependent type, we can't match it now; - // for now, we just drop it, until we have a reasonable way to - // represent the parsed-but-not-matched friend function template - // specialization in the AST. - return 0; - } else if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && - CheckMemberSpecialization(NewFD, Previous)) - NewFD->setInvalidDecl(); - // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, @@ -3166,17 +3336,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + NamedDecl *PrincipalDecl = (FunctionTemplate + ? cast<NamedDecl>(FunctionTemplate) + : NewFD); + if (isFriend && Redeclaration) { - AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess(); - if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(true); - FunctionTemplate->setAccess(Access); - } else { - NewFD->setObjectOfFriendDecl(true); - } + AccessSpecifier Access = AS_public; + if (!NewFD->isInvalidDecl()) + Access = NewFD->getPreviousDeclaration()->getAccess(); + NewFD->setAccess(Access); + if (FunctionTemplate) FunctionTemplate->setAccess(Access); + + PrincipalDecl->setObjectOfFriendDecl(true); } + if (NewFD->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); + // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { @@ -3286,7 +3464,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: Also include static functions declared but not defined. if (!NewFD->isInvalidDecl() && IsFunctionDefinition && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage - && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>()) + && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>() + && !NewFD->hasAttr<ConstructorAttr>() + && !NewFD->hasAttr<DestructorAttr>()) UnusedStaticFuncs.push_back(NewFD); return NewFD; @@ -3761,7 +3941,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { } } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClass() == VarDecl::Extern) + if (VDecl->getStorageClass() == VarDecl::Extern && + (!getLangOptions().CPlusPlus || + !Context.getBaseElementType(VDecl->getType()).isConstQualified())) Diag(VDecl->getLocation(), diag::warn_extern_init); if (!VDecl->isInvalidDecl()) { InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); @@ -4030,8 +4212,10 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. VarDecl::StorageClass StorageClass = VarDecl::None; + VarDecl::StorageClass StorageClassAsWritten = VarDecl::None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { StorageClass = VarDecl::Register; + StorageClassAsWritten = VarDecl::Register; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); @@ -4084,55 +4268,24 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { } } - // Parameters can not be abstract class types. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!CurContext->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, - diag::err_abstract_type_in_decl, - AbstractParamType)) - D.setInvalidType(true); - - QualType T = adjustParameterType(parmDeclType); - // Temporarily put parameter variables in the translation unit, not // the enclosing context. This prevents them from accidentally // looking like class members in C++. - DeclContext *DC = Context.getTranslationUnitDecl(); - - ParmVarDecl *New - = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II, - T, TInfo, StorageClass, 0); + ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), + TInfo, parmDeclType, II, + D.getIdentifierLoc(), + StorageClass, StorageClassAsWritten); if (D.isInvalidType()) - New->setInvalidDecl(); - - // Parameter declarators cannot be interface types. All ObjC objects are - // passed by reference. - if (T->isObjCInterfaceType()) { - Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; - New->setInvalidDecl(); - } - + New->setInvalidDecl(); + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) << D.getCXXScopeSpec().getRange(); New->setInvalidDecl(); } - - // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage - // duration shall not be qualified by an address-space qualifier." - // Since all parameters have automatic store duration, they can not have - // an address space. - if (T.getAddressSpace() != 0) { - Diag(D.getIdentifierLoc(), - diag::err_arg_with_address_space); - New->setInvalidDecl(); - } - - + // Add the parameter declaration into this scope. S->AddDecl(DeclPtrTy::make(New)); if (II) @@ -4146,9 +4299,43 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy::make(New); } -void Sema::ActOnObjCCatchParam(DeclPtrTy D) { - ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>()); - Param->setDeclContext(CurContext); +ParmVarDecl *Sema::CheckParameter(DeclContext *DC, + TypeSourceInfo *TSInfo, QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + VarDecl::StorageClass StorageClass, + VarDecl::StorageClass StorageClassAsWritten) { + ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name, + adjustParameterType(T), TSInfo, + StorageClass, StorageClassAsWritten, + 0); + + // Parameters can not be abstract class types. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!CurContext->isRecord() && + RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl, + AbstractParamType)) + New->setInvalidDecl(); + + // Parameter declarators cannot be interface types. All ObjC objects are + // passed by reference. + if (T->isObjCInterfaceType()) { + Diag(NameLoc, + diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; + New->setInvalidDecl(); + } + + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // duration shall not be qualified by an address-space qualifier." + // Since all parameters have automatic store duration, they can not have + // an address space. + if (T.getAddressSpace() != 0) { + Diag(NameLoc, diag::err_arg_with_address_space); + New->setInvalidDecl(); + } + + return New; } void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, @@ -4692,7 +4879,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -4711,6 +4898,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may @@ -4761,12 +4949,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, IsDependent = true; return DeclPtrTy(); } + } else { + DC = computeDeclContext(SS, true); + if (!DC) { + Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) + << SS.getRange(); + return DeclPtrTy(); + } } - if (RequireCompleteDeclContext(SS)) + if (RequireCompleteDeclContext(SS, DC)) return DeclPtrTy::make((Decl *)0); - DC = computeDeclContext(SS, true); SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); @@ -4891,17 +5085,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // class or function, the friend class or function is a member of // the innermost enclosing namespace. SearchDC = SearchDC->getEnclosingNamespaceContext(); - - // Look up through our scopes until we find one with an entity which - // matches our declaration context. - while (S->getEntity() && - ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { - S = S->getParent(); - assert(S && "No enclosing scope matching the enclosing namespace."); - } } - // In C++, look for a shadow friend decl. + // In C++, we need to do a redeclaration lookup to properly + // diagnose some problems. if (getLangOptions().CPlusPlus) { Previous.setRedeclarationKind(ForRedeclaration); LookupQualifiedName(Previous, SearchDC); @@ -4909,8 +5096,32 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (!Previous.empty()) { - assert(Previous.isSingleResult()); - NamedDecl *PrevDecl = Previous.getFoundDecl(); + NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl(); + + // It's okay to have a tag decl in the same scope as a typedef + // which hides a tag decl in the same scope. Finding this + // insanity with a redeclaration lookup can only actually happen + // in C++. + // + // This is also okay for elaborated-type-specifiers, which is + // technically forbidden by the current standard but which is + // okay according to the likely resolution of an open issue; + // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 + if (getLangOptions().CPlusPlus) { + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) { + if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { + TagDecl *Tag = TT->getDecl(); + if (Tag->getDeclName() == Name && + Tag->getDeclContext()->getLookupContext() + ->Equals(TD->getDeclContext()->getLookupContext())) { + PrevDecl = Tag; + Previous.clear(); + Previous.addDecl(Tag); + } + } + } + } + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -5002,23 +5213,61 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. + + + // Otherwise, PrevDecl is not a tag, but was found with tag + // lookup. This is only actually possible in C++, where a few + // things like templates still live in the tag namespace. } else { - // PrevDecl is a namespace, template, or anything else - // that lives in the IDNS_Tag identifier namespace. - if (TUK == TUK_Reference || TUK == TUK_Friend || - isDeclInScope(PrevDecl, SearchDC, S)) { - // The tag name clashes with a namespace name, issue an error and - // recover by making this tag be anonymous. + assert(getLangOptions().CPlusPlus); + + // Use a better diagnostic if an elaborated-type-specifier + // found the wrong kind of type on the first + // (non-redeclaration) lookup. + if ((TUK == TUK_Reference || TUK == TUK_Friend) && + !Previous.isForRedeclaration()) { + unsigned Kind = 0; + if (isa<TypedefDecl>(PrevDecl)) Kind = 1; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; + Diag(PrevDecl->getLocation(), diag::note_declared_at); + Invalid = true; + + // Otherwise, only diagnose if the declaration is in scope. + } else if (!isDeclInScope(PrevDecl, SearchDC, S)) { + // do nothing + + // Diagnose implicit declarations introduced by elaborated types. + } else if (TUK == TUK_Reference || TUK == TUK_Friend) { + unsigned Kind = 0; + if (isa<TypedefDecl>(PrevDecl)) Kind = 1; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; + Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; + Invalid = true; + + // Otherwise it's a declaration. Call out a particularly common + // case here. + } else if (isa<TypedefDecl>(PrevDecl)) { + Diag(NameLoc, diag::err_tag_definition_of_typedef) + << Name + << cast<TypedefDecl>(PrevDecl)->getUnderlyingType(); + Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; + Invalid = true; + + // Otherwise, diagnose. + } else { + // The tag name clashes with something else in the target scope, + // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; - Previous.clear(); Invalid = true; - } else { - // The existing declaration isn't relevant to us; we're in a - // new scope, so clear out the previous declaration. - Previous.clear(); } + + // The existing declaration isn't relevant to us; we're in a + // new scope, so clear out the previous declaration. + Previous.clear(); } } @@ -5089,28 +5338,6 @@ CreateNewDecl: New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8)); } - if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) { - // C++ [dcl.typedef]p3: - // [...] Similarly, in a given scope, a class or enumeration - // shall not be declared with the same name as a typedef-name - // that is declared in that scope and refers to a type other - // than the class or enumeration itself. - LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); - LookupName(Lookup, S); - TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>(); - NamedDecl *PrevTypedefNamed = PrevTypedef; - if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && - Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != - Context.getCanonicalType(Context.getTypeDeclType(New))) { - Diag(Loc, diag::err_tag_definition_of_typedef) - << Context.getTypeDeclType(New) - << PrevTypedef->getUnderlyingType(); - Diag(PrevTypedef->getLocation(), diag::note_previous_definition); - Invalid = true; - } - } - // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) @@ -5175,7 +5402,7 @@ CreateNewDecl: void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); - + // Enter the tag context. PushDeclContext(S, Tag); } @@ -5321,11 +5548,23 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, if (!FieldTy->isDependentType()) { uint64_t TypeSize = Context.getTypeSize(FieldTy); if (Value.getZExtValue() > TypeSize) { + if (!getLangOptions().CPlusPlus) { + if (FieldName) + return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)Value.getZExtValue() + << (unsigned)TypeSize; + + return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) + << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; + } + if (FieldName) - return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) - << FieldName << (unsigned)TypeSize; - return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) - << (unsigned)TypeSize; + Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)Value.getZExtValue() + << (unsigned)TypeSize; + else + Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size) + << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } } @@ -5363,7 +5602,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { @@ -5506,21 +5745,17 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // because otherwise we'll never get complaints about // copy constructors. - const CXXSpecialMember invalid = (CXXSpecialMember) -1; - - CXXSpecialMember member; + CXXSpecialMember member = CXXInvalid; if (!RDecl->hasTrivialCopyConstructor()) member = CXXCopyConstructor; else if (!RDecl->hasTrivialConstructor()) - member = CXXDefaultConstructor; + member = CXXConstructor; else if (!RDecl->hasTrivialCopyAssignment()) member = CXXCopyAssignment; else if (!RDecl->hasTrivialDestructor()) member = CXXDestructor; - else - member = invalid; - if (member != invalid) { + if (member != CXXInvalid) { Diag(Loc, diag::err_illegal_union_member) << Name << member; DiagnoseNontrivial(RT, member); NewFD->setInvalidDecl(); @@ -5562,14 +5797,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { // Check whether the member was user-declared. switch (member) { - case CXXDefaultConstructor: + case CXXInvalid: + break; + + case CXXConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ const FunctionDecl *body = 0; ci->getBody(body); - if (!body || - !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) { + if (!body || !cast<CXXConstructorDecl>(body)->isImplicitlyDefined()) { SourceLocation CtorLoc = ci->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; @@ -5637,7 +5874,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { bool (CXXRecordDecl::*hasTrivial)() const; switch (member) { - case CXXDefaultConstructor: + case CXXConstructor: hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break; case CXXCopyConstructor: hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; @@ -5727,10 +5964,13 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // validate II. } - + if (T->isReferenceType()) { + Diag(Loc, diag::err_ivar_reference_type); + D.setInvalidType(); + } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. - if (T->isVariablyModifiedType()) { + else if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); D.setInvalidType(); } @@ -5747,8 +5987,16 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Case of ivar declared in an implementation. Context is that of its class. EnclosingContext = IMPDecl->getClassInterface(); assert(EnclosingContext && "Implementation has no class interface!"); - } else + } else { + if (ObjCCategoryDecl *CDecl = + dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { + if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) { + Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); + return DeclPtrTy(); + } + } EnclosingContext = EnclosingDecl; + } // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, @@ -5756,7 +6004,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, TInfo, ac, (Expr *)BitfieldWidth); if (II) { - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { @@ -5926,16 +6174,14 @@ void Sema::ActOnFields(Scope* S, CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); } else if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { - if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) - Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); - else { - // FIXME. Class extension does not have a LocEnd field. - // CDecl->setLocEnd(RBrac); - // Add ivar's to class extension's DeclContext. - for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { - ClsFields[i]->setLexicalDeclContext(CDecl); - CDecl->addDecl(ClsFields[i]); - } + // case of ivars in class extension; all other cases have been + // reported as errors elsewhere. + // FIXME. Class extension does not have a LocEnd field. + // CDecl->setLocEnd(RBrac); + // Add ivar's to class extension's DeclContext. + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + ClsFields[i]->setLexicalDeclContext(CDecl); + CDecl->addDecl(ClsFields[i]); } } } @@ -5950,7 +6196,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, QualType T) { assert(T->isIntegralType() && "Integral type required!"); - unsigned BitWidth = Context.getTypeSize(T); + unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) return Value.getActiveBits() < BitWidth; @@ -6083,7 +6329,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); - EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, @@ -6105,7 +6351,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. - EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); } @@ -6131,7 +6377,7 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. - NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName, + NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. @@ -6357,6 +6603,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, CastExpr::CK_IntegralCast, ECD->getInitExpr(), + CXXBaseSpecifierArray(), /*isLvalue=*/false)); if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an @@ -6383,7 +6630,7 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { - Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { PrevDecl->addAttr(::new (Context) WeakAttr()); @@ -6399,7 +6646,8 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { - Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc, + LookupOrdinaryName); WeakInfo W = WeakInfo(Name, NameLoc); if (PrevDecl) { diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index cc24735..90aa9c1 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -118,7 +118,7 @@ static bool isFunctionOrMethodVariadic(const Decl *d) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) - return BD->IsVariadic(); + return BD->isVariadic(); else { return cast<ObjCMethodDecl>(d)->isVariadic(); } @@ -490,16 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // NOTE: We don't add the attribute to a FunctionDecl because the noreturn - // trait will be part of the function's type. - - // Don't apply as a decl attribute to ValueDecl. - // FIXME: probably ought to diagnose this. - if (isa<ValueDecl>(d)) - return; - - if (HandleCommonNoReturnAttr(d, Attr, S)) - d->addAttr(::new (S.Context) NoReturnAttr()); + /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */ + assert(Attr.isInvalid() == false); + d->addAttr(::new (S.Context) NoReturnAttr()); } static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, @@ -900,9 +893,12 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // We ignore weak import on properties and methods return; } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; + // Don't issue the warning for darwin as target; yet, ignore the attribute. + if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin || + !isa<ObjCInterfaceDecl>(D)) + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; } // Merge should handle any subsequent violations. @@ -1022,8 +1018,11 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // Look up the function + // FIXME: Lookup probably isn't looking in the right place + // FIXME: The lookup source location should be in the attribute, not the + // start of the attribute. NamedDecl *CleanupDecl - = S.LookupSingleName(S.TUScope, Attr.getParameterName(), + = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(), Sema::LookupOrdinaryName); if (!CleanupDecl) { S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) << @@ -1643,6 +1642,27 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) GNUInlineAttr()); } +static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Diagnostic is emitted elsewhere: here we store the (valid) Attr + // in the Decl node for syntactic reasoning, e.g., pretty-printing. + assert(Attr.isInvalid() == false); + + switch (Attr.getKind()) { + case AttributeList::AT_fastcall: + d->addAttr(::new (S.Context) FastCallAttr()); + return; + case AttributeList::AT_stdcall: + d->addAttr(::new (S.Context) StdCallAttr()); + return; + case AttributeList::AT_cdecl: + d->addAttr(::new (S.Context) CDeclAttr()); + return; + default: + llvm_unreachable("unexpected attribute kind"); + return; + } +} + static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -1843,6 +1863,9 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) { /// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) { + if (Attr.isInvalid()) + return; + if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) // FIXME: Try to deal with other __declspec attributes! return; @@ -1927,7 +1950,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_stdcall: case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: - // These are all treated as type attributes. + HandleCallConvAttr(D, Attr, S); break; default: // Ask target about the attribute. @@ -1972,7 +1995,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), - VD->getStorageClass()); + VD->getStorageClass(), + VD->getStorageClassAsWritten()); if (VD->getQualifier()) { VarDecl *NewVD = cast<VarDecl>(NewD); NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange()); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 39e3739..6259b85a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -16,12 +16,13 @@ #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" @@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { << OldParam->getDefaultArgRange(); Invalid = true; } else if (OldParam->hasDefaultArg()) { - // Merge the old default argument into the new parameter + // Merge the old default argument into the new parameter. + // It's important to use getInit() here; getDefaultArg() + // strips off any top-level CXXExprWithTemporaries. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); else - NewParam->setDefaultArg(OldParam->getDefaultArg()); + NewParam->setDefaultArg(OldParam->getInit()); } else if (NewParam->hasDefaultArg()) { if (New->getDescribedFunctionTemplate()) { // Paragraph 4, quoted above, only applies to non-template functions. @@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { return DerivedRD->isDerivedFrom(BaseRD, Paths); } +void Sema::BuildBasePathArray(const CXXBasePaths &Paths, + CXXBaseSpecifierArray &BasePathArray) { + assert(BasePathArray.empty() && "Base path array must be empty!"); + assert(Paths.isRecordingPaths() && "Must record paths!"); + + const CXXBasePath &Path = Paths.front(); + + // We first go backward and check if we have a virtual base. + // FIXME: It would be better if CXXBasePath had the base specifier for + // the nearest virtual base. + unsigned Start = 0; + for (unsigned I = Path.size(); I != 0; --I) { + if (Path[I - 1].Base->isVirtual()) { + Start = I - 1; + break; + } + } + + // Now add all bases. + for (unsigned I = Start, E = Path.size(); I != E; ++I) + BasePathArray.push_back(Path[I].Base); +} + /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, - DeclarationName Name) { + DeclarationName Name, + CXXBaseSpecifierArray *BasePath) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to @@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (!InaccessibleBaseID) - return false; - - // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), - InaccessibleBaseID)) { - case AR_accessible: return false; - case AR_inaccessible: return true; - case AR_dependent: return false; - case AR_delayed: return false; + if (InaccessibleBaseID) { + // Check that the base class can be accessed. + switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), + InaccessibleBaseID)) { + case AR_inaccessible: + return true; + case AR_accessible: + case AR_dependent: + case AR_delayed: + break; + } } + + // Build a base path if necessary. + if (BasePath) + BuildBasePathArray(Paths, *BasePath); + return false; } // We know that the derived-to-base conversion is ambiguous, and @@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, + CXXBaseSpecifierArray *BasePath, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, IgnoreAccess ? 0 : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, - Loc, Range, DeclarationName()); + Loc, Range, DeclarationName(), + BasePath); } @@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef, Sema::MemInitResult Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + // We don't want access-control diagnostics here. + R.suppressDiagnostics(); + if (SS.isSet() && isDependentScopeSpecifier(SS)) { bool NotUnknownSpecialization = false; DeclContext *DC = computeDeclContext(SS, false); @@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!NotUnknownSpecialization) { // When the scope specifier can refer to a member of an unknown // specialization, we take it as a type name. - BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + BaseType = CheckTypenameType(ETK_None, + (NestedNameSpecifier *)SS.getScopeRep(), *MemberOrBase, SS.getRange()); if (BaseType.isNull()) return true; @@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // If no results were found, try to correct typos. if (R.empty() && BaseType.isNull() && - CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { + CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && + R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { // We have found a non-static data member with a similar @@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); if (FieldType->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. @@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, ExprTemporaries.end()); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + /*IsVirtual=*/false, LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); @@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() + << BaseType << Context.getTypeDeclType(ClassDecl) << BaseTInfo->getTypeLoc().getSourceRange(); CXXBaseSpecifier *BaseSpec @@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Initialize the base. InitializedEntity BaseEntity = - InitializedEntity::InitializeBase(Context, BaseSpec); + InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); @@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, Init.takeAs<Expr>(), RParenLoc); } return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); } +/// ImplicitInitializerKind - How an implicit base or member initializer should +/// initialize its base or member. +enum ImplicitInitializerKind { + IIK_Default, + IIK_Copy, + IIK_Move +}; + +static bool +BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + CXXBaseSpecifier *BaseSpec, + bool IsInheritedVirtualBase, + CXXBaseOrMemberInitializer *&CXXBaseInit) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, + IsInheritedVirtualBase); + + Sema::OwningExprResult BaseInit(SemaRef); + + switch (ImplicitInitKind) { + case IIK_Default: { + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + break; + } + + case IIK_Copy: { + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *CopyCtorArg = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + Constructor->getLocation(), ParamType, 0); + + // Cast to the base class to avoid ambiguities. + QualType ArgTy = + SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), + ParamType.getQualifiers()); + SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, + CXXBaseSpecifierArray(BaseSpec)); + + InitializationKind InitKind + = InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, + (void**)&CopyCtorArg, 1)); + break; + } + + case IIK_Move: + assert(false && "Unhandled initializer kind!"); + } + + BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) + return true; + + CXXBaseInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), + SourceLocation()), + BaseSpec->isVirtual(), + SourceLocation(), + BaseInit.takeAs<Expr>(), + SourceLocation()); + + return false; +} + +static bool +BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + FieldDecl *Field, + CXXBaseOrMemberInitializer *&CXXMemberInit) { + if (ImplicitInitKind == IIK_Copy) { + // FIXME: We should not return early here, but will do so until + // we know how to handle copy initialization of arrays. + CXXMemberInit = 0; + return false; + + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *MemberExprBase = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + SourceLocation(), ParamType, 0); + + + Expr *CopyCtorArg = + MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, + 0, SourceRange(), Field, + DeclAccessPair::make(Field, Field->getAccess()), + SourceLocation(), 0, + Field->getType().getNonReferenceType()); + + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = 0; + return false; + } + + assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!"); + + QualType FieldBaseElementType = + SemaRef.Context.getBaseElementType(Field->getType()); + + if (FieldBaseElementType->isRecordType()) { + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(Constructor->getLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + return false; + } + + if (FieldBaseElementType->isReferenceType()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 0 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + if (FieldBaseElementType.isConstQualified()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 1 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + // Nothing to initialize. + CXXMemberInit = 0; + return false; +} + bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { - if (Constructor->isDependentContext()) { + if (Constructor->getDeclContext()->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { @@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, return false; } + ImplicitInitializerKind ImplicitInitKind = IIK_Default; + + // FIXME: Handle implicit move constructors. + if (Constructor->isImplicit() && Constructor->isCopyConstructor()) + ImplicitInitKind = IIK_Copy; + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); @@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields[Member->getMember()] = Member; } - llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; + // Keep track of the direct virtual bases. + llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases; + for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); I != E; ++I) { + if (I->isVirtual()) + DirectVBases.insert(I); + } // Push virtual bases before others. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), @@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, VBase); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { + bool IsInheritedVirtualBase = !DirectVBases.count(VBase); + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + VBase, IsInheritedVirtualBase, + CXXBaseInit)) { HadError = true; continue; } - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } @@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, Base); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + Base, /*IsInheritedVirtualBase=*/false, + CXXBaseInit)) { HadError = true; continue; } - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); AllToInit.push_back(CXXBaseInit); } } @@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } - if ((*Field)->getType()->isDependentType() || AnyErrors) + if (AnyErrors) continue; - QualType FT = Context.getBaseElementType((*Field)->getType()); - if (FT->getAs<RecordType>()) { - InitializedEntity InitEntity - = InitializedEntity::InitializeMember(*Field); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); - if (MemberInit.isInvalid()) { - HadError = true; - continue; - } - - // Don't attach synthesized member initializers in a dependent - // context; they'll be regenerated a template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Context, - *Field, SourceLocation(), - SourceLocation(), - MemberInit.takeAs<Expr>(), - SourceLocation()); - - AllToInit.push_back(Member); - } - else if (FT->isReferenceType()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 0 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - HadError = true; - } - else if (FT.isConstQualified()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 1 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); + CXXBaseOrMemberInitializer *Member; + if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind, + *Field, Member)) { HadError = true; + continue; } + + // If the member doesn't need to be initialized, it will be null. + if (Member) + AllToInit.push_back(Member); } NumInitializers = AllToInit.size(); @@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context, if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) Field = Member->getAnonUnionMember(); - // If the field is a member of an anonymous union, we use record decl of the - // union as the key. + // If the field is a member of an anonymous struct or union, our key + // is the anonymous record decl that's a direct child of the class. RecordDecl *RD = Field->getParent(); - if (RD->isAnonymousStructOrUnion() && RD->isUnion()) + if (RD->isAnonymousStructOrUnion()) { + while (true) { + RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext()); + if (Parent->isAnonymousStructOrUnion()) + RD = Parent; + else + break; + } + return static_cast<void *>(RD); + } return static_cast<void *>(Field); } @@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context, static void DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, const CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **MemInits, - unsigned NumMemInits) { - if (Constructor->isDependentContext()) + CXXBaseOrMemberInitializer **Inits, + unsigned NumInits) { + if (Constructor->getDeclContext()->isDependentContext()) return; - if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) == - Diagnostic::Ignored && - SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) == - Diagnostic::Ignored) + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order) + == Diagnostic::Ignored) return; - // Also issue warning if order of ctor-initializer list does not match order - // of 1) base class declarations and 2) order of non-static data members. - llvm::SmallVector<const void*, 32> AllBaseOrMembers; + // Build the list of bases and members in the order that they'll + // actually be initialized. The explicit initializers should be in + // this same order but may be missing things. + llvm::SmallVector<const void*, 32> IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); - // Push virtual bases before others. + // 1. Virtual bases. for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - VBase->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType())); + // 2. Non-virtual bases. for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are alread in the virtual base list and are constructed - // first. if (Base->isVirtual()) continue; - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - Base->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType())); } + // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) - AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field)); + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - int Last = AllBaseOrMembers.size(); - int curIndex = 0; - CXXBaseOrMemberInitializer *PrevMember = 0; - for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; - void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true); + unsigned NumIdealInits = IdealInitKeys.size(); + unsigned IdealIndex = 0; + + CXXBaseOrMemberInitializer *PrevInit = 0; + for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { + CXXBaseOrMemberInitializer *Init = Inits[InitIndex]; + void *InitKey = GetKeyForMember(SemaRef.Context, Init, true); - for (; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + // Scan forward to try to find this initializer in the idealized + // initializers list. + for (; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; - if (curIndex == Last) { - assert(PrevMember && "Member not in member list?!"); - // Initializer as specified in ctor-initializer list is out of order. - // Issue a warning diagnostic. - if (PrevMember->isBaseInitializer()) { - // Diagnostics is for an initialized base class. - Type *BaseClass = PrevMember->getBaseClass(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_base_initialized) - << QualType(BaseClass, 0); - } else { - FieldDecl *Field = PrevMember->getMember(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_field_initialized) - << Field->getNameAsString(); - } - // Also the note! - if (FieldDecl *Field = Member->getMember()) - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 0 - << Field->getNameAsString(); - else { - Type *BaseClass = Member->getBaseClass(); - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 1 - << QualType(BaseClass, 0); - } - for (curIndex = 0; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + + // If we didn't find this initializer, it must be because we + // scanned past it on a previous iteration. That can only + // happen if we're out of order; emit a warning. + if (IdealIndex == NumIdealInits) { + assert(PrevInit && "initializer not found in initializer list"); + + Sema::SemaDiagnosticBuilder D = + SemaRef.Diag(PrevInit->getSourceLocation(), + diag::warn_initializer_out_of_order); + + if (PrevInit->isMemberInitializer()) + D << 0 << PrevInit->getMember()->getDeclName(); + else + D << 1 << PrevInit->getBaseClassInfo()->getType(); + + if (Init->isMemberInitializer()) + D << 0 << Init->getMember()->getDeclName(); + else + D << 1 << Init->getBaseClassInfo()->getType(); + + // Move back to the initializer's location in the ideal list. + for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; + + assert(IdealIndex != NumIdealInits && + "initializer not found in initializer list"); } - PrevMember = Member; + + PrevInit = Init; } } +namespace { +bool CheckRedundantInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + CXXBaseOrMemberInitializer *&PrevInit) { + if (!PrevInit) { + PrevInit = Init; + return false; + } + + if (FieldDecl *Field = Init->getMember()) + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + else { + Type *BaseClass = Init->getBaseClass(); + assert(BaseClass && "neither field nor base"); + S.Diag(Init->getSourceLocation(), + diag::err_multiple_base_initialization) + << QualType(BaseClass, 0) + << Init->getSourceRange(); + } + S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer) + << 0 << PrevInit->getSourceRange(); + + return true; +} + +typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry; +typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap; + +bool CheckRedundantUnionInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + RedundantUnionMap &Unions) { + FieldDecl *Field = Init->getMember(); + RecordDecl *Parent = Field->getParent(); + if (!Parent->isAnonymousStructOrUnion()) + return false; + + NamedDecl *Child = Field; + do { + if (Parent->isUnion()) { + UnionEntry &En = Unions[Parent]; + if (En.first && En.first != Child) { + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_union_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer) + << 0 << En.second->getSourceRange(); + return true; + } else if (!En.first) { + En.first = Child; + En.second = Init; + } + } + + Child = Parent; + Parent = cast<RecordDecl>(Parent->getDeclContext()); + } while (Parent->isAnonymousStructOrUnion()); + + return false; +} +} + /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, @@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, CXXBaseOrMemberInitializer **MemInits = reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits); - + + // Mapping for the duplicate initializers check. + // For member initializers, this is keyed with a FieldDecl*. + // For base initializers, this is keyed with a Type*. llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members; + + // Mapping for the inconsistent anonymous-union initializers check. + RedundantUnionMap MemberUnions; + bool HadError = false; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; + CXXBaseOrMemberInitializer *Init = MemInits[i]; - void *KeyToMember = GetKeyForMember(Context, Member); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; - } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << Field->getNameAsString() - << Member->getSourceRange(); - else { - Type *BaseClass = Member->getBaseClass(); - assert(BaseClass && "ActOnMemInitializers - neither field or base"); - Diag(Member->getSourceLocation(), - diag::error_multiple_base_initialization) - << QualType(BaseClass, 0) - << Member->getSourceRange(); + if (Init->isMemberInitializer()) { + FieldDecl *Field = Init->getMember(); + if (CheckRedundantInit(*this, Init, Members[Field]) || + CheckRedundantUnionInit(*this, Init, MemberUnions)) + HadError = true; + } else { + void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); + if (CheckRedundantInit(*this, Init, Members[Key])) + HadError = true; } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - HadError = true; } if (HadError) @@ -2060,12 +2298,12 @@ namespace { /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. -void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { +void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!Record || Record->isInvalidDecl()) return; if (!Record->isDependentType()) - AddImplicitlyDeclaredMembersToClass(Record); + AddImplicitlyDeclaredMembersToClass(S, Record); if (Record->isInvalidDecl()) return; @@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->isAbstract() && !Record->isInvalidDecl()) (void)AbstractClassUsageDiagnoser(*this, Record); + + // If this is not an aggregate type and has no user-declared constructor, + // complain about any non-static data members of reference or const scalar + // type, since they will never get initializers. + if (!Record->isInvalidDecl() && !Record->isDependentType() && + !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) { + bool Complained = false; + for (RecordDecl::field_iterator F = Record->field_begin(), + FEnd = Record->field_end(); + F != FEnd; ++F) { + if (F->getType()->isReferenceType() || + (F->getType().isConstQualified() && F->getType()->isScalarType())) { + if (!Complained) { + Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst) + << Record->getTagKind() << Record; + Complained = true; + } + + Diag(F->getLocation(), diag::note_refconst_member_not_initialized) + << F->getType()->isReferenceType() + << F->getDeclName(); + } + } + } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); - CheckCompletedCXXClass( + CheckCompletedCXXClass(S, dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>())); } @@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, /// constructor, or destructor, to the given C++ class (C++ /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. -void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { +/// +/// The scope, if provided, is the class scope. +void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, + CXXRecordDecl *ClassDecl) { CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); @@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { DefaultCon->setAccess(AS_public); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); - ClassDecl->addDecl(DefaultCon); + if (S) + PushOnScopeChains(DefaultCon, S, true); + else + ClassDecl->addDecl(DefaultCon); } if (!ClassDecl->hasUserDeclaredCopyConstructor()) { @@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyConstructor->setParams(&FromParam, 1); - ClassDecl->addDecl(CopyConstructor); + if (S) + PushOnScopeChains(CopyConstructor, S, true); + else + ClassDecl->addDecl(CopyConstructor); } if (!ClassDecl->hasUserDeclaredCopyAssignment()) { @@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*FIXME:*/false, false, 0, 0, FunctionType::ExtInfo()), - /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/FunctionDecl::None, + /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), - /*IdentifierInfo=*/0, + /*Id=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyAssignment->setParams(&FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. - ClassDecl->addDecl(CopyAssignment); + if (S) + PushOnScopeChains(CopyAssignment, S, true); + else + ClassDecl->addDecl(CopyAssignment); AddOverriddenMethods(ClassDecl, CopyAssignment); } @@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - ClassDecl->addDecl(Destructor); + if (S) + PushOnScopeChains(Destructor, S, true); + else + ClassDecl->addDecl(Destructor); // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); @@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { } } - // Notify the class that we've added a constructor. - ClassDecl->addedConstructor(Context, Constructor); + // Notify the class that we've added a constructor. In principle we + // don't need to do this for out-of-line declarations; in practice + // we only instantiate the most recent declaration of a method, so + // we have to call this for everything but friends. + if (!Constructor->getFriendObjectKind()) + ClassDecl->addedConstructor(Context, Constructor); } /// CheckDestructor - Checks a fully-formed destructor for well-formedness, @@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); SC = FunctionDecl::None; } + + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: @@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + // Make sure we don't have any parameters. - if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) { + if (Proto->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. D.getTypeObject(0).Fun.freeArgs(); D.setInvalidType(); + } else if (Proto->isVariadic()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + D.setInvalidType(); } - // Make sure the conversion function isn't variadic. - if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) { - Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + // Diagnose "&operator bool()" and other such nonsense. This + // is actually a gcc extension which we don't support. + if (Proto->getResultType() != ConvType) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) + << Proto->getResultType(); D.setInvalidType(); + ConvType = Proto->getResultType(); } // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); - R = Context.getFunctionType(ConvType, 0, 0, false, - Proto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + if (D.isInvalidType()) { + R = Context.getFunctionType(ConvType, 0, 0, false, + Proto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getExtInfo()); + } // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. NamedDecl *PrevDecl - = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, + = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName, ForRedeclaration); if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { @@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { @@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, @@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (!LookupContext) return D; UsingDecl *UD = cast<UsingDecl>(D); - if (RequireCompleteDeclContext(SS)) { + if (RequireCompleteDeclContext(SS, LookupContext)) { UD->setInvalidDecl(); return UD; } @@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { @@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, LookupParsedName(R, S, &SS); // Check if we have a previous declaration with the same name. - if (NamedDecl *PrevDecl - = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) { + NamedDecl *PrevDecl + = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, + ForRedeclaration); + if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) + PrevDecl = 0; + + if (PrevDecl) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. @@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy::make(AliasDecl); } +namespace { + /// \brief Scoped object used to handle the state changes required in Sema + /// to implicitly define the body of a C++ member function; + class ImplicitlyDefinedFunctionScope { + Sema &S; + DeclContext *PreviousContext; + + public: + ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) + : S(S), PreviousContext(S.CurContext) + { + S.CurContext = Method; + S.PushFunctionScope(); + S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + } + + ~ImplicitlyDefinedFunctionScope() { + S.PopExpressionEvaluationContext(); + S.PopFunctionOrBlockScope(); + S.CurContext = PreviousContext; + } + }; +} + void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && !Constructor->isUsed()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Constructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Constructor; + ImplicitlyDefinedFunctionScope Scope(*this, Constructor); if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); + << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); } - CurContext = PreviousContext; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Destructor; + ImplicitlyDefinedFunctionScope Scope(*this, Destructor); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); @@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); - CurContext = PreviousContext; - return; } - CurContext = PreviousContext; Destructor->setUsed(); } -void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl) { - assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && - MethodDecl->getOverloadedOperator() == OO_Equal && - !MethodDecl->isUsed()) && - "DefineImplicitOverloadedAssign - call it for implicit assignment op"); +/// \brief Builds a statement that copies the given entity from \p From to +/// \c To. +/// +/// This routine is used to copy the members of a class with an +/// implicitly-declared copy assignment operator. When the entities being +/// copied are arrays, this routine builds for loops to copy them. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param Loc The location where the implicit copy is being generated. +/// +/// \param T The type of the expressions being copied. Both expressions must +/// have this type. +/// +/// \param To The expression we are copying to. +/// +/// \param From The expression we are copying from. +/// +/// \param Depth Internal parameter recording the depth of the recursion. +/// +/// \returns A statement or a loop that copies the expressions. +static Sema::OwningStmtResult +BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, + Sema::OwningExprResult To, Sema::OwningExprResult From, + unsigned Depth = 0) { + typedef Sema::OwningStmtResult OwningStmtResult; + typedef Sema::OwningExprResult OwningExprResult; + + // C++0x [class.copy]p30: + // Each subobject is assigned in the manner appropriate to its type: + // + // - if the subobject is of class type, the copy assignment operator + // for the class is used (as if by explicit qualification; that is, + // ignoring any possible virtual overriding functions in more derived + // classes); + if (const RecordType *RecordTy = T->getAs<RecordType>()) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + + // Look for operator=. + DeclarationName Name + = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(OpLookup, ClassDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = OpLookup.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Create the nested-name-specifier that will be used to qualify the + // reference to operator=; this is required to suppress the virtual + // call mechanism. + CXXScopeSpec SS; + SS.setRange(Loc); + SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false, + T.getTypePtr())); + + // Create the reference to operator=. + OwningExprResult OpEqualRef + = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS, + /*FirstQualifierInScope=*/0, OpLookup, + /*TemplateArgs=*/0, + /*SuppressQualifierCheck=*/true); + if (OpEqualRef.isInvalid()) + return S.StmtError(); + + // Build the call to the assignment operator. + Expr *FromE = From.takeAs<Expr>(); + OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, + OpEqualRef.takeAs<Expr>(), + Loc, &FromE, 1, 0, Loc); + if (Call.isInvalid()) + return S.StmtError(); + + return S.Owned(Call.takeAs<Stmt>()); + } + + // - if the subobject is of scalar type, the built-in assignment + // operator is used. + const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T); + if (!ArrayTy) { + OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc, + BinaryOperator::Assign, + To.takeAs<Expr>(), + From.takeAs<Expr>()); + if (Assignment.isInvalid()) + return S.StmtError(); + + return S.Owned(Assignment.takeAs<Stmt>()); + } + + // - if the subobject is an array, each element is assigned, in the + // manner appropriate to the element type; + + // Construct a loop over the array bounds, e.g., + // + // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0) + // + // that will copy each of the array elements. + QualType SizeType = S.Context.getSizeType(); + + // Create the iteration variable. + IdentifierInfo *IterationVarName = 0; + { + llvm::SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << Depth; + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, + IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), + VarDecl::None, VarDecl::None); + + // Initialize the iteration variable to zero. + llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); + IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc)); + + // Create a reference to the iteration variable; we'll use this several + // times throughout. + Expr *IterationVarRef + = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>(); + assert(IterationVarRef && "Reference to invented variable cannot fail!"); + + // Create the DeclStmt that holds the iteration variable. + Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc); + + // Create the comparison against the array bound. + llvm::APInt Upper = ArrayTy->getSize(); + Upper.zextOrTrunc(S.Context.getTypeSize(SizeType)); + OwningExprResult Comparison + = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(), + new (S.Context) IntegerLiteral(Upper, SizeType, Loc), + BinaryOperator::NE, S.Context.BoolTy, Loc)); + + // Create the pre-increment of the iteration variable. + OwningExprResult Increment + = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(), + UnaryOperator::PreInc, + SizeType, Loc)); + + // Subscript the "from" and "to" expressions with the iteration variable. + From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + assert(!From.isInvalid() && "Builtin subscripting can't fail!"); + assert(!To.isInvalid() && "Builtin subscripting can't fail!"); + + // Build the copy for an individual element of the array. + OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc, + ArrayTy->getElementType(), + move(To), move(From), Depth+1); + if (Copy.isInvalid()) { + InitStmt->Destroy(S.Context); + return S.StmtError(); + } + + // Construct the loop that copies all elements of this array. + return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt), + S.MakeFullExpr(Comparison), + Sema::DeclPtrTy(), + S.MakeFullExpr(Increment), + Loc, move(Copy)); +} - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(MethodDecl->getDeclContext()); +void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *CopyAssignOperator) { + assert((CopyAssignOperator->isImplicit() && + CopyAssignOperator->isOverloadedOperator() && + CopyAssignOperator->getOverloadedOperator() == OO_Equal && + !CopyAssignOperator->isUsed()) && + "DefineImplicitCopyAssignment called for wrong function"); + + CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - DeclContext *PreviousContext = CurContext; - CurContext = MethodDecl; + if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + CopyAssignOperator->setUsed(); - // C++[class.copy] p12 - // Before the implicitly-declared copy assignment operator for a class is - // implicitly defined, all implicitly-declared copy assignment operators - // for its direct base classes and its nonstatic data members shall have - // been implicitly defined. - bool err = false; + ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + + // C++0x [class.copy]p30: + // The implicitly-defined or explicitly-defaulted copy assignment operator + // for a non-union class X performs memberwise copy assignment of its + // subobjects. The direct base classes of X are assigned first, in the + // order of their declaration in the base-specifier-list, and then the + // immediate non-static data members of X are assigned, in the order in + // which they were declared in the class definition. + + // The statements that form the synthesized function body. + ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + + // The parameter for the "other" object, which we are copying from. + ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); + Qualifiers OtherQuals = Other->getType().getQualifiers(); + QualType OtherRefType = Other->getType(); + if (const LValueReferenceType *OtherRef + = OtherRefType->getAs<LValueReferenceType>()) { + OtherRefType = OtherRef->getPointeeType(); + OtherQuals = OtherRefType.getQualifiers(); + } + + // Our location for everything implicitly-generated. + SourceLocation Loc = CopyAssignOperator->getLocation(); + + // Construct a reference to the "other" object. We'll be using this + // throughout the generated ASTs. + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>(); + assert(OtherRef && "Reference to parameter cannot fail!"); + + // Construct the "this" pointer. We'll be using this throughout the generated + // ASTs. + Expr *This = ActOnCXXThis(Loc).takeAs<Expr>(); + assert(This && "Reference to this cannot fail!"); + + // Assign base classes. + bool Invalid = false; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *BaseAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - BaseClassDecl)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseAssignOpMethod, - PDiag(diag::err_access_assign_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); + // Form the assignment: + // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other)); + QualType BaseType = Base->getType().getUnqualifiedType(); + CXXRecordDecl *BaseClassDecl = 0; + if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>()) + BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl()); + else { + Invalid = true; + continue; + } + + // Construct the "from" expression, which is an implicit cast to the + // appropriately-qualified base type. + Expr *From = OtherRef->Retain(); + ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), + CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true, + CXXBaseSpecifierArray(Base)); + + // Dereference "this". + OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + // Implicitly cast "this" to the appropriately-qualified base type. + Expr *ToE = To.takeAs<Expr>(); + ImpCastExprToType(ToE, + Context.getCVRQualifiedType(BaseType, + CopyAssignOperator->getTypeQualifiers()), + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, CXXBaseSpecifierArray(Base)); + To = Owned(ToE); + + // Build the copy. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, + move(To), Owned(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Expr>()); } + + // \brief Reference to the __builtin_memcpy function. + Expr *BuiltinMemCpyRef = 0; + + // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXMethodDecl *FieldAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - FieldClassDecl)) { - CheckDirectMemberAccess(Field->getLocation(), - FieldAssignOpMethod, - PDiag(diag::err_access_assign_field) - << Field->getDeclName() << Field->getType()); - - MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); - } - } else if (FieldType->isReferenceType()) { + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + // Check for members of reference type; we can't copy those. + if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; - } else if (FieldType.isConstQualified()) { + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; + } + + // Check for members of const-qualified, non-class type. + QualType BaseType = Context.getBaseElementType(Field->getType()); + if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; } + + QualType FieldType = Field->getType().getNonReferenceType(); + + // Build references to the field in the object we're copying from and to. + CXXScopeSpec SS; // Intentionally empty + LookupResult MemberLookup(*this, Field->getDeclName(), Loc, + LookupMemberName); + MemberLookup.addDecl(*Field); + MemberLookup.resolveKind(); + OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()), + OtherRefType, + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); + OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()), + This->getType(), + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); + assert(!From.isInvalid() && "Implicit field reference cannot fail"); + assert(!To.isInvalid() && "Implicit field reference cannot fail"); + + // If the field should be copied with __builtin_memcpy rather than via + // 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())) { + // Compute the size of the memory buffer to be copied. + QualType SizeType = Context.getSizeType(); + llvm::APInt Size(Context.getTypeSize(SizeType), + Context.getTypeSizeInChars(BaseType).getQuantity()); + for (const ConstantArrayType *Array + = Context.getAsConstantArrayType(FieldType); + Array; + Array = Context.getAsConstantArrayType(Array->getElementType())) { + llvm::APInt ArraySize = Array->getSize(); + ArraySize.zextOrTrunc(Size.getBitWidth()); + Size *= ArraySize; + } + + // Take the address of the field references for "from" and "to". + From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From)); + To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To)); + + // Create a reference to the __builtin_memcpy builtin function. + if (!BuiltinMemCpyRef) { + LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, + LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>(); + if (!BuiltinMemCpy) { + // Something went horribly wrong earlier, and we will have complained + // about it. + Invalid = true; + continue; + } + + BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, + BuiltinMemCpy->getType(), + Loc, 0).takeAs<Expr>(); + assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); + } + + ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this); + CallArgs.push_back(To.takeAs<Expr>()); + CallArgs.push_back(From.takeAs<Expr>()); + CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc)); + llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly + Commas.push_back(Loc); + Commas.push_back(Loc); + OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, + Owned(BuiltinMemCpyRef->Retain()), + Loc, move_arg(CallArgs), + Commas.data(), Loc); + assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); + Statements.push_back(Call.takeAs<Expr>()); + continue; + } + + // Build the copy of this field. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, + move(To), move(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; + } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Stmt>()); } - if (!err) - MethodDecl->setUsed(); - CurContext = PreviousContext; -} + if (!Invalid) { + // Add a "return *this;" + OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj)); + if (Return.isInvalid()) + Invalid = true; + else { + Statements.push_back(Return.takeAs<Stmt>()); + } + } -CXXMethodDecl * -Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, - ParmVarDecl *ParmDecl, - CXXRecordDecl *ClassDecl) { - QualType LHSType = Context.getTypeDeclType(ClassDecl); - QualType RHSType(LHSType); - // If class's assignment operator argument is const/volatile qualified, - // look for operator = (const/volatile B&). Otherwise, look for - // operator = (B&). - RHSType = Context.getCVRQualifiedType(RHSType, - ParmDecl->getType().getCVRQualifiers()); - ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, - SourceLocation())); - ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, - CurrentLocation)); - Expr *Args[2] = { &*LHS, &*RHS }; - OverloadCandidateSet CandidateSet(CurrentLocation); - AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, - CandidateSet); - OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success) - return cast<CXXMethodDecl>(Best->Function); - assert(false && - "getAssignOperatorMethod - copy assignment operator method not found"); - return 0; + if (Invalid) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + /*isStmtExpr=*/false); + assert(!Body.isInvalid() && "Compound statement creation cannot fail"); + CopyAssignOperator->setBody(Body.takeAs<Stmt>()); } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, @@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, !CopyConstructor->isUsed()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(CopyConstructor->getDeclContext()); + CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = CopyConstructor; + ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); - // C++ [class.copy] p209 - // Before the implicitly-declared copy constructor for a class is - // implicitly defined, all the implicitly-declared copy constructors - // for its base class and its non-static data members shall have been - // implicitly defined. - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseCopyCtor, - PDiag(diag::err_access_copy_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); - } + if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + CopyConstructor->setInvalidDecl(); + } else { + CopyConstructor->setUsed(); } + + // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of + // fields, this code below should be removed. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { @@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } } - CopyConstructor->setUsed(); - - CurContext = PreviousContext; } Sema::OwningExprResult @@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { bool Elidable = false; // C++0x [class.copy]p34: @@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, move(ExprArgs), RequiresZeroInit, - BaseInitialization); + ConstructKind); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, BaseInitialization)); + RequiresZeroInit, ConstructKind)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, @@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, FinalizeVarWithDestructor(VDecl, Record); } -/// \brief Add the applicable constructor candidates for an initialization -/// by constructor. -static void AddConstructorInitializationCandidates(Sema &SemaRef, - QualType ClassType, - Expr **Args, - unsigned NumArgs, - InitializationKind Kind, - OverloadCandidateSet &CandidateSet) { - // C++ [dcl.init]p14: - // If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. The - // applicable constructors are enumerated (13.3.1.3), and the - // best one is chosen through overload resolution (13.3). The - // constructor so selected is called to initialize the object, - // with the initializer expression(s) as its argument(s). If no - // constructor applies, or the overload resolution is ambiguous, - // the initialization is ill-formed. - const RecordType *ClassRec = ClassType->getAs<RecordType>(); - assert(ClassRec && "Can only initialize a class type here"); - - // FIXME: When we decide not to synthesize the implicitly-declared - // constructors, we'll need to make them appear here. - - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); - DeclarationName ConstructorName - = SemaRef.Context.DeclarationNames.getCXXConstructorName( - SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType()); - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(*Con); - - if ((Kind.getKind() == InitializationKind::IK_Direct) || - (Kind.getKind() == InitializationKind::IK_Value) || - (Kind.getKind() == InitializationKind::IK_Copy && - Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - ((Kind.getKind() == InitializationKind::IK_Default) && - Constructor->isDefaultConstructor())) { - if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet); - else - SemaRef.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet); - } - } -} - -/// \brief Attempt to perform initialization by constructor -/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or -/// copy-initialization. -/// -/// This routine determines whether initialization by constructor is possible, -/// but it does not emit any diagnostics in the case where the initialization -/// is ill-formed. -/// -/// \param ClassType the type of the object being initialized, which must have -/// class type. -/// -/// \param Args the arguments provided to initialize the object -/// -/// \param NumArgs the number of arguments provided to initialize the object -/// -/// \param Kind the type of initialization being performed -/// -/// \returns the constructor used to initialize the object, if successful. -/// Otherwise, emits a diagnostic and returns NULL. -CXXConstructorDecl * -Sema::TryInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, - InitializationKind Kind) { - // Build the overload candidate set - OverloadCandidateSet CandidateSet(Loc); - AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, - CandidateSet); - - // Determine whether we found a constructor we can use. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Loc, Best)) { - case OR_Success: - case OR_Deleted: - // We found a constructor. Return it. - return cast<CXXConstructorDecl>(Best->Function); - - case OR_No_Viable_Function: - case OR_Ambiguous: - // Overload resolution failed. Return nothing. - return 0; - } - - // Silence GCC warning - return 0; -} - /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. @@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, return Invalid; } -/// CompareReferenceRelationship - Compare the two types T1 and T2 to -/// determine whether they are reference-related, -/// reference-compatible, reference-compatible with added -/// qualification, or incompatible, for use in C++ initialization by -/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference -/// type, and the first type (T1) is the pointee type of the reference -/// type being initialized. -Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(SourceLocation Loc, - QualType OrigT1, QualType OrigT2, - bool& DerivedToBase) { - assert(!OrigT1->isReferenceType() && - "T1 must be the pointee type of the reference type"); - assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); - - QualType T1 = Context.getCanonicalType(OrigT1); - QualType T2 = Context.getCanonicalType(OrigT2); - Qualifiers T1Quals, T2Quals; - QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); - QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); - - // C++ [dcl.init.ref]p4: - // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is - // reference-related to "cv2 T2" if T1 is the same type as T2, or - // T1 is a base class of T2. - if (UnqualT1 == UnqualT2) - DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && - !RequireCompleteType(Loc, OrigT2, PDiag()) && - IsDerivedFrom(UnqualT2, UnqualT1)) - DerivedToBase = true; - else - return Ref_Incompatible; - - // At this point, we know that T1 and T2 are reference-related (at - // least). - - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); - - // C++ [dcl.init.ref]p4: - // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is - // reference-related to T2 and cv1 is the same cv-qualification - // as, or greater cv-qualification than, cv2. For purposes of - // overload resolution, cases for which cv1 is greater - // cv-qualification than cv2 are identified as - // reference-compatible with added qualification (see 13.3.3.2). - if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) - return Ref_Compatible; - else if (T1.isMoreQualifiedThan(T2)) - return Ref_Compatible_With_Added_Qualification; - else - return Ref_Related; -} - -/// CheckReferenceInit - Check the initialization of a reference -/// variable with the given initializer (C++ [dcl.init.ref]). Init is -/// the initializer (either a simple initializer or an initializer -/// list), and DeclType is the type of the declaration. When ICS is -/// non-null, this routine will compute the implicit conversion -/// sequence according to C++ [over.ics.ref] and will not produce any -/// diagnostics; when ICS is null, it will emit diagnostics when any -/// errors are found. Either way, a return value of true indicates -/// that there was a failure, a return value of false indicates that -/// the reference initialization succeeded. -/// -/// When @p SuppressUserConversions, user-defined conversions are -/// suppressed. -/// When @p AllowExplicit, we also permit explicit user-defined -/// conversion functions. -/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. -/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion. -/// This is used when this is called from a C-style cast. -bool -Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, - SourceLocation DeclLoc, - bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue, - ImplicitConversionSequence *ICS, - bool IgnoreBaseAccess) { - assert(DeclType->isReferenceType() && "Reference init needs a reference"); - - QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); - QualType T2 = Init->getType(); - - // If the initializer is the address of an overloaded function, try - // to resolve the overloaded function. If all goes well, T2 is the - // type of the resulting function. - if (Context.getCanonicalType(T2) == Context.OverloadTy) { - DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0, Found); - if (Fn) { - // Since we're performing this reference-initialization for - // real, update the initializer with the resulting function. - if (!ICS) { - if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; - - CheckAddressOfMemberAccess(Init, Found); - Init = FixOverloadedFunctionReference(Init, Found, Fn); - } - - T2 = Fn->getType(); - } - } - - // Compute some basic properties of the types and the initializer. - bool isRValRef = DeclType->isRValueReferenceType(); - bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : - Init->isLvalue(Context); - ReferenceCompareResult RefRelationship - = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); - - // Most paths end in a failed conversion. - if (ICS) { - ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType); - } - - // C++ [dcl.init.ref]p5: - // A reference to type "cv1 T1" is initialized by an expression - // of type "cv2 T2" as follows: - - // -- If the initializer expression - - // Rvalue references cannot bind to lvalues (N2812). - // There is absolutely no situation where they can. In particular, note that - // this is ill-formed, even if B has a user-defined conversion to A&&: - // B b; - // A&& r = b; - if (isRValRef && InitLvalue == Expr::LV_Valid) { - if (!ICS) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - return true; - } - - bool BindsDirectly = false; - // -- is an lvalue (but is not a bit-field), and "cv1 T1" is - // reference-compatible with "cv2 T2," or - // - // Note that the bit-field check is skipped if we are just computing - // the implicit conversion sequence (C++ [over.best.ics]p2). - if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - BindsDirectly = true; - - if (ICS) { - // C++ [over.ics.ref]p1: - // When a parameter of reference type binds directly (8.5.3) - // to an argument expression, the implicit conversion sequence - // is the identity conversion, unless the argument expression - // has a type that is a derived class of the parameter type, - // in which case the implicit conversion sequence is a - // derived-to-base Conversion (13.3.3.1). - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = true; - ICS->Standard.RRefBinding = false; - ICS->Standard.CopyConstructor = 0; - - // Nothing more to do: the inaccessibility/ambiguity check for - // derived-to-base conversions is suppressed when we're - // computing the implicit conversion sequence (C++ - // [over.best.ics]p2). - return false; - } else { - // Perform the conversion. - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true); - } - } - - // -- has a class type (i.e., T2 is a class type) and can be - // implicitly converted to an lvalue of type "cv3 T3," - // where "cv1 T1" is reference-compatible with "cv3 T3" - // 92) (this conversion is selected by enumerating the - // applicable conversion functions (13.3.1.6) and choosing - // the best one through overload resolution (13.3)), - if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !RequireCompleteType(DeclLoc, T2, 0)) { - CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - - OverloadCandidateSet CandidateSet(DeclLoc); - const UnresolvedSetImpl *Conversions - = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; - CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - FunctionTemplateDecl *ConvTemplate - = dyn_cast<FunctionTemplateDecl>(D); - CXXConversionDecl *Conv; - if (ConvTemplate) - Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); - else - Conv = cast<CXXConversionDecl>(D); - - // If the conversion function doesn't return a reference type, - // it can't be considered for this conversion. - if (Conv->getConversionType()->isLValueReferenceType() && - (AllowExplicit || !Conv->isExplicit())) { - if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet); - else - AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet); - } - } - - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, DeclLoc, Best)) { - case OR_Success: - // C++ [over.ics.ref]p1: - // - // [...] If the parameter binds directly to the result of - // applying a conversion function to the argument - // expression, the implicit conversion sequence is a - // user-defined conversion sequence (13.3.3.1.2), with the - // second standard conversion sequence either an identity - // conversion or, if the conversion function returns an - // entity of a type that is a derived class of the parameter - // type, a derived-to-base Conversion. - if (!Best->FinalConversion.DirectBinding) - break; - - // This is a direct binding. - BindsDirectly = true; - - if (ICS) { - ICS->setUserDefined(); - ICS->UserDefined.Before = Best->Conversions[0].Standard; - ICS->UserDefined.After = Best->FinalConversion; - ICS->UserDefined.ConversionFunction = Best->Function; - ICS->UserDefined.EllipsisConversion = false; - assert(ICS->UserDefined.After.ReferenceBinding && - ICS->UserDefined.After.DirectBinding && - "Expected a direct reference binding!"); - return false; - } else { - OwningExprResult InitConversion = - BuildCXXCastArgument(DeclLoc, QualType(), - CastExpr::CK_UserDefinedConversion, - cast<CXXMethodDecl>(Best->Function), - Owned(Init)); - Init = InitConversion.takeAs<Expr>(); - - if (CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion, - /*isLvalue=*/true); - } - break; - - case OR_Ambiguous: - if (ICS) { - ICS->setAmbiguous(); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) - if (Cand->Viable) - ICS->Ambiguous.addConversion(Cand->Function); - break; - } - Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() - << Init->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1); - return true; - - case OR_No_Viable_Function: - case OR_Deleted: - // There was no suitable conversion, or we found a deleted - // conversion; continue with other checks. - break; - } - } - - if (BindsDirectly) { - // C++ [dcl.init.ref]p4: - // [...] In all cases where the reference-related or - // reference-compatible relationship of two types is used to - // establish the validity of a reference binding, and T1 is a - // base class of T2, a program that necessitates such a binding - // is ill-formed if T1 is an inaccessible (clause 11) or - // ambiguous (10.2) base class of T2. - // - // Note that we only check this condition when we're allowed to - // complain about errors, because we should not be checking for - // ambiguity (or inaccessibility) unless the reference binding - // actually happens. - if (DerivedToBase) - return CheckDerivedToBaseConversion(T2, T1, DeclLoc, - Init->getSourceRange(), - IgnoreBaseAccess); - else - return false; - } - - // -- Otherwise, the reference shall be to a non-volatile const - // type (i.e., cv1 shall be const), or the reference shall be an - // rvalue reference and the initializer expression shall be an rvalue. - if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { - if (!ICS) - Diag(DeclLoc, diag::err_not_reference_to_const_init) - << T1.isVolatileQualified() - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // -- If the initializer expression is an rvalue, with T2 a - // class type, and "cv1 T1" is reference-compatible with - // "cv2 T2," the reference is bound in one of the - // following ways (the choice is implementation-defined): - // - // -- The reference is bound to the object represented by - // the rvalue (see 3.10) or to a sub-object within that - // object. - // - // -- A temporary of type "cv1 T2" [sic] is created, and - // a constructor is called to copy the entire rvalue - // object into the temporary. The reference is bound to - // the temporary or to a sub-object within the - // temporary. - // - // The constructor that would be used to make the copy - // shall be callable whether or not the copy is actually - // done. - // - // Note that C++0x [dcl.init.ref]p5 takes away this implementation - // freedom, so we will always take the first option and never build - // a temporary in this case. FIXME: We will, however, have to check - // for the presence of a copy constructor in C++98/03 mode. - if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - if (ICS) { - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = false; - ICS->Standard.RRefBinding = isRValRef; - ICS->Standard.CopyConstructor = 0; - } else { - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false); - } - return false; - } - - // -- Otherwise, a temporary of type "cv1 T1" is created and - // initialized from the initializer expression using the - // rules for a non-reference copy initialization (8.5). The - // reference is then bound to the temporary. If T1 is - // reference-related to T2, cv1 must be the same - // cv-qualification as, or greater cv-qualification than, - // cv2; otherwise, the program is ill-formed. - if (RefRelationship == Ref_Related) { - // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then - // we would be reference-compatible or reference-compatible with - // added qualification. But that wasn't the case, so the reference - // initialization fails. - if (!ICS) - Diag(DeclLoc, diag::err_reference_init_drops_quals) - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // If at least one of the types is a class type, the types are not - // related, and we aren't allowed any user conversions, the - // reference binding fails. This case is important for breaking - // recursion, since TryImplicitConversion below will attempt to - // create a temporary through the use of a copy constructor. - if (SuppressUserConversions && RefRelationship == Ref_Incompatible && - (T1->isRecordType() || T2->isRecordType())) { - if (!ICS) - Diag(DeclLoc, diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange(); - return true; - } - - // Actually try to convert the initializer to T1. - if (ICS) { - // C++ [over.ics.ref]p2: - // - // When a parameter of reference type is not bound directly to - // an argument expression, the conversion sequence is the one - // required to convert the argument expression to the - // underlying type of the reference according to - // 13.3.3.1. Conceptually, this conversion sequence corresponds - // to copy-initializing a temporary of the underlying type with - // the argument expression. Any difference in top-level - // cv-qualification is subsumed by the initialization itself - // and does not constitute a conversion. - *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - // Of course, that's still a reference binding. - if (ICS->isStandard()) { - ICS->Standard.ReferenceBinding = true; - ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->isUserDefined()) { - ICS->UserDefined.After.ReferenceBinding = true; - ICS->UserDefined.After.RRefBinding = isRValRef; - } - return ICS->isBad(); - } else { - ImplicitConversionSequence Conversions; - bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, - false, false, - Conversions); - if (badConversion) { - if (Conversions.isAmbiguous()) { - Diag(DeclLoc, - diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.Ambiguous.conversions().size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; - NoteOverloadCandidate(Func); - } - } - else { - if (isRValRef) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - else - Diag(DeclLoc, diag::err_invalid_initialization) - << DeclType << Init->getType() << Init->getSourceRange(); - } - } - return badConversion; - } -} - static inline bool CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { @@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { bool Valid = false; - // FIXME: Check for the one valid template signature - // template <char...> type operator "" name(); - - if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // template <char...> type operator "" name() is the only valid template + // signature, and the only valid signature with no parameters. + if (FnDecl->param_size() == 0) { + if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) { + // Must have only one template parameter + TemplateParameterList *Params = TpDecl->getTemplateParameters(); + if (Params->size() == 1) { + NonTypeTemplateParmDecl *PmDecl = + cast<NonTypeTemplateParmDecl>(Params->getParam(0)); + + // The template parameter must be a char parameter pack. + // FIXME: This test will always fail because non-type parameter packs + // have not been implemented. + if (PmDecl && PmDecl->isTemplateParameterPack() && + Context.hasSameType(PmDecl->getType(), Context.CharTy)) + Valid = true; + } + } + } else { // Check the first parameter + FunctionDecl::param_iterator Param = FnDecl->param_begin(); + QualType T = (*Param)->getType(); - // unsigned long long int and long double are allowed, but only - // alone. - // We also allow any character type; their omission seems to be a bug - // in n3000 + // unsigned long long int, long double, and any character type are allowed + // as the only parameters. if (Context.hasSameType(T, Context.UnsignedLongLongTy) || Context.hasSameType(T, Context.LongDoubleTy) || Context.hasSameType(T, Context.CharTy) || @@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { goto FinishedParams; } - // Otherwise it must be a pointer to const; let's strip those. + // Otherwise it must be a pointer to const; let's strip those qualifiers. const PointerType *PT = T->getAs<PointerType>(); if (!PT) goto FinishedParams; @@ -5121,13 +5186,12 @@ FinishedParams: Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; - if (strncmp(Lang, "\"C\"", StrSize) == 0) + if (Lang == "\"C\"") Language = LinkageSpecDecl::lang_c; - else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + else if (Lang == "\"C++\"") Language = LinkageSpecDecl::lang_cxx; else { Diag(LangLoc, diag::err_bad_language); @@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, Invalid = true; VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, TInfo, VarDecl::None); - + Name, ExDeclType, TInfo, VarDecl::None, + VarDecl::None); + ExDecl->setExceptionVariable(true); + if (!Invalid) { if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) { // C++ [except.handle]p16: @@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); - if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { + if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); @@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, return DeclPtrTy::make(Decl); } +/// \brief Perform semantic analysis of the given friend type declaration. +/// +/// \returns A friend declaration that. +FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, + TypeSourceInfo *TSInfo) { + assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); + + QualType T = TSInfo->getType(); + SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); + + if (!getLangOptions().CPlusPlus0x) { + // C++03 [class.friend]p2: + // An elaborated-type-specifier shall be used in a friend declaration + // for a class.* + // + // * The class-key of the elaborated-type-specifier is required. + if (!ActiveTemplateInstantiations.empty()) { + // Do not complain about the form of friend template types during + // template instantiation; we will already have complained when the + // template was declared. + } else if (!T->isElaboratedTypeSpecifier()) { + // If we evaluated the type to a record type, suggest putting + // a tag in front. + if (const RecordType *RT = T->getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + + std::string InsertionText = std::string(" ") + RD->getKindName(); + + Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type) + << (unsigned) RD->getTagKind() + << T + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc), + InsertionText); + } else { + Diag(FriendLoc, diag::ext_nonclass_type_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } else if (T->getAs<EnumType>()) { + Diag(FriendLoc, diag::ext_enum_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } + + // C++0x [class.friend]p3: + // If the type specifier in a friend declaration designates a (possibly + // cv-qualified) class type, that class is declared as a friend; otherwise, + // the friend declaration is ignored. + + // FIXME: C++0x has some syntactic restrictions on friend type declarations + // in [class.friend]p3 that we do not implement. + + return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc); +} + /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// @@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TheDeclarator.isInvalidType()) return DeclPtrTy(); + if (!TSI) + TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin()); + // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just // poorly written. @@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << DS.getSourceRange(); return DeclPtrTy(); } - - // C++ [class.friend]p2: - // An elaborated-type-specifier shall be used in a friend declaration - // for a class.* - // * The class-key of the elaborated-type-specifier is required. - // This is one of the rare places in Clang where it's legitimate to - // ask about the "spelling" of the type. - if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { - // If we evaluated the type to a record type, suggest putting - // a tag in front. - if (const RecordType *RT = T->getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); - - std::string InsertionText = std::string(" ") + RD->getKindName(); - - Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type) - << (unsigned) RD->getTagKind() - << T - << SourceRange(DS.getFriendSpecLoc()) - << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText); - return DeclPtrTy(); - }else { - Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) - << DS.getSourceRange(); - return DeclPtrTy(); - } - } - - // Enum types cannot be friends. - if (T->getAs<EnumType>()) { - Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend) - << SourceRange(DS.getFriendSpecLoc()); - return DeclPtrTy(); - } - + // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 @@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend a member of an arbitrary specialization of your template). Decl *D; - if (TempParams.size()) + if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, - TempParams.size(), + NumTempParamLists, (TemplateParameterList**) TempParams.release(), TSI, DS.getFriendSpecLoc()); else - D = FriendDecl::Create(Context, CurContext, Loc, TSI, - DS.getFriendSpecLoc()); + D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI); + + if (!D) + return DeclPtrTy(); + D->setAccess(AS_public); CurContext->addDecl(D); @@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S, LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { - // FIXME: RequireCompleteDeclContext DC = computeDeclContext(ScopeQual); // FIXME: handle dependent contexts if (!DC) return DeclPtrTy(); + if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy(); LookupQualifiedName(Previous, DC); @@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) - FrD->setSpecialization(true); - return DeclPtrTy::make(ND); } @@ -5701,10 +5794,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // Check if we the conversion from derived to base is valid. if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, - diag::err_covariant_return_inaccessible_base, - diag::err_covariant_return_ambiguous_derived_to_base_conv, - // FIXME: Should this point to the return type? - New->getLocation(), SourceRange(), New->getDeclName())) { + diag::err_covariant_return_inaccessible_base, + diag::err_covariant_return_ambiguous_derived_to_base_conv, + // FIXME: Should this point to the return type? + New->getLocation(), SourceRange(), New->getDeclName(), 0)) { Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } @@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { +static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) { // Ignore dependent types. if (MD->isDependentContext()) return false; @@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, // We will need to mark all of the virtual members as referenced to build the // vtable. - if (!needsVtable(MD, Context)) + if (!needsVTable(MD, Context)) return; TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); @@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, MarkVirtualMembersReferenced(Loc, Base); } } + +/// SetIvarInitializers - This routine builds initialization ASTs for the +/// Objective-C implementation whose ivars need be initialized. +void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { + if (!getLangOptions().CPlusPlus) + return; + if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { + llvm::SmallVector<ObjCIvarDecl*, 8> ivars; + CollectIvarsToConstructOrDestruct(OID, ivars); + if (ivars.empty()) + return; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; + for (unsigned i = 0; i < ivars.size(); i++) { + FieldDecl *Field = ivars[i]; + CXXBaseOrMemberInitializer *Member; + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(ObjCImplementation->getLocation()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, + Sema::MultiExprArg(*this, 0, 0)); + MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + // Note, MemberInit could actually come back empty if no initialization + // is required (e.g., because it would call a trivial default constructor) + if (!MemberInit.get() || MemberInit.isInvalid()) + continue; + + Member = + new (Context) CXXBaseOrMemberInitializer(Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + AllToInit.push_back(Member); + } + ObjCImplementation->setIvarInitializers(Context, + AllToInit.data(), AllToInit.size()); + } +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 0c47e63..d446cc1 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -66,13 +66,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); - if (PrevDecl && PrevDecl->isTemplateParameter()) { - // Maybe we will complain about the shadowed template parameter. - DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl); - // Just pretend that we didn't see the previous declaration. - PrevDecl = 0; - } + NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, + LookupOrdinaryName, ForRedeclaration); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; @@ -98,6 +93,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Since this ObjCInterfaceDecl was created by a forward declaration, // we now add it to the DeclContext since it wasn't added before // (see ActOnForwardClassDeclaration). + IDecl->setLexicalDeclContext(CurContext); CurContext->addDecl(IDecl); if (AttrList) @@ -114,12 +110,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (SuperName) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName); + PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); if (!PrevDecl) { // Try to correct for a typo in the superclass name. LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) { Diag(SuperLoc, diag::err_undef_superclass_suggest) << SuperName << ClassName << PrevDecl->getDeclName(); @@ -198,7 +195,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, IdentifierInfo *ClassName, SourceLocation ClassLocation) { // Look for previous declaration of alias name - NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); + NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation, + LookupOrdinaryName, ForRedeclaration); if (ADecl) { if (isa<ObjCCompatibleAliasDecl>(ADecl)) Diag(AliasLocation, diag::warn_previous_alias_decl); @@ -208,13 +206,15 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, return DeclPtrTy(); } // Check for class declaration - NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, + LookupOrdinaryName, ForRedeclaration); if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCInterfaceType()) { if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) { ClassName = IDecl->getIdentifier(); - CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, + LookupOrdinaryName, ForRedeclaration); } } } @@ -243,7 +243,8 @@ void Sema::CheckForwardProtocolDeclarationForCircularDependency( for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), E = PList.end(); I != E; ++I) { - if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) { + if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(), + Ploc)) { if (PDecl->getIdentifier() == PName) { Diag(Ploc, diag::err_protocol_has_circular_dependency); Diag(PrevLoc, diag::note_previous_definition); @@ -265,7 +266,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, AttributeList *AttrList) { // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); - ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName); + ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc); if (PDecl) { // Protocol already seen. Better be a forward protocol declaration if (!PDecl->isForwardDecl()) { @@ -312,11 +313,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, unsigned NumProtocols, llvm::SmallVectorImpl<DeclPtrTy> &Protocols) { for (unsigned i = 0; i != NumProtocols; ++i) { - ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first); + 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) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (PDecl = R.getAsSingle<ObjCProtocolDecl>())) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) << ProtocolId[i].first << R.getLookupName(); @@ -382,7 +384,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; - ObjCProtocolDecl *PDecl = LookupProtocol(Ident); + ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); if (PDecl == 0) { // Not already seen? PDecl = ObjCProtocolDecl::Create(Context, CurContext, IdentList[i].second, Ident); @@ -413,7 +415,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = 0; - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); /// Check that class of this category is already completely declared. if (!IDecl || IDecl->isForwardDecl()) { @@ -491,7 +493,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = 0; if (IDecl) { CatIDecl = IDecl->FindCategoryDeclaration(CatName); @@ -539,7 +541,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( ObjCInterfaceDecl* IDecl = 0; // Check for another declaration kind with the same name. NamedDecl *PrevDecl - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -553,7 +556,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( // 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) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { // Suggest the (potentially) correct interface name. However, put the // fix-it hint itself in a separate note, since changing the name in @@ -576,7 +579,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( ObjCInterfaceDecl* SDecl = 0; if (SuperClassname) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName); + PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc, + LookupOrdinaryName); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(SuperClassLoc, diag::err_redefinition_different_kind) << SuperClassname; @@ -1003,7 +1007,8 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. NamedDecl *PrevDecl - = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName); + = LookupSingleName(TUScope, IdentList[i], IdentLocs[i], + LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl); @@ -1436,6 +1441,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, IDecl = IDecl->getSuperClass(); } } + SetIvarInitializers(IC); } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { CatImplClass->setAtEndRange(AtEnd); @@ -1487,6 +1493,16 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { return ret; } +static inline +bool containsInvalidMethodImplAttribute(const AttributeList *A) { + // The 'ibaction' attribute is allowed on method definitions because of + // how the IBAction macro is used on both method declarations and definitions. + // If the method definitions contains any other attributes, return true. + while (A && A->getKind() == AttributeList::AT_IBAction) + A = A->getNext(); + return A != NULL; +} + Sema::DeclPtrTy Sema::ActOnMethodDeclaration( SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, DeclPtrTy classDecl, @@ -1495,7 +1511,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, - llvm::SmallVectorImpl<Declarator> &Cdecls, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic) { Decl *ClassDecl = classDecl.getAs<Decl>(); @@ -1550,7 +1566,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, DI, - VarDecl::None, 0); + VarDecl::None, VarDecl::None, 0); if (ArgType->isObjCInterfaceType()) { Diag(ArgInfo[i].NameLoc, @@ -1568,7 +1584,27 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( Params.push_back(Param); } - ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs()); + for (unsigned i = 0, e = CNumArgs; i != e; ++i) { + ParmVarDecl *Param = CParamInfo[i].Param.getAs<ParmVarDecl>(); + QualType ArgType = Param->getType(); + if (ArgType.isNull()) + ArgType = Context.getObjCIdType(); + else + // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). + ArgType = adjustParameterType(ArgType); + if (ArgType->isObjCInterfaceType()) { + Diag(Param->getLocation(), + diag::err_object_cannot_be_passed_returned_by_value) + << 1 << ArgType; + Param->setInvalidDecl(); + } + Param->setDeclContext(ObjCMethod); + IdResolver.RemoveDecl(Param); + Params.push_back(Param); + } + + ObjCMethod->setMethodParams(Context, Params.data(), Params.size(), + Sel.getNumArgs()); ObjCMethod->setObjCDeclQualifier( CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); const ObjCMethodDecl *PrevMethod = 0; @@ -1593,7 +1629,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, MethodType == tok::minus); - if (AttrList) + if (containsInvalidMethodImplAttribute(AttrList)) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { @@ -1604,7 +1640,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = CatImpDecl->getClassMethod(Sel); CatImpDecl->addClassMethod(ObjCMethod); } - if (AttrList) + if (containsInvalidMethodImplAttribute(AttrList)) Diag(EndLoc, diag::warn_attribute_method_def); } if (PrevMethod) { @@ -1638,7 +1674,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclPtrTy> &Decls) { // Check that ClassName is a valid class - ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { Diag(DeclStart, diag::err_undef_interface) << ClassName; return; @@ -1672,3 +1708,146 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, } } +/// \brief Build a type-check a new Objective-C exception variable declaration. +VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, + QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool Invalid) { + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // duration shall not be qualified by an address-space qualifier." + // Since all parameters have automatic store duration, they can not have + // an address space. + if (T.getAddressSpace() != 0) { + Diag(NameLoc, diag::err_arg_with_address_space); + Invalid = true; + } + + // An @catch parameter must be an unqualified object pointer type; + // FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"? + if (Invalid) { + // Don't do any further checking. + } else if (T->isDependentType()) { + // Okay: we don't know what this type will instantiate to. + } else if (!T->isObjCObjectPointerType()) { + Invalid = true; + Diag(NameLoc ,diag::err_catch_param_not_objc_type); + } else if (T->isObjCQualifiedIdType()) { + Invalid = true; + Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm); + } + + VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo, + VarDecl::None, VarDecl::None); + New->setExceptionVariable(true); + + if (Invalid) + New->setInvalidDecl(); + return New; +} + +Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { + const DeclSpec &DS = D.getDeclSpec(); + + // We allow the "register" storage class on exception variables because + // GCC did, but we drop it completely. Any other storage class is an error. + if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm) + << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc())); + } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { + Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) + << DS.getStorageClassSpec(); + } + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + + DiagnoseFunctionSpecifiers(D); + + // Check that there are no default arguments inside the type of this + // exception object (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + TypeSourceInfo *TInfo = 0; + TagDecl *OwnedDecl = 0; + QualType ExceptionType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl); + + 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.getIdentifier(), + D.getIdentifierLoc(), + D.isInvalidType()); + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_objc_catch_parm) + << D.getCXXScopeSpec().getRange(); + New->setInvalidDecl(); + } + + // Add the parameter declaration into this scope. + S->AddDecl(DeclPtrTy::make(New)); + if (D.getIdentifier()) + IdResolver.AddDecl(New); + + ProcessDeclAttributes(S, New, D); + + if (New->hasAttr<BlocksAttr>()) + Diag(New->getLocation(), diag::err_block_on_nonlocal); + return DeclPtrTy::make(New); +} + +/// CollectIvarsToConstructOrDestruct - Collect those ivars which require +/// initialization. +void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + + // Find ivars to construct/destruct in class extension. + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + } + + // Also add any ivar defined in this class's implementation. This + // includes synthesized ivars. + if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) { + for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), + E = ImplDecl->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + } +} + +void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, + CXXBaseOrMemberInitializer ** initializers, + unsigned numInitializers) { + if (numInitializers > 0) { + NumIvarInitializers = numInitializers; + CXXBaseOrMemberInitializer **ivarInitializers = + new (C) CXXBaseOrMemberInitializer*[NumIvarInitializers]; + memcpy(ivarInitializers, initializers, + numInitializers * sizeof(CXXBaseOrMemberInitializer*)); + IvarInitializers = ivarInitializers; + } +} + diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2dfb954..c4ab03f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -16,10 +16,13 @@ #include "Lookup.h" #include "AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -80,6 +83,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, const SentinelAttr *attr = D->getAttr<SentinelAttr>(); if (!attr) return; + + // FIXME: In C++0x, if any of the arguments are parameter pack + // expansions, we can't check for the sentinel now. int sentinelPos = attr->getSentinel(); int nullPos = attr->getNullPos(); @@ -155,6 +161,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } Expr *sentinelExpr = Args[sentinel]; if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) && + !sentinelExpr->isTypeDependent() && + !sentinelExpr->isValueDependent() && (!sentinelExpr->getType()->isPointerType() || !sentinelExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)))) { @@ -454,7 +462,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, } if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (isa<NonTypeTemplateParmDecl>(VD)) { + // Non-type template parameters can be referenced anywhere they are + // visible. + } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function) @@ -769,24 +780,6 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, return true; } -/// Determines if this is an instance member of a class. -static bool IsInstanceMember(NamedDecl *D) { - assert(D->isCXXClassMember() && - "checking whether non-member is instance member"); - - if (isa<FieldDecl>(D)) return true; - - if (isa<CXXMethodDecl>(D)) - return !cast<CXXMethodDecl>(D)->isStatic(); - - if (isa<FunctionTemplateDecl>(D)) { - D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); - return !cast<CXXMethodDecl>(D)->isStatic(); - } - - return false; -} - enum IMAKind { /// The reference is definitely not an instance member access. IMA_Static, @@ -846,8 +839,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, bool hasNonInstance = false; llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = (*I)->getUnderlyingDecl(); - if (IsInstanceMember(D)) { + NamedDecl *D = *I; + if (D->isCXXInstanceMember()) { CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); // If this is a member of an anonymous record, move out to the @@ -913,7 +906,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef, /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found -bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, +bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R) { DeclarationName Name = R.getLookupName(); @@ -964,43 +957,55 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, } // We didn't find anything, so try to correct for a typo. - if (S && CorrectTypo(R, S, &SS)) { - if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { - if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - else - Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() - << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) - Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); - - // Tell the callee to try to recover. - return false; - } + DeclarationName Corrected; + if (S && (Corrected = CorrectTypo(R, S, &SS))) { + if (!R.empty()) { + if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange() + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + + // Tell the callee to try to recover. + return false; + } + + if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { + // 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(); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange(); - if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { - // 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. + // Don't try to recover; it won't work. + return true; + } + } else { + // 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 << R.getLookupName(); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() - << SS.getRange(); - - // Don't try to recover; it won't work. + << Name << computeDeclContext(SS, false) << Corrected + << SS.getRange(); return true; } - R.clear(); } @@ -1019,7 +1024,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Id, bool HasTrailingLParen, bool isAddressOfOperand) { @@ -1064,6 +1069,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, if (TemplateArgs) { // Just re-use the lookup done by isTemplateName. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); @@ -1123,16 +1137,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Warn about constructs like: // if (void *X = foo()) { ... } else { X }. // In the else block, the pointer is always false. - if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; while (CheckS && CheckS->getControlParent()) { - if (CheckS->isWithinElse() && + if ((CheckS->getFlags() & Scope::ElseScope) && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { ExprError(Diag(NameLoc, diag::warn_value_always_zero) << Var->getDeclName() - << (Var->getType()->isPointerType()? 2 : - Var->getType()->isBooleanType()? 1 : 0)); + << (Var->getType()->isPointerType() ? 2 : + Var->getType()->isBooleanType() ? 1 : 0)); break; } @@ -1218,15 +1231,16 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, /// There's a large number of things which don't need to be done along /// this path. Sema::OwningExprResult -Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, +Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc) { DeclContext *DC; - if (!(DC = computeDeclContext(SS, false)) || - DC->isDependentContext() || - RequireCompleteDeclContext(SS)) + if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext()) return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0); + if (RequireCompleteDeclContext(SS, DC)) + return ExprError(); + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); LookupQualifiedName(R, DC); @@ -1251,9 +1265,9 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, /// Returns a null sentinel to indicate trivial success. Sema::OwningExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II, - bool AllowBuiltinCreation) { + IdentifierInfo *II, bool AllowBuiltinCreation) { SourceLocation Loc = Lookup.getNameLoc(); + ObjCMethodDecl *CurMethod = getCurMethodDecl(); // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have @@ -1264,7 +1278,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // If we're in a class method, we don't normally want to look for // ivars. But if we don't find anything else, and there's an // ivar, that's an error. - bool IsClassMethod = getCurMethodDecl()->isClassMethod(); + bool IsClassMethod = CurMethod->isClassMethod(); bool LookForIvars; if (Lookup.empty()) @@ -1276,7 +1290,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); ObjCInterfaceDecl *IFace = 0; if (LookForIvars) { - IFace = getCurMethodDecl()->getClassInterface(); + IFace = CurMethod->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { // Diagnose using an ivar in a class method. @@ -1311,9 +1325,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCIvarRefExpr(IV, IV->getType(), Loc, SelfExpr.takeAs<Expr>(), true, true)); } - } else if (getCurMethodDecl()->isInstanceMethod()) { + } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. - ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { if (IV->getAccessControl() != ObjCIvarDecl::Private || @@ -1322,17 +1336,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, } } - // Needed to implement property "super.method" notation. - if (Lookup.empty() && II->isStr("super")) { - QualType T; - - if (getCurMethodDecl()->isInstanceMethod()) - T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( - getCurMethodDecl()->getClassInterface())); - else - T = Context.getObjCClassType(); - return Owned(new (Context) ObjCSuperExpr(Loc, T)); - } if (Lookup.empty() && II && AllowBuiltinCreation) { // FIXME. Consolidate this with similar code in LookupName. if (unsigned BuiltinID = II->getBuiltinID()) { @@ -1449,14 +1452,15 @@ Sema::PerformObjectMemberConversion(Expr *&From, // type of the object type, in which case we just ignore it. // Otherwise build the appropriate casts. if (IsDerivedFrom(FromRecordType, QRecordType)) { + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, - FromLoc, FromRange)) + FromLoc, FromRange, &BasePath)) return true; if (PointerConversions) QType = Context.getPointerType(QType); ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1484,15 +1488,16 @@ Sema::PerformObjectMemberConversion(Expr *&From, // conversion is non-trivial. if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { assert(IsDerivedFrom(FromRecordType, URecordType)); + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(FromRecordType, URecordType, - FromLoc, FromRange)) + FromLoc, FromRange, &BasePath)) return true; - + QualType UType = URecordType; if (PointerConversions) UType = Context.getPointerType(UType); ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1502,23 +1507,22 @@ Sema::PerformObjectMemberConversion(Expr *&From, IgnoreAccess = true; } - if (CheckDerivedToBaseConversion(FromRecordType, - DestRecordType, - FromLoc, - FromRange, + CXXBaseSpecifierArray BasePath; + if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, + FromLoc, FromRange, &BasePath, IgnoreAccess)) return true; ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); return false; } /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, - NamedDecl *FoundDecl, SourceLocation Loc, - QualType Ty, + DeclAccessPair FoundDecl, + SourceLocation Loc, QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -2484,7 +2488,8 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, } } - assert(BaseType->isDependentType() || Name.isDependentName()); + assert(BaseType->isDependentType() || Name.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. @@ -2510,11 +2515,8 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, if (!BaseExpr) return DiagnoseInstanceReference(SemaRef, SS, R); - // FIXME: this is an exceedingly lame diagnostic for some of the more - // complicated cases here. - DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); - SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) - << SS.getRange() << DC << BaseType; + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated) + << SS.getRange() << R.getRepresentativeDecl() << BaseType; } // Check whether the declarations we found through a nested-name @@ -2545,7 +2547,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, 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 && !IsInstanceMember((*I)->getUnderlyingDecl())) + if (!BaseExpr && !(*I)->isCXXInstanceMember()) return false; // Note that we use the DC of the decl, not the underlying decl. @@ -2567,7 +2569,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, const CXXScopeSpec &SS) { + SourceLocation OpLoc, CXXScopeSpec &SS) { RecordDecl *RDecl = RTy->getDecl(); if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), SemaRef.PDiag(diag::err_typecheck_incomplete_tag) @@ -2580,7 +2582,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // nested-name-specifier. DC = SemaRef.computeDeclContext(SS, false); - if (SemaRef.RequireCompleteDeclContext(SS)) { + if (SemaRef.RequireCompleteDeclContext(SS, DC)) { SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) << SS.getRange() << DC; return true; @@ -2604,7 +2606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // We didn't find anything with the given name, so try to correct // for typos. DeclarationName Name = R.getLookupName(); - if (SemaRef.CorrectTypo(R, 0, &SS, DC) && + if (SemaRef.CorrectTypo(R, 0, &SS, DC, 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() @@ -2624,7 +2627,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Sema::OwningExprResult Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs) { @@ -2675,13 +2678,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck) { Expr *BaseExpr = Base.takeAs<Expr>(); QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); BaseType = BaseType->getAs<PointerType>()->getPointeeType(); } + R.setBaseObjectType(BaseType); NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); @@ -2713,6 +2718,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if ((SS.isSet() || !BaseExpr || (isa<CXXThisExpr>(BaseExpr) && cast<CXXThisExpr>(BaseExpr)->isImplicit())) && + !SuppressQualifierCheck && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); @@ -2742,7 +2748,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } assert(R.isSingleResult()); - NamedDecl *FoundDecl = *R.begin(); + DeclAccessPair FoundDecl = R.begin().getPair(); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2756,7 +2762,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, // Handle the implicit-member-access case. if (!BaseExpr) { // If this is not an instance member, convert to a non-member access. - if (!IsInstanceMember(MemberDecl)) + if (!MemberDecl->isCXXInstanceMember()) return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); SourceLocation Loc = R.getNameLoc(); @@ -2833,16 +2839,18 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Owned(BaseExpr); + // We found something that we didn't expect. Complain. if (isa<TypeDecl>(MemberDecl)) - return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) - << MemberName << int(IsArrow)); + 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); - // We found a declaration kind that we didn't expect. This is a - // generic error message that tells the user that she can't refer - // to this member with '.' or '->'. - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_unknown) - << MemberName << int(IsArrow)); + Diag(MemberDecl->getLocation(), diag::note_member_declared_here) + << MemberName; + R.suppressDiagnostics(); + return ExprError(); } /// Look up the given member of the given non-type-dependent @@ -2858,7 +2866,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool &IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); @@ -3060,7 +3068,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Attempt to correct for typos in ivar names. LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), LookupMemberName); - if (CorrectTypo(Res, 0, 0, IDecl) && + if (CorrectTypo(Res, 0, 0, IDecl, false, CTC_MemberLookup) && (IV = Res.getAsSingle<ObjCIvarDecl>())) { Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) @@ -3145,117 +3153,23 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (DiagnoseUseOfDecl(OMD, MemberLoc)) return ExprError(); - return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel, - OMD->getResultType(), - OMD, OpLoc, MemberLoc, - NULL, 0)); + return Owned(ObjCMessageExpr::Create(Context, + OMD->getResultType().getNonReferenceType(), + OpLoc, BaseExpr, Sel, + OMD, NULL, 0, MemberLoc)); } } return ExprError(Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); } + // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. - const ObjCObjectPointerType *OPT; - if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) { - const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); - ObjCInterfaceDecl *IFace = IFaceT->getDecl(); - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - // Search for a declared property first. - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - QualType ResTy = PD->getType(); - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) - ResTy = Getter->getResultType(); - return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, - MemberLoc, BaseExpr)); - } - // Check protocols on qualified interfaces. - for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), - E = OPT->qual_end(); I != E; ++I) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); - } - // If that failed, look for an "implicit" property by seeing if the nullary - // selector is implemented. - - // FIXME: The logic for looking up nullary and unary selectors should be - // shared with the code in ActOnInstanceMessage. - - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - - // If this reference is in an @implementation, check for 'private' methods. - if (!Getter) - Getter = IFace->lookupPrivateInstanceMethod(Sel); - - // Look through local category implementations associated with the class. - if (!Getter) - Getter = IFace->getCategoryInstanceMethod(Sel); - if (Getter) { - // Check if we can reference this property. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } - // 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->lookupInstanceMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateInstanceMethod(SetterSel); - } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryInstanceMethod(SetterSel); - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - if (Getter) { - QualType PType; - PType = Getter->getResultType(); - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, - Setter, MemberLoc, BaseExpr)); - } - - // Attempt to correct for typos in property names. - LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), - LookupOrdinaryName); - if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && - Res.getAsSingle<ObjCPropertyDecl>()) { - Diag(R.getNameLoc(), diag::err_property_not_found_suggest) - << MemberName << BaseType << Res.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - Res.getLookupName().getAsString()); - ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); - Diag(Property->getLocation(), diag::note_previous_decl) - << Property->getDeclName(); - - return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl); - } - Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType; - if (Setter && !Getter) - Diag(Setter->getLocation(), diag::note_getter_unavailable) - << MemberName << BaseExpr->getSourceRange(); - return ExprError(); - } + if (!IsArrow) + if (const ObjCObjectPointerType *OPT = + BaseType->getAsObjCInterfacePointerType()) + return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc); // Handle the following exceptional case (*Obj).isa. if (!IsArrow && @@ -3296,7 +3210,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Id, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen) { @@ -3323,7 +3237,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); - if (Base->getType()->isDependentType() || Name.isDependentName()) { + if (Base->getType()->isDependentType() || Name.isDependentName() || + isDependentScopeSpecifier(SS)) { Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, @@ -3334,6 +3249,21 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, if (TemplateArgs) { // Re-use the lookup done for the template name. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } else { + QualType BaseType = Base->getType(); + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + if (CXXRecordDecl *NamingClass = BaseType->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, SS, ObjCImpDecl); @@ -3443,7 +3373,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (NumArgs < NumArgsInProto) { if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); + << Fn->getType()->isBlockPointerType() + << NumArgsInProto << NumArgs << Fn->getSourceRange(); Call->setNumArgs(Context, NumArgsInProto); } @@ -3453,7 +3384,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (!Proto->isVariadic()) { Diag(Args[NumArgsInProto]->getLocStart(), diag::err_typecheck_call_too_many_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange() + << Fn->getType()->isBlockPointerType() + << NumArgsInProto << NumArgs << Fn->getSourceRange() << SourceRange(Args[NumArgsInProto]->getLocStart(), Args[NumArgs-1]->getLocEnd()); // This deletes the extra arguments. @@ -3613,7 +3545,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // declarations (all methods or method templates) or a single // method template. assert((MemE->getNumDecls() > 1) || - isa<FunctionTemplateDecl>(*MemE->decls_begin())); + isa<FunctionTemplateDecl>( + (*MemE->decls_begin())->getUnderlyingDecl())); (void)MemE; return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, @@ -3666,7 +3599,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Expr *NakedFn = Fn->IgnoreParens(); if (isa<UnresolvedLookupExpr>(NakedFn)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn); - return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs, + return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); } @@ -3851,8 +3784,8 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. - InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, - RBraceLoc); + InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList, + NumInit, RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return Owned(E); } @@ -3895,11 +3828,11 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, /// CheckCastTypes - Check type constraints for casting between types. bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, CastExpr::CastKind& Kind, - CXXMethodDecl *& ConversionDecl, + CXXBaseSpecifierArray &BasePath, bool FunctionalStyle) { if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle, - ConversionDecl); + return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath, + FunctionalStyle); DefaultFunctionArrayLvalueConversion(castExpr); @@ -3962,9 +3895,6 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (castExpr->getType()->isVectorType()) return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); - if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) - return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - if (isa<ObjCSelectorExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); @@ -4062,27 +3992,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, ExprArg Op) { Expr *castExpr = static_cast<Expr*>(Op.get()); - CXXMethodDecl *Method = 0; CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXBaseSpecifierArray BasePath; if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, Method)) + Kind, BasePath)) return ExprError(); - if (Method) { - // FIXME: preserve type source info here - OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(), - Kind, Method, move(Op)); - - if (CastArg.isInvalid()) - return ExprError(); - - castExpr = CastArg.takeAs<Expr>(); - } else { - Op.release(); - } - + Op.release(); return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(), - Kind, castExpr, Ty, + Kind, castExpr, BasePath, Ty, LParenLoc, RParenLoc)); } @@ -4126,7 +4044,8 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. Op.release(); - InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], + InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc, + &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); @@ -4856,7 +4775,7 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, QualType UnionType, FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. - InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(), + InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), &E, 1, SourceLocation()); Initializer->setType(UnionType); @@ -5419,11 +5338,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, DiagRuntimeBehavior(Loc, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) - << literalString->getSourceRange() - << FixItHint::CreateReplacement(SourceRange(Loc), ", ") - << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(") - << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison)); + << literalString->getSourceRange()); } } @@ -5480,7 +5395,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(lex, rex, + QualType T = FindCompositePointerType(Loc, lex, rex, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) @@ -5553,7 +5468,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // that is the union of the cv-qualification signatures of the operand // types. bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(lex, rex, + QualType T = FindCompositePointerType(Loc, lex, rex, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) @@ -5944,7 +5859,7 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, - bool isInc) { + bool isInc, bool isPrefix) { if (Op->isTypeDependent()) return Context.DependentTy; @@ -6007,7 +5922,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, *this)) return QualType(); - return ResType; + // In C++, a prefix increment is the same type as the operand. Otherwise + // (in C or with postfix), the increment is the unqualified type of the + // operand. + return isPrefix && getLangOptions().CPlusPlus + ? ResType : ResType.getUnqualifiedType(); } /// getPrimaryDecl - Helper function for CheckAddressOfOperand(). @@ -6395,33 +6314,37 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, - SourceRange ParenRange, - const PartialDiagnostic &SecondPD, + const PartialDiagnostic &FirstNote, + SourceRange FirstParenRange, + const PartialDiagnostic &SecondNote, SourceRange SecondParenRange) { - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); - if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, PD); + 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, PD) - << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + Self.Diag(Loc, FirstNote) + << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") << FixItHint::CreateInsertion(EndLoc, ")"); - if (!SecondPD.getDiagID()) + 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, SecondPD); + Self.Diag(Loc, SecondNote); return; } - Self.Diag(Loc, SecondPD) + Self.Diag(Loc, SecondNote) << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") << FixItHint::CreateInsertion(EndLoc, ")"); } @@ -6455,19 +6378,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange(), Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); + SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()), + Self.PDiag(diag::note_precedence_bitwise_silence) + << BinOp::getOpcodeStr(lhsopc), + lhs->getSourceRange()); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange(), Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); + SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()), + Self.PDiag(diag::note_precedence_bitwise_silence) + << BinOp::getOpcodeStr(rhsopc), + rhs->getSourceRange()); } /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky @@ -6532,14 +6459,16 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UnaryOperator::OffsetOf: assert(false && "Invalid unary operator"); break; - + case UnaryOperator::PreInc: case UnaryOperator::PreDec: case UnaryOperator::PostInc: case UnaryOperator::PostDec: resultType = CheckIncrementDecrementOperand(Input, OpLoc, Opc == UnaryOperator::PreInc || - Opc == UnaryOperator::PostInc); + Opc == UnaryOperator::PostInc, + Opc == UnaryOperator::PreInc || + Opc == UnaryOperator::PreDec); break; case UnaryOperator::AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); @@ -6690,6 +6619,157 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt, return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc)); } +Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc) { + QualType ArgTy = TInfo->getType(); + bool Dependent = ArgTy->isDependentType(); + SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange(); + + // We must have at least one component that refers to the type, and the first + // one is known to be a field designator. Verify that the ArgTy represents + // a struct/union/class. + if (!Dependent && !ArgTy->isRecordType()) + return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type) + << ArgTy << TypeRange); + + // Type must be complete per C99 7.17p3 because a declaring a variable + // with an incomplete type would be ill-formed. + if (!Dependent + && RequireCompleteType(BuiltinLoc, ArgTy, + PDiag(diag::err_offsetof_incomplete_type) + << TypeRange)) + return ExprError(); + + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a + // GCC extension, diagnose them. + // FIXME: This diagnostic isn't actually visible because the location is in + // a system header! + if (NumComponents != 1) + Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) + << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); + + bool DidWarnAboutNonPOD = false; + QualType CurrentType = ArgTy; + typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; + llvm::SmallVector<OffsetOfNode, 4> Comps; + llvm::SmallVector<Expr*, 4> Exprs; + for (unsigned i = 0; i != NumComponents; ++i) { + const OffsetOfComponent &OC = CompPtr[i]; + if (OC.isBrackets) { + // Offset of an array sub-field. TODO: Should we allow vector elements? + if (!CurrentType->isDependentType()) { + const ArrayType *AT = Context.getAsArrayType(CurrentType); + if(!AT) + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) + << CurrentType); + CurrentType = AT->getElementType(); + } else + CurrentType = Context.DependentTy; + + // The expression must be an integral expression. + // FIXME: An integral constant expression? + Expr *Idx = static_cast<Expr*>(OC.U.E); + if (!Idx->isTypeDependent() && !Idx->isValueDependent() && + !Idx->getType()->isIntegerType()) + return ExprError(Diag(Idx->getLocStart(), + diag::err_typecheck_subscript_not_integer) + << Idx->getSourceRange()); + + // Record this array index. + Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd)); + Exprs.push_back(Idx); + continue; + } + + // Offset of a field. + if (CurrentType->isDependentType()) { + // We have the offset of a field, but we can't look into the dependent + // type. Just record the identifier of the field. + Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd)); + CurrentType = Context.DependentTy; + continue; + } + + // We need to have a complete type to look into. + if (RequireCompleteType(OC.LocStart, CurrentType, + diag::err_offsetof_incomplete_type)) + return ExprError(); + + // Look for the designated field. + const RecordType *RC = CurrentType->getAs<RecordType>(); + if (!RC) + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) + << CurrentType); + RecordDecl *RD = RC->getDecl(); + + // C++ [lib.support.types]p5: + // The macro offsetof accepts a restricted set of type arguments in this + // International Standard. type shall be a POD structure or a POD union + // (clause 9). + if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (!CRD->isPOD() && !DidWarnAboutNonPOD && + DiagRuntimeBehavior(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << CurrentType)) + DidWarnAboutNonPOD = true; + } + + // Look for the field. + LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); + LookupQualifiedName(R, RD); + FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); + if (!MemberDecl) + return ExprError(Diag(BuiltinLoc, diag::err_no_member) + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, + OC.LocEnd)); + + // C99 7.17p3: + // (If the specified member is a bit-field, the behavior is undefined.) + // + // We diagnose this as an error. + if (MemberDecl->getBitWidth()) { + Diag(OC.LocEnd, diag::err_offsetof_bitfield) + << MemberDecl->getDeclName() + << SourceRange(BuiltinLoc, RParenLoc); + Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); + return ExprError(); + } + + // If the member was found in a base class, introduce OffsetOfNodes for + // the base class indirections. + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (IsDerivedFrom(CurrentType, + Context.getTypeDeclType(MemberDecl->getParent()), + Paths)) { + CXXBasePath &Path = Paths.front(); + for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end(); + B != BEnd; ++B) + Comps.push_back(OffsetOfNode(B->Base)); + } + + if (cast<RecordDecl>(MemberDecl->getDeclContext())-> + isAnonymousStructOrUnion()) { + llvm::SmallVector<FieldDecl*, 4> Path; + BuildAnonymousStructUnionMemberPath(MemberDecl, Path); + unsigned n = Path.size(); + for (int j = n - 1; j > -1; --j) + Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd)); + } else { + Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd)); + } + CurrentType = MemberDecl->getType().getNonReferenceType(); + } + + return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, + TInfo, Comps.data(), Comps.size(), + Exprs.data(), Exprs.size(), RParenLoc)); +} + Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, @@ -6697,45 +6777,56 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, OffsetOfComponent *CompPtr, unsigned NumComponents, SourceLocation RPLoc) { - // FIXME: This function leaks all expressions in the offset components on - // error. - // FIXME: Preserve type source info. - QualType ArgTy = GetTypeFromParser(argty); - assert(!ArgTy.isNull() && "Missing type argument!"); - bool Dependent = ArgTy->isDependentType(); + TypeSourceInfo *ArgTInfo; + QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo); + if (ArgTy.isNull()) + return ExprError(); + if (getLangOptions().CPlusPlus) { + if (!ArgTInfo) + ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); + + return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, + RPLoc); + } + + // FIXME: The code below is marked for death, once we have proper CodeGen + // support for non-constant OffsetOf expressions. + + bool Dependent = ArgTy->isDependentType(); + // We must have at least one component that refers to the type, and the first // one is known to be a field designator. Verify that the ArgTy represents // a struct/union/class. if (!Dependent && !ArgTy->isRecordType()) return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy); - + // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable // with an incomplete type would be illegal. - + // Otherwise, create a null pointer as the base, and iteratively process // the offsetof designators. QualType ArgTyPtr = Context.getPointerType(ArgTy); Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr); Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref, ArgTy, SourceLocation()); - + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a // GCC extension, diagnose them. // FIXME: This diagnostic isn't actually visible because the location is in // a system header! if (NumComponents != 1) Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) - << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); - + << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); + if (!Dependent) { bool DidWarnAboutNonPOD = false; - + if (RequireCompleteType(TypeLoc, Res->getType(), diag::err_offsetof_incomplete_type)) return ExprError(); - + // FIXME: Dependent case loses a lot of information here. And probably // leaks like a sieve. for (unsigned i = 0; i != NumComponents; ++i) { @@ -6746,71 +6837,83 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (!AT) { Res->Destroy(Context); return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) - << Res->getType()); + << Res->getType()); } - + // FIXME: C++: Verify that operator[] isn't overloaded. - + // Promote the array so it looks more like a normal array subscript // expression. DefaultFunctionArrayLvalueConversion(Res); - + // C99 6.5.2.1p1 Expr *Idx = static_cast<Expr*>(OC.U.E); // FIXME: Leaks Res if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType()) return ExprError(Diag(Idx->getLocStart(), diag::err_typecheck_subscript_not_integer) - << Idx->getSourceRange()); - + << Idx->getSourceRange()); + Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd); continue; } - + const RecordType *RC = Res->getType()->getAs<RecordType>(); if (!RC) { Res->Destroy(Context); return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) - << Res->getType()); + << Res->getType()); } - + // Get the decl corresponding to this. RecordDecl *RD = RC->getDecl(); if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { if (!CRD->isPOD() && !DidWarnAboutNonPOD && DiagRuntimeBehavior(BuiltinLoc, PDiag(diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType())) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType())) DidWarnAboutNonPOD = true; } - + LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); - + FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); // FIXME: Leaks Res if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) - << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); - + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); + + // C99 7.17p3: + // (If the specified member is a bit-field, the behavior is undefined.) + // + // We diagnose this as an error. + if (MemberDecl->getBitWidth()) { + Diag(OC.LocEnd, diag::err_offsetof_bitfield) + << MemberDecl->getDeclName() + << SourceRange(BuiltinLoc, RPLoc); + Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); + return ExprError(); + } + // FIXME: C++: Verify that MemberDecl isn't a static field. // FIXME: Verify that MemberDecl isn't a bitfield. if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) { Res = BuildAnonymousStructUnionMemberReference( - OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); + OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); } else { PerformObjectMemberConversion(Res, /*Qualifier=*/0, *R.begin(), MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, - MemberDecl->getType().getNonReferenceType()); + MemberDecl->getType().getNonReferenceType()); } } } - + return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(), BuiltinLoc)); } @@ -7127,7 +7230,7 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, +static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, Expr *SrcExpr, FixItHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; @@ -7155,7 +7258,11 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, AssignmentAction Action) { + Expr *SrcExpr, AssignmentAction Action, + bool *Complained) { + if (Complained) + *Complained = false; + // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; @@ -7218,8 +7325,30 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; } - Diag(Loc, DiagKind) << DstType << SrcType << Action + QualType FirstType, SecondType; + switch (Action) { + case AA_Assigning: + case AA_Initializing: + // The destination type comes first. + FirstType = DstType; + SecondType = SrcType; + break; + + case AA_Returning: + case AA_Passing: + case AA_Converting: + case AA_Sending: + case AA_Casting: + // The source type comes first. + FirstType = SrcType; + SecondType = DstType; + break; + } + + Diag(Loc, DiagKind) << FirstType << SecondType << Action << SrcExpr->getSourceRange() << Hint; + if (Complained) + *Complained = true; return isInvalid; } @@ -7328,8 +7457,13 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and // -Wunused-parameters) if (isa<ParmVarDecl>(D) || - (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) + (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) { D->setUsed(true); + return; + } + + if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) + return; // Do not mark anything as "used" within a dependent context; wait for // an instantiation. @@ -7375,7 +7509,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed()) - DefineImplicitOverloadedAssign(Loc, MethodDecl); + DefineImplicitCopyAssignment(Loc, MethodDecl); } } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -7536,12 +7670,12 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - Diag(Loc, diagnostic) - << E->getSourceRange() - << FixItHint::CreateInsertion(Open, "(") - << FixItHint::CreateInsertion(Close, ")"); + Diag(Loc, diagnostic) << E->getSourceRange(); Diag(Loc, diag::note_condition_assign_to_comparison) << FixItHint::CreateReplacement(Loc, "=="); + Diag(Loc, diag::note_condition_assign_silence) + << FixItHint::CreateInsertion(Open, "(") + << FixItHint::CreateInsertion(Close, ")"); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 501c877..425fc2d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -29,7 +29,7 @@ using namespace clang; Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, TypeTy *ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. @@ -261,7 +261,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Range = SourceRange(NameLoc); } - return CheckTypenameType(NNS, II, Range).getAsOpaquePtr(); + return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr(); } if (ObjectTypePtr) @@ -273,89 +273,107 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, return 0; } -/// ActOnCXXTypeidOfType - Parse typeid( type-id ). +/// \brief Build a C++ typeid expression with a type operand. +Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + // C++ [expr.typeid]p4: + // The top-level cv-qualifiers of the lvalue expression or the type-id + // that is the operand of typeid are always ignored. + // If the type of the type-id is a class type or a reference to a class + // type, the class shall be completely-defined. + QualType T = Operand->getType().getNonReferenceType(); + if (T->getAs<RecordType>() && + RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), + Operand, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// \brief Build a C++ typeid expression with an expression operand. +Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + ExprArg Operand, + SourceLocation RParenLoc) { + bool isUnevaluatedOperand = true; + Expr *E = static_cast<Expr *>(Operand.get()); + if (E && !E->isTypeDependent()) { + QualType T = E->getType(); + if (const RecordType *RecordT = T->getAs<RecordType>()) { + CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); + // C++ [expr.typeid]p3: + // [...] If the type of the expression is a class type, the class + // shall be completely-defined. + if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + + // C++ [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] [the] expression is an unevaluated + // operand. [...] + if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) + isUnevaluatedOperand = false; + } + + // C++ [expr.typeid]p4: + // [...] If the type of the type-id is a reference to a possibly + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced + // type. + if (T.hasQualifiers()) { + ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp, + E->isLvalue(Context)); + Operand.release(); + Operand = Owned(E); + } + } + + // If this is an unevaluated operand, clear out the set of + // declaration references we have been computing and eliminate any + // temporaries introduced in its computation. + if (isUnevaluatedOperand) + ExprEvalContexts.back().Context = Unevaluated; + + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), + Operand.takeAs<Expr>(), + SourceRange(TypeidLoc, RParenLoc))); +} + +/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // Find the std::type_info type. if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - if (isType) { - // C++ [expr.typeid]p4: - // The top-level cv-qualifiers of the lvalue expression or the type-id - // that is the operand of typeid are always ignored. - // FIXME: Preserve type source info. - // FIXME: Preserve the type before we stripped the cv-qualifiers? - QualType T = GetTypeFromParser(TyOrExpr); - if (T.isNull()) - return ExprError(); - - // C++ [expr.typeid]p4: - // If the type of the type-id is a class type or a reference to a class - // type, the class shall be completely-defined. - QualType CheckT = T; - if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>()) - CheckT = RefType->getPointeeType(); - - if (CheckT->getAs<RecordType>() && - RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid)) - return ExprError(); - - TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr(); - } - IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, StdNamespace); RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - + QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); + + if (isType) { + // The operand is a type; handle it as such. + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeFromParser(TyOrExpr, &TInfo); + if (T.isNull()) + return ExprError(); + + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); - if (!isType) { - bool isUnevaluatedOperand = true; - Expr *E = static_cast<Expr *>(TyOrExpr); - if (E && !E->isTypeDependent()) { - QualType T = E->getType(); - if (const RecordType *RecordT = T->getAs<RecordType>()) { - CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); - // C++ [expr.typeid]p3: - // [...] If the type of the expression is a class type, the class - // shall be completely-defined. - if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) - return ExprError(); - - // C++ [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] [the] expression is an unevaluated - // operand. [...] - if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) - isUnevaluatedOperand = false; - } - - // C++ [expr.typeid]p4: - // [...] If the type of the type-id is a reference to a possibly - // cv-qualified type, the result of the typeid expression refers to a - // std::type_info object representing the cv-unqualified referenced - // type. - if (T.hasQualifiers()) { - ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp, - E->isLvalue(Context)); - TyOrExpr = E; - } - } - - // If this is an unevaluated operand, clear out the set of - // declaration references we have been computing and eliminate any - // temporaries introduced in its computation. - if (isUnevaluatedOperand) - ExprEvalContexts.back().Context = Unevaluated; + return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } - return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, - TypeInfoType.withConst(), - SourceRange(OpLoc, RParenLoc))); + // The operand is an expression. + return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. @@ -399,10 +417,10 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = E->getType(); - int isPointer = 0; + bool isPointer = false; if (const PointerType* Ptr = Ty->getAs<PointerType>()) { Ty = Ptr->getPointeeType(); - isPointer = 1; + isPointer = true; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, @@ -411,20 +429,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { << E->getSourceRange())) return true; - // FIXME: This is just a hack to mark the copy constructor referenced. - // This should go away when the next FIXME is fixed. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) - return false; - - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialCopyConstructor()) - return false; - CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0); - MarkDeclarationReferenced(ThrowLoc, CopyCtor); + if (RequireNonAbstractType(ThrowLoc, E->getType(), + PDiag(diag::err_throw_abstract_type) + << E->getSourceRange())) + return true; } - // FIXME: Construct a temporary here. + // Initialize the exception result. This implicitly weeds out + // abstract types or types with inaccessible copy constructors. + InitializedEntity Entity = + InitializedEntity::InitializeException(ThrowLoc, E->getType()); + OwningExprResult Res = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(E)); + if (Res.isInvalid()) + return true; + E = Res.takeAs<Expr>(); return false; } @@ -499,25 +519,17 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // if (NumExprs == 1) { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXMethodDecl *Method = 0; - if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method, + CXXBaseSpecifierArray BasePath; + if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath, /*FunctionalStyle=*/true)) return ExprError(); exprs.release(); - if (Method) { - OwningExprResult CastArg - = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(), - Kind, Method, Owned(Exprs[0])); - if (CastArg.isInvalid()) - return ExprError(); - - Exprs[0] = CastArg.takeAs<Expr>(); - } return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), TInfo, TyBeginLoc, Kind, - Exprs[0], RParenLoc)); + Exprs[0], BasePath, + RParenLoc)); } if (const RecordType *RT = Ty->getAs<RecordType>()) { @@ -708,10 +720,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, OperatorNew->getType()->getAs<FunctionProtoType>(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; - bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew, - Proto, 1, PlaceArgs, NumPlaceArgs, - AllPlaceArgs, CallType); - if (Invalid) + + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, + Proto, 1, PlaceArgs, NumPlaceArgs, + AllPlaceArgs, CallType)) return ExprError(); NumPlaceArgs = AllPlaceArgs.size(); @@ -726,6 +738,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, unsigned NumConsArgs = ConstructorArgs.size(); ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + // Array 'new' can't have any initializers. + if (NumConsArgs && ArraySize) { + SourceRange InitRange(ConsArgs[0]->getLocStart(), + ConsArgs[NumConsArgs - 1]->getLocEnd()); + + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; + return ExprError(); + } + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { // C++0x [expr.new]p15: @@ -892,6 +913,13 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, return true; } + // We don't need an operator delete if we're running under + // -fno-exceptions. + if (!getLangOptions().Exceptions) { + OperatorDelete = 0; + return false; + } + // FindAllocationOverload can change the passed in arguments, so we need to // copy them back. if (NumPlaceArgs > 0) @@ -1214,7 +1242,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FunctionType::ExtInfo()); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, /*TInfo=*/0, FunctionDecl::None, false, true); + FnType, /*TInfo=*/0, FunctionDecl::None, + FunctionDecl::None, false, true); Alloc->setImplicit(); if (AddMallocAttr) @@ -1222,6 +1251,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); Alloc->setParams(&Param, 1); @@ -1258,8 +1288,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { - Diag((*F)->getLocation(), - diag::note_delete_member_function_declared_here) + Diag((*F)->getLocation(), diag::note_member_declared_here) << Name; } @@ -1396,6 +1425,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); } + MarkDeclarationReferenced(StartLoc, OperatorDelete); + // FIXME: Check access and ambiguity of operator delete and destructor. } @@ -1469,45 +1500,43 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return false; } -/// PerformImplicitConversion - Perform an implicit conversion of the -/// expression From to the type ToType. Returns true if there was an -/// error, false otherwise. The expression From is replaced with the -/// converted expression. Flavor is the kind of conversion we're -/// performing, used in the error message. If @p AllowExplicit, -/// explicit user-defined conversions are permitted. @p Elidable should be true -/// when called for copies which may be elided (C++ 12.8p15). C++0x overload -/// resolution works differently in that case. -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, bool AllowExplicit, - bool Elidable) { - ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Action, AllowExplicit, - Elidable, ICS); -} - -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, bool AllowExplicit, - bool Elidable, - ImplicitConversionSequence& ICS) { - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - if (Elidable && getLangOptions().CPlusPlus0x) { - ICS = TryImplicitConversion(From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*ForceRValue=*/true, - /*InOverloadResolution=*/false); - } - if (ICS.isBad()) { - ICS = TryImplicitConversion(From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - } - return PerformImplicitConversion(From, ToType, ICS, Action); -} +static Sema::OwningExprResult BuildCXXCastArgument(Sema &S, + SourceLocation CastLoc, + QualType Ty, + CastExpr::CastKind Kind, + CXXMethodDecl *Method, + Sema::ExprArg Arg) { + Expr *From = Arg.takeAs<Expr>(); + + switch (Kind) { + default: assert(0 && "Unhandled cast kind!"); + case CastExpr::CK_ConstructorConversion: { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + + if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + Sema::MultiExprArg(S, (void **)&From, 1), + CastLoc, ConstructorArgs)) + return S.ExprError(); + + Sema::OwningExprResult Result = + S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + if (Result.isInvalid()) + return S.ExprError(); + + return S.MaybeBindToTemporary(Result.takeAs<Expr>()); + } + + case CastExpr::CK_UserDefinedConversion: { + assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); + + // Create an implicit call expr that calls it. + // FIXME: pass the FoundDecl for the user-defined conversion here + CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method); + return S.MaybeBindToTemporary(CE); + } + } +} /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit @@ -1560,7 +1589,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } OwningExprResult CastArg - = BuildCXXCastArgument(From->getLocStart(), + = BuildCXXCastArgument(*this, + From->getLocStart(), ToType.getNonReferenceType(), CastKind, cast<CXXMethodDecl>(FD), Owned(From)); @@ -1639,6 +1669,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } + // Resolve overloaded function references. + if (Context.hasSameType(FromType, Context.OverloadTy)) { + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, + true, Found); + if (!Fn) + return true; + + if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) + return true; + + From = FixOverloadedFunctionReference(From, Found, Fn); + FromType = From->getType(); + } + // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: @@ -1652,25 +1697,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Function_To_Pointer: - if (Context.getCanonicalType(FromType) == Context.OverloadTy) { - DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, - true, Found); - if (!Fn) - return true; - - if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) - return true; - - From = FixOverloadedFunctionReference(From, Found, Fn); - FromType = From->getType(); - - // If there's already an address-of operator in the expression, we have - // the right type already, and the code below would just introduce an - // invalid additional pointer level. - if (FromType->isPointerType() || FromType->isMemberFunctionPointerType()) - break; - } FromType = Context.getPointerType(FromType); ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); break; @@ -1741,19 +1767,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) + CXXBaseSpecifierArray BasePath; + if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) return true; - ImpCastExprToType(From, ToType, Kind); + ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); break; } case ICK_Pointer_Member: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) + CXXBaseSpecifierArray BasePath; + if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, + IgnoreBaseAccess)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; - ImpCastExprToType(From, ToType, Kind); + ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); break; } case ICK_Boolean_Conversion: { @@ -1769,7 +1798,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), + From->getSourceRange(), 0, IgnoreBaseAccess)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), @@ -1790,8 +1819,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_NoOp, - ToType->isLValueReferenceType()); + CastExpr::CK_NoOp, ToType->isLValueReferenceType()); if (SCS.DeprecatedStringLiteralToCharPtr) Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion) @@ -1847,6 +1875,9 @@ QualType Sema::CheckPointerToMemberOperands( QualType Class(MemPtr->getClass(), 0); + if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete)) + return QualType(); + // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to @@ -1864,7 +1895,12 @@ QualType Sema::CheckPointerToMemberOperands( } if (!Context.hasSameUnqualifiedType(Class, LType)) { - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + // If we want to check the hierarchy, we need a complete type. + if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs) + << OpSpelling << (int)isIndirect)) { + return QualType(); + } + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? @@ -1877,7 +1913,11 @@ QualType Sema::CheckPointerToMemberOperands( // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid; - ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue); + + CXXBaseSpecifierArray BasePath; + BuildBasePathArray(Paths, BasePath); + ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue, + BasePath); } if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) { @@ -2201,7 +2241,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. bool NonStandardCompositeType = false; - QualType Composite = FindCompositePointerType(LHS, RHS, + QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS, isSFINAEContext()? 0 : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) @@ -2231,11 +2271,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// type and returns it. /// It does not emit diagnostics. /// +/// \param Loc The location of the operator requiring these two expressions to +/// be converted to the composite pointer type. +/// /// If \p NonStandardCompositeType is non-NULL, then we are permitted to find /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. -QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, +QualType Sema::FindCompositePointerType(SourceLocation Loc, + Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; @@ -2372,48 +2416,70 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, } } - ImplicitConversionSequence E1ToC1 = - TryImplicitConversion(E1, Composite1, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - ImplicitConversionSequence E2ToC1 = - TryImplicitConversion(E2, Composite1, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - bool ToC2Viable = false; - ImplicitConversionSequence E1ToC2, E2ToC2; - if (Context.getCanonicalType(Composite1) != - Context.getCanonicalType(Composite2)) { - E1ToC2 = TryImplicitConversion(E1, Composite2, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - E2ToC2 = TryImplicitConversion(E2, Composite2, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); - } - - bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); - if (ToC1Viable && !ToC2Viable) { - if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && - !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) - return Composite1; - } - if (ToC2Viable && !ToC1Viable) { - if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) && - !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting)) - return Composite2; + // Try to convert to the first composite pointer type. + InitializedEntity Entity1 + = InitializedEntity::InitializeTemporary(Composite1); + InitializationKind Kind + = InitializationKind::CreateCopy(Loc, SourceLocation()); + InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1); + InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1); + + if (E1ToC1 && E2ToC1) { + // Conversion to Composite1 is viable. + if (!Context.hasSameType(Composite1, Composite2)) { + // Composite2 is a different type from Composite1. Check whether + // Composite2 is also viable. + InitializedEntity Entity2 + = InitializedEntity::InitializeTemporary(Composite2); + InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); + InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + if (E1ToC2 && E2ToC2) { + // Both Composite1 and Composite2 are viable and are different; + // this is an ambiguity. + return QualType(); + } + } + + // Convert E1 to Composite1 + OwningExprResult E1Result + = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E1,1)); + if (E1Result.isInvalid()) + return QualType(); + E1 = E1Result.takeAs<Expr>(); + + // Convert E2 to Composite1 + OwningExprResult E2Result + = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E2,1)); + if (E2Result.isInvalid()) + return QualType(); + E2 = E2Result.takeAs<Expr>(); + + return Composite1; } - return QualType(); + + // Check whether Composite2 is viable. + InitializedEntity Entity2 + = InitializedEntity::InitializeTemporary(Composite2); + InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); + InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + if (!E1ToC2 || !E2ToC2) + return QualType(); + + // Convert E1 to Composite2 + OwningExprResult E1Result + = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E1, 1)); + if (E1Result.isInvalid()) + return QualType(); + E1 = E1Result.takeAs<Expr>(); + + // Convert E2 to Composite2 + OwningExprResult E2Result + = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E2, 1)); + if (E2Result.isInvalid()) + return QualType(); + E2 = E2Result.takeAs<Expr>(); + + return Composite2; } Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { @@ -2450,8 +2516,12 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); if (CXXDestructorDecl *Destructor = - const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) + const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) { MarkDeclarationReferenced(E->getExprLoc(), Destructor); + CheckDestructorAccess(E->getExprLoc(), Destructor, + PDiag(diag::err_access_dtor_temp) + << E->getType()); + } // FIXME: Add the temporary to the temporaries vector. return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } @@ -2701,7 +2771,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, @@ -2869,43 +2939,6 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, return CE; } -Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, - QualType Ty, - CastExpr::CastKind Kind, - CXXMethodDecl *Method, - ExprArg Arg) { - Expr *From = Arg.takeAs<Expr>(); - - switch (Kind) { - default: assert(0 && "Unhandled cast kind!"); - case CastExpr::CK_ConstructorConversion: { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method), - MultiExprArg(*this, (void **)&From, 1), - CastLoc, ConstructorArgs)) - return ExprError(); - - OwningExprResult Result = - BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs)); - if (Result.isInvalid()) - return ExprError(); - - return MaybeBindToTemporary(Result.takeAs<Expr>()); - } - - case CastExpr::CK_UserDefinedConversion: { - assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - - // Create an implicit call expr that calls it. - // FIXME: pass the FoundDecl for the user-defined conversion here - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method); - return MaybeBindToTemporary(CE); - } - } -} - Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d5a22ca..db9a2e2 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -12,9 +12,12 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" +#include "SemaInit.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" #include "llvm/ADT/SmallString.h" #include "clang/Lex/Preprocessor.h" @@ -75,9 +78,25 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, QualType Ty = Context.getObjCConstantStringInterface(); if (!Ty.isNull()) { Ty = Context.getObjCObjectPointerType(Ty); + } else if (getLangOptions().NoConstantCFStrings) { + IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0], + LookupOrdinaryName); + if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { + Context.setObjCConstantStringInterface(StrIF); + Ty = Context.getObjCConstantStringInterface(); + Ty = Context.getObjCObjectPointerType(Ty); + } else { + // If there is no NSConstantString interface defined then treat this + // as error and recover from it. + Diag(S->getLocStart(), diag::err_no_nsconstant_string_class) << NSIdent + << S->getSourceRange(); + Ty = Context.getObjCIdType(); + } } else { IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); - NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0], + LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { Context.setObjCConstantStringInterface(StrIF); Ty = Context.getObjCConstantStringInterface(); @@ -93,8 +112,9 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, } Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, - QualType EncodedType, + TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc) { + QualType EncodedType = EncodedTypeInfo->getType(); QualType StrTy; if (EncodedType->isDependentType()) StrTy = Context.DependentTy; @@ -112,7 +132,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, ArrayType::Normal, 0); } - return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc); + return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc); } Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, @@ -121,9 +141,13 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, TypeTy *ty, SourceLocation RParenLoc) { // FIXME: Preserve type source info ? - QualType EncodedType = GetTypeFromParser(ty); + TypeSourceInfo *TInfo; + QualType EncodedType = GetTypeFromParser(ty, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(EncodedType, + PP.getLocForEndOfToken(LParenLoc)); - return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc); + return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc); } Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, @@ -148,7 +172,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId); + ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc); if (!PDecl) { Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; @@ -168,8 +192,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, QualType &ReturnType) { if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). - for (unsigned i = 0; i != NumArgs; i++) + for (unsigned i = 0; i != NumArgs; i++) { + if (Args[i]->isTypeDependent()) + continue; + DefaultArgumentPromotion(Args[i]); + } unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; @@ -179,50 +207,68 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return false; } - ReturnType = Method->getResultType(); + ReturnType = Method->getResultType().getNonReferenceType(); unsigned NumNamedArgs = Sel.getNumArgs(); - assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); + // Method might have more arguments than selector indicates. This is due + // to addition of c-style arguments in method. + if (Method->param_size() > Sel.getNumArgs()) + NumNamedArgs = Method->param_size(); + // FIXME. This need be cleaned up. + if (NumArgs < NumNamedArgs) { + Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2 + << NumNamedArgs << NumArgs; + return false; + } bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { - Expr *argExpr = Args[i]; - assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + // We can't do any type-checking on a type-dependent argument. + if (Args[i]->isTypeDependent()) + continue; - QualType lhsType = Method->param_begin()[i]->getType(); - QualType rhsType = argExpr->getType(); + Expr *argExpr = Args[i]; - // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. - if (lhsType->isArrayType()) - lhsType = Context.getArrayDecayedType(lhsType); - else if (lhsType->isFunctionType()) - lhsType = Context.getPointerType(lhsType); + ParmVarDecl *Param = Method->param_begin()[i]; + assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); - AssignConvertType Result = - CheckSingleAssignmentConstraints(lhsType, argExpr); - if (Args[i] != argExpr) // The expression was converted. - Args[i] = argExpr; // Make sure we store the converted expression. + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), + Param->getType(), + PDiag(diag::err_call_incomplete_argument) + << argExpr->getSourceRange())) + return true; - IsError |= - DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, - argExpr, AA_Sending); + InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); + OwningExprResult ArgE = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(argExpr->Retain())); + if (ArgE.isInvalid()) + IsError = true; + else + Args[i] = ArgE.takeAs<Expr>(); } // Promote additional arguments to variadic methods. if (Method->isVariadic()) { - for (unsigned i = NumNamedArgs; i < NumArgs; ++i) + for (unsigned i = NumNamedArgs; i < NumArgs; ++i) { + if (Args[i]->isTypeDependent()) + continue; + IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); + } } else { // Check for extra arguments to non-variadic methods. if (NumArgs != NumNamedArgs) { Diag(Args[NumNamedArgs]->getLocStart(), diag::err_typecheck_call_too_many_args) - << 2 /*method*/ << Method->getSourceRange() + << 2 /*method*/ << NumNamedArgs << NumArgs + << Method->getSourceRange() << SourceRange(Args[NumNamedArgs]->getLocStart(), Args[NumArgs-1]->getLocEnd()); } } + DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); return IsError; } @@ -281,20 +327,147 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, return Method; } -Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( - IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation &receiverNameLoc, - SourceLocation &propertyNameLoc) { +/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an +/// objective C interface. This is a property reference expression. +Action::OwningExprResult Sema:: +HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, DeclarationName MemberName, + SourceLocation MemberLoc) { + const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); + ObjCInterfaceDecl *IFace = IFaceT->getDecl(); + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - IdentifierInfo *receiverNamePtr = &receiverName; - ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); - if (!IFace) { - Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + // Search for a declared property first. + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + QualType ResTy = PD->getType(); + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); + if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) + ResTy = Getter->getResultType(); + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, + MemberLoc, BaseExpr)); + } + // Check protocols on qualified interfaces. + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + // If that failed, look for an "implicit" property by seeing if the nullary + // selector is implemented. + + // FIXME: The logic for looking up nullary and unary selectors should be + // shared with the code in ActOnInstanceMessage. + + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); + + // If this reference is in an @implementation, check for 'private' methods. + if (!Getter) + Getter = IFace->lookupPrivateInstanceMethod(Sel); + + // Look through local category implementations associated with the class. + if (!Getter) + Getter = IFace->getCategoryInstanceMethod(Sel); + if (Getter) { + // Check if we can reference this property. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // 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->lookupInstanceMethod(SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = IFace->lookupPrivateInstanceMethod(SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) + Setter = IFace->getCategoryInstanceMethod(SetterSel); + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); + + if (Getter) { + QualType PType; + PType = Getter->getResultType(); + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, + Setter, MemberLoc, BaseExpr)); + } + + // 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(); + 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); + } + + Diag(MemberLoc, diag::err_property_not_found) + << MemberName << QualType(OPT, 0); + if (Setter && !Getter) + Diag(Setter->getLocation(), diag::note_getter_unavailable) + << MemberName << BaseExpr->getSourceRange(); + return ExprError(); +} + + + +Action::OwningExprResult Sema:: +ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc) { + + IdentifierInfo *receiverNamePtr = &receiverName; + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, + receiverNameLoc); + if (IFace == 0) { + // If the "receiver" is 'super' in a method, handle it as an expression-like + // property reference. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + if (receiverNamePtr->isStr("super")) { + if (CurMethod->isInstanceMethod()) { + QualType T = + Context.getObjCInterfaceType(CurMethod->getClassInterface()); + T = Context.getObjCObjectPointerType(T); + Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T); + + return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + SuperExpr, &propertyName, + propertyNameLoc); + } + + // Otherwise, if this is a class method, try dispatching to our + // superclass. + IFace = CurMethod->getClassInterface()->getSuperClass(); + } + + if (IFace == 0) { + Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + return ExprError(); + } } - // Search for a declared property first. + // Search for a declared property first. Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel); @@ -351,329 +524,502 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( << &propertyName << Context.getObjCInterfaceType(IFace)); } +Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType) { + ReceiverType = 0; + + // If the identifier is "super" and there is no trailing dot, we're + // messaging super. + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); + LookupName(Result, S); + + switch (Result.getResultKind()) { + case LookupResult::NotFound: + // Normal name lookup didn't find anything. If we're in an + // Objective-C method, look for ivars. If we find one, we're done! + // FIXME: This is a hack. Ivar lookup should be part of normal lookup. + if (ObjCMethodDecl *Method = getCurMethodDecl()) { + ObjCInterfaceDecl *ClassDeclared; + if (Method->getClassInterface()->lookupInstanceVariable(Name, + ClassDeclared)) + return ObjCInstanceMessage; + } + + // Break out; we'll perform typo correction below. + break; + + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + case LookupResult::Ambiguous: + Result.suppressDiagnostics(); + return ObjCInstanceMessage; + + case LookupResult::Found: { + // We found something. If it's a type, then we have a class + // message. Otherwise, it's an instance message. + NamedDecl *ND = Result.getFoundDecl(); + QualType T; + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) + T = Context.getObjCInterfaceType(Class); + else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) + T = Context.getTypeDeclType(Type); + else + return ObjCInstanceMessage; + + // We have a class message, and T is the type we're + // messaging. Build source-location information for it. + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); + ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + return ObjCClassMessage; + } + } -// ActOnClassMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnClassMessage( - Scope *S, - IdentifierInfo *receiverName, Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, - SourceLocation selectorLoc, SourceLocation rbrac, - ExprTy **Args, unsigned NumArgs) { - assert(receiverName && "missing receiver class name"); - - Expr **ArgExprs = reinterpret_cast<Expr **>(Args); - ObjCInterfaceDecl* ClassDecl = 0; - bool isSuper = false; - - if (receiverName->isStr("super")) { - if (getCurMethodDecl()) { - isSuper = true; - ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface(); - if (!OID) - return Diag(lbrac, diag::error_no_super_class_message) - << getCurMethodDecl()->getDeclName(); - ClassDecl = OID->getSuperClass(); - if (!ClassDecl) - return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); - if (getCurMethodDecl()->isInstanceMethod()) { - QualType superTy = Context.getObjCInterfaceType(ClassDecl); - superTy = Context.getObjCObjectPointerType(superTy); - ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), - superTy); - // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, - selectorLoc, rbrac, Args, NumArgs); + // Determine our typo-correction context. + CorrectTypoContext CTC = CTC_Expression; + if (ObjCMethodDecl *Method = getCurMethodDecl()) + if (Method->getClassInterface() && + Method->getClassInterface()->getSuperClass()) + CTC = CTC_ObjCMessageReceiver; + + if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) { + if (Result.isSingleResult()) { + // 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() + << FixItHint::CreateReplacement(SourceRange(NameLoc), + ND->getNameAsString()); + Diag(ND->getLocation(), diag::note_previous_decl) + << Corrected; + + QualType T = Context.getObjCInterfaceType(Class); + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); + ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + return ObjCClassMessage; } - // We are sending a message to 'super' within a class method. Do nothing, - // the receiver will pass through as 'super' (how convenient:-). - } else { - // 'super' has been used outside a method context. If a variable named - // 'super' has been declared, redirect. If not, produce a diagnostic. - NamedDecl *SuperDecl - = LookupSingleName(S, receiverName, LookupOrdinaryName); - ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl); - if (VD) { - ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), - receiverLoc); - // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, - selectorLoc, rbrac, Args, NumArgs); - } - else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) { - const ObjCInterfaceType *OCIT; - OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); - if (!OCIT) { - Diag(receiverLoc, diag::err_invalid_receiver_to_message); - return true; - } - ClassDecl = OCIT->getDecl(); - } - else - return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; - } - } else - ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); - - // The following code allows for the following GCC-ism: - // - // typedef XCElementDisplayRect XCElementGraphicsRect; - // - // @implementation XCRASlice - // - whatever { // Note that XCElementGraphicsRect is a typedef name. - // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init]; - // } - // - // If necessary, the following lookup could move to getObjCInterfaceDecl(). - if (!ClassDecl) { - NamedDecl *IDecl - = LookupSingleName(TUScope, receiverName, LookupOrdinaryName); - if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) - if (const ObjCInterfaceType *OCIT - = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>()) - ClassDecl = OCIT->getDecl(); - - if (!ClassDecl) { - Diag(receiverLoc, diag::err_invalid_receiver_to_message); - return true; + } else if (Result.empty() && Corrected.getAsIdentifierInfo() && + Corrected.getAsIdentifierInfo()->isStr("super")) { + // If we've found the keyword "super", this is a send to super. + Diag(NameLoc, diag::err_unknown_receiver_suggest) + << Name << Corrected + << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); + Name = Corrected.getAsIdentifierInfo(); + return ObjCSuperMessage; } } - assert(ClassDecl && "missing interface declaration"); - ObjCMethodDecl *Method = 0; - QualType returnType; - if (ClassDecl->isForwardDecl()) { - // A forward class used in messaging is tread as a 'Class' - Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName(); - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); - if (Method) - Diag(Method->getLocation(), diag::note_method_sent_forward_class) - << Method->getDeclName(); + + // Fall back: let the parser try to parse it as an instance message. + return ObjCInstanceMessage; +} + +Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S, + SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + // Determine whether we are inside a method or not. + ObjCMethodDecl *Method = getCurMethodDecl(); + if (!Method) { + Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); + return ExprError(); } - if (!Method) - Method = ClassDecl->lookupClassMethod(Sel); - // If we have an implementation in scope, check "private" methods. - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + ObjCInterfaceDecl *Class = Method->getClassInterface(); + if (!Class) { + Diag(SuperLoc, diag::error_no_super_class_message) + << Method->getDeclName(); + return ExprError(); + } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; + ObjCInterfaceDecl *Super = Class->getSuperClass(); + if (!Super) { + // The current class does not have a superclass. + Diag(SuperLoc, diag::error_no_super_class) << Class->getIdentifier(); + return ExprError(); + } - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, - lbrac, rbrac, returnType)) - return true; + // We are in a method whose class has a superclass, so 'super' + // is acting as a keyword. + if (Method->isInstanceMethod()) { + // Since we are in an instance method, this is an instance + // message to the superclass instance. + QualType SuperTy = Context.getObjCInterfaceType(Super); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + return BuildInstanceMessage(ExprArg(*this), SuperTy, SuperLoc, + Sel, /*Method=*/0, LBracLoc, RBracLoc, + move(Args)); + } + + // Since we are in a class method, this is a class message to + // the superclass. + return BuildClassMessage(/*ReceiverTypeInfo=*/0, + Context.getObjCInterfaceType(Super), + SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc, + move(Args)); +} + +/// \brief Build an Objective-C class message expression. +/// +/// This routine takes care of both normal class messages and +/// class messages to the superclass. +/// +/// \param ReceiverTypeInfo Type source information that describes the +/// receiver of this message. This may be NULL, in which case we are +/// sending to the superclass and \p SuperLoc must be a valid source +/// location. + +/// \param ReceiverType The type of the object receiving the +/// message. When \p ReceiverTypeInfo is non-NULL, this is the same +/// type as that refers to. For a superclass send, this is the type of +/// the superclass. +/// +/// \param SuperLoc The location of the "super" keyword in a +/// superclass message. +/// +/// \param Sel The selector to which the message is being sent. +/// +/// \param Method The method that this class message is invoking, if +/// already known. +/// +/// \param LBracLoc The location of the opening square bracket ']'. +/// +/// \param RBrac The location of the closing square bracket ']'. +/// +/// \param Args The message arguments. +Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + if (ReceiverType->isDependentType()) { + // If the receiver type is dependent, we can't type-check anything + // at this point. Build a dependent expression. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + assert(SuperLoc.isInvalid() && "Message to super with dependent type"); + return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc, + ReceiverTypeInfo, Sel, /*Method=*/0, + Args, NumArgs, RBracLoc)); + } + + SourceLocation Loc = SuperLoc.isValid()? SuperLoc + : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); + + // Find the class to which we are sending this message. + ObjCInterfaceDecl *Class = 0; + if (const ObjCInterfaceType *ClassType + = ReceiverType->getAs<ObjCInterfaceType>()) + Class = ClassType->getDecl(); + else { + Diag(Loc, diag::err_invalid_receiver_class_message) + << ReceiverType; + return ExprError(); + } + assert(Class && "We don't know which class we're messaging?"); + + // Find the method we are messaging. + if (!Method) { + if (Class->isForwardDecl()) { + // 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) + Diag(Method->getLocation(), diag::note_method_sent_forward_class) + << Method->getDeclName(); + } + if (!Method) + Method = Class->lookupClassMethod(Sel); - returnType = returnType.getNonReferenceType(); - - // If we have the ObjCInterfaceDecl* for the class that is receiving the - // message, use that to construct the ObjCMessageExpr. Otherwise pass on the - // IdentifierInfo* for the class. - // FIXME: need to do a better job handling 'super' usage within a class. For - // now, we simply pass the "super" identifier through (which isn't consistent - // with instance methods. - if (isSuper) - return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc, - Sel, returnType, Method, lbrac, rbrac, - ArgExprs, NumArgs); - else - return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc, - Sel, returnType, Method, lbrac, rbrac, - ArgExprs, NumArgs); + // If we have an implementation in scope, check "private" methods. + if (!Method) + Method = LookupPrivateClassMethod(Sel, Class); + + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); + } + + // Check the argument types and determine the result type. + QualType ReturnType; + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, + LBracLoc, RBracLoc, ReturnType)) { + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + return ExprError(); + } + + // Construct the appropriate ObjCMessageExpr. + if (SuperLoc.isValid()) + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, Method, Args, + NumArgs, RBracLoc)); + + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + ReceiverTypeInfo, Sel, Method, Args, + NumArgs, RBracLoc)); } -// ActOnInstanceMessage - used for both unary and keyword messages. +// ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, - SourceLocation lbrac, - SourceLocation receiverLoc, - SourceLocation rbrac, - ExprTy **Args, unsigned NumArgs) { - assert(receiver && "missing receiver expression"); - - Expr **ArgExprs = reinterpret_cast<Expr **>(Args); - Expr *RExpr = static_cast<Expr *>(receiver); - - // If necessary, apply function/array conversion to the receiver. - // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayLvalueConversion(RExpr); - - QualType returnType; - QualType ReceiverCType = - Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); - - // Handle messages to 'super'. - if (isa<ObjCSuperExpr>(RExpr)) { - ObjCMethodDecl *Method = 0; - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - // If we have an interface in scope, check 'super' methods. - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) - if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) { - Method = SuperDecl->lookupInstanceMethod(Sel); +Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S, + TypeTy *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + TypeSourceInfo *ReceiverTypeInfo; + QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo); + if (ReceiverType.isNull()) + return ExprError(); - if (!Method) - // If we have implementations in scope, check "private" methods. - Method = LookupPrivateInstanceMethod(Sel, SuperDecl); - } - } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; + if (!ReceiverTypeInfo) + ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; + return BuildClassMessage(ReceiverTypeInfo, ReceiverType, + /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, + LBracLoc, RBracLoc, move(Args)); +} - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); - } +/// \brief Build an Objective-C instance message expression. +/// +/// This routine takes care of both normal instance messages and +/// instance messages to the superclass instance. +/// +/// \param Receiver The expression that computes the object that will +/// receive this message. This may be empty, in which case we are +/// sending to the superclass instance and \p SuperLoc must be a valid +/// source location. +/// +/// \param ReceiverType The (static) type of the object receiving the +/// message. When a \p Receiver expression is provided, this is the +/// same type as that expression. For a superclass instance send, this +/// is a pointer to the type of the superclass. +/// +/// \param SuperLoc The location of the "super" keyword in a +/// superclass instance message. +/// +/// \param Sel The selector to which the message is being sent. +/// +/// \param Method The method that this instance message is invoking, if +/// already known. +/// +/// \param LBracLoc The location of the opening square bracket ']'. +/// +/// \param RBrac The location of the closing square bracket ']'. +/// +/// \param Args The message arguments. +Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + // If we have a receiver expression, perform appropriate promotions + // and determine receiver type. + Expr *Receiver = ReceiverE.takeAs<Expr>(); + if (Receiver) { + if (Receiver->isTypeDependent()) { + // If the receiver is type-dependent, we can't type-check anything + // at this point. Build a dependent expression. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + assert(SuperLoc.isInvalid() && "Message to super with dependent type"); + return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, + LBracLoc, Receiver, Sel, + /*Method=*/0, Args, NumArgs, + RBracLoc)); + } - // Handle messages to id. - if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() || - Context.isObjCNSObjectType(RExpr->getType())) { - ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (!Method) - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac)); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); + // If necessary, apply function/array conversion to the receiver. + // C99 6.7.5.3p[7,8]. + DefaultFunctionArrayLvalueConversion(Receiver); + ReceiverType = Receiver->getType(); } - // Handle messages to Class. - if (ReceiverCType->isObjCClassType() || - ReceiverCType->isObjCQualifiedClassType()) { - ObjCMethodDecl *Method = 0; + // The location of the receiver. + SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // First check the public methods in the class interface. - Method = ClassDecl->lookupClassMethod(Sel); + if (!Method) { + // Handle messages to id. + if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType() || + (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (!Method) + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + } else if (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()) { + // Handle messages to Class. + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // First check the public methods in the class interface. + Method = ClassDecl->lookupClassMethod(Sel); - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); - // FIXME: if we still haven't found a method, we need to look in - // protocols (if we have qualifiers). + // FIXME: if we still haven't found a method, we need to look in + // protocols (if we have qualifiers). + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; - } - if (!Method) { - // If not messaging 'self', look for any factory method named 'Sel'. - if (!isSelfExpr(RExpr)) { - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(lbrac, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(lbrac, rbrac); - } + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!Receiver || !isSelfExpr(Receiver)) { + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (!Method) { + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (Method) + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(Loc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } } } - } - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); - } + } else { + ObjCInterfaceDecl* ClassDecl = 0; + + // We allow sending a message to a qualified ID ("id<foo>"), which is ok as + // long as one of the protocols implements the selector (if not, warn). + if (const ObjCObjectPointerType *QIdTy + = ReceiverType->getAsObjCQualifiedIdType()) { + // Search protocols for instance methods. + for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + ObjCProtocolDecl *PDecl = *I; + if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) + break; + // Since we aren't supporting "Class<foo>", look for a class method. + if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) + break; + } + } else if (const ObjCObjectPointerType *OCIType + = ReceiverType->getAsObjCInterfacePointerType()) { + // We allow sending a message to a pointer to an interface (an object). + ClassDecl = OCIType->getInterfaceDecl(); + // 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 InstanceMethodPool. + Method = ClassDecl->lookupInstanceMethod(Sel); - ObjCMethodDecl *Method = 0; - ObjCInterfaceDecl* ClassDecl = 0; - - // We allow sending a message to a qualified ID ("id<foo>"), which is ok as - // long as one of the protocols implements the selector (if not, warn). - if (const ObjCObjectPointerType *QIdTy = - ReceiverCType->getAsObjCQualifiedIdType()) { - // Search protocols for instance methods. - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - ObjCProtocolDecl *PDecl = *I; - if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) - break; - // Since we aren't supporting "Class<foo>", look for a class method. - if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) - break; - } - } else if (const ObjCObjectPointerType *OCIType = - ReceiverCType->getAsObjCInterfacePointerType()) { - // We allow sending a message to a pointer to an interface (an object). - - ClassDecl = OCIType->getInterfaceDecl(); - // 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 InstanceMethodPool. - Method = ClassDecl->lookupInstanceMethod(Sel); - - if (!Method) { - // Search protocol qualifiers. - for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), - E = OCIType->qual_end(); QI != E; ++QI) { - if ((Method = (*QI)->lookupInstanceMethod(Sel))) - break; - } - } - if (!Method) { - // If we have implementations in scope, check "private" methods. - Method = LookupPrivateInstanceMethod(Sel, ClassDecl); - - if (!Method && !isSelfExpr(RExpr)) { - // 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 - // compatibility. FIXME: should we deviate?? - if (OCIType->qual_empty()) { - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) - Diag(lbrac, diag::warn_maynot_respond) - << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel; + if (!Method) { + // Search protocol qualifiers. + for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), + E = OCIType->qual_end(); QI != E; ++QI) { + if ((Method = (*QI)->lookupInstanceMethod(Sel))) + break; + } } + if (!Method) { + // If we have implementations in scope, check "private" methods. + Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + + 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 + // compatibility. FIXME: should we deviate?? + if (OCIType->qual_empty()) { + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) + Diag(Loc, diag::warn_maynot_respond) + << OCIType->getInterfaceDecl()->getIdentifier() << Sel; + } + } + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); + } else if (!Context.getObjCIdType().isNull() && + (ReceiverType->isPointerType() || + (ReceiverType->isIntegerType() && + ReceiverType->isScalarType()))) { + // Implicitly convert integers and pointers to 'id' but emit a warning. + Diag(Loc, diag::warn_bad_receiver_type) + << ReceiverType + << Receiver->getSourceRange(); + if (ReceiverType->isPointerType()) + ImpCastExprToType(Receiver, Context.getObjCIdType(), + CastExpr::CK_BitCast); + else + ImpCastExprToType(Receiver, Context.getObjCIdType(), + CastExpr::CK_IntegralToPointer); + ReceiverType = Receiver->getType(); + } else { + // Reject other random receiver types (e.g. structs). + Diag(Loc, diag::err_bad_receiver_type) + << ReceiverType << Receiver->getSourceRange(); + return ExprError(); } } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; - } else if (!Context.getObjCIdType().isNull() && - (ReceiverCType->isPointerType() || - (ReceiverCType->isIntegerType() && - ReceiverCType->isScalarType()))) { - // Implicitly convert integers and pointers to 'id' but emit a warning. - Diag(lbrac, diag::warn_bad_receiver_type) - << RExpr->getType() << RExpr->getSourceRange(); - if (ReceiverCType->isPointerType()) - ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast); - else - ImpCastExprToType(RExpr, Context.getObjCIdType(), - CastExpr::CK_IntegralToPointer); - } else { - // Reject other random receiver types (e.g. structs). - Diag(lbrac, diag::err_bad_receiver_type) - << RExpr->getType() << RExpr->getSourceRange(); - return true; } - if (Method) - DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); + // Check the message arguments. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + QualType ReturnType; + if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false, + LBracLoc, RBracLoc, ReturnType)) + return ExprError(); + + // Construct the appropriate ObjCMessageExpr instance. + if (SuperLoc.isValid()) + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, Method, + Args, NumArgs, RBracLoc)); + + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, + Sel, Method, Args, NumArgs, RBracLoc)); +} + +// ActOnInstanceMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::OwningExprResult Sema::ActOnInstanceMessage(Scope *S, + ExprArg ReceiverE, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + Expr *Receiver = static_cast<Expr *>(ReceiverE.get()); + if (!Receiver) + return ExprError(); + + return BuildInstanceMessage(move(ReceiverE), Receiver->getType(), + /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, + LBracLoc, RBracLoc, move(Args)); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1d0575c..0aa3446 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -281,7 +281,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. - ILE->updateInit(Init, MemberInit.takeAs<Expr>()); + ILE->updateInit(SemaRef.Context, Init, MemberInit.takeAs<Expr>()); RequiresSecondPass = true; } } else if (InitListExpr *InnerILE @@ -391,7 +391,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. - ILE->updateInit(Init, ElementInit.takeAs<Expr>()); + ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>()); RequiresSecondPass = true; } } else if (InitListExpr *InnerILE @@ -458,7 +458,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, if (T->isArrayType()) maxElements = numArrayElements(T); - else if (T->isStructureType() || T->isUnionType()) + else if (T->isRecordType()) maxElements = numStructUnionElements(T); else if (T->isVectorType()) maxElements = T->getAs<VectorType>()->getNumElements(); @@ -624,10 +624,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); + } else if (DeclType->isObjCInterfaceType()) { + SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) + << DeclType; + hadError = true; } else { - // In C, all types are either scalars or aggregates, but - // additional handling is needed here for C++ (and possibly others?). - assert(0 && "Unsupported initializer type"); + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; + hadError = true; } } @@ -884,9 +888,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, } } - // OpenCL & AltiVec require all elements to be initialized. + // OpenCL requires all elements to be initialized. if (numEltsInit != maxElements) - if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec) + if (SemaRef.getLangOptions().OpenCL) SemaRef.Diag(IList->getSourceRange().getBegin(), diag::err_vector_incorrect_num_initializers) << (numEltsInit < maxElements) << maxElements << numEltsInit; @@ -1354,7 +1358,8 @@ 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()) && + if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, + Sema::CTC_NoKeywords) && (ReplacementField = R.getAsSingle<FieldDecl>()) && ReplacementField->getDeclContext()->getLookupContext() ->Equals(RT->getDecl())) { @@ -1702,7 +1707,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, } InitListExpr *Result - = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, + = new (SemaRef.Context) InitListExpr(SemaRef.Context, + InitRange.getBegin(), 0, 0, InitRange.getEnd()); Result->setType(CurrentObjectType.getNonReferenceType()); @@ -1740,12 +1746,12 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, if (NumElements < NumInits) NumElements = IList->getNumInits(); - Result->reserveInits(NumElements); + Result->reserveInits(SemaRef.Context, NumElements); // Link this new initializer list into the structured initializer // lists. if (StructuredList) - StructuredList->updateInit(StructuredIndex, Result); + StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result); else { Result->setSyntacticForm(IList); SyntacticToSemantic[IList] = Result; @@ -1763,7 +1769,8 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, if (!StructuredList) return; - if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) { + if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context, + StructuredIndex, expr)) { // This initializer overwrites a previous initializer. Warn. SemaRef.Diag(expr->getSourceRange().getBegin(), diag::warn_initializer_overrides) @@ -1918,11 +1925,15 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base) + CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase) { InitializedEntity Result; Result.Kind = EK_Base; - Result.Base = Base; + Result.Base = reinterpret_cast<uintptr_t>(Base); + if (IsInheritedVirtualBase) + Result.Base |= 0x01; + Result.Type = Base->getType(); return Result; } @@ -1984,6 +1995,7 @@ void InitializationSequence::Step::Destroy() { case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionRValue: case SK_QualificationConversionLValue: @@ -2033,6 +2045,10 @@ bool InitializationSequence::isAmbiguous() const { return false; } +bool InitializationSequence::isConstructorInitialization() const { + return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization; +} + void InitializationSequence::AddAddressOverloadResolutionStep( FunctionDecl *Function, DeclAccessPair Found) { @@ -2060,6 +2076,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, Steps.push_back(S); } +void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) { + Step S; + S.Kind = SK_ExtraneousCopyToTemporary; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, DeclAccessPair FoundDecl, QualType T) { @@ -2388,15 +2411,11 @@ static void TryReferenceInitialization(Sema &S, T2 = cv2T2.getUnqualifiedType(); } - // FIXME: Rvalue references - bool ForceRValue = false; - // Compute some basic properties of the types and the initializer. bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : - Initializer->isLvalue(S.Context); + Expr::isLvalueResult InitLvalue = Initializer->isLvalue(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); @@ -2480,6 +2499,18 @@ static void TryReferenceInitialization(Sema &S, // reference-compatible with "cv2 T2", or if (InitLvalue != Expr::LV_Valid && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the + // compiler the freedom to perform a copy here or bind to the + // object, while C++0x requires that we bind directly to the + // object. Hence, we always bind to the object without making an + // extra copy. However, in C++03 requires that we check for the + // presence of a suitable copy constructor: + // + // The constructor that would be used to make the copy shall + // be callable whether or not the copy is actually done. + if (!S.getLangOptions().CPlusPlus0x) + Sequence.AddExtraneousCopyToTemporary(cv2T2); + if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), @@ -2528,9 +2559,7 @@ static void TryReferenceInitialization(Sema &S, ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, cv1T1, /*SuppressUserConversions=*/false, AllowExplicit, - /*ForceRValue=*/false, - /*FIXME:InOverloadResolution=*/false, - /*UserCast=*/Kind.isExplicitCast()); + /*FIXME:InOverloadResolution=*/false); if (ICS.isBad()) { // FIXME: Use the conversion function set stored in ICS to turn @@ -2595,6 +2624,12 @@ static void TryConstructorInitialization(Sema &S, bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || Kind.getKind() == InitializationKind::IK_Value || Kind.getKind() == InitializationKind::IK_Default); + + // The type we're constructing needs to be complete. + if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + return; + } // The type we're converting to is a class type. Enumerate its constructors // to see if one is suitable. @@ -2611,25 +2646,36 @@ static void TryConstructorInitialization(Sema &S, Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - + bool SuppressUserConversions = false; + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); - else + else { Constructor = cast<CXXConstructorDecl>(D); + + // If we're performing copy initialization using a copy constructor, we + // suppress user-defined conversions on the arguments. + // FIXME: Move constructors? + if (Kind.getKind() == InitializationKind::IK_Copy && + Constructor->isCopyConstructor()) + SuppressUserConversions = true; + } if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet); + Args, NumArgs, CandidateSet, + SuppressUserConversions); else S.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet); + Args, NumArgs, CandidateSet, + SuppressUserConversions); } } @@ -2770,36 +2816,51 @@ static void TryUserDefinedConversion(Sema &S, CXXRecordDecl *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getDecl()); - DeclarationName ConstructorName - = S.Context.DeclarationNames.getCXXConstructorName( + // Try to complete the type we're converting to. + if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( S.Context.getCanonicalType(DestType).getUnqualifiedType()); - DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); - - if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + bool SuppressUserConversions = false; + + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - &Initializer, 1, CandidateSet); - else - S.AddOverloadCandidate(Constructor, FoundDecl, - &Initializer, 1, CandidateSet); - } - } + Constructor = cast<CXXConstructorDecl>( + ConstructorTmpl->getTemplatedDecl()); + else { + Constructor = cast<CXXConstructorDecl>(D); + + // If we're performing copy initialization using a copy constructor, + // we suppress user-defined conversions on the arguments. + // FIXME: Move constructors? + if (Kind.getKind() == InitializationKind::IK_Copy && + Constructor->isCopyConstructor()) + SuppressUserConversions = true; + + } + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet, + SuppressUserConversions); + else + S.AddOverloadCandidate(Constructor, FoundDecl, + &Initializer, 1, CandidateSet, + SuppressUserConversions); + } + } + } } SourceLocation DeclLoc = Initializer->getLocStart(); @@ -2865,10 +2926,21 @@ static void TryUserDefinedConversion(Sema &S, // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getResultType().getNonReferenceType(); - Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); + if (ConvType->getAs<RecordType>()) { + // If we're converting to a class type, there may be an copy if + // the resulting temporary object (possible to create an object of + // a base class type). That copy is not a separate conversion, so + // we just make a note of the actual destination type (possibly a + // base class of the type returned by the conversion function) and + // let the user-defined conversion step handle the conversion. + Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType); + return; + } - // If the conversion following the call to the conversion function is - // interesting, add it as a separate step. + Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); + + // If the conversion following the call to the conversion function + // is interesting, add it as a separate step. if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; @@ -2889,9 +2961,7 @@ static void TryImplicitConversion(Sema &S, = S.TryImplicitConversion(Initializer, Entity.getType(), /*SuppressUserConversions=*/true, /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*FIXME:InOverloadResolution=*/false, - /*UserCast=*/Kind.isExplicitCast()); + /*InOverloadResolution=*/false); if (ICS.isBad()) { Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); @@ -3054,7 +3124,10 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: - // FIXME: Can we tell when we're sending vs. passing? + if (Entity.getDecl() && + isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext())) + return Sema::AA_Sending; + return Sema::AA_Passing; case InitializedEntity::EK_Result: @@ -3078,6 +3151,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Converting; } +/// \brief Whether we should binding a created object as a temporary when +/// initializing the given entity. static bool shouldBindAsTemporary(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_ArrayElement: @@ -3098,14 +3173,57 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } +/// \brief Whether the given entity, when initialized with an object +/// created for that initialization, requires destruction. +static bool shouldDestroyTemporary(const InitializedEntity &Entity) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Member: + case InitializedEntity::EK_Result: + case InitializedEntity::EK_New: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_VectorElement: + return false; + + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_Exception: + return true; + } + + llvm_unreachable("missed an InitializedEntity kind?"); +} + +/// \brief Make a (potentially elidable) temporary copy of the object +/// provided by the given initializer by calling the appropriate copy +/// constructor. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param T The type of the temporary object, which must either by +/// the type of the initializer expression or a superclass thereof. +/// +/// \param Enter The entity being initialized. +/// +/// \param CurInit The initializer expression. +/// +/// \param IsExtraneousCopy Whether this is an "extraneous" copy that +/// is permitted in C++03 (but not C++0x) when binding a reference to +/// an rvalue. +/// +/// \returns An expression that copies the initializer expression into +/// a temporary object, or an error expression if a copy could not be +/// created. static Sema::OwningExprResult CopyObject(Sema &S, + QualType T, const InitializedEntity &Entity, - const InitializationKind &Kind, - Sema::OwningExprResult CurInit) { - // Determine which class type we're copying. + Sema::OwningExprResult CurInit, + bool IsExtraneousCopy) { + // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); CXXRecordDecl *Class = 0; - if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>()) + if (const RecordType *Record = T->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); if (!Class) return move(CurInit); @@ -3126,7 +3244,7 @@ static Sema::OwningExprResult CopyObject(Sema &S, // not yet) handled as part of constructor initialization, while // copy elision for exception handlers is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject() && - S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType()); + S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); SourceLocation Loc; switch (Entity.getKind()) { case InitializedEntity::EK_Result: @@ -3151,7 +3269,11 @@ static Sema::OwningExprResult CopyObject(Sema &S, Loc = CurInitExpr->getLocStart(); break; } - + + // Make sure that the type we are copying is complete. + if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete))) + return move(CurInit); + // Perform overload resolution using the class's copy constructors. DeclarationName ConstructorName = S.Context.DeclarationNames.getCXXConstructorName( @@ -3163,7 +3285,8 @@ static Sema::OwningExprResult CopyObject(Sema &S, // Only consider copy constructors. CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con); if (!Constructor || Constructor->isInvalidDecl() || - !Constructor->isCopyConstructor()) + !Constructor->isCopyConstructor() || + !Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) continue; DeclAccessPair FoundDecl @@ -3202,16 +3325,71 @@ static Sema::OwningExprResult CopyObject(Sema &S, return S.ExprError(); } - S.CheckConstructorAccess(Loc, - cast<CXXConstructorDecl>(Best->Function), + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + CurInit.release(); // Ownership transferred into MultiExprArg, below. + + S.CheckConstructorAccess(Loc, Constructor, Entity, Best->FoundDecl.getAccess()); - CurInit.release(); - return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(), - cast<CXXConstructorDecl>(Best->Function), - Elidable, - Sema::MultiExprArg(S, - (void**)&CurInitExpr, 1)); + if (IsExtraneousCopy) { + // If this is a totally extraneous copy for C++03 reference + // binding purposes, just return the original initialization + // expression. We don't generate an (elided) copy operation here + // because doing so would require us to pass down a flag to avoid + // infinite recursion, where each step adds another extraneous, + // elidable copy. + + // Instantiate the default arguments of any extra parameters in + // the selected copy constructor, as if we were going to create a + // proper call to the copy constructor. + for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) { + ParmVarDecl *Parm = Constructor->getParamDecl(I); + if (S.RequireCompleteType(Loc, Parm->getType(), + S.PDiag(diag::err_call_incomplete_argument))) + break; + + // Build the default argument expression; we don't actually care + // if this succeeds or not, because this routine will complain + // if there was a problem. + S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm); + } + + return S.Owned(CurInitExpr); + } + + // Determine the arguments required to actually perform the + // constructor call (we might have derived-to-base conversions, or + // the copy constructor may have default arguments). + if (S.CompleteConstructorCall(Constructor, + Sema::MultiExprArg(S, + (void **)&CurInitExpr, + 1), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Actually perform the constructor call. + CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, + move_arg(ConstructorArgs)); + + // If we're supposed to bind temporaries, do so. + if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + return move(CurInit); +} + +void InitializationSequence::PrintInitLocationNote(Sema &S, + const InitializedEntity &Entity) { + if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) { + if (Entity.getDecl()->getLocation().isInvalid()) + return; + + if (Entity.getDecl()->getDeclName()) + S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_named_here) + << Entity.getDecl()->getDeclName(); + else + S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here); + } } Action::OwningExprResult @@ -3304,6 +3482,7 @@ InitializationSequence::Perform(Sema &S, case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionLValue: case SK_QualificationConversionRValue: @@ -3348,17 +3527,20 @@ InitializationSequence::Perform(Sema &S, // We have a derived-to-base cast that produces either an rvalue or an // lvalue. Perform that cast. + CXXBaseSpecifierArray BasePath; + // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, CurInitExpr->getLocStart(), - CurInitExpr->getSourceRange(), - IgnoreBaseAccess)) + CurInitExpr->getSourceRange(), + &BasePath, IgnoreBaseAccess)) return S.ExprError(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, CastExpr::CK_DerivedToBase, - (Expr*)CurInit.release(), + (Expr*)CurInit.release(), + BasePath, Step->Kind == SK_CastDerivedToBaseLValue)); break; } @@ -3379,6 +3561,7 @@ InitializationSequence::Perform(Sema &S, S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) << Entity.getType().isVolatileQualified() << CurInitExpr->getSourceRange(); + PrintInitLocationNote(S, Entity); return S.ExprError(); } @@ -3399,6 +3582,11 @@ InitializationSequence::Perform(Sema &S, break; + case SK_ExtraneousCopyToTemporary: + CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + /*IsExtraneousCopy=*/true); + break; + case SK_UserConversion: { // We have a user-defined conversion that invokes either a constructor // or a conversion function. @@ -3406,6 +3594,7 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool CreatedObject = false; bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. @@ -3428,7 +3617,7 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return S.ExprError(); - S.CheckConstructorAccess(Kind.getLocation(), Constructor, + S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); CastKind = CastExpr::CK_ConstructorConversion; @@ -3436,6 +3625,8 @@ InitializationSequence::Perform(Sema &S, if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) IsCopy = true; + + CreatedObject = true; } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); @@ -3461,21 +3652,37 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); CastKind = CastExpr::CK_UserDefinedConversion; + + CreatedObject = Conversion->getResultType()->isRecordType(); } bool RequiresCopy = !IsCopy && getKind() != InitializationSequence::ReferenceBinding; if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - + else if (CreatedObject && shouldDestroyTemporary(Entity)) { + CurInitExpr = static_cast<Expr *>(CurInit.get()); + QualType T = CurInitExpr->getType(); + if (const RecordType *Record = T->getAs<RecordType>()) { + CXXDestructorDecl *Destructor + = cast<CXXRecordDecl>(Record->getDecl())->getDestructor(S.Context); + S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.PDiag(diag::err_access_dtor_temp) << T); + S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); + } + } + CurInitExpr = CurInit.takeAs<Expr>(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, + CXXBaseSpecifierArray(), IsLvalue)); if (RequiresCopy) - CurInit = CopyObject(S, Entity, Kind, move(CurInit)); + CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, + move(CurInit), /*IsExtraneousCopy=*/false); + break; } @@ -3483,21 +3690,24 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionRValue: // Perform a qualification conversion; these can never go wrong. S.ImpCastExprToType(CurInitExpr, Step->Type, - CastExpr::CK_NoOp, + CastExpr::CK_NoOp, Step->Kind == SK_QualificationConversionLValue); CurInit.release(); CurInit = S.Owned(CurInitExpr); break; - case SK_ConversionSequence: - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting, - false, false, *Step->ICS)) + case SK_ConversionSequence: { + bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); + + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, + Sema::AA_Converting, IgnoreBaseAccess)) return S.ExprError(); CurInit.release(); - CurInit = S.Owned(CurInitExpr); + CurInit = S.Owned(CurInitExpr); break; - + } + case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); QualType Ty = Step->Type; @@ -3510,6 +3720,7 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitialization: { + unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); @@ -3523,8 +3734,9 @@ InitializationSequence::Perform(Sema &S, Loc, ConstructorArgs)) return S.ExprError(); - // Build the an expression that constructs a temporary. + // Build the expression that constructs a temporary. if (Entity.getKind() == InitializedEntity::EK_Temporary && + NumArgs != 1 && // FIXME: Hack to work around cast weirdness (Kind.getKind() == InitializationKind::IK_Direct || Kind.getKind() == InitializationKind::IK_Value)) { // An explicitly-constructed temporary, e.g., X(1, 2). @@ -3537,23 +3749,33 @@ InitializationSequence::Perform(Sema &S, Kind.getLocation(), Exprs, NumExprs, - Kind.getParenRange().getEnd())); - } else + Kind.getParenRange().getEnd(), + ConstructorInitRequiresZeroInit)); + } else { + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete; + + if (Entity.getKind() == InitializedEntity::EK_Base) { + ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? + CXXConstructExpr::CK_VirtualBase : + CXXConstructExpr::CK_NonVirtualBase; + } CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, move_arg(ConstructorArgs), ConstructorInitRequiresZeroInit, - Entity.getKind() == InitializedEntity::EK_Base); + ConstructKind); + } if (CurInit.isInvalid()) return S.ExprError(); // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, + S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - + break; } @@ -3589,10 +3811,16 @@ InitializationSequence::Perform(Sema &S, == Sema::Compatible) ConvTy = Sema::Compatible; + bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInitExpr, getAssignmentAction(Entity))) + CurInitExpr, + getAssignmentAction(Entity), + &Complained)) { + PrintInitLocationNote(S, Entity); return S.ExprError(); + } else if (Complained) + PrintInitLocationNote(S, Entity); CurInit.release(); CurInit = S.Owned(CurInitExpr); @@ -3866,6 +4094,7 @@ bool InitializationSequence::Diagnose(Sema &S, break; } + PrintInitLocationNote(S, Entity); return true; } @@ -4013,9 +4242,12 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { OS << "bind reference to a temporary"; break; + case SK_ExtraneousCopyToTemporary: + OS << "extraneous C++03 copy to temporary"; + break; + case SK_UserConversion: - OS << "user-defined conversion via " - << S->Function.Function->getNameAsString(); + OS << "user-defined conversion via " << S->Function.Function; break; case SK_QualificationConversionRValue: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 7c6327f..5f2592f 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -92,11 +92,12 @@ private: unsigned Location; /// \brief When Kind == EK_Base, the base specifier that provides the - /// base class. - CXXBaseSpecifier *Base; + /// base class. The lower bit specifies whether the base is an inherited + /// virtual base. + uintptr_t Base; - /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the - /// index of the array or vector element being initialized. + /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the + /// index of the array or vector element being initialized. unsigned Index; }; @@ -141,7 +142,12 @@ public: /// \brief Create the initialization entity for a parameter that is /// only known by its type. static InitializedEntity InitializeParameter(QualType Type) { - return InitializedEntity(EK_Parameter, SourceLocation(), Type); + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Type; + Entity.Parent = 0; + Entity.VariableOrMember = 0; + return Entity; } /// \brief Create the initialization entity for the result of a function. @@ -168,7 +174,8 @@ public: /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base); + CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase); /// \brief Create the initialization entity for a member subobject. static InitializedEntity InitializeMember(FieldDecl *Member, @@ -204,7 +211,13 @@ public: /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); - return Base; + return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1); + } + + /// \brief Return whether the base is an inherited virtual base. + bool isInheritedVirtualBase() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base & 0x1; } /// \brief Determine the location of the 'return' keyword when initializing @@ -416,6 +429,10 @@ public: SK_BindReference, /// \brief Reference binding to a temporary. SK_BindReferenceToTemporary, + /// \brief An optional copy of a temporary object to another + /// temporary object, which is permitted (but not required) by + /// C++98/03 but not C++0x. + SK_ExtraneousCopyToTemporary, /// \brief Perform a user-defined conversion, either via a conversion /// function or via a constructor. SK_UserConversion, @@ -525,7 +542,11 @@ private: /// \brief The candidate set created when initialization failed. OverloadCandidateSet FailedCandidateSet; - + + /// \brief Prints a follow-up note that highlights the location of + /// the initialized entity, if it's remote. + void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); + public: /// \brief Try to perform initialization of the given entity, creating a /// record of the steps required to perform the initialization. @@ -606,6 +627,10 @@ public: /// \brief Determine whether this initialization failed due to an ambiguity. bool isAmbiguous() const; + /// \brief Determine whether this initialization is direct call to a + /// constructor. + bool isConstructorInitialization() const; + /// \brief Add a new step in the initialization that resolves the address /// of an overloaded function to a specific function declaration. /// @@ -625,11 +650,26 @@ public: /// \brief Add a new step binding a reference to an object. /// - /// \param BindingTemporary true if we are binding a reference to a temporary + /// \param BindingTemporary True if we are binding a reference to a temporary /// object (thereby extending its lifetime); false if we are binding to an /// lvalue or an lvalue treated as an rvalue. + /// + /// \param UnnecessaryCopy True if we should check for a copy + /// constructor for a completely unnecessary but void AddReferenceBindingStep(QualType T, bool BindingTemporary); - + + /// \brief Add a new step that makes an extraneous copy of the input + /// to a temporary of the same class type. + /// + /// This extraneous copy only occurs during reference binding in + /// C++98/03, where we are permitted (but not required) to introduce + /// an extra copy. At a bare minimum, we must check that we could + /// call the copy constructor, and produce a diagnostic if the copy + /// constructor is inaccessible or no copy constructor matches. + // + /// \param T The type of the temporary being created. + void AddExtraneousCopyToTemporary(QualType T); + /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. void AddUserConversionStep(FunctionDecl *Function, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a29c4d4..337a4a3 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -193,62 +193,6 @@ namespace { }; } -static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) { - return D->isInIdentifierNamespace(IDNS); -} - -static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) { - return D->isInIdentifierNamespace(IDNS) && - !D->getDeclContext()->isRecord(); -} - -static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) { - // This lookup ignores everything that isn't a type. - - // This is a fast check for the far most common case. - if (D->isInIdentifierNamespace(Decl::IDNS_Tag)) - return true; - - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - return isa<TypeDecl>(D); -} - -static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) { - // We don't need to look through using decls here because - // using decls aren't allowed to name namespaces. - - return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); -} - -/// Gets the default result filter for the given lookup. -static inline -LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) { - switch (NameKind) { - case Sema::LookupOrdinaryName: - case Sema::LookupTagName: - case Sema::LookupMemberName: - case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping - case Sema::LookupUsingDeclName: - case Sema::LookupObjCProtocolName: - case Sema::LookupObjCImplementationName: - return &IsAcceptableIDNS; - - case Sema::LookupOperatorName: - return &IsAcceptableOperatorName; - - case Sema::LookupNestedNameSpecifierName: - return &IsAcceptableNestedNameSpecifierName; - - case Sema::LookupNamespaceName: - return &IsAcceptableNamespaceName; - } - - llvm_unreachable("unkknown lookup kind"); - return 0; -} - // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. static inline unsigned getIDNS(Sema::LookupNameKind NameKind, @@ -257,19 +201,35 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, unsigned IDNS = 0; switch (NameKind) { case Sema::LookupOrdinaryName: - case Sema::LookupOperatorName: case Sema::LookupRedeclarationWithLinkage: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { - IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } break; + case Sema::LookupOperatorName: + // Operator lookup is its own crazy thing; it is not the same + // as (e.g.) looking up an operator name for redeclaration. + assert(!Redeclaration && "cannot do redeclaration operator lookup"); + IDNS = Decl::IDNS_NonMemberOperator; + break; + case Sema::LookupTagName: - IDNS = Decl::IDNS_Tag; - if (CPlusPlus && Redeclaration) - IDNS |= Decl::IDNS_TagFriend; + if (CPlusPlus) { + IDNS = Decl::IDNS_Type; + + // When looking for a redeclaration of a tag name, we add: + // 1) TagFriend to find undeclared friend decls + // 2) Namespace because they can't "overload" with tag decls. + // 3) Tag because it includes class templates, which can't + // "overload" with tag decls. + if (Redeclaration) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace; + } else { + IDNS = Decl::IDNS_Tag; + } break; case Sema::LookupMemberName: @@ -279,8 +239,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, break; case Sema::LookupNestedNameSpecifierName: + IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace; + break; + case Sema::LookupNamespaceName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; + IDNS = Decl::IDNS_Namespace; break; case Sema::LookupUsingDeclName: @@ -291,10 +254,6 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; - - case Sema::LookupObjCImplementationName: - IDNS = Decl::IDNS_ObjCImplementation; - break; } return IDNS; } @@ -303,7 +262,6 @@ void LookupResult::configure() { IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); - IsAcceptableFn = getResultFilter(LookupKind); // If we're looking for one of the allocation or deallocation // operators, make sure that the implicitly-declared new and delete @@ -341,9 +299,10 @@ void LookupResult::resolveKind() { // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { - if (isa<FunctionTemplateDecl>(*Decls.begin())) + NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); + if (isa<FunctionTemplateDecl>(D)) ResultKind = FoundOverloaded; - else if (isa<UnresolvedUsingValueDecl>(*Decls.begin())) + else if (isa<UnresolvedUsingValueDecl>(D)) ResultKind = FoundUnresolvedValue; return; } @@ -1169,7 +1128,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: - case LookupObjCImplementationName: // These lookups will never find a member in a C++ class (or base class). return false; @@ -1291,7 +1249,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// context of the scope-specifier SS (if present). /// /// @returns True if any decls were found (but possibly ambiguous) -bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, +bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation, bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for @@ -1303,7 +1261,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. - if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; R.setContextRange(SS->getRange()); @@ -1428,10 +1386,18 @@ addAssociatedClassesAndNamespaces(QualType T, Sema::AssociatedNamespaceSet &AssociatedNamespaces, Sema::AssociatedClassSet &AssociatedClasses); -static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces, - DeclContext *Ctx) { +static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, + DeclContext *Ctx) { + // Add the associated namespace for this class. + + // We don't use DeclContext::getEnclosingNamespaceContext() as this may + // be a locally scoped record. + + while (Ctx->isRecord() || Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + if (Ctx->isFileContext()) - Namespaces.insert(Ctx); + Namespaces.insert(Ctx->getPrimaryContext()); } // \brief Add the associated classes and namespaces for argument-dependent @@ -1467,9 +1433,7 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); } break; } @@ -1513,9 +1477,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); // Add the class itself. If we've already seen this class, we don't // need to visit base classes. @@ -1537,9 +1499,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -1580,9 +1540,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (AssociatedClasses.insert(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); - while (BaseCtx->isRecord()) - BaseCtx = BaseCtx->getParent(); - CollectNamespace(AssociatedNamespaces, BaseCtx); + CollectEnclosingNamespace(AssociatedNamespaces, BaseCtx); // Make sure we visit the bases of this base class. if (BaseDecl->bases_begin() != BaseDecl->bases_end()) @@ -1657,9 +1615,7 @@ addAssociatedClassesAndNamespaces(QualType T, AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); return; } @@ -1825,16 +1781,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, } NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl) { - LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl); + LookupResult R(*this, Name, Loc, NameKind, Redecl); LookupName(R, S); return R.getAsSingle<NamedDecl>(); } /// \brief Find the protocol with the given name, if any. -ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { - Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName); +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, + SourceLocation IdLoc) { + Decl *D = LookupSingleName(TUScope, II, IdLoc, + LookupObjCProtocolName); return cast_or_null<ObjCProtocolDecl>(D); } @@ -1864,16 +1823,17 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); Op != OpEnd; ++Op) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) { + NamedDecl *Found = (*Op)->getUnderlyingDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD + Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(*Op)) { + = dyn_cast<FunctionTemplateDecl>(Found)) { // FIXME: friend operators? // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) - Functions.addDecl(FunTmpl, Op.getAccess()); + Functions.addDecl(*Op, Op.getAccess()); } } } @@ -2137,7 +2097,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag && + if ((*I)->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -2276,6 +2236,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } + + // If there is an implementation, traverse it. We do this to find + // synthesized ivars. + if (IFace->getImplementation()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(IFace->getImplementation(), Result, + QualifiedNameLookup, true, Consumer, Visited); + } } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { @@ -2290,6 +2258,13 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } + + // If there is an implementation, traverse it. + if (Category->getImplementation()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(Category->getImplementation(), Result, + QualifiedNameLookup, true, Consumer, Visited); + } } } @@ -2421,6 +2396,9 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { /// found (so far) with the typo name. llvm::SmallVector<NamedDecl *, 4> BestResults; + /// \brief The keywords that have the smallest edit distance. + llvm::SmallVector<IdentifierInfo *, 4> BestKeywords; + /// \brief The best edit distance found so far. unsigned BestEditDistance; @@ -2429,13 +2407,23 @@ public: : Typo(Typo->getName()) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); + void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword); typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; iterator begin() const { return BestResults.begin(); } iterator end() const { return BestResults.end(); } - bool empty() const { return BestResults.empty(); } - - unsigned getBestEditDistance() const { return BestEditDistance; } + void clear_decls() { BestResults.clear(); } + + bool empty() const { return BestResults.empty() && BestKeywords.empty(); } + + typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator + keyword_iterator; + keyword_iterator keyword_begin() const { return BestKeywords.begin(); } + keyword_iterator keyword_end() const { return BestKeywords.end(); } + bool keyword_empty() const { return BestKeywords.empty(); } + unsigned keyword_size() const { return BestKeywords.size(); } + + unsigned getBestEditDistance() const { return BestEditDistance; } }; } @@ -2457,11 +2445,12 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, // 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->getName()); - if (!BestResults.empty()) { + if (!BestResults.empty() || !BestKeywords.empty()) { if (ED < BestEditDistance) { // This result is better than any we've seen before; clear out // the previous results. BestResults.clear(); + BestKeywords.clear(); BestEditDistance = ED; } else if (ED > BestEditDistance) { // This result is worse than the best results we've seen so far; @@ -2474,6 +2463,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, BestResults.push_back(ND); } +void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, + 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 (!BestResults.empty() || !BestKeywords.empty()) { + if (ED < BestEditDistance) { + BestResults.clear(); + BestKeywords.clear(); + BestEditDistance = ED; + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } + } else + BestEditDistance = ED; + + BestKeywords.push_back(&Context.Idents.get(Keyword)); +} + /// \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. @@ -2494,42 +2505,50 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// +/// \param CTC The context in which typo correction occurs, which impacts the +/// set of keywords permitted. +/// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// -/// \returns true if the typo was corrected, in which case the \p Res -/// structure will contain the results of name lookup for the -/// corrected name. Otherwise, returns false. -bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext, bool EnteringContext, - const ObjCObjectPointerType *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) { if (Diags.hasFatalErrorOccurred()) - return false; + return DeclarationName(); // 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. // FIXME: Is this the right solution? if (TyposCorrected == 20) - return false; + return DeclarationName(); ++TyposCorrected; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) - return false; + return DeclarationName(); // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) - return false; + return DeclarationName(); // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) - return false; - + return DeclarationName(); + TypoCorrectionConsumer Consumer(Typo); + + // Perform name lookup to find visible, similarly-named entities. if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); @@ -2543,45 +2562,239 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, } else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) - return false; + return DeclarationName(); LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); } else { LookupVisibleDecls(S, Res.getLookupKind(), Consumer); } + // 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; + 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_MemberLookup: + if (getLangOptions().CPlusPlus) + Consumer.addKeywordResult(Context, "template"); + 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", "_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"); + } + } + + if (getLangOptions().GNUMode) + Consumer.addKeywordResult(Context, "typeof"); + } + + if (WantCXXNamedCasts) { + Consumer.addKeywordResult(Context, "const_cast"); + Consumer.addKeywordResult(Context, "dynamic_cast"); + Consumer.addKeywordResult(Context, "reinterpret_cast"); + Consumer.addKeywordResult(Context, "static_cast"); + } + + if (WantExpressionKeywords) { + Consumer.addKeywordResult(Context, "sizeof"); + if (getLangOptions().Bool || getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "false"); + Consumer.addKeywordResult(Context, "true"); + } + + 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]); + + if (isa<CXXMethodDecl>(CurContext) && + cast<CXXMethodDecl>(CurContext)->isInstance()) + Consumer.addKeywordResult(Context, "this"); + + if (getLangOptions().CPlusPlus0x) { + Consumer.addKeywordResult(Context, "alignof"); + Consumer.addKeywordResult(Context, "nullptr"); + } + } + } + + 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 (!getSwitchStack().empty()) { + Consumer.addKeywordResult(Context, "case"); + Consumer.addKeywordResult(Context, "default"); + } + } else { + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "namespace"); + Consumer.addKeywordResult(Context, "template"); + } + + 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"); + } + } + + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "using"); + + if (getLangOptions().CPlusPlus0x) + Consumer.addKeywordResult(Context, "static_assert"); + } + } + + // If we haven't found anything, we're done. if (Consumer.empty()) - return false; + return DeclarationName(); // Only allow a single, closest name in the result set (it's okay to // have overloads of that name, though). - TypoCorrectionConsumer::iterator I = Consumer.begin(); - DeclarationName BestName = (*I)->getDeclName(); - - // If we've found an Objective-C ivar or property, don't perform - // name lookup again; we'll just return the result directly. - NamedDecl *FoundBest = 0; - if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) - FoundBest = *I; - ++I; - for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) { - if (BestName != (*I)->getDeclName()) - return false; - - // FIXME: If there are both ivars and properties of the same name, - // don't return both because the callee can't handle two - // results. We really need to separate ivar lookup from property - // lookup to avoid this problem. - FoundBest = 0; + DeclarationName BestName; + NamedDecl *BestIvarOrPropertyDecl = 0; + bool FoundIvarOrPropertyDecl = false; + + // Check all of the declaration results to find the best name so far. + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + IEnd = Consumer.end(); + I != IEnd; ++I) { + if (!BestName) + BestName = (*I)->getDeclName(); + else if (BestName != (*I)->getDeclName()) + return DeclarationName(); + + // \brief Keep track of either an Objective-C ivar or a property, but not + // both. + if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) { + if (FoundIvarOrPropertyDecl) + BestIvarOrPropertyDecl = 0; + else { + BestIvarOrPropertyDecl = *I; + FoundIvarOrPropertyDecl = true; + } + } } + // Now check all of the keyword results to find the best name. + switch (Consumer.keyword_size()) { + case 0: + // No keywords matched. + break; + + case 1: + // If we already have a name + if (!BestName) { + // We did not have anything previously, + BestName = *Consumer.keyword_begin(); + } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) { + // We have a declaration with the same name as a context-sensitive + // keyword. The keyword takes precedence. + BestIvarOrPropertyDecl = 0; + FoundIvarOrPropertyDecl = false; + Consumer.clear_decls(); + } else { + // Name collision; we will not correct typos. + return DeclarationName(); + } + break; + + default: + // Name collision; we will not correct typos. + return DeclarationName(); + } + // BestName is the closest viable name to what the user // typed. However, to make sure that we don't pick something that's // way off, make sure that the user typed at least 3 characters for // each correction. unsigned ED = Consumer.getBestEditDistance(); - if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) - return false; + if (ED == 0 || !BestName.getAsIdentifierInfo() || + (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) + return DeclarationName(); // Perform name lookup again with the name we chose, and declare // success if we found something that was not ambiguous. @@ -2590,11 +2803,14 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // If we found an ivar or property, add that result; no further // lookup is required. - if (FoundBest) - Res.addDecl(FoundBest); + if (BestIvarOrPropertyDecl) + Res.addDecl(BestIvarOrPropertyDecl); // If we're looking into the context of a member, perform qualified // name lookup on the best name. - else if (MemberContext) + else if (!Consumer.keyword_empty()) { + // The best match was a keyword. Return it. + return BestName; + } else if (MemberContext) LookupQualifiedName(Res, MemberContext); // Perform lookup as if we had just parsed the best name. else @@ -2603,8 +2819,11 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, if (Res.isAmbiguous()) { Res.suppressDiagnostics(); - return false; + return DeclarationName(); } - return Res.getResultKind() != LookupResult::NotFound; + if (Res.getResultKind() != LookupResult::NotFound) + return BestName; + + return DeclarationName(); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index cda1f0b..b73739f 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -204,7 +204,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, ObjCInterfaceDecl *IDecl = OIT->getDecl(); if (IDecl) if (ObjCProtocolDecl* PNSCopying = - LookupProtocol(&Context.Idents.get("NSCopying"))) + LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc)) if (IDecl->ClassImplementsProtocol(PNSCopying, true)) Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; } @@ -356,7 +356,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (!Ivar) { Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyIvar, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, + ObjCIvarDecl::Protected, (Expr *)0); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); @@ -719,7 +719,10 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, // scan through class's protocols. for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), E = IDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); + // Exclude property for protocols which conform to class's super-class, + // as super-class has to implement the property. + if (!ProtocolConformsToSuperClass(IDecl, (*PI))) + CollectImmediateProperties((*PI), PropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { if (!CATDecl->IsClassExtension()) @@ -748,6 +751,33 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// ProtocolConformsToSuperClass - Returns true if class's given protocol +/// conforms to one of its super class's protocols. +bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl) { + if (const ObjCInterfaceDecl *CDecl = IDecl->getSuperClass()) { + for (ObjCInterfaceDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) { + if (ProtocolConformsToProtocol((*PI), PDecl)) + return true; + return ProtocolConformsToSuperClass(CDecl, PDecl); + } + } + return false; +} + +bool Sema::ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl) { + if (PDecl->getIdentifier() == NestedProtocol->getIdentifier()) + return true; + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + if (ProtocolConformsToProtocol(NestedProtocol, (*PI))) + return true; + return false; +} + /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, @@ -810,9 +840,9 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop)) continue; - if (LangOpts.ObjCNonFragileABI2) { + if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) { ActOnPropertyImplDecl(IMPDecl->getLocation(), - SourceLocation(), + IMPDecl->getLocation(), true, DeclPtrTy::make(IMPDecl), Prop->getIdentifier(), Prop->getIdentifier()); @@ -953,8 +983,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getType(), /*TInfo=*/0, VarDecl::None, + VarDecl::None, 0); - SetterMethod->setMethodParams(Context, &Argument, 1); + SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); } else // A user declared setter will be synthesize when @synthesize of @@ -1066,21 +1097,3 @@ void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); } - -ObjCIvarDecl* -Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII) { - ObjCIvarDecl *Ivar = 0; - ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); - if (Prop && !Prop->isInvalidDecl()) { - QualType PropType = Context.getCanonicalType(Prop->getType()); - Ivar = ObjCIvarDecl::Create(Context, IDecl, Prop->getLocation(), NameII, - PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, (Expr *)0); - Ivar->setLexicalDeclContext(IDecl); - IDecl->addDecl(Ivar); - Prop->setPropertyIvarDecl(Ivar); - } - return Ivar; -} - diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index bc10a58..21f2a51 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -226,7 +226,7 @@ void UserDefinedConversionSequence::DebugPrint() const { Before.DebugPrint(); OS << " -> "; } - OS << "'" << ConversionFunction->getNameAsString() << "'"; + OS << '\'' << ConversionFunction << '\''; if (After.First || After.Second || After.Third) { OS << " -> "; After.DebugPrint(); @@ -374,8 +374,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { if (OldQType != NewQType && (OldType->getNumArgs() != NewType->getNumArgs() || OldType->isVariadic() != NewType->isVariadic() || - !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), - NewType->arg_type_begin()))) + !FunctionArgTypesAreEqual(OldType, NewType))) return true; // C++ [temp.over.link]p4: @@ -436,16 +435,11 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { /// not permitted. /// If @p AllowExplicit, then explicit user-defined conversions are /// permitted. -/// If @p ForceRValue, then overloading is performed as if From was an rvalue, -/// no matter its actual lvalueness. -/// If @p UserCast, the implicit conversion is being done for a user-specified -/// cast. ImplicitConversionSequence Sema::TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue, - bool InOverloadResolution, - bool UserCast) { + bool AllowExplicit, + bool InOverloadResolution) { ImplicitConversionSequence ICS; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) { ICS.setStandard(); @@ -457,11 +451,47 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } + if (SuppressUserConversions) { + // C++ [over.ics.user]p4: + // A conversion of an expression of class type to the same class + // type is given Exact Match rank, and a conversion of an + // expression of class type to a base class of that type is + // given Conversion rank, in spite of the fact that a copy/move + // constructor (i.e., a user-defined conversion function) is + // called for those cases. + QualType FromType = From->getType(); + if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() || + !(Context.hasSameUnqualifiedType(FromType, ToType) || + IsDerivedFrom(FromType, ToType))) { + // We're not in the case above, so there is no conversion that + // we can perform. + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); + return ICS; + } + + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.setFromType(FromType); + ICS.Standard.setAllToTypes(ToType); + + // We don't actually check at this point whether there is a valid + // copy/move constructor, since overloading just assumes that it + // exists. When we actually perform initialization, we'll find the + // appropriate constructor to copy the returned object, if needed. + ICS.Standard.CopyConstructor = 0; + + // Determine whether this is considered a derived-to-base conversion. + if (!Context.hasSameUnqualifiedType(FromType, ToType)) + ICS.Standard.Second = ICK_Derived_To_Base; + + return ICS; + } + + // Attempt user-defined conversion. OverloadCandidateSet Conversions(From->getExprLoc()); OverloadingResult UserDefResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, - !SuppressUserConversions, AllowExplicit, - ForceRValue, UserCast); + AllowExplicit); if (UserDefResult == OR_Success) { ICS.setUserDefined(); @@ -516,6 +546,30 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +/// PerformImplicitConversion - Perform an implicit conversion of the +/// expression From to the type ToType. Returns true if there was an +/// error, false otherwise. The expression From is replaced with the +/// converted expression. Flavor is the kind of conversion we're +/// performing, used in the error message. If @p AllowExplicit, +/// explicit user-defined conversions are permitted. +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + AssignmentAction Action, bool AllowExplicit) { + ImplicitConversionSequence ICS; + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); +} + +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + AssignmentAction Action, bool AllowExplicit, + ImplicitConversionSequence& ICS) { + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*InOverloadResolution=*/false); + 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, @@ -567,8 +621,36 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). - DeclAccessPair AccessPair; - + if (FromType == Context.OverloadTy) { + DeclAccessPair AccessPair; + if (FunctionDecl *Fn + = ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { + // We were able to resolve the address of the overloaded function, + // so we can convert to the type of that function. + FromType = Fn->getType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { + if (!Method->isStatic()) { + Type *ClassType + = Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FromType = Context.getMemberPointerType(FromType, ClassType); + } + } + + // If the "from" expression takes the address of the overloaded + // function, update the type of the resulting expression accordingly. + if (FromType->getAs<FunctionType>()) + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens())) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + FromType = Context.getPointerType(FromType); + + // Check that we've computed the proper type after overload resolution. + assert(Context.hasSameType(FromType, + FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); + } else { + return false; + } + } // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. @@ -613,31 +695,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); - } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false, - AccessPair)) { - // Address of overloaded function (C++ [over.over]). - SCS.First = ICK_Function_To_Pointer; - - // We were able to resolve the address of the overloaded function, - // so we can convert to the type of that function. - FromType = Fn->getType(); - if (ToType->isLValueReferenceType()) - FromType = Context.getLValueReferenceType(FromType); - else if (ToType->isRValueReferenceType()) - FromType = Context.getRValueReferenceType(FromType); - else if (ToType->isMemberPointerType()) { - // Resolve address only succeeds if both sides are member pointers, - // but it doesn't have to be the same class. See DR 247. - // Note that this means that the type of &Derived::fn can be - // Ret (Base::*)(Args) if the fn overload actually found is from the - // base class, even if it was brought into the derived class via a - // using declaration. The standard isn't clear on this issue at all. - CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); - FromType = Context.getMemberPointerType(FromType, - Context.getTypeDeclType(M->getParent()).getTypePtr()); - } else - FromType = Context.getPointerType(FromType); } else { // We don't require any conversions for the first step. SCS.First = ICK_Identity; @@ -1274,6 +1331,47 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, return false; } + +/// FunctionArgTypesAreEqual - This routine checks two function proto types +/// for equlity of their argument types. Caller has already checked that +/// they have same number of arguments. This routine assumes that Objective-C +/// pointer types which only differ in their protocol qualifiers are equal. +bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, + FunctionProtoType* NewType){ + if (!getLangOptions().ObjC1) + return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), + NewType->arg_type_begin()); + + for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), + N = NewType->arg_type_begin(), + E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { + QualType ToType = (*O); + QualType FromType = (*N); + if (ToType != FromType) { + if (const PointerType *PTTo = ToType->getAs<PointerType>()) { + if (const PointerType *PTFr = FromType->getAs<PointerType>()) + if (PTTo->getPointeeType()->isObjCQualifiedIdType() && + PTFr->getPointeeType()->isObjCQualifiedIdType() || + PTTo->getPointeeType()->isObjCQualifiedClassType() && + PTFr->getPointeeType()->isObjCQualifiedClassType()) + continue; + } + else if (ToType->isObjCObjectPointerType() && + FromType->isObjCObjectPointerType()) { + QualType ToInterfaceTy = ToType->getPointeeType(); + QualType FromInterfaceTy = FromType->getPointeeType(); + if (const ObjCInterfaceType *OITTo = + ToInterfaceTy->getAs<ObjCInterfaceType>()) + if (const ObjCInterfaceType *OITFr = + FromInterfaceTy->getAs<ObjCInterfaceType>()) + if (OITTo->getDecl() == OITFr->getDecl()) + continue; + } + return false; + } + } + return true; +} /// CheckPointerConversion - Check the pointer conversion from the /// expression From to the type ToType. This routine checks for @@ -1283,6 +1381,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, /// error, or returns false otherwise. bool Sema::CheckPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray& BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); @@ -1297,7 +1396,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // ambiguous or inaccessible conversion. if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, From->getExprLoc(), - From->getSourceRange(), + From->getSourceRange(), &BasePath, IgnoreBaseAccess)) return true; @@ -1368,6 +1467,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); @@ -1391,7 +1491,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, assert(FromClass->isRecordType() && "Pointer into non-class."); assert(ToClass->isRecordType() && "Pointer into non-class."); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); assert(DerivationOkay && @@ -1419,6 +1519,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, diag::err_downcast_from_inaccessible_base); // Must be a base to derived member conversion. + BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_BaseToDerivedMemberPointer; return false; } @@ -1482,48 +1583,39 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// and this routine will return true. Otherwise, this routine returns /// false and User is unspecified. /// -/// \param AllowConversionFunctions true if the conversion should -/// consider conversion functions at all. If false, only constructors -/// will be considered. -/// /// \param AllowExplicit true if the conversion should consider C++0x /// "explicit" conversion functions as well as non-explicit conversion /// functions (C++0x [class.conv.fct]p2). -/// -/// \param ForceRValue true if the expression should be treated as an rvalue -/// for overload resolution. -/// \param UserCast true if looking for user defined conversion for a static -/// cast. OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowConversionFunctions, - bool AllowExplicit, - bool ForceRValue, - bool UserCast) { + OverloadCandidateSet& CandidateSet, + bool AllowExplicit) { + // Whether we will only visit constructors. + bool ConstructorsOnly = false; + + // If the type we are conversion to is a class type, enumerate its + // constructors. if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { + // C++ [over.match.ctor]p1: + // When objects of class type are direct-initialized (8.5), or + // copy-initialized from an expression of the same or a + // derived class type (8.5), overload resolution selects the + // constructor. [...] For copy-initialization, the candidate + // functions are all the converting constructors (12.3.1) of + // that class. The argument list is the expression-list within + // the parentheses of the initializer. + if (Context.hasSameUnqualifiedType(ToType, From->getType()) || + (From->getType()->getAs<RecordType>() && + IsDerivedFrom(From->getType(), ToType))) + ConstructorsOnly = true; + if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { // We're not going to find any constructors. } else if (CXXRecordDecl *ToRecordDecl = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { - // C++ [over.match.ctor]p1: - // When objects of class type are direct-initialized (8.5), or - // copy-initialized from an expression of the same or a - // derived class type (8.5), overload resolution selects the - // constructor. [...] For copy-initialization, the candidate - // functions are all the converting constructors (12.3.1) of - // that class. The argument list is the expression-list within - // the parentheses of the initializer. - bool SuppressUserConversions = !UserCast; - if (Context.hasSameUnqualifiedType(ToType, From->getType()) || - IsDerivedFrom(From->getType(), ToType)) { - SuppressUserConversions = false; - AllowConversionFunctions = false; - } - DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ToType).getUnqualifiedType()); + Context.getCanonicalType(ToType).getUnqualifiedType()); DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = ToRecordDecl->lookup(ConstructorName); @@ -1547,26 +1639,25 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &From, 1, CandidateSet, - SuppressUserConversions, ForceRValue); + /*SuppressUserConversions=*/!ConstructorsOnly); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). AddOverloadCandidate(Constructor, FoundDecl, &From, 1, CandidateSet, - SuppressUserConversions, ForceRValue); + /*SuppressUserConversions=*/!ConstructorsOnly); } } } } - if (!AllowConversionFunctions) { - // Don't allow any conversion functions to enter the overload set. + // Enumerate conversion functions, if we're allowed to. + if (ConstructorsOnly) { } else if (RequireCompleteType(From->getLocStart(), From->getType(), - PDiag(0) - << From->getSourceRange())) { + PDiag(0) << From->getSourceRange())) { // No conversion functions from incomplete types. } else if (const RecordType *FromRecordType - = From->getType()->getAs<RecordType>()) { + = From->getType()->getAs<RecordType>()) { if (CXXRecordDecl *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. @@ -1672,7 +1763,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { OverloadCandidateSet CandidateSet(From->getExprLoc()); OverloadingResult OvResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, - CandidateSet, true, false, false); + CandidateSet, false); if (OvResult == OR_Ambiguous) Diag(From->getSourceRange().getBegin(), diag::err_typecheck_ambiguous_condition) @@ -1708,15 +1799,14 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // described in 13.3.3.2, the ambiguous conversion sequence is // treated as a user-defined sequence that is indistinguishable // from any other user-defined conversion sequence. - if (ICS1.getKind() < ICS2.getKind()) { - if (!(ICS1.isUserDefined() && ICS2.isAmbiguous())) - return ImplicitConversionSequence::Better; - } else if (ICS2.getKind() < ICS1.getKind()) { - if (!(ICS2.isUserDefined() && ICS1.isAmbiguous())) - return ImplicitConversionSequence::Worse; - } + if (ICS1.getKindRank() < ICS2.getKindRank()) + return ImplicitConversionSequence::Better; + else if (ICS2.getKindRank() < ICS1.getKindRank()) + return ImplicitConversionSequence::Worse; - if (ICS1.isAmbiguous() || ICS2.isAmbiguous()) + // The following checks require both conversion sequences to be of + // the same kind. + if (ICS1.getKind() != ICS2.getKind()) return ImplicitConversionSequence::Indistinguishable; // Two implicit conversion sequences of the same form are @@ -2143,9 +2233,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } } - if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) && - (SCS2.ReferenceBinding || SCS2.CopyConstructor) && - SCS1.Second == ICK_Derived_To_Base) { + if (SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, // -- binding of an expression of type C to a reference of type // B& is better than binding an expression of type C to a @@ -2174,34 +2262,353 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, return ImplicitConversionSequence::Indistinguishable; } +/// CompareReferenceRelationship - Compare the two types T1 and T2 to +/// determine whether they are reference-related, +/// reference-compatible, reference-compatible with added +/// qualification, or incompatible, for use in C++ initialization by +/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference +/// type, and the first type (T1) is the pointee type of the reference +/// type being initialized. +Sema::ReferenceCompareResult +Sema::CompareReferenceRelationship(SourceLocation Loc, + QualType OrigT1, QualType OrigT2, + bool& DerivedToBase) { + assert(!OrigT1->isReferenceType() && + "T1 must be the pointee type of the reference type"); + assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); + + QualType T1 = Context.getCanonicalType(OrigT1); + QualType T2 = Context.getCanonicalType(OrigT2); + Qualifiers T1Quals, T2Quals; + QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); + + // C++ [dcl.init.ref]p4: + // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is + // reference-related to "cv2 T2" if T1 is the same type as T2, or + // T1 is a base class of T2. + if (UnqualT1 == UnqualT2) + DerivedToBase = false; + else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && + !RequireCompleteType(Loc, OrigT2, PDiag()) && + IsDerivedFrom(UnqualT2, UnqualT1)) + DerivedToBase = true; + else + return Ref_Incompatible; + + // At this point, we know that T1 and T2 are reference-related (at + // least). + + // If the type is an array type, promote the element qualifiers to the type + // for comparison. + if (isa<ArrayType>(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa<ArrayType>(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); + + // C++ [dcl.init.ref]p4: + // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is + // reference-related to T2 and cv1 is the same cv-qualification + // as, or greater cv-qualification than, cv2. For purposes of + // overload resolution, cases for which cv1 is greater + // cv-qualification than cv2 are identified as + // reference-compatible with added qualification (see 13.3.3.2). + if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) + return Ref_Compatible; + else if (T1.isMoreQualifiedThan(T2)) + return Ref_Compatible_With_Added_Qualification; + else + return Ref_Related; +} + +/// \brief Compute an implicit conversion sequence for reference +/// initialization. +static ImplicitConversionSequence +TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, + SourceLocation DeclLoc, + bool SuppressUserConversions, + bool AllowExplicit) { + assert(DeclType->isReferenceType() && "Reference init needs a reference"); + + // Most paths end in a failed conversion. + ImplicitConversionSequence ICS; + ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); + + QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); + QualType T2 = Init->getType(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + DeclAccessPair Found; + if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType, + false, Found)) + T2 = Fn->getType(); + } + + // Compute some basic properties of the types and the initializer. + bool isRValRef = DeclType->isRValueReferenceType(); + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = Init->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); + + + // C++ [over.ics.ref]p3: + // Except for an implicit object parameter, for which see 13.3.1, + // a standard conversion sequence cannot be formed if it requires + // binding an lvalue reference to non-const to an rvalue or + // binding an rvalue reference to an lvalue. + // + // FIXME: DPG doesn't trust this code. It seems far too early to + // abort because of a binding of an rvalue reference to an lvalue. + if (isRValRef && InitLvalue == Expr::LV_Valid) + return ICS; + + // C++0x [dcl.init.ref]p16: + // A reference to type "cv1 T1" is initialized by an expression + // of type "cv2 T2" as follows: + + // -- If the initializer expression + // -- is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.ics.ref]p4, we don't check the bit-field property here. + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // C++ [over.ics.ref]p1: + // When a parameter of reference type binds directly (8.5.3) + // to an argument expression, the implicit conversion sequence + // is the identity conversion, unless the argument expression + // has a type that is a derived class of the parameter type, + // in which case the implicit conversion sequence is a + // derived-to-base Conversion (13.3.3.1). + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = true; + ICS.Standard.RRefBinding = false; + ICS.Standard.CopyConstructor = 0; + + // Nothing more to do: the inaccessibility/ambiguity check for + // derived-to-base conversions is suppressed when we're + // computing the implicit conversion sequence (C++ + // [over.best.ics]p2). + return ICS; + } + + // -- has a class type (i.e., T2 is a class type), where T1 is + // not reference-related to T2, and can be implicitly + // converted to an lvalue of type "cv3 T3," where "cv1 T1" + // is reference-compatible with "cv3 T3" 92) (this + // conversion is selected by enumerating the applicable + // conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && + !S.RequireCompleteType(DeclLoc, T2, 0) && + RefRelationship == Sema::Ref_Incompatible) { + CXXRecordDecl *T2RecordDecl + = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); + + OverloadCandidateSet CandidateSet(DeclLoc); + const UnresolvedSetImpl *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate + = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(D); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. + if (Conv->getConversionType()->isLValueReferenceType() && + (AllowExplicit || !Conv->isExplicit())) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, + Init, DeclType, CandidateSet); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, + DeclType, CandidateSet); + } + } + + OverloadCandidateSet::iterator Best; + switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + case OR_Success: + // C++ [over.ics.ref]p1: + // + // [...] If the parameter binds directly to the result of + // applying a conversion function to the argument + // expression, the implicit conversion sequence is a + // user-defined conversion sequence (13.3.3.1.2), with the + // second standard conversion sequence either an identity + // conversion or, if the conversion function returns an + // entity of a type that is a derived class of the parameter + // type, a derived-to-base Conversion. + if (!Best->FinalConversion.DirectBinding) + break; + + ICS.setUserDefined(); + ICS.UserDefined.Before = Best->Conversions[0].Standard; + ICS.UserDefined.After = Best->FinalConversion; + ICS.UserDefined.ConversionFunction = Best->Function; + ICS.UserDefined.EllipsisConversion = false; + assert(ICS.UserDefined.After.ReferenceBinding && + ICS.UserDefined.After.DirectBinding && + "Expected a direct reference binding!"); + return ICS; + + case OR_Ambiguous: + ICS.setAmbiguous(); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + return ICS; + + case OR_No_Viable_Function: + case OR_Deleted: + // There was no suitable conversion, or we found a deleted + // conversion; continue with other checks. + break; + } + } + + // -- Otherwise, the reference shall be to a non-volatile const + // type (i.e., cv1 shall be const), or the reference shall be an + // rvalue reference and the initializer expression shall be an rvalue. + // + // We actually handle one oddity of C++ [over.ics.ref] at this + // point, which is that, due to p2 (which short-circuits reference + // binding by only attempting a simple conversion for non-direct + // bindings) and p3's strange wording, we allow a const volatile + // reference to bind to an rvalue. Hence the check for the presence + // of "const" rather than checking for "const" being the only + // qualifier. + if (!isRValRef && !T1.isConstQualified()) + return ICS; + + // -- if T2 is a class type and + // -- the initializer expression is an rvalue and "cv1 T1" + // is reference-compatible with "cv2 T2," or + // + // -- T1 is not reference-related to T2 and the initializer + // expression can be implicitly converted to an rvalue + // of type "cv3 T3" (this conversion is selected by + // enumerating the applicable conversion functions + // (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + // + // then the reference is bound to the initializer + // expression rvalue in the first case and to the object + // that is the result of the conversion in the second case + // (or, in either case, to the appropriate base class + // subobject of the object). + // + // We're only checking the first case here, which is a direct + // binding in C++0x but not in C++03. + if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; + ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.CopyConstructor = 0; + return ICS; + } + + // -- Otherwise, a temporary of type "cv1 T1" is created and + // initialized from the initializer expression using the + // rules for a non-reference copy initialization (8.5). The + // reference is then bound to the temporary. If T1 is + // reference-related to T2, cv1 must be the same + // cv-qualification as, or greater cv-qualification than, + // cv2; otherwise, the program is ill-formed. + if (RefRelationship == Sema::Ref_Related) { + // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then + // we would be reference-compatible or reference-compatible with + // added qualification. But that wasn't the case, so the reference + // initialization fails. + return ICS; + } + + // If at least one of the types is a class type, the types are not + // related, and we aren't allowed any user conversions, the + // reference binding fails. This case is important for breaking + // recursion, since TryImplicitConversion below will attempt to + // create a temporary through the use of a copy constructor. + if (SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible && + (T1->isRecordType() || T2->isRecordType())) + return ICS; + + // C++ [over.ics.ref]p2: + // When a parameter of reference type is not bound directly to + // an argument expression, the conversion sequence is the one + // required to convert the argument expression to the + // underlying type of the reference according to + // 13.3.3.1. Conceptually, this conversion sequence corresponds + // to copy-initializing a temporary of the underlying type with + // the argument expression. Any difference in top-level + // cv-qualification is subsumed by the initialization itself + // and does not constitute a conversion. + ICS = S.TryImplicitConversion(Init, T1, SuppressUserConversions, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false); + + // Of course, that's still a reference binding. + if (ICS.isStandard()) { + ICS.Standard.ReferenceBinding = true; + ICS.Standard.RRefBinding = isRValRef; + } else if (ICS.isUserDefined()) { + ICS.UserDefined.After.ReferenceBinding = true; + ICS.UserDefined.After.RRefBinding = isRValRef; + } + return ICS; +} + /// TryCopyInitialization - Try to copy-initialize a value of type /// ToType from the expression From. Return the implicit conversion /// sequence required to pass this argument, which may be a bad /// conversion sequence (meaning that the argument cannot be passed to /// a parameter of this type). If @p SuppressUserConversions, then we -/// do not permit any user-defined conversion sequences. If @p ForceRValue, -/// then we treat @p From as an rvalue, even if it is an lvalue. -ImplicitConversionSequence -Sema::TryCopyInitialization(Expr *From, QualType ToType, - bool SuppressUserConversions, bool ForceRValue, - bool InOverloadResolution) { - if (ToType->isReferenceType()) { - ImplicitConversionSequence ICS; - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - CheckReferenceInit(From, ToType, - /*FIXME:*/From->getLocStart(), - SuppressUserConversions, - /*AllowExplicit=*/false, - ForceRValue, - &ICS); - return ICS; - } else { - return TryImplicitConversion(From, ToType, +/// do not permit any user-defined conversion sequences. +static ImplicitConversionSequence +TryCopyInitialization(Sema &S, Expr *From, QualType ToType, + bool SuppressUserConversions, + bool InOverloadResolution) { + if (ToType->isReferenceType()) + return TryReferenceInit(S, From, ToType, + /*FIXME:*/From->getLocStart(), + SuppressUserConversions, + /*AllowExplicit=*/false); + + return S.TryImplicitConversion(From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, - ForceRValue, InOverloadResolution); - } } /// TryObjectArgumentInitialization - Try to initialize the object @@ -2310,7 +2717,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, if (!Context.hasSameType(From->getType(), DestType)) ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, - /*isLvalue=*/!From->getType()->getAs<PointerType>()); + /*isLvalue=*/!From->getType()->isPointerType()); return false; } @@ -2321,7 +2728,6 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); } @@ -2343,9 +2749,6 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// candidate functions, using the given function call arguments. If /// @p SuppressUserConversions, then don't allow user-defined /// conversions via constructors or conversion operators. -/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly -/// hacky way to implement the overloading rules for elidable copy -/// initialization in C++0x (C++0x 12.8p15). /// /// \para PartialOverloading true if we are performing "partial" overloading /// based on an incomplete set of function arguments. This feature is used by @@ -2356,7 +2759,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, - bool ForceRValue, bool PartialOverloading) { const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); @@ -2375,7 +2777,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Args, NumArgs, CandidateSet, - SuppressUserConversions, ForceRValue); + SuppressUserConversions); return; } // We treat a constructor like a non-member function, since its object @@ -2445,8 +2847,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; @@ -2504,7 +2906,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, bool ForceRValue) { + bool SuppressUserConversions) { NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); @@ -2518,12 +2920,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, /*ExplicitArgs*/ 0, ObjectType, Args, NumArgs, CandidateSet, - SuppressUserConversions, - ForceRValue); + SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions, ForceRValue); + CandidateSet, SuppressUserConversions); } } @@ -2533,15 +2934,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, /// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't /// allow user-defined conversions via constructors or conversion -/// operators. If @p ForceRValue, treat all arguments as rvalues. This is -/// a slightly hacky way to implement the overloading rules for elidable copy -/// initialization in C++0x (C++0x 12.8p15). +/// operators. void Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, bool ForceRValue) { + bool SuppressUserConversions) { const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -2614,8 +3013,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -2642,8 +3041,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool ForceRValue) { + bool SuppressUserConversions) { if (!CandidateSet.isNewCandidate(MethodTmpl)) return; @@ -2674,7 +3072,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, "Specialization is not a member function?"); AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions, ForceRValue); + CandidateSet, SuppressUserConversions); } /// \brief Add a C++ function template specialization as a candidate @@ -2686,8 +3084,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool ForceRValue) { + bool SuppressUserConversions) { if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; @@ -2724,7 +3121,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet, - SuppressUserConversions, ForceRValue); + SuppressUserConversions); } /// AddConversionCandidate - Add a C++ conversion function as a @@ -2741,7 +3138,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, OverloadCandidateSet& CandidateSet) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); - + QualType ConvType = Conversion->getConversionType().getNonReferenceType(); if (!CandidateSet.isNewCandidate(Conversion)) return; @@ -2756,7 +3153,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.setFromType(Conversion->getConversionType()); + Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); // Determine the implicit conversion sequence for the implicit @@ -2789,7 +3186,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, return; } - // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to // convert to (ToType), we need to synthesize a call to the @@ -2802,7 +3198,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, From->getLocStart()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), CastExpr::CK_FunctionToPointerDecay, - &ConversionRef, false); + &ConversionRef, CXXBaseSpecifierArray(), false); // 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 @@ -2811,14 +3207,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Conversion->getConversionType().getNonReferenceType(), From->getLocStart()); ImplicitConversionSequence ICS = - TryCopyInitialization(&Call, ToType, + TryCopyInitialization(*this, &Call, ToType, /*SuppressUserConversions=*/true, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; + + // C++ [over.ics.user]p3: + // If the user-defined conversion is specified by a specialization of a + // conversion function template, the second standard conversion sequence + // shall have exact match rank. + if (Conversion->getPrimaryTemplate() && + GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_final_conversion_not_exact; + } + break; case ImplicitConversionSequence::BadConversion: @@ -2948,9 +3354,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -2966,31 +3371,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } -// FIXME: This will eventually be removed, once we've migrated all of the -// operator overloading logic over to the scheme used by binary operators, which -// works for template instantiation. -void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange) { - UnresolvedSet<16> Fns; - - QualType T1 = Args[0]->getType(); - QualType T2; - if (NumArgs > 1) - T2 = Args[1]->getType(); - - DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); - if (S) - LookupOverloadedOperatorName(Op, S, T1, T2, Fns); - AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false); - AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0, - CandidateSet); - AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); - AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); -} - /// \brief Add overload candidates for overloaded operators that are /// member functions. /// @@ -3092,9 +3472,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]); } else { Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], + = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx], ArgIdx == 0 && IsAssignmentOperator, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); } if (Candidate.Conversions[ArgIdx].isBad()) { @@ -3362,7 +3741,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { const RecordType *TyRec; if (const MemberPointerType *RHSMPType = ArgExpr->getType()->getAs<MemberPointerType>()) - TyRec = cast<RecordType>(RHSMPType->getClass()); + TyRec = RHSMPType->getClass()->getAs<RecordType>(); else TyRec = ArgExpr->getType()->getAs<RecordType>(); if (!TyRec) { @@ -4161,7 +4540,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, continue; AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, - false, false, PartialOverloading); + false, PartialOverloading); } else AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, @@ -4628,6 +5007,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: + case ovl_fail_final_conversion_not_exact: return S.NoteOverloadCandidate(Fn); case ovl_fail_bad_conversion: { @@ -4823,10 +5203,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(!Cand->Conversions[ConvIdx].isInitialized() && "remaining conversion is initialized?"); - // FIXME: these should probably be preserved from the overload + // FIXME: this should probably be preserved from the overload // operation somehow. bool SuppressUserConversions = false; - bool ForceRValue = false; const FunctionProtoType* Proto; unsigned ArgIdx = ConvIdx; @@ -4848,10 +5227,10 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(ConvCount <= 3); for (; ConvIdx != ConvCount; ++ConvIdx) Cand->Conversions[ConvIdx] - = S.TryCopyInitialization(Args[ConvIdx], - Cand->BuiltinTypes.ParamTypes[ConvIdx], - SuppressUserConversions, ForceRValue, - /*InOverloadResolution*/ true); + = TryCopyInitialization(S, Args[ConvIdx], + Cand->BuiltinTypes.ParamTypes[ConvIdx], + SuppressUserConversions, + /*InOverloadResolution*/ true); return; } @@ -4860,9 +5239,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { if (ArgIdx < NumArgsInProto) Cand->Conversions[ConvIdx] - = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx), - SuppressUserConversions, ForceRValue, - /*InOverloadResolution=*/true); + = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), + SuppressUserConversions, + /*InOverloadResolution=*/true); else Cand->Conversions[ConvIdx].setEllipsis(); } @@ -4966,15 +5345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, IsMember = true; } - // We only look at pointers or references to functions. - FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); - if (!FunctionType->isFunctionType()) - return 0; - - // Find the actual overloaded function declaration. - if (From->getType() != Context.OverloadTy) - return 0; - // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -4987,6 +5357,18 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); ExplicitTemplateArgs = &ETABuffer; } + + // We expect a pointer or reference to function, or a function pointer. + FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); + if (!FunctionType->isFunctionType()) { + if (Complain) + Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref) + << OvlExpr->getName() << ToType; + + return 0; + } + + assert(From->getType() == Context.OverloadTy); // Look through all of the overloaded functions, searching for one // whose type matches exactly. @@ -5068,9 +5450,19 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // If there were 0 or 1 matches, we're done. - if (Matches.empty()) + if (Matches.empty()) { + if (Complain) { + Diag(From->getLocStart(), diag::err_addr_ovl_no_viable) + << OvlExpr->getName() << FunctionType; + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); + I != E; ++I) + if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) + NoteOverloadCandidate(F); + } + return 0; - else if (Matches.size() == 1) { + } else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); @@ -5223,7 +5615,7 @@ static void AddOverloadedCallCandidate(Sema &S, if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { assert(!ExplicitTemplateArgs && "Explicit template arguments?"); S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet, - false, false, PartialOverloading); + false, PartialOverloading); return; } @@ -5310,7 +5702,7 @@ static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn, /// /// Returns true if new candidates were found. static Sema::OwningExprResult -BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, +BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -5332,7 +5724,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R)) + if (SemaRef.DiagnoseEmptyLookup(S, SS, R)) return Destroy(SemaRef, Fn, Args, NumArgs); assert(!R.empty() && "lookup results empty despite recovery"); @@ -5368,7 +5760,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, /// resolution. Otherwise, emits diagnostics, deletes all of the /// arguments and Fn, and returns NULL. Sema::OwningExprResult -Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, +Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -5401,7 +5793,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, // AddRecoveryCallCandidates diagnoses the error itself, so we just // bailout out if it fails. if (CandidateSet.empty()) - return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs, + return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); OverloadCandidateSet::iterator Best; @@ -6003,7 +6395,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemberExpr *MemExpr; CXXMethodDecl *Method = 0; - NamedDecl *FoundDecl = 0; + DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); NestedNameSpecifier *Qualifier = 0; if (isa<MemberExpr>(NakedMemExpr)) { MemExpr = cast<MemberExpr>(NakedMemExpr); @@ -6281,7 +6673,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), - CommaLocs, RParenLoc).release(); + CommaLocs, RParenLoc).result(); } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); @@ -6385,7 +6777,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (CheckFunctionCall(Method, TheCall.get())) return true; - return MaybeBindToTemporary(TheCall.release()).release(); + return MaybeBindToTemporary(TheCall.release()).result(); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> @@ -6486,7 +6878,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, +Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), @@ -6508,7 +6900,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, return new (Context) ImplicitCastExpr(ICE->getType(), ICE->getCastKind(), - SubExpr, + SubExpr, CXXBaseSpecifierArray(), ICE->isLvalueCast()); } @@ -6619,7 +7011,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, } Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, - NamedDecl *Found, + DeclAccessPair Found, FunctionDecl *Fn) { return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index cff4774..5e61111 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -34,7 +34,7 @@ namespace clang { OR_Success, ///< Overload resolution succeeded. OR_No_Viable_Function, ///< No viable function found. OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. + OR_Deleted ///< Succeeded, but refers to a deleted function. }; /// ImplicitConversionKind - The kind of implicit conversion used to @@ -381,6 +381,33 @@ namespace clang { assert(isInitialized() && "querying uninitialized conversion"); return Kind(ConversionKind); } + + /// \brief Return a ranking of the implicit conversion sequence + /// kind, where smaller ranks represent better conversion + /// sequences. + /// + /// In particular, this routine gives user-defined conversion + /// sequences and ambiguous conversion sequences the same rank, + /// per C++ [over.best.ics]p10. + unsigned getKindRank() const { + switch (getKind()) { + case StandardConversion: + return 0; + + case UserDefinedConversion: + case AmbiguousConversion: + return 1; + + case EllipsisConversion: + return 2; + + case BadConversion: + return 3; + } + + return 3; + } + bool isBad() const { return getKind() == BadConversion; } bool isStandard() const { return getKind() == StandardConversion; } bool isEllipsis() const { return getKind() == EllipsisConversion; } @@ -440,7 +467,11 @@ namespace clang { /// This conversion candidate is not viable because its result /// type is not implicitly convertible to the desired type. - ovl_fail_bad_final_conversion + ovl_fail_bad_final_conversion, + + /// This conversion function template specialization candidate is not + /// viable because the final conversion was not an exact match. + ovl_fail_final_conversion_not_exact }; /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 791de8c..9d6132d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" @@ -125,7 +126,27 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; return; } + } else if (const CXXFunctionalCastExpr *FC + = dyn_cast<CXXFunctionalCastExpr>(E)) { + if (isa<CXXConstructExpr>(FC->getSubExpr()) || + isa<CXXTemporaryObjectExpr>(FC->getSubExpr())) + return; + } + // Diagnose "(void*) blah" as a typo for "(void) blah". + else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) { + TypeSourceInfo *TI = CE->getTypeInfoAsWritten(); + QualType T = TI->getType(); + + // We really do want to use the non-canonical type here. + if (T == Context.VoidPtrTy) { + PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc()); + + Diag(Loc, diag::warn_unused_voidptr) + << FixItHint::CreateRemoval(TL.getStarLoc()); + return; + } } + Diag(Loc, DiagID) << R1 << R2; } @@ -572,7 +593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, return StmtError(); } - if (CondTypeBeforePromotion->isBooleanType()) { + if (CondExpr->isKnownToHaveBooleanValue()) { // switch(bool_expr) {...} is often a programmer error, e.g. // switch(n && mask) { ... } // Doh - should be "n & mask". // One can always use an if statement instead of switch(bool_expr). @@ -967,19 +988,22 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag(VD->getLocation(), diag::err_non_variable_decl_in_for)); } else { - if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid) + Expr *FirstE = cast<Expr>(First); + if (!FirstE->isTypeDependent() && + FirstE->isLvalue(Context) != Expr::LV_Valid) return StmtError(Diag(First->getLocStart(), diag::err_selector_element_not_lvalue) << First->getSourceRange()); FirstType = static_cast<Expr*>(First)->getType(); } - if (!FirstType->isObjCObjectPointerType() && + if (!FirstType->isDependentType() && + !FirstType->isObjCObjectPointerType() && !FirstType->isBlockPointerType()) Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second) { + if (Second && !Second->isTypeDependent()) { DefaultFunctionArrayLvalueConversion(Second); QualType SecondType = Second->getType(); if (!SecondType->isObjCObjectPointerType()) @@ -1422,53 +1446,72 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. - // Int/ptr operands have some special cases that we allow. - if ((OutTy->isIntegerType() || OutTy->isPointerType()) && - (InTy->isIntegerType() || InTy->isPointerType())) { - - // They are ok if they are the same size. Tying void* to int is ok if - // they are the same size, for example. This also allows tying void* to - // int*. - uint64_t OutSize = Context.getTypeSize(OutTy); - uint64_t InSize = Context.getTypeSize(InTy); - if (OutSize == InSize) - continue; - - // If the smaller input/output operand is not mentioned in the asm string, - // then we can promote it and the asm string won't notice. Check this - // case now. - bool SmallerValueMentioned = false; - for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { - AsmStmt::AsmStringPiece &Piece = Pieces[p]; - if (!Piece.isOperand()) continue; - - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (Piece.getOperandNo() == i+NumOutputs) { - if (InSize < OutSize) { - SmallerValueMentioned = true; - break; - } - } + // Decide if the input and output are in the same domain (integer/ptr or + // floating point. + enum AsmDomain { + AD_Int, AD_FP, AD_Other + } InputDomain, OutputDomain; + + if (InTy->isIntegerType() || InTy->isPointerType()) + InputDomain = AD_Int; + else if (InTy->isFloatingType()) + InputDomain = AD_FP; + else + InputDomain = AD_Other; - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (Piece.getOperandNo() == TiedTo) { - if (InSize > OutSize) { - SmallerValueMentioned = true; - break; - } + if (OutTy->isIntegerType() || OutTy->isPointerType()) + OutputDomain = AD_Int; + else if (OutTy->isFloatingType()) + OutputDomain = AD_FP; + else + OutputDomain = AD_Other; + + // They are ok if they are the same size and in the same domain. This + // allows tying things like: + // void* to int* + // void* to int if they are the same size. + // double to long double if they are the same size. + // + uint64_t OutSize = Context.getTypeSize(OutTy); + uint64_t InSize = Context.getTypeSize(InTy); + if (OutSize == InSize && InputDomain == OutputDomain && + InputDomain != AD_Other) + continue; + + // If the smaller input/output operand is not mentioned in the asm string, + // then we can promote it and the asm string won't notice. Check this + // case now. + bool SmallerValueMentioned = false; + for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { + AsmStmt::AsmStringPiece &Piece = Pieces[p]; + if (!Piece.isOperand()) continue; + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == i+NumOutputs) { + if (InSize < OutSize) { + SmallerValueMentioned = true; + break; } } - // If the smaller value wasn't mentioned in the asm string, and if the - // output was a register, just extend the shorter one to the size of the - // larger one. - if (!SmallerValueMentioned && - OutputConstraintInfos[TiedTo].allowsRegister()) - continue; + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == TiedTo) { + if (InSize > OutSize) { + SmallerValueMentioned = true; + break; + } + } } + // If the smaller value wasn't mentioned in the asm string, and if the + // output was a register, just extend the shorter one to the size of the + // larger one. + if (!SmallerValueMentioned && InputDomain != AD_Other && + OutputConstraintInfos[TiedTo].allowsRegister()) + continue; + Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() @@ -1483,27 +1526,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, Action::OwningStmtResult Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, DeclPtrTy Parm, - StmtArg Body, StmtArg catchList) { - Stmt *CatchList = catchList.takeAs<Stmt>(); - ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>()); - - // PVD == 0 implies @catch(...). - if (PVD) { - // If we already know the decl is invalid, reject it. - if (PVD->isInvalidDecl()) - return StmtError(); - - if (!PVD->getType()->isObjCObjectPointerType()) - return StmtError(Diag(PVD->getLocation(), - diag::err_catch_param_not_objc_type)); - if (PVD->getType()->isObjCQualifiedIdType()) - return StmtError(Diag(PVD->getLocation(), - diag::err_illegal_qualifiers_on_catch_parm)); - } - - ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen, - PVD, Body.takeAs<Stmt>(), CatchList); - return Owned(CatchList ? CatchList : CS); + StmtArg Body) { + VarDecl *Var = cast_or_null<VarDecl>(Parm.getAs<Decl>()); + if (Var && Var->isInvalidDecl()) + return StmtError(); + + return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, + Body.takeAs<Stmt>())); } Action::OwningStmtResult @@ -1513,18 +1542,38 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { } Action::OwningStmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, StmtArg Catch, StmtArg Finally) { +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, + MultiStmtArg CatchStmts, StmtArg Finally) { FunctionNeedsScopeChecking() = true; - return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(), - Catch.takeAs<Stmt>(), - Finally.takeAs<Stmt>())); + unsigned NumCatchStmts = CatchStmts.size(); + return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(), + (Stmt **)CatchStmts.release(), + NumCatchStmts, + Finally.takeAs<Stmt>())); +} + +Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg ThrowE) { + Expr *Throw = static_cast<Expr *>(ThrowE.get()); + if (Throw) { + QualType ThrowType = Throw->getType(); + // Make sure the expression type is an ObjC pointer or "void *". + if (!ThrowType->isDependentType() && + !ThrowType->isObjCObjectPointerType()) { + const PointerType *PT = ThrowType->getAs<PointerType>(); + if (!PT || !PT->getPointeeType()->isVoidType()) + return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) + << Throw->getType() << Throw->getSourceRange()); + } + } + + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>())); } Action::OwningStmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { - Expr *ThrowExpr = expr.takeAs<Expr>(); - if (!ThrowExpr) { +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, + Scope *CurScope) { + if (!Throw.get()) { // @throw without an expression designates a rethrow (which much occur // in the context of an @catch clause). Scope *AtCatchParent = CurScope; @@ -1532,17 +1581,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); - } else { - QualType ThrowType = ThrowExpr->getType(); - // Make sure the expression type is an ObjC pointer or "void *". - if (!ThrowType->isObjCObjectPointerType()) { - const PointerType *PT = ThrowType->getAs<PointerType>(); - if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) - << ThrowExpr->getType() << ThrowExpr->getSourceRange()); - } - } - return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr)); + } + + return BuildObjCAtThrowStmt(AtLoc, move(Throw)); } Action::OwningStmtResult @@ -1552,7 +1593,8 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, // Make sure the expression type is an ObjC pointer or "void *". Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get()); - if (!SyncExpr->getType()->isObjCObjectPointerType()) { + if (!SyncExpr->getType()->isDependentType() && + !SyncExpr->getType()->isObjCObjectPointerType()) { const PointerType *PT = SyncExpr->getType()->getAs<PointerType>(); if (!PT || !PT->getPointeeType()->isVoidType()) return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 40ec4bcb..694b21c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -63,20 +63,40 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { } static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { + // The set of class templates we've already seen. + llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl()); if (!Repl) filter.erase(); - else if (Repl != Orig) + else if (Repl != Orig) { + + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in an + // ambiguity in certain cases (for example, if it is found in more than + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not + // ambiguous. + // + // FIXME: Will we eventually have to do the same for alias templates? + if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) + if (!ClassTemplates.insert(ClassTmpl)) { + filter.erase(); + continue; + } + filter.replace(Repl); + } } filter.done(); } TemplateNameKind Sema::isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, @@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupOrdinaryName); R.suppressDiagnostics(); LookupTemplateName(R, S, SS, ObjectType, EnteringContext); - if (R.empty()) + if (R.empty() || R.isAmbiguous()) return TNK_Non_template; TemplateName Template; @@ -169,7 +189,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, } void Sema::LookupTemplateName(LookupResult &Found, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext) { // Determine where to perform name lookup @@ -190,7 +210,7 @@ void Sema::LookupTemplateName(LookupResult &Found, isDependent = isDependentScopeSpecifier(SS); // The declaration context must be complete. - if (LookupCtx && RequireCompleteDeclContext(SS)) + if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return; } @@ -227,14 +247,11 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupName(Found, S); } - // FIXME: Cope with ambiguous name-lookup results. - assert(!Found.isAmbiguous() && - "Cannot handle template name-lookup ambiguities"); - if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (CorrectTypo(Found, S, &SS, LookupCtx)) { + if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, + false, CTC_CXXCasts)) { FilterAcceptableTemplateNames(Context, Found); if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) { if (LookupCtx) @@ -271,8 +288,7 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupOrdinaryName); LookupName(FoundOuter, S); FilterAcceptableTemplateNames(Context, FoundOuter); - // FIXME: Handle ambiguities in this lookup better - + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise @@ -439,7 +455,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, bool Invalid = false; if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc, + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, PrevDecl); @@ -560,7 +578,9 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdentifierInfo *ParamName = D.getIdentifier(); if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -705,7 +725,7 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { Sema::DeclResult Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, @@ -733,25 +753,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, ForRedeclaration); if (SS.isNotEmpty() && !SS.isInvalid()) { - if (RequireCompleteDeclContext(SS)) - return true; - SemanticContext = computeDeclContext(SS, true); if (!SemanticContext) { // FIXME: Produce a reasonable diagnostic here return true; } + if (RequireCompleteDeclContext(SS, SemanticContext)) + return true; + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; LookupName(Previous, S); } - assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); + if (Previous.isAmbiguous()) + return true; + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) - PrevDecl = *Previous.begin(); + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. @@ -779,22 +801,24 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // declared as a friend, and when the name of the friend class or // function is neither a qualified name nor a template-id, scopes outside // the innermost enclosing namespace scope are not considered. - DeclContext *OutermostContext = CurContext; - while (!OutermostContext->isFileContext()) - OutermostContext = OutermostContext->getLookupParent(); - - if (PrevDecl && - (OutermostContext->Equals(PrevDecl->getDeclContext()) || - OutermostContext->Encloses(PrevDecl->getDeclContext()))) { - SemanticContext = PrevDecl->getDeclContext(); - } else { - // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semantic context for our new - // declaration. - PrevDecl = PrevClassTemplate = 0; - SemanticContext = OutermostContext; + if (!SS.isSet()) { + DeclContext *OutermostContext = CurContext; + while (!OutermostContext->isFileContext()) + OutermostContext = OutermostContext->getLookupParent(); + + if (PrevDecl && + (OutermostContext->Equals(PrevDecl->getDeclContext()) || + OutermostContext->Encloses(PrevDecl->getDeclContext()))) { + SemanticContext = PrevDecl->getDeclContext(); + } else { + // Declarations in outer scopes don't matter. However, the outermost + // context we computed is the semantic context for our new + // declaration. + PrevDecl = PrevClassTemplate = 0; + SemanticContext = OutermostContext; + } } - + if (CurContext->isDependentContext()) { // If this is a dependent context, we don't want to link the friend // class template to the template in scope, because that would perform @@ -804,7 +828,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -861,9 +885,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, TPC_ClassTemplate)) Invalid = true; - // FIXME: If we had a scope specifier, we better have a previous template - // declaration! - + if (SS.isSet()) { + // If the name of the template was qualified, we must be defining the + // template out-of-line. + if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && + !(TUK == TUK_Friend && CurContext->isDependentContext())) + Diag(NameLoc, diag::err_member_def_does_not_match) + << Name << SemanticContext << SS.getRange(); + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -1206,6 +1236,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, /// /// \param NumParamLists the number of template parameter lists in ParamLists. /// +/// \param IsFriend Whether to apply the slightly different rules for +/// matching template parameters to scope specifiers in friend +/// declarations. +/// /// \param IsExplicitSpecialization will be set true if the entity being /// declared is an explicit specialization, false otherwise. /// @@ -1220,6 +1254,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization) { IsExplicitSpecialization = false; @@ -1285,6 +1320,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (Idx >= NumParamLists) { // We have a template-id without a corresponding template parameter // list. + + // ...which is fine if this is a friend declaration. + if (IsFriend) { + IsExplicitSpecialization = true; + break; + } + if (DependentTemplateId) { // FIXME: the location information here isn't great. Diag(SS.getRange().getBegin(), @@ -1302,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // Check the template parameter list against its corresponding template-id. if (DependentTemplateId) { - TemplateDecl *Template - = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); - - if (ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>(Template)) { - TemplateParameterList *ExpectedTemplateParams = 0; - // Is this template-id naming the primary template? - if (Context.hasSameType(TemplateId, - ClassTemplate->getInjectedClassNameSpecialization(Context))) - ExpectedTemplateParams = ClassTemplate->getTemplateParameters(); - // ... or a partial specialization? - else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(TemplateId)) - ExpectedTemplateParams = PartialSpec->getTemplateParameters(); - - if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[Idx], - ExpectedTemplateParams, - true, TPL_TemplateMatch); + TemplateParameterList *ExpectedTemplateParams = 0; + + // Are there cases in (e.g.) friends where this won't match? + if (const InjectedClassNameType *Injected + = TemplateId->getAs<InjectedClassNameType>()) { + CXXRecordDecl *Record = Injected->getDecl(); + if (ClassTemplatePartialSpecializationDecl *Partial = + dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) + ExpectedTemplateParams = Partial->getTemplateParameters(); + else + ExpectedTemplateParams = Record->getDescribedClassTemplate() + ->getTemplateParameters(); } + if (ExpectedTemplateParams) + TemplateParameterListsAreEqual(ParamLists[Idx], + ExpectedTemplateParams, + true, TPL_TemplateMatch); + CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember); } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), @@ -1388,6 +1428,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, "Converted template argument list is too short!"); QualType CanonType; + bool IsCurrentInstantiation = false; if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( @@ -1409,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // In the future, we need to teach getTemplateSpecializationType to only // build the canonical type and return that to us. CanonType = Context.getCanonicalType(CanonType); + + // This might work out to be a current instantiation, in which + // case the canonical type needs to be the InjectedClassNameType. + // + // TODO: in theory this could be a simple hashtable lookup; most + // changes to CurContext don't change the set of current + // instantiations. + if (isa<ClassTemplateDecl>(Template)) { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { + // If we get out to a namespace, we're done. + if (Ctx->isFileContext()) break; + + // If this isn't a record, keep looking. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) continue; + + // Look for one of the two cases with InjectedClassNameTypes + // and check whether it's the same template. + if (!isa<ClassTemplatePartialSpecializationDecl>(Record) && + !Record->getDescribedClassTemplate()) + continue; + + // Fetch the injected class name type and check whether its + // injected type is equal to the type we just built. + QualType ICNT = Context.getTypeDeclType(Record); + QualType Injected = cast<InjectedClassNameType>(ICNT) + ->getInjectedSpecializationType(); + + if (CanonType != Injected->getCanonicalTypeInternal()) + continue; + + // If so, the canonical type of this TST is the injected + // class name type of the record we just found. + assert(ICNT.isCanonical()); + CanonType = ICNT; + IsCurrentInstantiation = true; + break; + } + } } else if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that @@ -1442,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType, + IsCurrentInstantiation); } Action::TypeResult @@ -1545,14 +1626,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // We actually only call this from template instantiation. Sema::OwningExprResult -Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, +Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &TemplateArgs) { DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext() || - RequireCompleteDeclContext(SS)) + RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); @@ -1586,7 +1667,7 @@ Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, /// of the "template" keyword, and "apply" is the \p Name. Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { @@ -1663,11 +1744,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. - if (Arg.getKind() != TemplateArgument::Type) { + switch(Arg.getKind()) { + case TemplateArgument::Type: // C++ [temp.arg.type]p1: // A template-argument for a template-parameter which is a // type shall be a type-id. + break; + case TemplateArgument::Template: { + // We have a template type parameter but the template argument + // is a template without any arguments. + SourceRange SR = AL.getSourceRange(); + TemplateName Name = Arg.getAsTemplate(); + Diag(SR.getBegin(), diag::err_template_missing_args) + << Name << SR; + if (TemplateDecl *Decl = Name.getAsTemplateDecl()) + Diag(Decl->getLocation(), diag::note_template_decl_here); + return true; + } + default: { // We have a template type parameter but the template argument // is not a type. SourceRange SR = AL.getSourceRange(); @@ -1676,6 +1771,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } + } if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; @@ -2317,14 +2413,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, DRE = dyn_cast<DeclRefExpr>(Arg); if (!DRE) { - if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) { - S.Diag(Arg->getLocStart(), - diag::err_template_arg_unresolved_overloaded_function) - << ParamType << Arg->getSourceRange(); - } else { - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); - } + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -2525,6 +2615,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Create the template argument. Converted = TemplateArgument(Entity->getCanonicalDecl()); + S.MarkDeclarationReferenced(Arg->getLocStart(), Entity); return false; } @@ -2797,16 +2888,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ParamType->getAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + if (!ParamType->isMemberPointerType()) return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, @@ -2851,17 +2945,20 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, - ParamRefType->getPointeeType(), - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); @@ -2964,9 +3061,21 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, return ExprError(); RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + + // 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. + if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), + ParamType.getUnqualifiedType())) { + Expr *RefE = RefExpr.takeAs<Expr>(); + ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), + CastExpr::CK_NoOp); + RefExpr = Owned(RefE); + } + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), - ParamType)); + ParamType.getUnqualifiedType())); return move(RefExpr); } } @@ -3467,7 +3576,7 @@ Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -3500,6 +3609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization); if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -3683,6 +3793,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); + unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber() + : ClassTemplate->getPartialSpecializations().size(); ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), @@ -3692,7 +3804,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted, TemplateArgs, CanonType, - PrevPartial); + PrevPartial, + SequenceNumber); SetNestedNameSpecifier(Partial, SS); if (PrevPartial) { @@ -4032,7 +4145,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // instantiation has no effect. // // In C++98/03 mode, we only give an extension warning here, because it - // is not not harmful to try to explicitly instantiate something that + // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. if (!getLangOptions().CPlusPlus0x) { Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) @@ -4068,6 +4181,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } +/// \brief Perform semantic analysis for the given dependent function +/// template specialization. The only possible way to get a dependent +/// function template specialization is with a friend declaration, +/// like so: +/// +/// template <class T> void foo(T); +/// template <class T> class A { +/// friend void foo<>(T); +/// }; +/// +/// There really isn't any useful analysis we can do here, so we +/// just store the information. +bool +Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous) { + // Remove anything from Previous that isn't a function template in + // the correct context. + DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next()->getUnderlyingDecl(); + if (!isa<FunctionTemplateDecl>(D) || + !FDLookupContext->Equals(D->getDeclContext()->getLookupContext())) + F.erase(); + } + F.done(); + + // Should this be diagnosed here? + if (Previous.empty()) return true; + + FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(), + ExplicitTemplateArgs); + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -4153,6 +4302,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + Specialization->setLocation(FD->getLocation()); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -4227,7 +4377,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); - + // Try to find the member we are instantiating. NamedDecl *Instantiation = 0; NamedDecl *InstantiatedFrom = 0; @@ -4273,6 +4423,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // this mismatch later. return false; } + + // If this is a friend, just bail out here before we start turning + // things into explicit specializations. + if (Member->getFriendObjectKind() != Decl::FOK_None) { + // Preserve instantiation information. + if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) { + cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), + cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind()); + } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) { + cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), + cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind()); + } + + Previous.clear(); + Previous.addDecl(Instantiation); + return false; + } // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { @@ -4612,7 +4781,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr) { @@ -5001,9 +5170,30 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } assert(Keyword != ETK_None && "Invalid tag kind!"); + if (TUK == TUK_Declaration || TUK == TUK_Definition) { + Diag(NameLoc, diag::err_dependent_tag_decl) + << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) + << SS.getRange(); + return true; + } + return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); } +static void FillTypeLoc(DependentNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + +static void FillTypeLoc(QualifiedNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { @@ -5012,10 +5202,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (!NNS) return true; - QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); + QualType T = CheckTypenameType(ETK_Typename, NNS, II, + SourceRange(TypenameLoc, IdLoc)); if (T.isNull()) return true; - return T.getAsOpaquePtr(); + + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } else { + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } + + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } Sema::TypeResult @@ -5034,48 +5237,49 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, // track of the nested-name-specifier. // FIXME: Note that the QualifiedNameType had the "typename" keyword! - return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); + + T = Context.getQualifiedNameType(NNS, T); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } - return Context.getDependentNameType(ETK_Typename, NNS, TemplateId) - .getAsOpaquePtr(); + T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range) { - CXXRecordDecl *CurrentInstantiation = 0; - if (NNS->isDependent()) { - CurrentInstantiation = getCurrentInstantiationOf(NNS); - - // If the nested-name-specifier does not refer to the current - // instantiation, then build a typename type. - if (!CurrentInstantiation) - return Context.getDependentNameType(ETK_Typename, NNS, &II); - - // The nested-name-specifier refers to the current instantiation, so the - // "typename" keyword itself is superfluous. In C++03, the program is - // actually ill-formed. However, DR 382 (in C++0x CD1) allows such - // extraneous "typename" keywords, and we retroactively apply this DR to - // C++03 code. + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + + DeclContext *Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(NNS->isDependent()); + return Context.getDependentNameType(Keyword, NNS, &II); } - DeclContext *Ctx = 0; + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code. In any case we continue. - if (CurrentInstantiation) - Ctx = CurrentInstantiation; - else { - CXXScopeSpec SS; - SS.setScopeRep(NNS); - SS.setRange(Range); - if (RequireCompleteDeclContext(SS)) - return QualType(); - - Ctx = computeDeclContext(SS); - } - assert(Ctx && "No declaration context?"); + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); DeclarationName Name(&II); LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); @@ -5089,7 +5293,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(ETK_Typename, NNS, &II); + return Context.getDependentNameType(Keyword, NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { @@ -5133,6 +5337,8 @@ namespace { DeclarationName Entity; public: + typedef TreeTransform<CurrentInstantiationRebuilder> inherited; + CurrentInstantiationRebuilder(Sema &SemaRef, SourceLocation Loc, DeclarationName Entity) @@ -5168,7 +5374,7 @@ namespace { /// FIXME: This is completely unsafe; we will need to actually clone the /// expressions. Sema::OwningExprResult TransformExpr(Expr *E) { - return getSema().Owned(E); + return getSema().Owned(E->Retain()); } /// \brief Transforms a typename type by determining whether the type now @@ -5256,15 +5462,30 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, /// in X<T> and returning a QualifiedNameType whose canonical type is the same /// as the canonical type of T*, allowing the return types of the out-of-line /// definition and the declaration to match. -QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, - DeclarationName Name) { - if (T.isNull() || !T->isDependentType()) +TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name) { + if (!T || !T->getType()->isDependentType()) return T; CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name); return Rebuilder.TransformType(T); } +bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { + if (SS.isInvalid()) return true; + + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), + DeclarationName()); + NestedNameSpecifier *Rebuilt = + Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); + if (!Rebuilt) return true; + + SS.setScopeRep(Rebuilt); + return false; +} + /// \brief Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string @@ -5344,8 +5565,15 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } case TemplateArgument::Expression: { - assert(false && "No expressions in deduced template arguments!"); - Result += "<expression>"; + // FIXME: This is non-optimal, since we're regurgitating the + // expression we were given. + std::string Str; + { + llvm::raw_string_ostream OS(Str); + Args[I].getAsExpr()->printPretty(OS, Context, 0, + Context.PrintingPolicy); + } + Result += Str; break; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index d61a767..2bb97eb 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -638,7 +638,8 @@ DeduceTemplateArguments(Sema &S, case Type::InjectedClassName: { // Treat a template's injected-class-name as if the template // specialization type had been used. - Param = cast<InjectedClassNameType>(Param)->getUnderlyingType(); + Param = cast<InjectedClassNameType>(Param) + ->getInjectedSpecializationType(); assert(isa<TemplateSpecializationType>(Param) && "injected class name is not a template specialization type"); // fall through @@ -960,32 +961,18 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); } -/// \brief Perform template argument deduction to determine whether -/// the given template arguments match the given class template -/// partial specialization per C++ [temp.class.spec.match]. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs, - TemplateDeductionInfo &Info) { - // C++ [temp.class.spec.match]p2: - // A partial specialization matches a given actual template - // argument list if the template arguments of the partial - // specialization can be deduced from the actual template argument - // list (14.8.2). - SFINAETrap Trap(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; - Deduced.resize(Partial->getTemplateParameters()->size()); - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, - Partial->getTemplateParameters(), - Partial->getTemplateArgs(), - TemplateArgs, Info, Deduced)) - return Result; - - InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, - Deduced.data(), Deduced.size()); - if (Inst) - return TDK_InstantiationDepth; +/// Complete template argument deduction for a class template partial +/// specialization. +static Sema::TemplateDeductionResult +FinishTemplateArgumentDeduction(Sema &S, + ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + Sema::TemplateDeductionInfo &Info) { + // Trap errors. + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, Partial); // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor @@ -995,18 +982,19 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { if (Deduced[I].isNull()) { Decl *Param - = const_cast<NamedDecl *>( + = const_cast<NamedDecl *>( Partial->getTemplateParameters()->getParam(I)); Info.Param = makeTemplateParameter(Param); - return TDK_Incomplete; + return Sema::TDK_Incomplete; } - + Builder.Append(Deduced[I]); } - + // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + = new (S.Context) TemplateArgumentList(S.Context, Builder, + /*TakeArgs=*/true); Info.reset(DeducedArgumentList); // Substitute the deduced template arguments into the template @@ -1016,7 +1004,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // to the class template. // FIXME: Do we have to correct the types of deduced non-type template // arguments (in particular, integral non-type template arguments?). - Sema::LocalInstantiationScope InstScope(*this); + Sema::LocalInstantiationScope InstScope(S); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); @@ -1029,11 +1017,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Decl *Param = const_cast<NamedDecl *>( ClassTemplate->getTemplateParameters()->getParam(I)); TemplateArgumentLoc InstArg; - if (Subst(PartialTemplateArgs[I], InstArg, - MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + if (S.Subst(PartialTemplateArgs[I], InstArg, + MultiLevelTemplateArgumentList(*DeducedArgumentList))) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I].getArgument(); - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } InstArgs.addArgument(InstArg); } @@ -1041,10 +1029,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, TemplateArgumentListBuilder ConvertedInstArgs( ClassTemplate->getTemplateParameters(), N); - if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), + if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), InstArgs, false, ConvertedInstArgs)) { // FIXME: fail with more useful information? - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { @@ -1060,26 +1048,60 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Expr *InstExpr = InstArg.getAsExpr(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { + if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Partial->getTemplateArgs()[I]; - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } } } - if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) { + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; - return TDK_NonDeducedMismatch; + return Sema::TDK_NonDeducedMismatch; } } if (Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; - return TDK_Success; + return Sema::TDK_Success; +} + +/// \brief Perform template argument deduction to determine whether +/// the given template arguments match the given class template +/// partial specialization per C++ [temp.class.spec.match]. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info) { + // C++ [temp.class.spec.match]p2: + // A partial specialization matches a given actual template + // argument list if the template arguments of the partial + // specialization can be deduced from the actual template argument + // list (14.8.2). + SFINAETrap Trap(*this); + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(*this, + Partial->getTemplateParameters(), + Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) + return Result; + + InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, + Deduced.data(), Deduced.size()); + if (Inst) + return TDK_InstantiationDepth; + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + Deduced, Info); } /// \brief Determine whether the given type T is a simple-template-id type. @@ -1162,6 +1184,8 @@ Sema::SubstituteExplicitTemplateArguments( if (Inst) return TDK_InstantiationDepth; + ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); + if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), ExplicitTemplateArgs, @@ -1310,6 +1334,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (Inst) return TDK_InstantiationDepth; + ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); + // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. @@ -1416,9 +1442,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. + DeclContext *Owner = FunctionTemplate->getDeclContext(); + if (FunctionTemplate->getFriendObjectKind()) + Owner = FunctionTemplate->getLexicalDeclContext(); Specialization = cast_or_null<FunctionDecl>( - SubstDecl(FunctionTemplate->getTemplatedDecl(), - FunctionTemplate->getDeclContext(), + SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, MultiLevelTemplateArgumentList(*DeducedArgumentList))); if (!Specialization) return TDK_SubstitutionFailure; @@ -2332,35 +2360,49 @@ Sema::getMoreSpecializedPartialSpecialization( // whose type is a class template specialization with the template // arguments of the second partial specialization. // - // Rather than synthesize function templates, we merely perform the - // equivalent partial ordering by performing deduction directly on the - // template arguments of the class template partial specializations. This - // computation is slightly simpler than the general problem of function - // template partial ordering, because class template partial specializations - // are more constrained. We know that every template parameter is deduc + // Rather than synthesize function templates, we merely perform the + // equivalent partial ordering by performing deduction directly on + // the template arguments of the class template partial + // specializations. This computation is slightly simpler than the + // general problem of function template partial ordering, because + // class template partial specializations are more constrained. We + // know that every template parameter is deducible from the class + // template partial specialization's template arguments, for + // example. llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Sema::TemplateDeductionInfo Info(Context, Loc); + + QualType PT1 = PS1->getInjectedSpecializationType(); + QualType PT2 = PS2->getInjectedSpecializationType(); // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS2->getTemplateParameters(), - Context.getTypeDeclType(PS2), - Context.getTypeDeclType(PS1), + PT2, + PT1, Info, Deduced, 0); - + if (Better1) + Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, + PS1->getTemplateArgs(), + Deduced, Info); + // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS1->getTemplateParameters(), - Context.getTypeDeclType(PS1), - Context.getTypeDeclType(PS2), + PT1, + PT2, Info, Deduced, 0); + if (Better2) + Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, + PS2->getTemplateArgs(), + Deduced, Info); if (Better1 == Better2) return 0; @@ -2537,6 +2579,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, break; } + case Type::InjectedClassName: + T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); + // fall through + case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec = cast<TemplateSpecializationType>(T); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d21862b..14bd243 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -38,10 +38,16 @@ using namespace clang; /// arguments relative to the primary template, even when we're /// dealing with a specialization. This is only relevant for function /// template specializations. +/// +/// \param Pattern If non-NULL, indicates the pattern from which we will be +/// instantiating the definition of the given declaration, \p D. This is +/// used to determine the proper set of template instantiation arguments for +/// friend function template specializations. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary) { + bool RelativeToPrimary, + const FunctionDecl *Pattern) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -89,9 +95,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // If this is a friend declaration and it declares an entity at // namespace scope, take arguments from its lexical parent - // instead of its semantic parent. + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! if (Function->getFriendObjectKind() && - Function->getDeclContext()->isFileContext()) { + Function->getDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { Ctx = Function->getLexicalDeclContext(); RelativeToPrimary = false; continue; @@ -339,12 +347,32 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( /// \brief Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { + // Determine which template instantiations to skip, if any. + unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart; + unsigned Limit = Diags.getTemplateBacktraceLimit(); + if (Limit && Limit < ActiveTemplateInstantiations.size()) { + SkipStart = Limit / 2 + Limit % 2; + SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2; + } + // FIXME: In all of these cases, we need to show the template arguments + unsigned InstantiationIdx = 0; for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; - ++Active) { + ++Active, ++InstantiationIdx) { + // Skip this instantiation? + if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) { + if (InstantiationIdx == SkipStart) { + // Note that we're skipping instantiations. + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_instantiation_contexts_suppressed) + << unsigned(ActiveTemplateInstantiations.size() - Limit); + } + continue; + } + switch (Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: { Decl *D = reinterpret_cast<Decl *>(Active->Entity); @@ -512,8 +540,7 @@ bool Sema::isSFINAEContext() const { // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { - class TemplateInstantiator - : public TreeTransform<TemplateInstantiator> { + class TemplateInstantiator : public TreeTransform<TemplateInstantiator> { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; @@ -569,6 +596,11 @@ namespace { IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); + /// \brief Rebuild the Objective-C exception declaration and register the + /// declaration as an instantiated local. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, QualType T); + /// \brief Check for tag mismatches when instantiating an /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); @@ -579,13 +611,9 @@ namespace { Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); - /// \brief Transforms a function proto type by performing - /// substitution in the function parameters, possibly adjusting - /// their types and marking default arguments as uninstantiated. - bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars); - + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); /// \brief Transforms a template type parameter type by performing @@ -667,7 +695,16 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, SourceRange TypeRange) { VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator, Name, Loc, TypeRange); - if (Var && !Var->isInvalidDecl()) + if (Var) + getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + return Var; +} + +VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, + QualType T) { + VarDecl *Var = inherited::RebuildObjCExceptionDecl(ExceptionDecl, TSInfo, T); + if (Var) getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); return Var; } @@ -791,63 +828,17 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( E->getParam()); } - -bool -TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { - // Create a local instantiation scope for the parameters. - // FIXME: When we implement the C++0x late-specified return type, - // we will need to move this scope out to the function type itself. - bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0); - Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope, - IsTemporaryScope); - - if (TreeTransform<TemplateInstantiator>:: - TransformFunctionTypeParams(TL, PTypes, PVars)) - return true; - - // Check instantiated parameters. - if (SemaRef.CheckInstantiatedParams(PVars)) - return true; - - return false; +QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType) { + // We need a local instantiation scope for this function prototype. + Sema::LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return inherited::TransformFunctionProtoType(TLB, TL, ObjectType); } ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { - TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); - if (!NewDI) - return 0; - - // TODO: do we have to clone this decl if the types match and - // there's no default argument? - - ParmVarDecl *NewParm - = ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - /* DefArg */ NULL); - - // Maybe adjust new parameter type. - NewParm->setType(SemaRef.adjustParameterType(NewParm->getType())); - - // Mark the (new) default argument as uninstantiated (if any). - if (OldParm->hasUninstantiatedDefaultArg()) { - Expr *Arg = OldParm->getUninstantiatedDefaultArg(); - NewParm->setUninstantiatedDefaultArg(Arg); - } else if (Expr *Arg = OldParm->getDefaultArg()) - NewParm->setUninstantiatedDefaultArg(Arg); - - NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); - - SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); - return NewParm; + return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs); } QualType @@ -959,6 +950,91 @@ QualType Sema::SubstType(QualType T, return Instantiator.TransformType(T); } +static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { + if (T->getType()->isDependentType()) + return true; + + TypeLoc TL = T->getTypeLoc(); + if (!isa<FunctionProtoTypeLoc>(TL)) + return false; + + FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL); + for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) { + ParmVarDecl *P = FP.getArg(I); + + // TODO: currently we always rebuild expressions. When we + // properly get lazier about this, we should use the same + // logic to avoid rebuilding prototypes here. + if (P->hasInit()) + return true; + } + + return false; +} + +/// A form of SubstType intended specifically for instantiating the +/// type of a FunctionDecl. Its purpose is solely to force the +/// instantiation of default-argument expressions. +TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (!NeedsInstantiationAsFunctionType(T)) + return T; + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + + TypeLocBuilder TLB; + + TypeLoc TL = T->getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); + + QualType Result = Instantiator.TransformType(TLB, TL, QualType()); + if (Result.isNull()) + return 0; + + return TLB.getTypeSourceInfo(Context, Result); +} + +ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), + OldParm->getDeclName()); + if (!NewDI) + return 0; + + if (NewDI->getType()->isVoidType()) { + Diag(OldParm->getLocation(), diag::err_param_with_void_type); + return 0; + } + + ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(), + NewDI, NewDI->getType(), + OldParm->getIdentifier(), + OldParm->getLocation(), + OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten()); + if (!NewParm) + return 0; + + // Mark the (new) default argument as uninstantiated (if any). + if (OldParm->hasUninstantiatedDefaultArg()) { + Expr *Arg = OldParm->getUninstantiatedDefaultArg(); + NewParm->setUninstantiatedDefaultArg(Arg); + } else if (Expr *Arg = OldParm->getDefaultArg()) + NewParm->setUninstantiatedDefaultArg(Arg); + + NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); + + CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + return NewParm; +} + /// \brief Perform substitution on the base class specifiers of the /// given class template specialization. /// @@ -1083,8 +1159,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - DeclContext *PreviousContext = CurContext; - CurContext = Instantiation; + ContextRAII SavedContext(*this, Instantiation); // If this is an instantiation of a local class, merge this local // instantiation scope with the enclosing scope. Otherwise, every @@ -1120,12 +1195,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); - CheckCompletedCXXClass(Instantiation); + CheckCompletedCXXClass(/*Scope=*/0, Instantiation); if (Instantiation->isInvalidDecl()) Invalid = true; // Exit the scope of this instantiation. - CurContext = PreviousContext; + SavedContext.pop(); // If this is a polymorphic C++ class without a key function, we'll // have to mark all of the virtual members to allow emission of a vtable @@ -1195,21 +1270,20 @@ Sema::InstantiateClassTemplateSpecialization( typedef std::pair<ClassTemplatePartialSpecializationDecl *, TemplateArgumentList *> MatchResult; llvm::SmallVector<MatchResult, 4> Matched; - for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator - Partial = Template->getPartialSpecializations().begin(), - PartialEnd = Template->getPartialSpecializations().end(); - Partial != PartialEnd; - ++Partial) { + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + Template->getPartialSpecializations(PartialSpecs); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; TemplateDeductionInfo Info(Context, PointOfInstantiation); if (TemplateDeductionResult Result - = DeduceTemplateArguments(&*Partial, + = DeduceTemplateArguments(Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { // FIXME: Store the failed-deduction information for use in // diagnostics, later. (void)Result; } else { - Matched.push_back(std::make_pair(&*Partial, Info.take())); + Matched.push_back(std::make_pair(Partial, Info.take())); } } @@ -1331,6 +1405,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Function, MSInfo->getTemplateSpecializationKind(), @@ -1363,6 +1441,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Var->isStaticDataMember()) { MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Var, MSInfo->getTemplateSpecializationKind(), @@ -1389,11 +1471,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, } } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { - if (Record->isInjectedClassName()) + // Always skip the injected-class-name, along with any + // redeclarations of nested classes, since both would cause us + // to try to instantiate the members of a class twice. + if (Record->isInjectedClassName() || Record->getPreviousDeclaration()) continue; MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Record, MSInfo->getTemplateSpecializationKind(), @@ -1502,3 +1592,29 @@ bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, return Instantiator.TransformTemplateArgument(Input, Output); } + +Decl *Sema::LocalInstantiationScope::getInstantiationOf(const Decl *D) { + for (LocalInstantiationScope *Current = this; Current; + Current = Current->Outer) { + // Check if we found something within this scope. + llvm::DenseMap<const Decl *, Decl *>::iterator Found + = Current->LocalDecls.find(D); + if (Found != Current->LocalDecls.end()) + return Found->second; + + // If we aren't combined with our outer scope, we're done. + if (!Current->CombineWithOuterScope) + break; + } + + assert(D->isInvalidDecl() && + "declaration was not instantiated in this scope!"); + return 0; +} + +void Sema::LocalInstantiationScope::InstantiatedLocal(const Decl *D, + Decl *Inst) { + Decl *&Stored = LocalDecls[D]; + assert((!Stored || Stored == Inst)&& "Already instantiated this local"); + Stored = Inst; +} diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3375ccc..8b851b2 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -200,12 +200,22 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { if (Invalid) Typedef->setInvalidDecl(); + if (const TagType *TT = DI->getType()->getAs<TagType>()) { + TagDecl *TD = TT->getDecl(); + + // If the TagDecl that the TypedefDecl points to is an anonymous decl + // keep track of the TypedefDecl. + if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) + TD->setTypedefForAnonDecl(Typedef); + } + if (TypedefDecl *Prev = D->getPreviousDeclaration()) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); @@ -322,7 +332,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), DI->getType(), DI, - D->getStorageClass()); + D->getStorageClass(), + D->getStorageClassAsWritten()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); @@ -354,6 +365,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Owner->makeDeclVisibleInContext(Var); } else { Owner->addDecl(Var); + + if (Owner->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); } // Link instantiations of static data members back to the template from @@ -476,47 +490,37 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { - FriendDecl::FriendUnion FU; - // Handle friend type expressions by simply substituting template - // parameters into the pattern type. + // parameters into the pattern type and checking the result. if (TypeSourceInfo *Ty = D->getFriendType()) { TypeSourceInfo *InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(), DeclarationName()); - if (!InstTy) return 0; - - // This assertion is valid because the source type was necessarily - // an elaborated-type-specifier with a record tag. - assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType()); - - FU = InstTy; - - // Handle everything else by appropriate substitution. - } else { - NamedDecl *ND = D->getFriendDecl(); - assert(ND && "friend decl must be a decl or a type!"); - - // FIXME: We have a problem here, because the nested call to Visit(ND) - // will inject the thing that the friend references into the current - // owner, which is wrong. - Decl *NewND; + if (!InstTy) + return 0; - // Hack to make this work almost well pending a rewrite. - if (D->wasSpecialization()) { - // Totally egregious hack to work around PR5866 + FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); + if (!FD) return 0; - } else { - NewND = Visit(ND); - } - if (!NewND) return 0; + + FD->setAccess(AS_public); + Owner->addDecl(FD); + return FD; + } + + NamedDecl *ND = D->getFriendDecl(); + assert(ND && "friend decl must be a decl or a type!"); - FU = cast<NamedDecl>(NewND); - } + // All of the Visit implementations for the various potential friend + // declarations have to be carefully written to work for friend + // objects, with the most important detail being that the target + // decl should almost certainly not be placed in Owner. + Decl *NewND = Visit(ND); + if (!NewND) return 0; FriendDecl *FD = - FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU, - D->getFriendLoc()); + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); Owner->addDecl(FD); return FD; @@ -619,21 +623,6 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } -namespace { - class SortDeclByLocation { - SourceManager &SourceMgr; - - public: - explicit SortDeclByLocation(SourceManager &SourceMgr) - : SourceMgr(SourceMgr) { } - - bool operator()(const Decl *X, const Decl *Y) const { - return SourceMgr.isBeforeInTranslationUnit(X->getLocation(), - Y->getLocation()); - } - }; -} - Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); @@ -698,19 +687,52 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return 0; } + bool AdoptedPreviousTemplateParams = false; if (PrevClassTemplate) { + bool Complain = true; + + // HACK: libstdc++ 4.2.1 contains an ill-formed friend class + // template for struct std::tr1::__detail::_Map_base, where the + // template parameters of the friend declaration don't match the + // template parameters of the original declaration. In this one + // case, we don't complain about the ill-formed friend + // declaration. + if (isFriend && Pattern->getIdentifier() && + Pattern->getIdentifier()->isStr("_Map_base") && + DC->isNamespace() && + cast<NamespaceDecl>(DC)->getIdentifier() && + cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__detail")) { + DeclContext *DCParent = DC->getParent(); + if (DCParent->isNamespace() && + cast<NamespaceDecl>(DCParent)->getIdentifier() && + cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) { + DeclContext *DCParent2 = DCParent->getParent(); + if (DCParent2->isNamespace() && + cast<NamespaceDecl>(DCParent2)->getIdentifier() && + cast<NamespaceDecl>(DCParent2)->getIdentifier()->isStr("std") && + DCParent2->getParent()->isTranslationUnit()) + Complain = false; + } + } + TemplateParameterList *PrevParams = PrevClassTemplate->getTemplateParameters(); // Make sure the parameter lists match. if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, - /*Complain=*/true, - Sema::TPL_TemplateMatch)) - return 0; + Complain, + Sema::TPL_TemplateMatch)) { + if (Complain) + return 0; + + AdoptedPreviousTemplateParams = true; + InstParams = PrevParams; + } // Do some additional validation, then merge default arguments // from the existing declarations. - if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + if (!AdoptedPreviousTemplateParams && + SemaRef.CheckTemplateParameterList(InstParams, PrevParams, Sema::TPC_ClassTemplate)) return 0; } @@ -730,7 +752,13 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { D->getIdentifier(), InstParams, RecordInst, PrevClassTemplate); RecordInst->setDescribedClassTemplate(Inst); + if (isFriend) { + if (PrevClassTemplate) + Inst->setAccess(PrevClassTemplate->getAccess()); + else + Inst->setAccess(D->getAccess()); + Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); // TODO: do we want to track the instantiation progeny of this // friend target decl? @@ -742,29 +770,19 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization(SemaRef.Context)); - + // Finish handling of friends. if (isFriend) { DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } - Inst->setAccess(D->getAccess()); Owner->addDecl(Inst); - // First, we sort the partial specializations by location, so - // that we instantiate them in the order they were declared. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; - for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator - P = D->getPartialSpecializations().begin(), - PEnd = D->getPartialSpecializations().end(); - P != PEnd; ++P) - PartialSpecs.push_back(&*P); - std::sort(PartialSpecs.begin(), PartialSpecs.end(), - SortDeclByLocation(SemaRef.SourceMgr)); - // Instantiate all of the partial specializations of this member class // template. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + D->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); @@ -807,7 +825,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // merged with the local instantiation scope for the function template // itself. Sema::LocalInstantiationScope Scope(SemaRef); - + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -963,7 +981,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getDeclName(), T, TInfo, - D->getStorageClass(), + D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); if (Qualifier) @@ -1027,11 +1045,47 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; + bool isExplicitSpecialization = false; LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (TemplateParams || !FunctionTemplate) { + if (DependentFunctionTemplateSpecializationInfo *Info + = D->getDependentSpecializationInfo()) { + assert(isFriend && "non-friend has dependent specialization info?"); + + // This needs to be set now for future sanity. + Function->setObjectOfFriendDecl(/*HasPrevious*/ true); + + // Instantiate the explicit template arguments. + TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), + Info->getRAngleLoc()); + for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) { + TemplateArgumentLoc Loc; + if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs)) + return 0; + + ExplicitArgs.addArgument(Loc); + } + + // Map the candidate templates to their instantiations. + for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { + Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), + Info->getTemplate(I), + TemplateArgs); + if (!Temp) return 0; + + Previous.addDecl(cast<FunctionTemplateDecl>(Temp)); + } + + if (SemaRef.CheckFunctionTemplateSpecialization(Function, + &ExplicitArgs, + Previous)) + Function->setInvalidDecl(); + + isExplicitSpecialization = true; + + } else if (TemplateParams || !FunctionTemplate) { // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. @@ -1046,25 +1100,30 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - false, Redeclaration, + isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); + NamedDecl *PrincipalDecl = (TemplateParams + ? cast<NamedDecl>(FunctionTemplate) + : Function); + // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. if (isFriend) { - NamedDecl *ToFriendD = 0; NamedDecl *PrevDecl; - if (TemplateParams) { - ToFriendD = cast<NamedDecl>(FunctionTemplate); + if (TemplateParams) PrevDecl = FunctionTemplate->getPreviousDeclaration(); - } else { - ToFriendD = Function; + else PrevDecl = Function->getPreviousDeclaration(); - } - ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); - DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false); + + PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); + DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); } + if (Function->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); + return Function; } @@ -1146,14 +1205,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->getLocation(), Name, T, TInfo, Constructor->isExplicit(), - Constructor->isInlineSpecified(), false); + Constructor->isInlineSpecified(), + false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXDestructorDecl::Create(SemaRef.Context, Record, Destructor->getLocation(), Name, - T, Destructor->isInlineSpecified(), false); + T, Destructor->isInlineSpecified(), + false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { CanQualType ConvTy = SemaRef.Context.getCanonicalType( @@ -1168,7 +1229,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, TInfo, - D->isStatic(), D->isInlineSpecified()); + D->isStatic(), + D->getStorageClassAsWritten(), + D->isInlineSpecified()); } if (Qualifier) @@ -1279,41 +1342,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - QualType T; - TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI) { - DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), - D->getDeclName()); - if (DI) T = DI->getType(); - } else { - T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), - D->getDeclName()); - DI = 0; - } - - if (T.isNull()) - return 0; - - T = SemaRef.adjustParameterType(T); - - // Allocate the parameter - ParmVarDecl *Param - = ParmVarDecl::Create(SemaRef.Context, - SemaRef.Context.getTranslationUnitDecl(), - D->getLocation(), - D->getIdentifier(), T, DI, D->getStorageClass(), 0); - - // Mark the default argument as being uninstantiated. - if (D->hasUninstantiatedDefaultArg()) - Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg()); - else if (Expr *Arg = D->getDefaultArg()) - Param->setUninstantiatedDefaultArg(Arg); - - // Note: we don't try to instantiate function parameters until after - // we've instantiated the function's type. Therefore, we don't have - // to check for 'void' parameter types here. - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); - return Param; + return SemaRef.SubstParmVarDecl(D, TemplateArgs); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( @@ -1718,7 +1747,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( Converted, InstTemplateArgs, CanonType, - 0); + 0, + ClassTemplate->getPartialSpecializations().size()); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) return 0; @@ -1733,48 +1763,50 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return false; } -bool -Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) { - bool Invalid = false; - for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i) - if (ParmVarDecl *PInst = Params[i]) { - if (PInst->isInvalidDecl()) - Invalid = true; - else if (PInst->getType()->isVoidType()) { - Diag(PInst->getLocation(), diag::err_param_with_void_type); - PInst->setInvalidDecl(); - Invalid = true; - } - else if (RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) { - PInst->setInvalidDecl(); - Invalid = true; - } - } - return Invalid; -} - TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params) { TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); - TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName()); + TypeSourceInfo *NewTInfo + = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); if (!NewTInfo) return 0; - // Get parameters from the new type info. - TypeLoc NewTL = NewTInfo->getTypeLoc(); - FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); - assert(NewProtoLoc && "Missing prototype?"); - for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) - Params.push_back(NewProtoLoc->getArg(i)); - + if (NewTInfo != OldTInfo) { + // Get parameters from the new type info. + TypeLoc OldTL = OldTInfo->getTypeLoc(); + if (FunctionProtoTypeLoc *OldProtoLoc + = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { + TypeLoc NewTL = NewTInfo->getTypeLoc(); + FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); + assert(NewProtoLoc && "Missing prototype?"); + for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) { + // FIXME: Variadic templates will break this. + Params.push_back(NewProtoLoc->getArg(i)); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + OldProtoLoc->getArg(i), + NewProtoLoc->getArg(i)); + } + } + } else { + // The function type itself was not dependent and therefore no + // substitution occurred. However, we still need to instantiate + // the function parameters themselves. + TypeLoc OldTL = OldTInfo->getTypeLoc(); + if (FunctionProtoTypeLoc *OldProtoLoc + = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { + for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) { + ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i)); + if (!Parm) + return 0; + Params.push_back(Parm); + } + } + } return NewTInfo; } @@ -1938,8 +1970,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) - return; - + return; + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. @@ -1971,7 +2003,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, CurContext = Function; MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function); + getTemplateInstantiationArgs(Function, 0, false, PatternDecl); // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = @@ -2459,7 +2491,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, T = Context.getTypeDeclType(Record); assert(isa<InjectedClassNameType>(T) && "type of partial specialization is not an InjectedClassNameType"); - T = cast<InjectedClassNameType>(T)->getUnderlyingType(); + T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); } if (!T.isNull()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8278691..d1a74be 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -81,9 +81,12 @@ static void ProcessDelayedFnAttrs(Sema &S, QualType &Type, DelayedAttributeSet &Attrs) { for (DelayedAttributeSet::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) - if (ProcessFnAttr(S, Type, *I->first)) + if (ProcessFnAttr(S, Type, *I->first)) { S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) << I->first->getName() << I->second; + // Avoid any further processing of this attribute. + I->first->setInvalid(); + } Attrs.clear(); } @@ -92,6 +95,8 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { E = Attrs.end(); I != E; ++I) { S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) << I->first->getName() << I->second; + // Avoid any further processing of this attribute. + I->first->setInvalid(); } Attrs.clear(); } @@ -280,6 +285,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (TheSema.getLangOptions().CPlusPlus) { TagDecl::TagKind Tag = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); + Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result); Result = Context.getElaboratedType(Result, Tag); } @@ -498,6 +504,8 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, Qs.removeRestrict(); } + assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType"); + // Build the pointer type. return Context.getQualifiedType(Context.getPointerType(T), Qs); } @@ -604,15 +612,31 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, SourceRange Brackets, DeclarationName Entity) { SourceLocation Loc = Brackets.getBegin(); - // C99 6.7.5.2p1: If the element type is an incomplete or function type, - // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - // Not in C++, though. There we only dislike void. if (getLangOptions().CPlusPlus) { + // C++ [dcl.array]p1: + // T is called the array element type; this type shall not be a reference + // type, the (possibly cv-qualified) type void, a function type or an + // abstract class type. + // + // Note: function types are handled in the common path with C. + if (T->isReferenceType()) { + Diag(Loc, diag::err_illegal_decl_array_of_references) + << getPrintableNameForEntity(Entity) << T; + return QualType(); + } + if (T->isVoidType()) { Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; return QualType(); } + + if (RequireNonAbstractType(Brackets.getBegin(), T, + diag::err_array_of_abstract_type)) + return QualType(); + } else { + // C99 6.7.5.2p1: If the element type is an incomplete or function type, + // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) if (RequireCompleteType(Loc, T, diag::err_illegal_decl_array_incomplete_type)) return QualType(); @@ -624,13 +648,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - // C++ 8.3.2p4: There shall be no ... arrays of references ... - if (T->isReferenceType()) { - Diag(Loc, diag::err_illegal_decl_array_of_references) - << getPrintableNameForEntity(Entity) << T; - return QualType(); - } - if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) { Diag(Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Entity); @@ -922,7 +939,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - + TypeSourceInfo *ReturnTypeInfo = 0; + llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec; switch (D.getName().getKind()) { @@ -948,12 +966,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Constructors and destructors don't have return types. Use // "void" instead. T = Context.VoidTy; + + if (TInfo) + ReturnTypeInfo = Context.getTrivialTypeSourceInfo(T, + D.getName().StartLocation); break; case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. - T = GetTypeFromParser(D.getName().ConversionFunctionId); + T = GetTypeFromParser(D.getName().ConversionFunctionId, + TInfo? &ReturnTypeInfo : 0); break; } @@ -1036,7 +1059,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>(); T = Context.getObjCObjectPointerType(T, - (ObjCProtocolDecl **)OIT->qual_begin(), + const_cast<ObjCProtocolDecl **>( + OIT->qual_begin()), OIT->getNumProtocols(), DeclType.Ptr.TypeQuals); break; @@ -1253,8 +1277,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } // The scope spec must refer to a class, or be dependent. QualType ClsType; - if (isDependentScopeSpecifier(DeclType.Mem.Scope()) - || dyn_cast_or_null<CXXRecordDecl>( + if (DeclType.Mem.Scope().isInvalid()) { + // Avoid emitting extra errors if we already errored on the scope. + D.setInvalidType(true); + } else if (isDependentScopeSpecifier(DeclType.Mem.Scope()) + || dyn_cast_or_null<CXXRecordDecl>( computeDeclContext(DeclType.Mem.Scope()))) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); @@ -1353,7 +1380,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.isInvalidType()) *TInfo = 0; else - *TInfo = GetTypeSourceInfoForDeclarator(D, T); + *TInfo = GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo); } return T; @@ -1538,8 +1565,14 @@ namespace { /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. +/// +/// \param ReturnTypeInfo For declarators whose return type does not show +/// up in the normal place in the declaration specifiers (such as a C++ +/// conversion function), this pointer will refer to a type source information +/// for that return type. TypeSourceInfo * -Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { +Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo) { TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); @@ -1549,7 +1582,18 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { } TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); - + + // We have source information for the return type that was not in the + // declaration specifiers; copy that information into the current type + // location so that it will be retained. This occurs, for example, with + // a C++ conversion function, where the return type occurs within the + // declarator-id rather than in the declaration specifiers. + if (ReturnTypeInfo && D.getDeclSpec().getTypeSpecType() == TST_unspecified) { + TypeLoc TL = ReturnTypeInfo->getTypeLoc(); + assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); + memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); + } + return TInfo; } @@ -1648,12 +1692,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, // for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); + Attr.setInvalid(); return; } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); @@ -1661,6 +1707,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1669,6 +1716,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (addrSpace.isNegative()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } addrSpace.setIsSigned(false); @@ -1678,6 +1726,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (addrSpace > max) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1691,6 +1740,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S) { if (Type.getObjCGCAttr() != Qualifiers::GCNone) { S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); + Attr.setInvalid(); return; } @@ -1698,11 +1748,13 @@ static void HandleObjCGCTypeAttribute(QualType &Type, if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; + Attr.setInvalid(); return; } Qualifiers::GC GCAttr; if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } if (Attr.getParameterName()->isStr("weak")) @@ -1712,6 +1764,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type, else { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << Attr.getParameterName(); + Attr.setInvalid(); return; } @@ -1725,6 +1778,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { // Complain immediately if the arg count is wrong. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + Attr.setInvalid(); return false; } @@ -1766,6 +1820,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { // Otherwise, a calling convention. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + Attr.setInvalid(); return false; } @@ -1788,13 +1843,17 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { CallingConv CCOld = Fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == - S.Context.getCanonicalCallConv(CCOld)) return false; + S.Context.getCanonicalCallConv(CCOld)) { + Attr.setInvalid(); + return false; + } if (CCOld != CC_Default) { // Should we diagnose reapplications of the same convention? S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); + Attr.setInvalid(); return false; } @@ -1803,6 +1862,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { if (isa<FunctionNoProtoType>(Fn)) { S.Diag(Attr.getLoc(), diag::err_cconv_knr) << FunctionType::getNameForCallConv(CC); + Attr.setInvalid(); return false; } @@ -1810,6 +1870,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { if (FnP->isVariadic()) { S.Diag(Attr.getLoc(), diag::err_cconv_varargs) << FunctionType::getNameForCallConv(CC); + Attr.setInvalid(); return false; } } @@ -1829,6 +1890,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S // Check the attribute arugments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); @@ -1836,12 +1898,14 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "vector_size" << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } // the base type must be integer or float, and can't already be a vector. if (CurType->isVectorType() || (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + Attr.setInvalid(); return; } unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); @@ -1852,11 +1916,13 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S if (vectorSize % typeSize) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } if (vectorSize == 0) { S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1873,8 +1939,12 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. for (; AL; AL = AL->getNext()) { - // If this is an attribute we can handle, do so now, otherwise, add it to - // the LeftOverAttrs list for rechaining. + // Skip attributes that were marked to be invalid. + if (AL->isInvalid()) + continue; + + // If this is an attribute we can handle, do so now, + // otherwise, add it to the FnAttrs list for rechaining. switch (AL->getKind()) { default: break; @@ -2029,7 +2099,10 @@ QualType Sema::BuildTypeofExprType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization, Specialization); + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); if (!E) return QualType(); } else { @@ -2049,7 +2122,10 @@ QualType Sema::BuildDecltypeType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization, Specialization); + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); if (!E) return QualType(); } else { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f9ffd3f..5ce268b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -338,6 +338,7 @@ public: QualType ObjectType); OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); + OwningExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); @@ -378,10 +379,6 @@ public: QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); - /// \brief Build a new Objective C object pointer type. - QualType RebuildObjCObjectPointerType(QualType PointeeType, - SourceLocation Sigil); - /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -577,10 +574,9 @@ public: TagDecl::TagKind Kind = TagDecl::TK_enum; switch (Keyword) { case ETK_None: - // FIXME: Note the lack of the "typename" specifier! - // Fall through + // Fall through. case ETK_Typename: - return SemaRef.CheckTypenameType(NNS, *Id, SR); + return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR); case ETK_Class: Kind = TagDecl::TK_class; break; case ETK_Struct: Kind = TagDecl::TK_struct; break; @@ -892,6 +888,88 @@ public: move(Exprs), move(AsmString), move(Clobbers), RParenLoc, MSAsm); } + + /// \brief Build a new Objective-C @try statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc, + StmtArg TryBody, + MultiStmtArg CatchStmts, + StmtArg Finally) { + return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(CatchStmts), + move(Finally)); + } + + /// \brief Rebuild an Objective-C exception declaration. + /// + /// By default, performs semantic analysis to build the new declaration. + /// Subclasses may override this routine to provide different behavior. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TInfo, QualType T) { + return getSema().BuildObjCExceptionDecl(TInfo, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation()); + } + + /// \brief Build a new Objective-C @catch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParenLoc, + VarDecl *Var, + StmtArg Body) { + return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc, + Sema::DeclPtrTy::make(Var), + move(Body)); + } + + /// \brief Build a new Objective-C @finally statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtFinallyStmt(SourceLocation AtLoc, + StmtArg Body) { + return getSema().ActOnObjCAtFinallyStmt(AtLoc, move(Body)); + } + + /// \brief Build a new Objective-C @throw statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Operand) { + return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand)); + } + + /// \brief Build a new Objective-C @synchronized statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprArg Object, + StmtArg Body) { + return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object), + move(Body)); + } + + /// \brief Build a new Objective-C fast enumeration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg Element, + ExprArg Collection, + SourceLocation RParenLoc, + StmtArg Body) { + return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + move(Element), + move(Collection), + RParenLoc, + move(Body)); + } /// \brief Build a new C++ exception declaration. /// @@ -989,6 +1067,19 @@ public: return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr)); } + /// \brief Build a new builtin offsetof expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc, + TypeSourceInfo *Type, + Action::OffsetOfComponent *Components, + unsigned NumComponents, + SourceLocation RParenLoc) { + return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components, + NumComponents, RParenLoc); + } + /// \brief Build a new sizeof or alignof expression with a type argument. /// /// By default, performs semantic analysis to build the new expression. @@ -1421,30 +1512,24 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, - SourceLocation LParenLoc, - QualType T, + OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true, - T.getAsOpaquePtr(), RParenLoc); + return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand, + RParenLoc); } /// \brief Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, - SourceLocation LParenLoc, + OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, ExprArg Operand, SourceLocation RParenLoc) { - OwningExprResult Result - = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(), - RParenLoc); - if (Result.isInvalid()) - return getSema().ExprError(); - - Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership - return move(Result); + return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, move(Operand), + RParenLoc); } /// \brief Build a new C++ "this" expression. @@ -1688,29 +1773,147 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc, - QualType T, + TypeSourceInfo *EncodeTypeInfo, SourceLocation RParenLoc) { - return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T, + return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo, RParenLoc)); } - /// \brief Build a new Objective-C protocol expression. + /// \brief Build a new Objective-C class message. + OwningExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + MultiExprArg Args, + SourceLocation RBracLoc) { + return SemaRef.BuildClassMessage(ReceiverTypeInfo, + ReceiverTypeInfo->getType(), + /*SuperLoc=*/SourceLocation(), + Sel, Method, LBracLoc, RBracLoc, + move(Args)); + } + + /// \brief Build a new Objective-C instance message. + OwningExprResult RebuildObjCMessageExpr(ExprArg Receiver, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + MultiExprArg Args, + SourceLocation RBracLoc) { + QualType ReceiverType = static_cast<Expr *>(Receiver.get())->getType(); + return SemaRef.BuildInstanceMessage(move(Receiver), + ReceiverType, + /*SuperLoc=*/SourceLocation(), + Sel, Method, LBracLoc, RBracLoc, + move(Args)); + } + + /// \brief Build a new Objective-C ivar reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression( - Protocol->getIdentifier(), - AtLoc, - ProtoLoc, - LParenLoc, - RParenLoc)); + OwningExprResult RebuildObjCIvarRefExpr(ExprArg BaseArg, ObjCIvarDecl *Ivar, + SourceLocation IvarLoc, + bool IsArrow, bool IsFreeIvar) { + // FIXME: We lose track of the IsFreeIvar bit. + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IvarLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IvarLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + + /// \brief Build a new Objective-C property reference expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCPropertyRefExpr(ExprArg BaseArg, + ObjCPropertyDecl *Property, + SourceLocation PropertyLoc) { + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), Property->getDeclName(), PropertyLoc, + Sema::LookupMemberName); + bool IsArrow = false; + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/PropertyLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/PropertyLoc, IsArrow, + SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + + /// \brief Build a new Objective-C implicit setter/getter reference + /// expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCImplicitSetterGetterRefExpr( + ObjCMethodDecl *Getter, + QualType T, + ObjCMethodDecl *Setter, + SourceLocation NameLoc, + ExprArg Base) { + // Since these expressions can only be value-dependent, we do not need to + // perform semantic analysis again. + return getSema().Owned( + new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T, + Setter, + NameLoc, + Base.takeAs<Expr>())); } + /// \brief Build a new Objective-C "isa" expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCIsaExpr(ExprArg BaseArg, SourceLocation IsaLoc, + bool IsArrow) { + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IsaLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IsaLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + /// \brief Build a new shuffle vector expression. /// /// By default, performs semantic analysis to build the new expression. @@ -2225,29 +2428,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { return T.getType(); } -// Ugly metaprogramming macros because I couldn't be bothered to make -// the equivalent template version work. -#define TransformPointerLikeType(TypeClass) do { \ - QualType PointeeType \ - = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ - if (PointeeType.isNull()) \ - return QualType(); \ - \ - QualType Result = TL.getType(); \ - if (getDerived().AlwaysRebuild() || \ - PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType, \ - TL.getSigilLoc()); \ - if (Result.isNull()) \ - return QualType(); \ - } \ - \ - TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \ - NewT.setSigilLoc(TL.getSigilLoc()); \ - \ - return Result; \ -} while(0) - template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T, @@ -2271,7 +2451,42 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL, QualType ObjectType) { - TransformPointerLikeType(PointerType); + QualType PointeeType + = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (PointeeType->isObjCInterfaceType()) { + // A dependent pointer type 'T *' has is being transformed such + // that an Objective-C class type is being replaced for 'T'. The + // resulting pointer type is an ObjCObjectPointerType, not a + // PointerType. + const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>(); + Result = SemaRef.Context.getObjCObjectPointerType(PointeeType, + const_cast<ObjCProtocolDecl **>( + IFace->qual_begin()), + IFace->getNumProtocols()); + + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getSigilLoc()); + NewT.setHasProtocolsAsWritten(false); + NewT.setLAngleLoc(SourceLocation()); + NewT.setRAngleLoc(SourceLocation()); + NewT.setHasBaseTypeAsWritten(true); + return Result; + } + + if (getDerived().AlwaysRebuild() || + PointeeType != TL.getPointeeLoc().getType()) { + Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result); + NewT.setSigilLoc(TL.getSigilLoc()); + return Result; } template<typename Derived> @@ -2279,7 +2494,23 @@ QualType TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, BlockPointerTypeLoc TL, QualType ObjectType) { - TransformPointerLikeType(BlockPointerType); + QualType PointeeType + = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != TL.getPointeeLoc().getType()) { + Result = getDerived().RebuildBlockPointerType(PointeeType, + TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + BlockPointerTypeLoc NewT = TLB.push<BlockPointerTypeLoc>(Result); + NewT.setSigilLoc(TL.getSigilLoc()); + return Result; } /// Transforms a reference type. Note that somewhat paradoxically we @@ -2630,6 +2861,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { NewDI->getType(), NewDI, OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten(), /* DefArg */ NULL); } @@ -2675,17 +2907,19 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, QualType ObjectType) { - FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - - // Transform the parameters. + // Transform the parameters. We do this first for the benefit of template + // instantiations, so that the ParmVarDecls get/ placed into the template + // instantiation scope before we transform the function type. llvm::SmallVector<QualType, 4> ParamTypes; llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) return QualType(); - + + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || @@ -3117,8 +3351,8 @@ QualType TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, ObjCInterfaceTypeLoc TL, QualType ObjectType) { - assert(false && "TransformObjCInterfaceType unimplemented"); - return QualType(); + // ObjCInterfaceType is never dependent. + return TL.getType(); } template<typename Derived> @@ -3126,8 +3360,8 @@ QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL, QualType ObjectType) { - assert(false && "TransformObjCObjectPointerType unimplemented"); - return QualType(); + // ObjCObjectPointerType is never dependent. + return TL.getType(); } //===----------------------------------------------------------------------===// @@ -3587,51 +3821,172 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @try statement"); - return SemaRef.Owned(S->Retain()); + // Transform the body of the @try. + OwningStmtResult TryBody = getDerived().TransformStmt(S->getTryBody()); + if (TryBody.isInvalid()) + return SemaRef.StmtError(); + + // Transform the @catch statements (if present). + bool AnyCatchChanged = false; + ASTOwningVector<&ActionBase::DeleteStmt> CatchStmts(SemaRef); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + OwningStmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I)); + if (Catch.isInvalid()) + return SemaRef.StmtError(); + if (Catch.get() != S->getCatchStmt(I)) + AnyCatchChanged = true; + CatchStmts.push_back(Catch.release()); + } + + // Transform the @finally statement (if present). + OwningStmtResult Finally(SemaRef); + if (S->getFinallyStmt()) { + Finally = getDerived().TransformStmt(S->getFinallyStmt()); + if (Finally.isInvalid()) + return SemaRef.StmtError(); + } + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + TryBody.get() == S->getTryBody() && + !AnyCatchChanged && + Finally.get() == S->getFinallyStmt()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), move(TryBody), + move_arg(CatchStmts), move(Finally)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @catch statement"); - return SemaRef.Owned(S->Retain()); + // Transform the @catch parameter, if there is one. + VarDecl *Var = 0; + if (VarDecl *FromVar = S->getCatchParamDecl()) { + TypeSourceInfo *TSInfo = 0; + if (FromVar->getTypeSourceInfo()) { + TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo()); + if (!TSInfo) + return SemaRef.StmtError(); + } + + QualType T; + if (TSInfo) + T = TSInfo->getType(); + else { + T = getDerived().TransformType(FromVar->getType()); + if (T.isNull()) + return SemaRef.StmtError(); + } + + Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T); + if (!Var) + return SemaRef.StmtError(); + } + + OwningStmtResult Body = getDerived().TransformStmt(S->getCatchBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(), + S->getRParenLoc(), + Var, move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @finally statement"); - return SemaRef.Owned(S->Retain()); + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getFinallyBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Body.get() == S->getFinallyBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(), + move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @throw statement"); - return SemaRef.Owned(S->Retain()); + OwningExprResult Operand(SemaRef); + if (S->getThrowExpr()) { + Operand = getDerived().TransformExpr(S->getThrowExpr()); + if (Operand.isInvalid()) + return getSema().StmtError(); + } + + if (!getDerived().AlwaysRebuild() && + Operand.get() == S->getThrowExpr()) + return getSema().Owned(S->Retain()); + + return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( ObjCAtSynchronizedStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @synchronized statement"); - return SemaRef.Owned(S->Retain()); + // Transform the object we are locking. + OwningExprResult Object = getDerived().TransformExpr(S->getSynchExpr()); + if (Object.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getSynchBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing change, just retain the current statement. + if (!getDerived().AlwaysRebuild() && + Object.get() == S->getSynchExpr() && + Body.get() == S->getSynchBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(), + move(Object), move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C for-each statement"); - return SemaRef.Owned(S->Retain()); + // Transform the element statement. + OwningStmtResult Element = getDerived().TransformStmt(S->getElement()); + if (Element.isInvalid()) + return SemaRef.StmtError(); + + // Transform the collection expression. + OwningExprResult Collection = getDerived().TransformExpr(S->getCollection()); + if (Collection.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Element.get() == S->getElement() && + Collection.get() == S->getCollection() && + Body.get() == S->getBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), + /*FIXME:*/S->getForLoc(), + move(Element), + move(Collection), + S->getRParenLoc(), + move(Body)); } @@ -3828,6 +4183,72 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { template<typename Derived> Sema::OwningExprResult +TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { + // Transform the type. + TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo()); + if (!Type) + return getSema().ExprError(); + + // Transform all of the components into components similar to what the + // parser uses. + // FIXME: It would be slightly more efficient in the non-dependent case to + // just map FieldDecls, rather than requiring the rebuilder to look for + // the fields again. However, __builtin_offsetof is rare enough in + // template code that we don't care. + bool ExprChanged = false; + typedef Action::OffsetOfComponent Component; + typedef OffsetOfExpr::OffsetOfNode Node; + llvm::SmallVector<Component, 4> Components; + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + const Node &ON = E->getComponent(I); + Component Comp; + Comp.isBrackets = true; + Comp.LocStart = ON.getRange().getBegin(); + Comp.LocEnd = ON.getRange().getEnd(); + switch (ON.getKind()) { + case Node::Array: { + Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex()); + OwningExprResult Index = getDerived().TransformExpr(FromIndex); + if (Index.isInvalid()) + return getSema().ExprError(); + + ExprChanged = ExprChanged || Index.get() != FromIndex; + Comp.isBrackets = true; + Comp.U.E = Index.takeAs<Expr>(); // FIXME: leaked + break; + } + + case Node::Field: + case Node::Identifier: + Comp.isBrackets = false; + Comp.U.IdentInfo = ON.getFieldName(); + if (!Comp.U.IdentInfo) + continue; + + break; + + case Node::Base: + // Will be recomputed during the rebuild. + continue; + } + + Components.push_back(Comp); + } + + // If nothing changed, retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Type == E->getTypeSourceInfo() && + !ExprChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new offsetof expression. + return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type, + Components.data(), Components.size(), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); @@ -4597,19 +5018,18 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isTypeOperand()) { - TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); - - QualType T = getDerived().TransformType(E->getTypeOperand()); - if (T.isNull()) + TypeSourceInfo *TInfo + = getDerived().TransformType(E->getTypeOperandSourceInfo()); + if (!TInfo) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getTypeOperand()) + TInfo == E->getTypeOperandSourceInfo()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), - /*FIXME:*/E->getLocStart(), - T, + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), + TInfo, E->getLocEnd()); } @@ -4627,8 +5047,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { SubExpr.get() == E->getExprOperand()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), - /*FIXME:*/E->getLocStart(), + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), move(SubExpr), E->getLocEnd()); } @@ -4997,6 +5417,17 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( SS.setScopeRep(Qualifier); SS.setRange(Old->getQualifierRange()); + } + + if (Old->getNamingClass()) { + CXXRecordDecl *NamingClass + = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + Old->getNameLoc(), + Old->getNamingClass())); + if (!NamingClass) + return SemaRef.ExprError(); + + R.setNamingClass(NamingClass); } // If we have no template arguments, it's a normal declaration name. @@ -5423,6 +5854,18 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) R.resolveKind(); + // Determine the naming class. + if (!Old->getNamingClass()) { + CXXRecordDecl *NamingClass + = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + Old->getMemberLoc(), + Old->getNamingClass())); + if (!NamingClass) + return SemaRef.ExprError(); + + R.setNamingClass(NamingClass); + } + TemplateArgumentListInfo TransArgs; if (Old->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(Old->getLAngleLoc()); @@ -5463,27 +5906,76 @@ TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { - // FIXME: poor source location - TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); - QualType EncodedType = getDerived().TransformType(E->getEncodedType()); - if (EncodedType.isNull()) + TypeSourceInfo *EncodedTypeInfo + = getDerived().TransformType(E->getEncodedTypeSourceInfo()); + if (!EncodedTypeInfo) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - EncodedType == E->getEncodedType()) + EncodedTypeInfo == E->getEncodedTypeSourceInfo()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(), - EncodedType, + EncodedTypeInfo, E->getRParenLoc()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform arguments. + bool ArgChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + ArgChanged = ArgChanged || Arg.get() != E->getArg(I); + Args.push_back(Arg.takeAs<Expr>()); + } + + if (E->getReceiverKind() == ObjCMessageExpr::Class) { + // Class message: transform the receiver type. + TypeSourceInfo *ReceiverTypeInfo + = getDerived().TransformType(E->getClassReceiverTypeInfo()); + if (!ReceiverTypeInfo) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing message send. + if (!getDerived().AlwaysRebuild() && + ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new class message send. + return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, + E->getSelector(), + E->getMethodDecl(), + E->getLeftLoc(), + move_arg(Args), + E->getRightLoc()); + } + + // Instance message: transform the receiver + assert(E->getReceiverKind() == ObjCMessageExpr::Instance && + "Only class and instance messages may be instantiated"); + OwningExprResult Receiver + = getDerived().TransformExpr(E->getInstanceReceiver()); + if (Receiver.isInvalid()) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing message send. + if (!getDerived().AlwaysRebuild() && + Receiver.get() == E->getInstanceReceiver() && !ArgChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new instance message send. + return getDerived().RebuildObjCMessageExpr(move(Receiver), + E->getSelector(), + E->getMethodDecl(), + E->getLeftLoc(), + move_arg(Args), + E->getRightLoc()); } template<typename Derived> @@ -5495,64 +5987,100 @@ TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { - ObjCProtocolDecl *Protocol - = cast_or_null<ObjCProtocolDecl>( - getDerived().TransformDecl(E->getLocStart(), - E->getProtocol())); - if (!Protocol) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - Protocol == E->getProtocol()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildObjCProtocolExpr(Protocol, - E->getAtLoc(), - /*FIXME:*/E->getAtLoc(), - /*FIXME:*/E->getAtLoc(), - E->getRParenLoc()); - + return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the ivar; it will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCIvarRefExpr(move(Base), E->getDecl(), + E->getLocation(), + E->isArrow(), E->isFreeIvar()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the property; it will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCPropertyRefExpr(move(Base), E->getProperty(), + E->getLocation()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // If this implicit setter/getter refers to class methods, it cannot have any + // dependent parts. Just retain the existing declaration. + if (E->getInterfaceDecl()) + return SemaRef.Owned(E->Retain()); + + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the getters/setters; they will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCImplicitSetterGetterRefExpr( + E->getGetterMethod(), + E->getType(), + E->getSetterMethod(), + E->getLocation(), + move(Base)); + } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); + // Can never occur in a dependent context. return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCIsaExpr(move(Base), E->getIsaMemberLoc(), + E->isArrow()); } template<typename Derived> @@ -5632,14 +6160,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, template<typename Derived> QualType -TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType, - SourceLocation Sigil) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil, - getDerived().getBaseEntity()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, @@ -5767,6 +6287,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); + // FIXME: Doesn't account for ObjCInterfaceDecl! TypeDecl *Ty; if (isa<UsingDecl>(D)) { UsingDecl *Using = cast<UsingDecl>(D); |