aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp369
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h35
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CXXFieldCollector.h5
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/Sema.h66
-rw-r--r--lib/Sema/SemaAccess.cpp290
-rw-r--r--lib/Sema/SemaChecking.cpp279
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp129
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--lib/Sema/SemaExpr.cpp42
-rw-r--r--lib/Sema/SemaExprCXX.cpp36
-rw-r--r--lib/Sema/SemaInit.cpp96
-rw-r--r--lib/Sema/SemaInit.h7
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaObjCProperty.cpp14
-rw-r--r--lib/Sema/SemaOverload.cpp186
-rw-r--r--lib/Sema/SemaOverload.h14
20 files changed, 1005 insertions, 636 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
new file mode 100644
index 000000000000..c4ceec0f8111
--- /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 000000000000..39da1b14d4a9
--- /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 237803a1c453..ac0dfd6c3af5 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 69d13515fa65..63c6ee3f74ba 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 898b3c230e87..7cd39895f6fd 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 3b4afef70b53..7112687605b7 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 4c258448daf2..b529e5b640ba 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 f0a38d5970cc..40b320c1be5e 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 3fac79deba4b..0a33485dd777 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 4693fa974edb..317eef8d60fc 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 dab7d883a1d6..e11e161ffde2 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 c27b0d5013c6..13a7ead76bdf 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 a39ba2f7d06e..fe6f3b9f5607 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 e1e5efa7d3a9..366089f2ab63 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 98a7eec232f6..f86ae51c2806 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 2b49df28fe86..18a0938f7c09 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 6caeec620d01..9ae520d27a65 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 3a0fe0a61afe..41ed6c630cb2 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 f73ec9cb61c5..410bf9a7c1e9 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 58e416c87e59..cff4774fba27 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 {