diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 369 | ||||
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.h | 35 | ||||
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/CXXFieldCollector.h | 5 | ||||
-rw-r--r-- | lib/Sema/ParseAST.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 66 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 290 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 279 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 129 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 59 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 96 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 186 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 14 |
20 files changed, 1005 insertions, 636 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp new file mode 100644 index 0000000..c4ceec0 --- /dev/null +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -0,0 +1,369 @@ +//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines analysis_warnings::[Policy,Executor]. +// Together they are used by Sema to issue warnings based on inexpensive +// static analysis algorithms in libAnalysis. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "AnalysisBasedWarnings.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/Analyses/ReachableCode.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/Casting.h" +#include <queue> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Unreachable code analysis. +//===----------------------------------------------------------------------===// + +namespace { + class UnreachableCodeHandler : public reachable_code::Callback { + Sema &S; + public: + UnreachableCodeHandler(Sema &s) : S(s) {} + + void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { + S.Diag(L, diag::warn_unreachable) << R1 << R2; + } + }; +} + +/// CheckUnreachable - Check for unreachable code. +static void CheckUnreachable(Sema &S, AnalysisContext &AC) { + UnreachableCodeHandler UC(S); + reachable_code::FindUnreachableCode(AC, UC); +} + +//===----------------------------------------------------------------------===// +// Check for missing return value. +//===----------------------------------------------------------------------===// + +enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, + AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // The CFG leaves in dead things, and we don't want the dead code paths to + // confuse us, so we mark all live things first. + std::queue<CFGBlock*> workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + live); + + bool AddEHEdges = AC.getAddEHEdges(); + if (!AddEHEdges && count != cfg->getNumBlockIDs()) + // When there are things remaining dead, and we didn't add EH edges + // from CallExprs to the catch clauses, we have to go back and + // mark them as live. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += reachable_code::ScanReachableFromBlock(b, live); + continue; + } + } + } + + // Now we know what is live, we check the live precessors of the exit block + // and look for fall through paths, being careful to ignore normal returns, + // and exceptional paths. + bool HasLiveReturn = false; + bool HasFakeEdge = false; + bool HasPlainEdge = false; + bool HasAbnormalEdge = false; + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), + E = cfg->getExit().pred_end(); + I != E; + ++I) { + CFGBlock& B = **I; + if (!live[B.getBlockID()]) + continue; + if (B.size() == 0) { + if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { + HasAbnormalEdge = true; + continue; + } + + // A labeled empty statement, or the entry block... + HasPlainEdge = true; + continue; + } + Stmt *S = B[B.size()-1]; + if (isa<ReturnStmt>(S)) { + HasLiveReturn = true; + continue; + } + if (isa<ObjCAtThrowStmt>(S)) { + HasFakeEdge = true; + continue; + } + if (isa<CXXThrowExpr>(S)) { + HasFakeEdge = true; + continue; + } + if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + if (isa<CXXTryStmt>(S)) { + HasAbnormalEdge = true; + continue; + } + + bool NoReturnEdge = false; + if (CallExpr *C = dyn_cast<CallExpr>(S)) { + if (B.succ_begin()[0] != &cfg->getExit()) { + HasAbnormalEdge = true; + continue; + } + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; + } + } + } + // FIXME: Add noreturn message sends. + if (NoReturnEdge == false) + HasPlainEdge = true; + } + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } + if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) + return MaybeFallThrough; + // This says AlwaysFallThrough for calls to functions that are not marked + // noreturn, that don't return. If people would like this warning to be more + // accurate, such functions should be marked as noreturn. + return AlwaysFallThrough; +} + +struct CheckFallThroughDiagnostics { + unsigned diag_MaybeFallThrough_HasNoReturn; + unsigned diag_MaybeFallThrough_ReturnsNonVoid; + unsigned diag_AlwaysFallThrough_HasNoReturn; + unsigned diag_AlwaysFallThrough_ReturnsNonVoid; + unsigned diag_NeverFallThroughOrReturn; + bool funMode; + + static CheckFallThroughDiagnostics MakeForFunction() { + CheckFallThroughDiagnostics D; + D.diag_MaybeFallThrough_HasNoReturn = + diag::warn_falloff_noreturn_function; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::warn_maybe_falloff_nonvoid_function; + D.diag_AlwaysFallThrough_HasNoReturn = + diag::warn_falloff_noreturn_function; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::warn_falloff_nonvoid_function; + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_function; + D.funMode = true; + return D; + } + + static CheckFallThroughDiagnostics MakeForBlock() { + CheckFallThroughDiagnostics D; + D.diag_MaybeFallThrough_HasNoReturn = + diag::err_noreturn_block_has_return_expr; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::err_maybe_falloff_nonvoid_block; + D.diag_AlwaysFallThrough_HasNoReturn = + diag::err_noreturn_block_has_return_expr; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::err_falloff_nonvoid_block; + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_block; + D.funMode = false; + return D; + } + + bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, + bool HasNoReturn) const { + if (funMode) { + return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid); + } + + // For blocks. + return ReturnsVoid && !HasNoReturn + && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid); + } +}; + +/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// function that should return a value. Check that we don't fall off the end +/// of a noreturn function. We assume that functions and blocks not marked +/// noreturn will return. +static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, + QualType BlockTy, + const CheckFallThroughDiagnostics& CD, + AnalysisContext &AC) { + + bool ReturnsVoid = false; + bool HasNoReturn = false; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + ReturnsVoid = FD->getResultType()->isVoidType(); + HasNoReturn = FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); + } + else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + ReturnsVoid = MD->getResultType()->isVoidType(); + HasNoReturn = MD->hasAttr<NoReturnAttr>(); + } + else if (isa<BlockDecl>(D)) { + if (const FunctionType *FT = + BlockTy->getPointeeType()->getAs<FunctionType>()) { + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + } + + Diagnostic &Diags = S.getDiagnostics(); + + // Short circuit for compilation speed. + if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) + return; + + // FIXME: Function try block + if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + S.Diag(Compound->getRBracLoc(), + CD.diag_MaybeFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(Compound->getRBracLoc(), + CD.diag_MaybeFallThrough_ReturnsNonVoid); + break; + case AlwaysFallThrough: + if (HasNoReturn) + S.Diag(Compound->getRBracLoc(), + CD.diag_AlwaysFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(Compound->getRBracLoc(), + CD.diag_AlwaysFallThrough_ReturnsNonVoid); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) + S.Diag(Compound->getLBracLoc(), + CD.diag_NeverFallThroughOrReturn); + break; + case NeverFallThrough: + break; + } + } +} + +//===----------------------------------------------------------------------===// +// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based +// warnings on a function, method, or block. +//===----------------------------------------------------------------------===// + +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { + Diagnostic &D = S.getDiagnostics(); + + enableCheckFallThrough = 1; + + enableCheckUnreachable = (unsigned) + (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); +} + +void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, + QualType BlockTy) { + + assert(BlockTy.isNull() || isa<BlockDecl>(D)); + + // Do not do any analysis for declarations in system headers if we are + // going to just ignore them. + if (S.getDiagnostics().getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation())) + return; + + // We avoid doing analysis-based warnings when there are errors for + // two reasons: + // (1) The CFGs often can't be constructed (if the body is invalid), so + // don't bother trying. + // (2) The code already has problems; running the analysis just takes more + // time. + if (S.getDiagnostics().hasErrorOccurred()) + return; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // For function templates, class templates and member function templates + // we'll do the analysis at instantiation time. + if (FD->isDependentContext()) + return; + } + + const Stmt *Body = D->getBody(); + assert(Body); + + // 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); + + // Warning: check missing 'return' + if (enableCheckFallThrough) { + const CheckFallThroughDiagnostics &CD = + (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() + : CheckFallThroughDiagnostics::MakeForFunction()); + CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); + } + + // Warning: check for unreachable code + if (enableCheckUnreachable) + CheckUnreachable(S, AC); +} diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h new file mode 100644 index 0000000..39da1b1 --- /dev/null +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -0,0 +1,35 @@ +//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisBasedWarnings, a worker object used by Sema +// that issues warnings based on dataflow-analysis. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H +#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H + +namespace clang { namespace sema { + +class AnalysisBasedWarnings { + Sema &S; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + +public: + + AnalysisBasedWarnings(Sema &s); + void IssueWarnings(const Decl *D, QualType BlockTy = QualType()); + + void disableCheckFallThrough() { enableCheckFallThrough = 0; } +}; + +}} // end namespace clang::sema + +#endif diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 237803a..ac0dfd6 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangSema + AnalysisBasedWarnings.cpp CodeCompleteConsumer.cpp IdentifierResolver.cpp JumpDiagnostics.cpp diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h index 69d1351..63c6ee3 100644 --- a/lib/Sema/CXXFieldCollector.h +++ b/lib/Sema/CXXFieldCollector.h @@ -58,7 +58,10 @@ public: } /// getCurNumField - The number of fields added to the currently parsed class. - size_t getCurNumFields() const { return FieldCount.back(); } + size_t getCurNumFields() const { + assert(!FieldCount.empty() && "no currently-parsed class"); + return FieldCount.back(); + } /// getCurFields - Pointer to array of fields added to the currently parsed /// class. diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 898b3c2..7cd3989 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -44,7 +44,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; // Initialize the parser. P.Initialize(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3b4afef..7112687 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -399,8 +399,3 @@ BlockScopeInfo *Sema::getCurBlock() { return dyn_cast<BlockScopeInfo>(FunctionScopes.back()); } - -void Sema::ActOnComment(SourceRange Comment) { - Context.Comments.push_back(Comment); -} - diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4c25844..b529e5b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -42,7 +42,6 @@ namespace llvm { } namespace clang { - class AnalysisContext; class ASTContext; class ASTConsumer; class CodeCompleteConsumer; @@ -321,6 +320,14 @@ public: Diag(0) { } + AccessedEntity(MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl) + : Access(FoundDecl.getAccess()), IsMember(true), + Target(FoundDecl.getDecl()), NamingClass(NamingClass), + Diag(0) { + } + AccessedEntity(BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, @@ -678,8 +685,6 @@ public: /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } - virtual void ActOnComment(SourceRange Comment); - //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // @@ -778,6 +783,7 @@ public: const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); + void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -938,6 +944,10 @@ public: virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, SourceLocation RBraceLoc); + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable + /// error parsing the definition of a tag. + virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl); + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, @@ -1126,12 +1136,12 @@ public: typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; void AddOverloadCandidate(NamedDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet); void AddOverloadCandidate(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, @@ -1141,20 +1151,21 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); - void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access, + void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, bool ForceRValue = false); - void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, + void AddMethodCandidate(CXXMethodDecl *Method, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -1163,24 +1174,24 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddConversionCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectTy, Expr **Args, unsigned NumArgs, @@ -1284,9 +1295,6 @@ public: OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, SourceLocation OpLoc); - /// CheckUnreachable - Check for unreachable code. - void CheckUnreachable(AnalysisContext &); - /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. @@ -1294,15 +1302,9 @@ public: CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. - void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &); - void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &); bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); - enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; - ControlFlowKind CheckFallThrough(AnalysisContext &); - Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup @@ -2473,10 +2475,11 @@ public: bool IsImplicitConstructor, bool AnyErrors); - /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl, - /// mark all its non-trivial member and base destructor declarations - /// as referenced. - void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, + /// mark all the non-trivial destructors of its members and bases as + /// referenced. + void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, + CXXRecordDecl *Record); /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual /// members need to be marked as referenced at the end of the translation @@ -2617,11 +2620,13 @@ public: AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); + AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, AccessSpecifier Access); @@ -2634,8 +2639,7 @@ public: AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index f0a38d5..40b320c 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -52,7 +52,7 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, namespace { struct EffectiveContext { - EffectiveContext() : Record(0), Function(0) {} + EffectiveContext() : Function(0) {} explicit EffectiveContext(DeclContext *DC) { if (isa<FunctionDecl>(DC)) { @@ -60,18 +60,28 @@ struct EffectiveContext { DC = Function->getDeclContext(); } else Function = 0; - - if (isa<CXXRecordDecl>(DC)) - Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); - else - Record = 0; + + // C++ [class.access.nest]p1: + // A nested class is a member and as such has the same access + // rights as any other member. + // C++ [class.access]p2: + // A member of a class can also access all the names to which + // the class has access. + // This implies that the privileges of nesting are transitive. + while (isa<CXXRecordDecl>(DC)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); + Records.push_back(Record); + DC = Record->getDeclContext(); + } } - bool isClass(const CXXRecordDecl *R) const { - return R->getCanonicalDecl() == Record; + bool includesClass(const CXXRecordDecl *R) const { + R = R->getCanonicalDecl(); + return std::find(Records.begin(), Records.end(), R) + != Records.end(); } - CXXRecordDecl *Record; + llvm::SmallVector<CXXRecordDecl*, 4> Records; FunctionDecl *Function; }; } @@ -83,48 +93,133 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { return DeclaringClass; } +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Friend) { + // FIXME: close matches becuse of dependency + if (EC.includesClass(Friend)) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; +} + +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *Friend) { + if (Type *T = Friend->getFriendType()) { + CanQualType CT = T->getCanonicalTypeUnqualified(); + if (const RecordType *RT = CT->getAs<RecordType>()) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); + + // TODO: we can fail early for a lot of type classes. + if (T->isDependentType()) + return Sema::AR_dependent; + + return Sema::AR_inaccessible; + } + + NamedDecl *D + = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + + // FIXME: declarations with dependent or templated scope. + + // For class templates, we want to check whether any of the records + // are possible specializations of the template. + if (isa<ClassTemplateDecl>(D)) { + for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CXXRecordDecl *Record = *I; + ClassTemplateDecl *CTD; + + // A specialization of the template... + if (isa<ClassTemplateSpecializationDecl>(Record)) { + CTD = cast<ClassTemplateSpecializationDecl>(Record) + ->getSpecializedTemplate(); + + // ... or the template pattern itself. + } else { + CTD = Record->getDescribedClassTemplate(); + } + + if (CTD && D == CTD->getCanonicalDecl()) + return Sema::AR_accessible; + } + + return Sema::AR_inaccessible; + } + + // Same thing for function templates. + if (isa<FunctionTemplateDecl>(D)) { + if (!EC.Function) return Sema::AR_inaccessible; + + FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); + if (!FTD) + FTD = EC.Function->getDescribedFunctionTemplate(); + + if (FTD && D == FTD->getCanonicalDecl()) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; + } + + // Friend functions. FIXME: close matches due to dependency. + // + // The decl pointers in EC have been canonicalized, so pointer + // equality is sufficient. + if (D == EC.Function) + return Sema::AR_accessible; + + if (isa<CXXRecordDecl>(D)) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(D)); + + return Sema::AR_inaccessible; +} + static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { // A class always has access to its own members. - if (EC.isClass(Class)) + if (EC.includesClass(Class)) return Sema::AR_accessible; + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + // Okay, check friends. for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), E = Class->friend_end(); I != E; ++I) { FriendDecl *Friend = *I; - if (Type *T = Friend->getFriendType()) { - if (EC.Record && - S.Context.hasSameType(QualType(T, 0), - S.Context.getTypeDeclType(EC.Record))) - return Sema::AR_accessible; - } else { - NamedDecl *D - = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + switch (MatchesFriend(S, EC, Friend)) { + case Sema::AR_accessible: + return Sema::AR_accessible; - // The decl pointers in EC have been canonicalized, so pointer - // equality is sufficient. - if (D == EC.Function || D == EC.Record) - return Sema::AR_accessible; - } + case Sema::AR_inaccessible: + break; + + case Sema::AR_dependent: + OnFailure = Sema::AR_dependent; + break; - // FIXME: templates! templated contexts! dependent delay! + case Sema::AR_delayed: + llvm_unreachable("cannot get delayed answer from MatchesFriend"); + } } // That's it, give up. - return Sema::AR_inaccessible; + return OnFailure; } /// Finds the best path from the naming class to the declaring class, /// taking friend declarations into account. /// +/// \param FinalAccess the access of the "final step", or AS_none if +/// there is no final step. /// \return null if friendship is dependent static CXXBasePath *FindBestPath(Sema &S, const EffectiveContext &EC, CXXRecordDecl *Derived, CXXRecordDecl *Base, + AccessSpecifier FinalAccess, CXXBasePaths &Paths) { // Derive the paths to the desired base. bool isDerived = Derived->isDerivedFrom(Base, Paths); @@ -133,28 +228,43 @@ static CXXBasePath *FindBestPath(Sema &S, CXXBasePath *BestPath = 0; + assert(FinalAccess != AS_none && "forbidden access after declaring class"); + // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { // Walk through the path backwards. - AccessSpecifier PathAccess = AS_public; + AccessSpecifier PathAccess = FinalAccess; CXXBasePath::iterator I = PI->end(), E = PI->begin(); while (I != E) { --I; + assert(PathAccess != AS_none); + + // If the declaration is a private member of a base class, there + // is no level of friendship in derived classes that can make it + // accessible. + if (PathAccess == AS_private) { + PathAccess = AS_none; + break; + } + AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); if (BaseAccess != AS_public) { switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_inaccessible: break; - case Sema::AR_accessible: BaseAccess = AS_public; break; - case Sema::AR_dependent: return 0; + case Sema::AR_inaccessible: + PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); + break; + case Sema::AR_accessible: + PathAccess = AS_public; + break; + case Sema::AR_dependent: + return 0; case Sema::AR_delayed: llvm_unreachable("friend resolution is never delayed"); break; } } - - PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); } // Note that we modify the path's Access field to the @@ -199,7 +309,8 @@ static void DiagnoseAccessPath(Sema &S, } CXXBasePaths Paths; - CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths); + CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, + AS_public, Paths); CXXBasePath::iterator I = Path.end(), E = Path.begin(); while (I != E) { @@ -304,7 +415,7 @@ static void TryElevateAccess(Sema &S, CXXRecordDecl *NamingClass = Entity.getNamingClass(); // Adjust the declaration of the referred entity. - AccessSpecifier DeclAccess = AS_none; + AccessSpecifier DeclAccess = AS_public; if (Entity.isMemberAccess()) { NamedDecl *Target = Entity.getTargetDecl(); @@ -329,17 +440,15 @@ static void TryElevateAccess(Sema &S, // Append the declaration's access if applicable. CXXBasePaths Paths; CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), - DeclaringClass, Paths); + DeclaringClass, DeclAccess, Paths); if (!Path) { // FIXME: delay dependent friendship return; } - // Grab the access along the best path. + // Grab the access along the best path (note that this includes the + // final-step access). AccessSpecifier NewAccess = Path->Access; - if (Entity.isMemberAccess()) - NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess); - assert(NewAccess <= Access && "access along best path worse than direct?"); Access = NewAccess; } @@ -350,51 +459,38 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, SourceLocation Loc, Sema::AccessedEntity const &Entity) { AccessSpecifier Access = Entity.getAccess(); - assert(Access != AS_public); + assert(Access != AS_public && "called for public access!"); + // Find a non-anonymous naming class. For records with access, + // there should always be one of these. CXXRecordDecl *NamingClass = Entity.getNamingClass(); while (NamingClass->isAnonymousStructOrUnion()) - // This should be guaranteed by the fact that the decl has - // non-public access. If not, we should make it guaranteed! NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); - if (!EC.Record) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - - if (!Entity.isQuiet()) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); - return Sema::AR_inaccessible; - } - - // White-list accesses from within the declaring class. - if (Access != AS_none && EC.isClass(NamingClass)) + // White-list accesses from classes with privileges equivalent to the + // naming class --- but only if the access path isn't forbidden + // (i.e. an access of a private member from a subclass). + if (Access != AS_none && EC.includesClass(NamingClass)) return Sema::AR_accessible; - - // If the access is worse than 'protected', try to promote to it using - // friend declarations. - bool TriedElevation = false; - if (Access != AS_protected) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - TriedElevation = true; - } + + // Try to elevate access. + // FIXME: delay if elevation was dependent? + // TODO: on some code, it might be better to do the protected check + // without trying to elevate first. + TryElevateAccess(S, EC, Entity, Access); + if (Access == AS_public) return Sema::AR_accessible; // Protected access. if (Access == AS_protected) { // FIXME: implement [class.protected]p1 - if (EC.Record->isDerivedFrom(NamingClass)) - return Sema::AR_accessible; + for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) + if ((*I)->isDerivedFrom(NamingClass)) + return Sema::AR_accessible; - // FIXME: delay dependent classes + // FIXME: delay if we can't decide class derivation yet. } - // We're about to reject; one last chance to promote access. - if (!TriedElevation) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - } - // Okay, that's it, reject it. if (!Entity.isQuiet()) DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); @@ -431,15 +527,13 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { } Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, - NamedDecl *D, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || !E->getNamingClass() || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, - E->getNamingClass(), Access, D); + AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -448,14 +542,12 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, /// Perform access-control checking on a previously-unresolved member /// access which has now been resolved to a member. Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, - NamedDecl *D, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, - E->getNamingClass(), Access, D); + AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -473,7 +565,8 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Dtor, Access)); Entity.setDiag(PDiag); // TODO: avoid copy return CheckAccess(*this, Loc, Entity); @@ -488,8 +581,8 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, - NamingClass, Access, Constructor); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Constructor, Access)); Entity.setDiag(diag::err_access_ctor); return CheckAccess(*this, UseLoc, Entity); @@ -506,29 +599,45 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Target, Access)); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); } +/// Checks access to an overloaded operator new or delete. +Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair Found) { + if (!getLangOptions().AccessControl || + !NamingClass || + Found.getAccess() == AS_public) + return AR_accessible; + + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + Entity.setDiag(diag::err_access) + << PlacementRange; + + return CheckAccess(*this, OpLoc, Entity); +} + /// Checks access to an overloaded member operator, including /// conversion operators. Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, Expr *ObjectExpr, Expr *ArgExpr, - NamedDecl *MemberOperator, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - AccessedEntity Entity(AccessedEntity::Member, - NamingClass, Access, MemberOperator); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -580,7 +689,8 @@ 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(AccessedEntity::Member, - R.getNamingClass(), I.getAccess(), *I); + R.getNamingClass(), + I.getPair()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 3fac79d..0a33485 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,9 +13,6 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -30,7 +27,6 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include <limits> -#include <queue> using namespace clang; /// getLocationOfStringLiteralByte - Return a source location that points to the @@ -2045,6 +2041,11 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, if (!tmp.isNull()) rt = tmp; } + if (const EnumType *E = lt->getAs<EnumType>()) + lt = E->getDecl()->getPromotionType(); + if (const EnumType *E = rt->getAs<EnumType>()) + rt = E->getDecl()->getPromotionType(); + // The rule is that the signed operand becomes unsigned, so isolate the // signed operand. Expr *signedOperand = lex, *unsignedOperand = rex; @@ -2219,276 +2220,6 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } - - -namespace { -class UnreachableCodeHandler : public reachable_code::Callback { - Sema &S; -public: - UnreachableCodeHandler(Sema *s) : S(*s) {} - - void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { - S.Diag(L, diag::warn_unreachable) << R1 << R2; - } -}; -} - -/// CheckUnreachable - Check for unreachable code. -void Sema::CheckUnreachable(AnalysisContext &AC) { - // We avoid checking when there are errors, as the CFG won't faithfully match - // the user's code. - if (getDiagnostics().hasErrorOccurred() || - Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - UnreachableCodeHandler UC(this); - reachable_code::FindUnreachableCode(AC, UC); -} - -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { - CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - - // The CFG leaves in dead things, and we don't want the dead code paths to - // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), - live); - - bool AddEHEdges = AC.getAddEHEdges(); - if (!AddEHEdges && count != cfg->getNumBlockIDs()) - // When there are things remaining dead, and we didn't add EH edges - // from CallExprs to the catch clauses, we have to go back and - // mark them as live. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - count += reachable_code::ScanReachableFromBlock(b, live); - continue; - } - } - } - - // Now we know what is live, we check the live precessors of the exit block - // and look for fall through paths, being careful to ignore normal returns, - // and exceptional paths. - bool HasLiveReturn = false; - bool HasFakeEdge = false; - bool HasPlainEdge = false; - bool HasAbnormalEdge = false; - for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), - E = cfg->getExit().pred_end(); - I != E; - ++I) { - CFGBlock& B = **I; - if (!live[B.getBlockID()]) - continue; - if (B.size() == 0) { - if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { - HasAbnormalEdge = true; - continue; - } - - // A labeled empty statement, or the entry block... - HasPlainEdge = true; - continue; - } - Stmt *S = B[B.size()-1]; - if (isa<ReturnStmt>(S)) { - HasLiveReturn = true; - continue; - } - if (isa<ObjCAtThrowStmt>(S)) { - HasFakeEdge = true; - continue; - } - if (isa<CXXThrowExpr>(S)) { - HasFakeEdge = true; - continue; - } - if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } - if (isa<CXXTryStmt>(S)) { - HasAbnormalEdge = true; - continue; - } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (B.succ_begin()[0] != &cfg->getExit()) { - HasAbnormalEdge = true; - continue; - } - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } - } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; - } - if (!HasPlainEdge) { - if (HasLiveReturn) - return NeverFallThrough; - return NeverFallThroughOrReturn; - } - if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) - return MaybeFallThrough; - // This says AlwaysFallThrough for calls to functions that are not marked - // noreturn, that don't return. If people would like this warning to be more - // accurate, such functions should be marked as noreturn. - return AlwaysFallThrough; -} - -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a -/// function that should return a value. Check that we don't fall off the end -/// of a noreturn function. We assume that functions and blocks not marked -/// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - - bool ReturnsVoid = false; - bool HasNoReturn = false; - - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // For function templates, class templates and member function templates - // we'll do the analysis at instantiation time. - if (FD->isDependentContext()) - return; - - ReturnsVoid = FD->getResultType()->isVoidType(); - HasNoReturn = FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); - - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - ReturnsVoid = MD->getResultType()->isVoidType(); - HasNoReturn = MD->hasAttr<NoReturnAttr>(); - } - - // Short circuit for compilation speed. - if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored || ReturnsVoid) - && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) - == Diagnostic::Ignored || !HasNoReturn) - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Function try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckFallThroughForBlock - Check that we don't fall off the end of a block -/// that should return a value. Check that we don't fall off the end of a -/// noreturn block. We assume that functions and blocks not marked noreturn -/// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ - if (FT->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FT->getNoReturnAttr()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if (ReturnsVoid - && !HasNoReturn - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Funtion try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); - break; - case NeverFallThrough: - break; - } - } -} - /// CheckParmsForFunctionDef - Check that the parameters of the given /// function are appropriate for the definition of a function. This /// takes care of any checks that cannot be performed on the diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 4693fa9..317eef8 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2253,7 +2253,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, Results.push_back(ResultCandidate(FDecl)); else // FIXME: access? - AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none), + Args, NumArgs, CandidateSet, false, false, /*PartialOverloading*/ true); } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dab7d88..e11e161 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/AnalysisContext.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -2403,6 +2403,10 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); } + // Diagnose shadowed variables before filtering for scope. + if (!D.getCXXScopeSpec().isSet()) + DiagnoseShadow(S, D, Previous); + // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). @@ -2454,6 +2458,72 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, return NewVD; } +/// \brief Diagnose variable or built-in function shadowing. +/// +/// This method is called as soon as a NamedDecl materializes to check +/// if it shadows another local or global variable, or a built-in function. +/// +/// For performance reasons, the lookup results are reused from the calling +/// context. +/// +/// \param S the scope in which the shadowing name is being declared +/// \param R the lookup of the name +/// +void Sema::DiagnoseShadow(Scope *S, Declarator &D, + const LookupResult& R) { + // Return if warning is ignored. + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) + return; + + // Don't diagnose declarations at file scope. The scope might not + // have a DeclContext if (e.g.) we're parsing a function prototype. + DeclContext *NewDC = static_cast<DeclContext*>(S->getEntity()); + if (NewDC && NewDC->isFileContext()) + return; + + // Only diagnose if we're shadowing an unambiguous field or variable. + if (R.getResultKind() != LookupResult::Found) + return; + + NamedDecl* ShadowedDecl = R.getFoundDecl(); + if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) + return; + + DeclContext *OldDC = ShadowedDecl->getDeclContext(); + + // Only warn about certain kinds of shadowing for class members. + if (NewDC && NewDC->isRecord()) { + // In particular, don't warn about shadowing non-class members. + if (!OldDC->isRecord()) + return; + + // TODO: should we warn about static data members shadowing + // static data members from base classes? + + // TODO: don't diagnose for inaccessible shadowed members. + // This is hard to do perfectly because we might friend the + // shadowing context, but that's just a false negative. + } + + // Determine what kind of declaration we're shadowing. + unsigned Kind; + if (isa<RecordDecl>(OldDC)) { + if (isa<FieldDecl>(ShadowedDecl)) + Kind = 3; // field + else + Kind = 2; // static data member + } else if (OldDC->isFileContext()) + Kind = 1; // global + else + Kind = 0; // local + + DeclarationName Name = R.getLookupName(); + + // Emit warning and note. + Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); +} + /// \brief Perform semantic checking on a newly-created variable /// declaration. /// @@ -3896,7 +3966,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); if (II) { - if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { + LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); + LookupName(R, S); + if (R.isSingleResult()) { + NamedDecl *PrevDecl = R.getFoundDecl(); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -3910,6 +3984,8 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { II = 0; D.SetIdentifier(0, D.getIdentifierLoc()); D.setInvalidType(true); + } else { + DiagnoseShadow(S, D, R); } } } @@ -4183,9 +4259,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 - // explosion for destrutors that can result and the compile time hit. - AnalysisContext AC(dcl, false); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); if (FunTmpl) @@ -4193,14 +4266,16 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, else FD = dyn_cast_or_null<FunctionDecl>(dcl); + sema::AnalysisBasedWarnings W(*this); + if (FD) { FD->setBody(Body); - if (FD->isMain()) + if (FD->isMain()) { // C and C++ allow for main to automagically return 0. // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); - else - CheckFallThroughForFunctionDef(FD, Body, AC); + W.disableCheckFallThrough(); + } if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); @@ -4212,9 +4287,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - CheckFallThroughForFunctionDef(MD, Body, AC); MD->setEndLoc(Body->getLocEnd()); - if (!MD->isInvalidDecl()) DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); } else { @@ -4267,28 +4340,40 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } if (Body) { - CheckUnreachable(AC); - // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) // Verify this. if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); - // Verify that that gotos and switch cases don't jump into scopes illegally. - // Verify that that gotos and switch cases don't jump into scopes illegally. + // Verify that that gotos and switch cases don't jump into scopes illegally. + // Verify that that gotos and switch cases don't jump into scopes illegally. if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) - MarkBaseAndMemberDestructorsReferenced(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (PP.getDiagnostics().hasErrorOccurred()) ExprTemporaries.clear(); - + else if (!isa<FunctionTemplateDecl>(dcl)) { + // Since the body is valid, issue any analysis-based warnings that are + // enabled. + QualType ResultType; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) { + ResultType = FD->getResultType(); + } + else { + ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl); + ResultType = MD->getResultType(); + } + W.IssueWarnings(dcl); + } + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); } @@ -5055,6 +5140,18 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, Consumer.HandleTagDeclDefinition(Tag); } +void Sema::ActOnTagDefinitionError(Scope *S, DeclPtrTy TagD) { + AdjustDeclIfTemplate(TagD); + TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + Tag->setInvalidDecl(); + + // We're undoing ActOnTagStartDefinition here, not + // ActOnStartCXXMemberDeclarations, so we don't have to mess with + // the FieldCollector. + + PopDeclContext(); +} + // Note that FieldName may be null for anonymous bitfields. bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, const Expr *BitWidth, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c27b0d5..13a7ead 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1643,29 +1643,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, Constructor->setNumBaseOrMemberInitializers(NumInitializers); CXXBaseOrMemberInitializer **baseOrMemberInitializers = new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; - + memcpy(baseOrMemberInitializers, AllToInit.data(), + NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); - for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) { - CXXBaseOrMemberInitializer *Member = AllToInit[Idx]; - baseOrMemberInitializers[Idx] = Member; - if (!Member->isBaseInitializer()) - continue; - const Type *BaseType = Member->getBaseClass(); - const RecordType *RT = BaseType->getAs<RecordType>(); - if (!RT) - continue; - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(RT->getDecl()); - - // We don't know if a dependent type will have an implicit destructor. - if (BaseClassDecl->isDependentType()) - continue; - if (BaseClassDecl->hasTrivialDestructor()) - continue; - CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context); - MarkDeclarationReferenced(Constructor->getLocation(), DD); - } + // Constructors implicitly reference the base and member + // destructors. + MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(), + Constructor->getParent()); } return HadError; @@ -1848,9 +1833,10 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } void -Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { - // Ignore dependent destructors. - if (Destructor->isDependentContext()) +Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, + CXXRecordDecl *ClassDecl) { + // Ignore dependent contexts. + if (ClassDecl->isDependentContext()) return; // FIXME: all the access-control diagnostics are positioned on the @@ -1858,8 +1844,6 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // user might reasonably want to know why the destructor is being // emitted, and we currently don't say. - CXXRecordDecl *ClassDecl = Destructor->getParent(); - // Non-static data members. for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { @@ -1881,8 +1865,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { << Field->getDeclName() << FieldType); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; @@ -1910,8 +1893,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { << Base->getType() << Base->getSourceRange()); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } // Virtual bases. @@ -1935,8 +1917,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { PartialDiagnostic(diag::err_access_dtor_vbase) << VBase->getType()); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } } @@ -3819,7 +3800,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Destructor; - MarkBaseAndMemberDestructorsReferenced(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); // FIXME: If CheckDestructor fails, we should emit a note about where the // implicit destructor was needed. @@ -4222,6 +4204,8 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, 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); @@ -4238,12 +4222,11 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, ((Kind.getKind() == InitializationKind::IK_Default) && Constructor->isDefaultConstructor())) { if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(), + SemaRef.AddOverloadCandidate(Constructor, FoundDecl, Args, NumArgs, CandidateSet); } } @@ -4553,10 +4536,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (Conv->getConversionType()->isLValueReferenceType() && (AllowExplicit || !Conv->isExplicit())) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC, + AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet); else - AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init, + AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet); } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a39ba2f..fe6f3b9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/AnalysisContext.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -1691,7 +1691,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ExprError(); } - if (VD->getType()->isArrayType() && !VD->hasAttr<BlocksAttr>()) { + if (VD->getType()->isArrayType()) { Diag(Loc, diag::err_ref_array_type); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); @@ -1751,7 +1751,10 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; - llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer); + bool Invalid = false; + llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); + if (Invalid) + return ExprError(); CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), PP); @@ -1789,7 +1792,10 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { const char *ThisTokBegin = &IntegerBuffer[0]; // Get the spelling of the token, which eliminates trigraphs, etc. - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + if (Invalid) + return ExprError(); NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, Tok.getLocation(), PP); @@ -4573,7 +4579,11 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers()) ConvTy = CompatiblePointerDiscardsQualifiers; - if (!Context.typesAreCompatible(lhptee, rhptee)) + if (!getLangOptions().CPlusPlus) { + if (!Context.typesAreBlockPointerCompatible(lhsType, rhsType)) + return IncompatibleBlockPointer; + } + else if (!Context.typesAreCompatible(lhptee, rhptee)) return IncompatibleBlockPointer; return ConvTy; } @@ -4582,8 +4592,18 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, /// for assignment compatibility. Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { - if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) + if (lhsType->isObjCBuiltinType()) { + // Class is not compatible with ObjC object pointers. + if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType()) + return IncompatiblePointer; + return Compatible; + } + if (rhsType->isObjCBuiltinType()) { + // Class is not compatible with ObjC object pointers. + if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType()) + return IncompatiblePointer; return Compatible; + } QualType lhptee = lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); QualType rhptee = @@ -5780,9 +5800,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_SubObjCPropertySetting: Diag = diag::error_no_subobject_property_setting; break; - case Expr::MLV_SubObjCPropertyGetterSetting: - Diag = diag::error_no_subobject_property_getter_setting; - break; } SourceRange Assign; @@ -6986,9 +7003,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, return ExprError(); } - AnalysisContext AC(BSI->TheDecl); - CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); - CheckUnreachable(AC); + // Issue any analysis-based warnings. + sema::AnalysisBasedWarnings W(*this); + W.IssueWarnings(BSI->TheDecl, BlockTy); + Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); PopFunctionOrBlockScope(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e1e5efa..366089f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -912,6 +912,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); LookupQualifiedName(FoundDelete, RD); } + if (FoundDelete.isAmbiguous()) + return true; // FIXME: clean up expressions? if (FoundDelete.empty()) { DeclareGlobalNewDelete(); @@ -919,8 +921,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, } FoundDelete.suppressDiagnostics(); - llvm::SmallVector<NamedDecl *, 4> Matches; - if (NumPlaceArgs > 1) { + + llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; + + if (NumPlaceArgs > 0) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the @@ -962,7 +966,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) - Matches.push_back(Fn); + Matches.push_back(std::make_pair(D.getPair(), Fn)); } } else { // C++ [expr.new]p20: @@ -973,7 +977,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) if (isNonPlacementDeallocationFunction(Fn)) - Matches.push_back(*D); + Matches.push_back(std::make_pair(D.getPair(), Fn)); } } @@ -982,8 +986,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // function, that function will be called; otherwise, no // deallocation function will be called. if (Matches.size() == 1) { - // FIXME: Drops access, using-declaration info! - OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl()); + OperatorDelete = Matches[0].second; // C++0x [expr.new]p20: // If the lookup finds the two-parameter form of a usual @@ -998,6 +1001,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; + } else { + CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), + Matches[0].first); } } @@ -1019,25 +1025,28 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, << Name << Range; } - // FIXME: handle ambiguity + if (R.isAmbiguous()) + return true; + + R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. + NamedDecl *D = (*Alloc)->getUnderlyingDecl(); - if (FunctionTemplateDecl *FnTemplate = - dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) { - AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(), + if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { + AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/0, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); continue; } - FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl()); - AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates, + FunctionDecl *Fn = cast<FunctionDecl>(D); + AddOverloadCandidate(Fn, Alloc.getPair(), Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); } @@ -1050,7 +1059,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // The first argument is size_t, and the first parameter must be size_t, // too. This is checked on declaration and can be assumed. (It can't be // asserted on, though, since invalid decls are left in there.) - // Whatch out for variadic allocator function. + // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { if (PerformCopyInitialization(Args[i], @@ -1059,6 +1068,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, return true; } Operator = FnDecl; + CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); return false; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 98a7eec..f86ae51 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2007,7 +2007,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep( S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); // Access is currently ignored for these. - S.Function = DeclAccessPair::make(Function, AccessSpecifier(0)); + S.Function.Function = Function; + S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none); Steps.push_back(S); } @@ -2028,12 +2029,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, } void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, QualType T) { Step S; S.Kind = SK_UserConversion; S.Type = T; - S.Function = DeclAccessPair::make(Function, Access); + S.Function.Function = Function; + S.Function.FoundDecl = FoundDecl; Steps.push_back(S); } @@ -2071,7 +2073,8 @@ InitializationSequence::AddConstructorInitializationStep( Step S; S.Kind = SK_ConstructorInitialization; S.Type = T; - S.Function = DeclAccessPair::make(Constructor, Access); + S.Function.Function = Constructor; + S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access); Steps.push_back(S); } @@ -2198,25 +2201,26 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = T1RecordDecl->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>(*Con); + FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, &Initializer, 1, CandidateSet); } } @@ -2257,11 +2261,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if ((AllowExplicit || !Conv->isExplicit()) && (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Initializer, ToType, CandidateSet); else - S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, ToType, CandidateSet); } } @@ -2284,7 +2288,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, T2 = cv1T1; // Add the user-defined conversion step. - Sequence.AddUserConversionStep(Function, Best->getAccess(), + Sequence.AddUserConversionStep(Function, Best->FoundDecl, T2.getNonReferenceType()); // Determine whether we need to perform derived-to-base or @@ -2574,25 +2578,26 @@ static void TryConstructorInitialization(Sema &S, 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>(*Con); + FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, Args, NumArgs, CandidateSet); } } @@ -2623,11 +2628,11 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. if (Kind.getKind() == InitializationKind::IK_Copy) { - Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType); + Sequence.AddUserConversionStep(Best->Function, Best->FoundDecl, DestType); } else { Sequence.AddConstructorInitializationStep( cast<CXXConstructorDecl>(Best->Function), - Best->getAccess(), + Best->FoundDecl.getAccess(), DestType); } } @@ -2744,25 +2749,27 @@ static void TryUserDefinedConversion(Sema &S, 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>(*Con); + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, &Initializer, 1, CandidateSet); } } @@ -2799,11 +2806,11 @@ static void TryUserDefinedConversion(Sema &S, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, CandidateSet); else - S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet); } } @@ -2825,13 +2832,13 @@ static void TryUserDefinedConversion(Sema &S, if (isa<CXXConstructorDecl>(Function)) { // Add the user-defined conversion step. Any cv-qualification conversion is // subsumed by the initialization. - Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType); return; } // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getResultType().getNonReferenceType(); - Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); // If the conversion following the call to the conversion function is // interesting, add it as a separate step. @@ -3135,8 +3142,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, if (!Constructor || Constructor->isInvalidDecl() || !Constructor->isCopyConstructor()) continue; - - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + + DeclAccessPair FoundDecl + = DeclAccessPair::make(Constructor, Constructor->getAccess()); + S.AddOverloadCandidate(Constructor, FoundDecl, &CurInitExpr, 1, CandidateSet); } @@ -3170,6 +3179,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, return S.ExprError(); } + S.CheckConstructorAccess(Loc, + cast<CXXConstructorDecl>(Best->Function), + Best->FoundDecl.getAccess()); + CurInit.release(); return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(), cast<CXXConstructorDecl>(Best->Function), @@ -3303,7 +3316,7 @@ InitializationSequence::Perform(Sema &S, // initializer to reflect that choice. // Access control was done in overload resolution. CurInit = S.FixOverloadedFunctionReference(move(CurInit), - cast<FunctionDecl>(Step->Function.getDecl())); + Step->Function.Function); break; case SK_CastDerivedToBaseRValue: @@ -3367,8 +3380,8 @@ InitializationSequence::Perform(Sema &S, // or a conversion function. CastExpr::CastKind CastKind = CastExpr::CK_Unknown; bool IsCopy = false; - FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl()); - AccessSpecifier FnAccess = Step->Function.getAccess(); + FunctionDecl *Fn = Step->Function.Function; + DeclAccessPair FoundFn = Step->Function.FoundDecl; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3390,7 +3403,8 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return S.ExprError(); - S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess); + S.CheckConstructorAccess(Kind.getLocation(), Constructor, + FoundFn.getAccess()); CastKind = CastExpr::CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -3402,7 +3416,7 @@ InitializationSequence::Perform(Sema &S, CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, - Conversion, FnAccess); + FoundFn); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -3469,7 +3483,7 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: { CXXConstructorDecl *Constructor - = cast<CXXConstructorDecl>(Step->Function.getDecl()); + = cast<CXXConstructorDecl>(Step->Function.Function); // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3506,7 +3520,8 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess()); + S.CheckConstructorAccess(Loc, Constructor, + Step->Function.FoundDecl.getAccess()); bool Elidable = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable(); @@ -3972,7 +3987,8 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_UserConversion: - OS << "user-defined conversion via " << S->Function->getNameAsString(); + OS << "user-defined conversion via " + << S->Function.Function->getNameAsString(); break; case SK_QualificationConversionRValue: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 2b49df2..18a0938 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -454,7 +454,10 @@ public: /// Always a FunctionDecl. /// For conversion decls, the naming class is the source type. /// For construct decls, the naming class is the target type. - DeclAccessPair Function; + struct { + FunctionDecl *Function; + DeclAccessPair FoundDecl; + } Function; /// \brief When Kind = SK_ConversionSequence, the implicit conversion /// sequence @@ -622,7 +625,7 @@ public: /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. void AddUserConversionStep(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, QualType T); /// \brief Add a new step that performs a qualification conversion to the diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 6caeec6..9ae520d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1176,7 +1176,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; - AccessSpecifier SubobjectAccess = AS_private; + AccessSpecifier SubobjectAccess = AS_none; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 3a0fe0a..41ed6c6 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -137,17 +137,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } - DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = - DC->lookup(PIDecl->getDeclName()); - bool PropertyInPrimaryClass = false; - for (; Found.first != Found.second; ++Found.first) - if (isa<ObjCPropertyDecl>(*Found.first)) { - PropertyInPrimaryClass = true; - break; - } - if (!PropertyInPrimaryClass) { + DeclContext *DC = cast<DeclContext>(CCPrimary); + if (!ObjCPropertyDecl::findPropertyDecl(DC, + PIDecl->getDeclName().getAsIdentifierInfo())) { // Protocol is not in the primary class. Must build one for it. ObjCDeclSpec ProtocolPropertyODS; // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f73ec9c..410bf9a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1525,28 +1525,30 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, for (llvm::tie(Con, ConEnd) = ToRecordDecl->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>(*Con); + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). - AddOverloadCandidate(Constructor, Constructor->getAccess(), + AddOverloadCandidate(Constructor, FoundDecl, &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -1569,7 +1571,8 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, = FromRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; + DeclAccessPair FoundDecl = I.getPair(); + NamedDecl *D = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); @@ -1583,11 +1586,11 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + AddTemplateConversionCandidate(ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet); else - AddConversionCandidate(Conv, I.getAccess(), ActingContext, + AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType, CandidateSet); } } @@ -2383,7 +2386,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// code completion. void Sema::AddOverloadCandidate(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, @@ -2404,7 +2407,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // function, e.g., X::f(). We use an empty type for the implied // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. - AddMethodCandidate(Method, Access, Method->getParent(), + AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; @@ -2434,8 +2437,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Function; - Candidate.Access = Access; Candidate.Viable = true; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2500,28 +2503,28 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { - // FIXME: using declarations - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) { + NamedDecl *D = F.getDecl()->getUnderlyingDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) - AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(), + AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(FD)->getParent(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, SuppressUserConversions); } else { - FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F); + FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D); if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) - AddMethodTemplateCandidate(FunTmpl, F.getAccess(), + AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddTemplateOverloadCandidate(FunTmpl, AS_none, + AddTemplateOverloadCandidate(FunTmpl, F.getPair(), /*FIXME: explicit args */ 0, Args, NumArgs, CandidateSet, SuppressUserConversions); @@ -2531,12 +2534,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, /// AddMethodCandidate - Adds a named decl (which is some kind of /// method) as a method candidate to the given overload set. -void Sema::AddMethodCandidate(NamedDecl *Decl, - AccessSpecifier Access, +void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { + NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); if (isa<UsingShadowDecl>(Decl)) @@ -2545,13 +2548,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0, + AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, + /*ExplicitArgs*/ 0, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } else { - AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext, + AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2567,7 +2571,7 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). void -Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, +Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2587,8 +2591,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Method; - Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2666,7 +2670,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -2702,7 +2706,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(Specialization && "Missing member function template specialization?"); assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access, + AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2712,7 +2716,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, /// an appropriate function template specialization. void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2737,8 +2741,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Args, NumArgs, Specialization, Info)) { CandidateSet.push_back(OverloadCandidate()); OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = FunctionTemplate->getTemplatedDecl(); - Candidate.Access = Access; Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; @@ -2753,7 +2757,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet, + AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2765,7 +2769,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { @@ -2781,8 +2785,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Conversion; - Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); @@ -2869,7 +2873,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// [temp.deduct.conv]). void Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet) { @@ -2893,7 +2897,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, Access, ActingDC, From, ToType, + AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, CandidateSet); } @@ -2903,7 +2907,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, /// with the given arguments (C++ [over.call.object]p2-4). Proto is /// the type of function that we'll eventually be calling. void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectType, @@ -2917,8 +2921,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = 0; - Candidate.Access = Access; Candidate.Surrogate = Conversion; Candidate.Viable = true; Candidate.IsSurrogate = true; @@ -3066,7 +3070,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, OperEnd = Operators.end(); Oper != OperEnd; ++Oper) - AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(), + AddMethodCandidate(Oper.getPair(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } @@ -3091,8 +3095,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = DeclAccessPair::make(0, AS_none); Candidate.Function = 0; - Candidate.Access = AS_none; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.BuiltinTypes.ResultTy = ResultTy; @@ -4179,15 +4183,16 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // For each of the ADL candidates we found, add it to the overload // set. for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { + DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none); if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { if (ExplicitTemplateArgs) continue; - AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, false, false, PartialOverloading); } else AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), - AS_none, ExplicitTemplateArgs, + FoundDecl, ExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } @@ -4951,12 +4956,11 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } } -static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D, - AccessSpecifier AS) { +static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { if (isa<UnresolvedLookupExpr>(E)) - return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS); + return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D); - return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS); + return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D); } /// ResolveAddressOfOverloadedFunction - Try to resolve the address of @@ -5013,7 +5017,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. - UnresolvedSet<4> Matches; // contains only FunctionDecls + llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -5057,8 +5061,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // a candidate? Find a testcase before changing the code. assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()), - I.getAccess()); + Matches.push_back(std::make_pair(I.getPair(), + cast<FunctionDecl>(Specialization->getCanonicalDecl()))); } continue; @@ -5081,8 +5085,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, ResultTy)) { - Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()), - I.getAccess()); + Matches.push_back(std::make_pair(I.getPair(), + cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; } } @@ -5092,10 +5096,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.empty()) return 0; else if (Matches.size() == 1) { - FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin()); + FunctionDecl *Result = Matches[0].second; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess()); + CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); return Result; } @@ -5112,50 +5116,54 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // two-pass algorithm (similar to the one used to identify the // best viable function in an overload set) that identifies the // best function template (if it exists). + + UnresolvedSet<4> MatchesCopy; // TODO: avoid! + for (unsigned I = 0, E = Matches.size(); I != E; ++I) + MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); UnresolvedSetIterator Result = - getMostSpecialized(Matches.begin(), Matches.end(), + getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), TPOC_Other, From->getLocStart(), PDiag(), PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0]->getDeclName(), + << Matches[0].second->getDeclName(), PDiag(diag::note_ovl_candidate) << (unsigned) oc_function_template); - assert(Result != Matches.end() && "no most-specialized template"); + assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); - if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess()); + if (Complain) { + DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first; + CheckUnresolvedAccess(*this, OvlExpr, FoundDecl); + } return cast<FunctionDecl>(*Result); } // [...] any function template specializations in the set are // eliminated if the set also contains a non-template function, [...] for (unsigned I = 0, N = Matches.size(); I != N; ) { - if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0) + if (Matches[I].second->getPrimaryTemplate() == 0) ++I; else { - Matches.erase(I); - --N; + Matches[I] = Matches[--N]; + Matches.set_size(N); } } // [...] After such eliminations, if any, there shall remain exactly one // selected function. if (Matches.size() == 1) { - UnresolvedSetIterator Match = Matches.begin(); - MarkDeclarationReferenced(From->getLocStart(), *Match); + MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess()); - return cast<FunctionDecl>(*Match); + CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + return cast<FunctionDecl>(Matches[0].second); } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) - << Matches[0]->getDeclName(); - for (UnresolvedSetIterator I = Matches.begin(), - E = Matches.end(); I != E; ++I) - NoteOverloadCandidate(cast<FunctionDecl>(*I)); + << Matches[0].second->getDeclName(); + for (unsigned I = 0, E = Matches.size(); I != E; ++I) + NoteOverloadCandidate(Matches[I].second); return 0; } @@ -5227,25 +5235,26 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, - NamedDecl *Callee, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { + NamedDecl *Callee = FoundDecl.getDecl(); if (isa<UsingShadowDecl>(Callee)) Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl(); if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { assert(!ExplicitTemplateArgs && "Explicit template arguments?"); - S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet, + S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet, false, false, PartialOverloading); return; } if (FunctionTemplateDecl *FuncTemplate = dyn_cast<FunctionTemplateDecl>(Callee)) { - S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs, + S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl, + ExplicitTemplateArgs, Args, NumArgs, CandidateSet); return; } @@ -5301,7 +5310,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) - AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs, + AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args, NumArgs, CandidateSet, PartialOverloading); @@ -5423,7 +5432,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; - CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess()); + CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); Fn = FixOverloadedFunctionReference(Fn, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5549,7 +5558,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl); if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) return ExprError(); @@ -5733,8 +5742,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { // Best->Access is only meaningful for class members. - CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method, - Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl); OwningExprResult Arg1 = PerformCopyInitialization( @@ -5908,8 +5916,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. - CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl, - Best->getAccess()); + CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6054,12 +6061,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (TemplateArgs) continue; - AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType, + AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), - I.getAccess(), ActingDC, TemplateArgs, + I.getPair(), ActingDC, TemplateArgs, ObjectType, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); @@ -6072,7 +6079,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast<CXXMethodDecl>(Best->Function); - CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess()); + CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); break; case OR_No_Viable_Function: @@ -6176,7 +6183,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(), + AddMethodCandidate(Oper.getPair(), Object->getType(), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -6221,7 +6228,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ConvType = ConvPtrType->getPointeeType(); if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto, + AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, Object->getType(), Args, NumArgs, CandidateSet); } @@ -6278,7 +6285,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); - CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6293,8 +6300,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CommaLocs, RParenLoc).release(); } - CheckMemberOperatorAccess(LParenLoc, Object, 0, - Best->Function, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); // We found an overloaded operator(). Build a CXXOperatorCallExpr // that calls this method, using Object for the implicit object @@ -6429,13 +6435,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - NamedDecl *D = *Oper; - CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext, - Base->getType(), 0, 0, CandidateSet, + AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } @@ -6470,6 +6470,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { return ExprError(); } + CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl); + // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method)) diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 58e416c..cff4774 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -450,6 +451,11 @@ namespace clang { /// function pointer or reference (C++ [over.call.object]). FunctionDecl *Function; + /// FoundDecl - The original declaration that was looked up / + /// invented / otherwise found, together with its access. + /// Might be a UsingShadowDecl or a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + // BuiltinTypes - Provides the return and parameter types of a // built-in overload candidate. Only valid when Function is NULL. struct { @@ -486,14 +492,6 @@ namespace clang { /// Actually an OverloadFailureKind. unsigned char FailureKind; - /// PathAccess - The 'path access' to the given function/conversion. - /// Actually an AccessSpecifier. - unsigned Access; - - AccessSpecifier getAccess() const { - return AccessSpecifier(Access); - } - /// A structure used to record information about a failed /// template argument deduction. struct DeductionFailureInfo { |