diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema')
38 files changed, 13416 insertions, 6530 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 7a14855e..babb8af 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -25,14 +26,23 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/UninitializedValues.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include <algorithm> +#include <vector> using namespace clang; @@ -86,7 +96,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); @@ -101,7 +111,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { 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); + count += reachable_code::ScanReachableFromBlock(&b, live); continue; } } @@ -126,31 +136,23 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { if (!live[B.getBlockID()]) continue; + // Skip blocks which contain an element marked as no-return. They don't + // represent actually viable edges into the exit block, so mark them as + // abnormal. + if (B.hasNoReturnElement()) { + HasAbnormalEdge = true; + continue; + } + // Destructors can appear after the 'return' in the CFG. This is // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); - bool hasNoReturnDtor = false; - - for ( ; ri != re ; ++ri) { - CFGElement CE = *ri; - - // FIXME: The right solution is to just sever the edges in the - // CFG itself. - if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>()) - if (iDtor->isNoReturn(AC.getASTContext())) { - hasNoReturnDtor = true; - HasFakeEdge = true; - break; - } - - if (isa<CFGStmt>(CE)) + + for ( ; ri != re ; ++ri) + if (isa<CFGStmt>(*ri)) break; - } - - if (hasNoReturnDtor) - continue; - + // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { @@ -163,7 +165,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } CFGStmt CS = cast<CFGStmt>(*ri); - Stmt *S = CS.getStmt(); + const Stmt *S = CS.getStmt(); if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; @@ -187,34 +189,13 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { HasAbnormalEdge = true; continue; } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) - == B.succ_end()) { - HasAbnormalEdge = true; - continue; - } - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - QualType calleeType = CEE->getType(); - if (calleeType == AC.getASTContext().BoundMemberTy) { - calleeType = Expr::findBoundMemberType(CEE); - assert(!calleeType.isNull() && "analyzing unresolved call?"); - } - if (getFunctionExtInfo(calleeType).getNoReturn()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } + if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) + == B.succ_end()) { + HasAbnormalEdge = true; + continue; } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; + + HasPlainEdge = true; } if (!HasPlainEdge) { if (HasLiveReturn) @@ -258,7 +239,23 @@ struct CheckFallThroughDiagnostics { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) isVirtualMethod = Method->isVirtual(); - if (!isVirtualMethod) + // Don't suggest that template instantiations be marked "noreturn" + bool isTemplateInstantiation = false; + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) { + switch (Function->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + break; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + isTemplateInstantiation = true; + break; + } + } + + if (!isVirtualMethod && !isTemplateInstantiation) D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function; else @@ -284,25 +281,25 @@ struct CheckFallThroughDiagnostics { return D; } - bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, + bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { return (ReturnsVoid || D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!HasNoReturn || D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } // For blocks. return ReturnsVoid && !HasNoReturn && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } }; @@ -340,7 +337,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, } } - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) @@ -369,9 +366,17 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) - S.Diag(Compound->getLBracLoc(), - CD.diag_NeverFallThroughOrReturn); + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 1 << MD; + } else { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); + } + } break; case NeverFallThrough: break; @@ -415,13 +420,58 @@ public: }; } +static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { + // Don't issue a fixit if there is already an initializer. + if (VD->getInit()) + return false; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType VariableTy = VD->getType().getCanonicalType(); + + if (VariableTy->isObjCObjectPointerType() || + VariableTy->isBlockPointerType()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (VariableTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (VariableTy->isEnumeralType()) + return false; + else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { + if (S.Context.getLangOptions().CPlusPlus0x) + initialization = " = nullptr"; + // Check if 'NULL' is defined. + else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) + initialization = " = NULL"; + else + initialization = " = 0"; + } + else if (VariableTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() + << FixItHint::CreateInsertion(loc, initialization); + return true; + } + return false; +} + /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed /// as a warning. If a pariticular use is one we omit warnings for, returns /// false. static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, - const Expr *E, bool isAlwaysUninit) { + const Expr *E, bool isAlwaysUninit, + bool alwaysReportSelfInit = false) { bool isSelfInit = false; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { @@ -441,7 +491,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, // TODO: Should we suppress maybe-uninitialized warnings for // variables initialized in this way? if (const Expr *Initializer = VD->getInit()) { - if (DRE == Initializer->IgnoreParenImpCasts()) + if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) return false; ContainsReference CR(S.Context, DRE); @@ -469,54 +519,15 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, } // Report where the variable was declared when the use wasn't within - // the initializer of that declaration. - if (!isSelfInit) + // the initializer of that declaration & we didn't already suggest + // an initialization fixit. + if (!isSelfInit && !SuggestInitializationFixit(S, VD)) S.Diag(VD->getLocStart(), diag::note_uninit_var_def) << VD->getDeclName(); return true; } -static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { - // Don't issue a fixit if there is already an initializer. - if (VD->getInit()) - return; - - // Suggest possible initialization (if any). - const char *initialization = 0; - QualType VariableTy = VD->getType().getCanonicalType(); - - if (VariableTy->isObjCObjectPointerType() || - VariableTy->isBlockPointerType()) { - // Check if 'nil' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) - initialization = " = nil"; - else - initialization = " = 0"; - } - else if (VariableTy->isRealFloatingType()) - initialization = " = 0.0"; - else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) - initialization = " = false"; - else if (VariableTy->isEnumeralType()) - return; - else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { - // Check if 'NULL' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) - initialization = " = NULL"; - else - initialization = " = 0"; - } - else if (VariableTy->isScalarType()) - initialization = " = 0"; - - if (initialization) { - SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); - S.Diag(loc, diag::note_var_fixit_add_initialization) - << FixItHint::CreateInsertion(loc, initialization); - } -} - typedef std::pair<const Expr*, bool> UninitUse; namespace { @@ -530,8 +541,8 @@ struct SLocSort { class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector<UninitUse, 2> UsesVec; - typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap; + typedef SmallVector<UninitUse, 2> UsesVec; + typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap; UsesMap *uses; public: @@ -539,17 +550,26 @@ public: ~UninitValsDiagReporter() { flushDiagnostics(); } - - void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, - bool isAlwaysUninit) { + + std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) { if (!uses) uses = new UsesMap(); - - UsesVec *&vec = (*uses)[vd]; + + UsesMap::mapped_type &V = (*uses)[vd]; + UsesVec *&vec = V.first; if (!vec) vec = new UsesVec(); - vec->push_back(std::make_pair(ex, isAlwaysUninit)); + return V; + } + + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, + bool isAlwaysUninit) { + getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit)); + } + + void handleSelfInit(const VarDecl *vd) { + getUses(vd).second = true; } void flushDiagnostics() { @@ -558,28 +578,34 @@ public: for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) { const VarDecl *vd = i->first; - UsesVec *vec = i->second; - - bool fixitIssued = false; - - // Sort the uses by their SourceLocations. While not strictly - // guaranteed to produce them in line/column order, this will provide - // a stable ordering. - std::sort(vec->begin(), vec->end(), SLocSort()); - - for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; - ++vi) { - if (!DiagnoseUninitializedUse(S, vd, vi->first, - /*isAlwaysUninit=*/vi->second)) - continue; - - // Suggest a fixit hint the first time we diagnose a use of a variable. - if (!fixitIssued) { - SuggestInitializationFixit(S, vd); - fixitIssued = true; + const UsesMap::mapped_type &V = i->second; + + UsesVec *vec = V.first; + bool hasSelfInit = V.second; + + // Specially handle the case where we have uses of an uninitialized + // variable, but the root cause is an idiomatic self-init. We want + // to report the diagnostic at the self-init since that is the root cause. + if (!vec->empty() && hasSelfInit) + DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(), + true, /* alwaysReportSelfInit */ true); + else { + // Sort the uses by their SourceLocations. While not strictly + // guaranteed to produce them in line/column order, this will provide + // a stable ordering. + std::sort(vec->begin(), vec->end(), SLocSort()); + + for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; + ++vi) { + if (DiagnoseUninitializedUse(S, vd, vi->first, + /*isAlwaysUninit=*/vi->second)) + // Skip further diagnostics for this variable. We try to warn only + // on the first point at which a variable is used uninitialized. + break; } } - + + // Release the uses vector. delete vec; } delete uses; @@ -587,6 +613,132 @@ public: }; } + +//===----------------------------------------------------------------------===// +// -Wthread-safety +//===----------------------------------------------------------------------===// +namespace clang { +namespace thread_safety { +typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag; +typedef llvm::SmallVector<DelayedDiag, 4> DiagList; + +struct SortDiagBySourceLocation { + Sema &S; + SortDiagBySourceLocation(Sema &S) : S(S) {} + + bool operator()(const DelayedDiag &left, const DelayedDiag &right) { + // Although this call will be slow, this is only called when outputting + // multiple warnings. + return S.getSourceManager().isBeforeInTranslationUnit(left.first, + right.first); + } +}; + +class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { + Sema &S; + DiagList Warnings; + + // Helper functions + void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(DiagID) << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + public: + ThreadSafetyReporter(Sema &S) : S(S) {} + + /// \brief Emit all buffered diagnostics in order of sourcelocation. + /// We need to output diagnostics produced while iterating through + /// the lockset in deterministic order, so this function orders diagnostics + /// and outputs them. + void emitDiagnostics() { + SortDiagBySourceLocation SortDiagBySL(S); + sort(Warnings.begin(), Warnings.end(), SortDiagBySL); + for (DiagList::iterator I = Warnings.begin(), E = Warnings.end(); + I != E; ++I) + S.Diag(I->first, I->second); + } + + void handleInvalidLockExp(SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc); + } + + void handleDoubleLock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_double_lock, LockName, Loc); + } + + void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc, + LockErrorKind LEK){ + unsigned DiagID = 0; + switch (LEK) { + case LEK_LockedSomePredecessors: + DiagID = diag::warn_lock_at_end_of_scope; + break; + case LEK_LockedSomeLoopIterations: + DiagID = diag::warn_expecting_lock_held_on_loop; + break; + case LEK_LockedAtEndOfFunction: + DiagID = diag::warn_no_unlock; + break; + } + warnLockMismatch(DiagID, LockName, Loc); + } + + + void handleExclusiveAndShared(Name LockName, SourceLocation Loc1, + SourceLocation Loc2) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName; + PartialDiagnostic Note = + S.PDiag(diag::note_lock_exclusive_and_shared) << LockName; + Warnings.push_back(DelayedDiag(Loc1, Warning)); + Warnings.push_back(DelayedDiag(Loc2, Note)); + } + + void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, + AccessKind AK, SourceLocation Loc) { + assert((POK == POK_VarAccess || POK == POK_VarDereference) + && "Only works for variables"); + unsigned DiagID = POK == POK_VarAccess? + diag::warn_variable_requires_any_lock: + diag::warn_var_deref_requires_any_lock; + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << getLockKindFromAccessKind(AK); + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK, + Name LockName, LockKind LK, SourceLocation Loc) { + unsigned DiagID = 0; + switch (POK) { + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock; + break; + } + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << LockName << LK; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } +}; +} +} + //===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. @@ -595,6 +747,7 @@ public: clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; enableCheckUnreachable = 0; + enableThreadSafetyAnalysis = 0; } clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) @@ -608,14 +761,18 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) MaxUninitAnalysisVariablesPerFunction(0), NumUninitAnalysisBlockVisits(0), MaxUninitAnalysisBlockVisitsPerFunction(0) { - Diagnostic &D = S.getDiagnostics(); + DiagnosticsEngine &D = S.getDiagnostics(); DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) != - Diagnostic::Ignored); + DiagnosticsEngine::Ignored); + DefaultPolicy.enableThreadSafetyAnalysis = (unsigned) + (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) != + DiagnosticsEngine::Ignored); + } static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) { - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -635,7 +792,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // don't bother trying. // (2) The code already has problems; running the analysis just takes more // time. - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Do not do any analysis for declarations in system headers if we are // going to just ignore them. @@ -656,17 +813,43 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, const Stmt *Body = D->getBody(); assert(Body); + AnalysisContext AC(D, 0); + // 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, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false, - /*addImplicitDtors=*/true, /*addInitializers=*/true); + AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; + AC.getCFGBuildOptions().AddEHEdges = false; + AC.getCFGBuildOptions().AddInitializers = true; + AC.getCFGBuildOptions().AddImplicitDtors = true; + + // Force that certain expressions appear as CFGElements in the CFG. This + // is used to speed up various analyses. + // FIXME: This isn't the right factoring. This is here for initial + // prototyping, but we need a way for analyses to say what expressions they + // expect to always be CFGElements and then fill in the BuildOptions + // appropriately. This is essentially a layering violation. + if (P.enableCheckUnreachable) { + // Unreachable code analysis requires a linearized CFG. + AC.getCFGBuildOptions().setAllAlwaysAdd(); + } + else { + AC.getCFGBuildOptions() + .setAlwaysAdd(Stmt::BinaryOperatorClass) + .setAlwaysAdd(Stmt::BlockExprClass) + .setAlwaysAdd(Stmt::CStyleCastExprClass) + .setAlwaysAdd(Stmt::DeclRefExprClass) + .setAlwaysAdd(Stmt::ImplicitCastExprClass) + .setAlwaysAdd(Stmt::UnaryOperatorClass); + } + // Construct the analysis context with the specified CFG build options. + // Emit delayed diagnostics. if (!fscope->PossiblyUnreachableDiags.empty()) { bool analyzed = false; // Register the expressions with the CFGBuilder. - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -676,7 +859,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (AC.getCFG()) { analyzed = true; - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) @@ -716,11 +899,18 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check for unreachable code if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - + + // Check for thread safety violations + if (P.enableThreadSafetyAnalysis) { + thread_safety::ThreadSafetyReporter Reporter(S); + thread_safety::runThreadSafetyAnalysis(AC, Reporter); + Reporter.emitDiagnostics(); + } + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) - != Diagnostic::Ignored || + != DiagnosticsEngine::Ignored || Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart()) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); UninitVariablesAnalysisStats stats; diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp index 5a8330b..13a0ede 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp @@ -98,7 +98,7 @@ AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, } AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - llvm::StringRef AttrName = Name->getName(); + StringRef AttrName = Name->getName(); // Normalize the attribute name, __foo__ becomes foo. if (AttrName.startswith("__") && AttrName.endswith("__")) @@ -159,10 +159,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("address_space", AT_address_space) .Case("opencl_image_access", AT_opencl_image_access) .Case("always_inline", AT_always_inline) - .Case("returns_twice", IgnoredAttribute) + .Case("returns_twice", AT_returns_twice) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("objc_method_family", AT_objc_method_family) + .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer) .Case("ext_vector_type", AT_ext_vector_type) .Case("neon_vector_type", AT_neon_vector_type) .Case("neon_polyvector_type", AT_neon_polyvector_type) @@ -170,15 +171,18 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("analyzer_noreturn", AT_analyzer_noreturn) .Case("warn_unused_result", AT_warn_unused_result) .Case("carries_dependency", AT_carries_dependency) + .Case("ns_bridged", AT_ns_bridged) .Case("ns_consumed", AT_ns_consumed) .Case("ns_consumes_self", AT_ns_consumes_self) .Case("ns_returns_autoreleased", AT_ns_returns_autoreleased) .Case("ns_returns_not_retained", AT_ns_returns_not_retained) .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_audited_transfer", AT_cf_audited_transfer) .Case("cf_consumed", AT_cf_consumed) .Case("cf_returns_not_retained", AT_cf_returns_not_retained) .Case("cf_returns_retained", AT_cf_returns_retained) .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased) + .Case("cf_unknown_transfer", AT_cf_unknown_transfer) .Case("ns_consumes_self", AT_ns_consumes_self) .Case("ns_consumed", AT_ns_consumed) .Case("objc_ownership", AT_objc_ownership) @@ -209,5 +213,23 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("uuid", AT_uuid) .Case("pcs", AT_pcs) .Case("ms_struct", AT_MsStruct) + .Case("guarded_var", AT_guarded_var) + .Case("pt_guarded_var", AT_pt_guarded_var) + .Case("scoped_lockable", AT_scoped_lockable) + .Case("lockable", AT_lockable) + .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis) + .Case("guarded_by", AT_guarded_by) + .Case("pt_guarded_by", AT_pt_guarded_by) + .Case("acquired_after", AT_acquired_after) + .Case("acquired_before", AT_acquired_before) + .Case("exclusive_lock_function", AT_exclusive_lock_function) + .Case("exclusive_locks_required", AT_exclusive_locks_required) + .Case("exclusive_trylock_function", AT_exclusive_trylock_function) + .Case("lock_returned", AT_lock_returned) + .Case("locks_excluded", AT_locks_excluded) + .Case("shared_lock_function", AT_shared_lock_function) + .Case("shared_locks_required", AT_shared_locks_required) + .Case("shared_trylock_function", AT_shared_trylock_function) + .Case("unlock_function", AT_unlock_function) .Default(UnknownAttribute); } diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index d7dc5b2..da98603 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -26,7 +26,6 @@ #include <functional> using namespace clang; -using llvm::StringRef; //===----------------------------------------------------------------------===// // Code completion context implementation @@ -68,7 +67,7 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_OtherWithMacros: case CCC_ObjCInstanceMessage: case CCC_ObjCClassMessage: - case CCC_ObjCSuperclass: + case CCC_ObjCInterfaceName: case CCC_ObjCCategoryName: return false; } @@ -191,14 +190,36 @@ CodeCompletionString::Chunk::CreateCurrentParameter( CodeCompletionString::CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, unsigned Priority, - CXAvailabilityKind Availability) - : NumChunks(NumChunks), Priority(Priority), Availability(Availability) + CXAvailabilityKind Availability, + const char **Annotations, + unsigned NumAnnotations) + : NumChunks(NumChunks), NumAnnotations(NumAnnotations) + , Priority(Priority), Availability(Availability) { + assert(NumChunks <= 0xffff); + assert(NumAnnotations <= 0xffff); + Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1); for (unsigned I = 0; I != NumChunks; ++I) StoredChunks[I] = Chunks[I]; + + const char **StoredAnnotations = reinterpret_cast<const char **>(StoredChunks + NumChunks); + for (unsigned I = 0; I != NumAnnotations; ++I) + StoredAnnotations[I] = Annotations[I]; +} + +unsigned CodeCompletionString::getAnnotationCount() const { + return NumAnnotations; +} + +const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const { + if (AnnotationNr < NumAnnotations) + return reinterpret_cast<const char * const*>(end())[AnnotationNr]; + else + return 0; } + std::string CodeCompletionString::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); @@ -228,14 +249,14 @@ const char *CodeCompletionString::getTypedText() const { return 0; } -const char *CodeCompletionAllocator::CopyString(llvm::StringRef String) { +const char *CodeCompletionAllocator::CopyString(StringRef String) { char *Mem = (char *)Allocate(String.size() + 1, 1); std::copy(String.begin(), String.end(), Mem); Mem[String.size()] = 0; return Mem; } -const char *CodeCompletionAllocator::CopyString(llvm::Twine String) { +const char *CodeCompletionAllocator::CopyString(Twine String) { // FIXME: It would be more efficient to teach Twine to tell us its size and // then add a routine there to fill in an allocated char* with the contents // of the string. @@ -245,11 +266,13 @@ const char *CodeCompletionAllocator::CopyString(llvm::Twine String) { CodeCompletionString *CodeCompletionBuilder::TakeString() { void *Mem = Allocator.Allocate( - sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), + sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() + + sizeof(const char *) * Annotations.size(), llvm::alignOf<CodeCompletionString>()); CodeCompletionString *Result = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), - Priority, Availability); + Priority, Availability, + Annotations.data(), Annotations.size()); Chunks.clear(); return Result; } @@ -329,7 +352,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case CodeCompletionResult::RK_Declaration: - OS << Results[I].Declaration; + OS << *Results[I].Declaration; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS @@ -377,7 +400,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -void CodeCompletionResult::computeCursorKindAndAvailability() { +void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { switch (Kind) { case RK_Declaration: // Set the availability based on attributes. @@ -419,13 +442,16 @@ void CodeCompletionResult::computeCursorKindAndAvailability() { // Do nothing: Patterns can come with cursor kinds! break; } + + if (!Accessible) + Availability = CXAvailability_NotAccessible; } /// \brief Retrieve the name that should be used to order a result. /// /// If the name needs to be constructed as a string, that string will be /// saved into Saved and the returned StringRef will refer to it. -static llvm::StringRef getOrderedName(const CodeCompletionResult &R, +static StringRef getOrderedName(const CodeCompletionResult &R, std::string &Saved) { switch (R.Kind) { case CodeCompletionResult::RK_Keyword: @@ -460,8 +486,8 @@ static llvm::StringRef getOrderedName(const CodeCompletionResult &R, bool clang::operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y) { std::string XSaved, YSaved; - llvm::StringRef XStr = getOrderedName(X, XSaved); - llvm::StringRef YStr = getOrderedName(Y, YSaved); + StringRef XStr = getOrderedName(X, XSaved); + StringRef YStr = getOrderedName(Y, YSaved); int cmp = XStr.compare_lower(YStr); if (cmp) return cmp < 0; diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index c87f2cf..f0a763e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/LocInfoType.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" @@ -27,7 +28,7 @@ using namespace clang; -static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, +static DiagnosticBuilder Diag(DiagnosticsEngine &D, SourceLocation Loc, unsigned DiagID) { return D.Report(Loc, DiagID); } @@ -242,6 +243,7 @@ bool Declarator::isDeclarationOfFunction() const { } switch (DS.getTypeSpecType()) { + case TST_atomic: case TST_auto: case TST_bool: case TST_char: @@ -255,6 +257,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_enum: case TST_error: case TST_float: + case TST_half: case TST_int: case TST_struct: case TST_union: @@ -371,6 +374,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_char16: return "char16_t"; case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; + case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; case DeclSpec::TST_bool: return "_Bool"; @@ -388,6 +392,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; + case DeclSpec::TST_atomic: return "_Atomic"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); @@ -403,21 +408,24 @@ const char *DeclSpec::getSpecifierName(TQ T) { llvm_unreachable("Unknown typespec!"); } -bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, +bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID, - const LangOptions &Lang) { - // OpenCL prohibits extern, auto, register, and static + unsigned &DiagID) { + // OpenCL 1.1 6.8g: "The extern, static, auto and register storage-class + // specifiers are not supported." // It seems sensible to prohibit private_extern too - if (Lang.OpenCL) { - switch (S) { + // The cl_clang_storage_class_specifiers extension enables support for + // these storage-class specifiers. + if (S.getLangOptions().OpenCL && + !S.getOpenCLOptions().cl_clang_storage_class_specifiers) { + switch (SC) { case SCS_extern: case SCS_private_extern: case SCS_auto: case SCS_register: case SCS_static: DiagID = diag::err_not_opencl_storage_class_specifier; - PrevSpec = getSpecifierName(S); + PrevSpec = getSpecifierName(SC); return true; default: break; @@ -425,17 +433,30 @@ bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { + // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + bool isInvalid = true; + if (TypeSpecType == TST_unspecified && S.getLangOptions().CPlusPlus) { + if (SC == SCS_auto) + return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID); + if (StorageClassSpec == SCS_auto) { + isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc, + PrevSpec, DiagID); + assert(!isInvalid && "auto SCS -> TST recovery failed"); + } + } + // Changing storage class is allowed only if the previous one // was the 'extern' that is part of a linkage specification and // the new storage class is 'typedef'. - if (!(SCS_extern_in_linkage_spec && + if (isInvalid && + !(SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern && - S == SCS_typedef)) - return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); + SC == SCS_typedef)) + return BadSpecifier(SC, (SCS)StorageClassSpec, PrevSpec, DiagID); } - StorageClassSpec = S; + StorageClassSpec = SC; StorageClassSpecLoc = Loc; - assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield"); + assert((unsigned)SC == StorageClassSpec && "SCS constants overflow bitfield"); return false; } @@ -637,7 +658,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, TypeQualifiers |= T; switch (T) { - default: assert(0 && "Unknown type qualifier!"); + default: llvm_unreachable("Unknown type qualifier!"); case TQ_const: TQ_constLoc = Loc; break; case TQ_restrict: TQ_restrictLoc = Loc; break; case TQ_volatile: TQ_volatileLoc = Loc; break; @@ -682,6 +703,18 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, return false; } +bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + if (isModulePrivateSpecified()) { + PrevSpec = "__module_private__"; + DiagID = diag::ext_duplicate_declspec; + return true; + } + + ModulePrivateLoc = Loc; + return false; +} + bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { // 'constexpr constexpr' is ok. @@ -732,7 +765,7 @@ void DeclSpec::SaveStorageSpecifierAsWritten() { /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. -void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { +void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); SaveStorageSpecifierAsWritten(); @@ -836,6 +869,27 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } } + // If no type specifier was provided and we're parsing a language where + // the type specifier is not optional, but we got 'auto' as a storage + // class specifier, then assume this is an attempt to use C++0x's 'auto' + // type specifier. + // FIXME: Does Microsoft really support implicit int in C++? + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().MicrosoftExt && + TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { + TypeSpecType = TST_auto; + StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified; + TSTLoc = TSTNameLoc = StorageClassSpecLoc; + StorageClassSpecLoc = SourceLocation(); + } + // Diagnose if we've recovered from an ill-formed 'auto' storage class + // specifier in a pre-C++0x dialect of C++. + if (!PP.getLangOptions().CPlusPlus0x && TypeSpecType == TST_auto) + Diag(D, TSTLoc, diag::ext_auto_type_specifier); + if (PP.getLangOptions().CPlusPlus && !PP.getLangOptions().CPlusPlus0x && + StorageClassSpec == SCS_auto) + Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) + << FixItHint::CreateRemoval(StorageClassSpecLoc); + // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. @@ -844,7 +898,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); + SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, diag::err_friend_storage_spec) << SpecName @@ -854,7 +908,7 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); - + // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. @@ -902,7 +956,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, Specifiers |= VS; switch (VS) { - default: assert(0 && "Unknown specifier!"); + default: llvm_unreachable("Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; case VS_Final: VS_finalLoc = Loc; break; } @@ -912,7 +966,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *VirtSpecifiers::getSpecifierName(Specifier VS) { switch (VS) { - default: assert(0 && "Unknown specifier"); + default: llvm_unreachable("Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; } diff --git a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp index c6744ed..d6c1ad1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp @@ -21,7 +21,7 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, const NamedDecl *D, - llvm::StringRef Msg) { + StringRef Msg) { DelayedDiagnostic DD; DD.Kind = Deprecation; DD.Triggered = false; diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp index 95420a3..a643267 100644 --- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp @@ -73,7 +73,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { } } - assert(0 && "Didn't find this decl on its identifier's chain!"); + llvm_unreachable("Didn't find this decl on its identifier's chain!"); } bool diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index 59bc263..3e74dfc 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -1,4 +1,4 @@ -//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===// +//===--- JumpDiagnostics.cpp - Protected scope jump analysis ------*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file implements the JumpScopeChecker class, which is used to diagnose -// jumps that enter a VLA scope in an invalid way. +// jumps that enter a protected scope in an invalid way. // //===----------------------------------------------------------------------===// @@ -58,12 +58,12 @@ class JumpScopeChecker { : ParentScope(parentScope), InDiag(InDiag), OutDiag(OutDiag), Loc(L) {} }; - llvm::SmallVector<GotoScope, 48> Scopes; + SmallVector<GotoScope, 48> Scopes; llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; - llvm::SmallVector<Stmt*, 16> Jumps; + SmallVector<Stmt*, 16> Jumps; - llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps; - llvm::SmallVector<LabelDecl*, 4> IndirectJumpTargets; + SmallVector<IndirectGotoStmt*, 4> IndirectJumps; + SmallVector<LabelDecl*, 4> IndirectJumpTargets; public: JumpScopeChecker(Stmt *Body, Sema &S); private: @@ -76,8 +76,8 @@ private: void VerifyIndirectJumps(); void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope, LabelDecl *Target, unsigned TargetScope); - void CheckJump(Stmt *From, Stmt *To, - SourceLocation DiagLoc, unsigned JumpDiag); + void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, + unsigned JumpDiag, unsigned JumpDiagWarning); unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; @@ -476,7 +476,8 @@ void JumpScopeChecker::VerifyJumps() { // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), - diag::err_goto_into_protected_scope); + diag::err_goto_into_protected_scope, + diag::warn_goto_into_protected_scope); continue; } @@ -484,7 +485,8 @@ void JumpScopeChecker::VerifyJumps() { if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { LabelDecl *Target = IGS->getConstantTarget(); CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(), - diag::err_goto_into_protected_scope); + diag::err_goto_into_protected_scope, + diag::warn_goto_into_protected_scope); continue; } @@ -493,7 +495,7 @@ void JumpScopeChecker::VerifyJumps() { SC = SC->getNextSwitchCase()) { assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); CheckJump(SS, SC, SC->getLocStart(), - diag::err_switch_into_protected_scope); + diag::err_switch_into_protected_scope, 0); } } } @@ -532,10 +534,10 @@ void JumpScopeChecker::VerifyIndirectJumps() { // indirect goto. For most code bases, this substantially cuts // down on the number of jump sites we'll have to consider later. typedef std::pair<unsigned, IndirectGotoStmt*> JumpScope; - llvm::SmallVector<JumpScope, 32> JumpScopes; + SmallVector<JumpScope, 32> JumpScopes; { llvm::DenseMap<unsigned, IndirectGotoStmt*> JumpScopesMap; - for (llvm::SmallVectorImpl<IndirectGotoStmt*>::iterator + for (SmallVectorImpl<IndirectGotoStmt*>::iterator I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) { IndirectGotoStmt *IG = *I; assert(LabelAndGotoScopes.count(IG) && @@ -554,7 +556,7 @@ void JumpScopeChecker::VerifyIndirectJumps() { // label whose address was taken somewhere in the function. // For most code bases, there will be only one such scope. llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; - for (llvm::SmallVectorImpl<LabelDecl*>::iterator + for (SmallVectorImpl<LabelDecl*>::iterator I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end(); I != E; ++I) { LabelDecl *TheLabel = *I; @@ -599,7 +601,7 @@ void JumpScopeChecker::VerifyIndirectJumps() { // Walk through all the jump sites, checking that they can trivially // reach this label scope. - for (llvm::SmallVectorImpl<JumpScope>::iterator + for (SmallVectorImpl<JumpScope>::iterator I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { unsigned Scope = I->first; @@ -660,10 +662,20 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump, S.Diag(Scopes[I].Loc, Scopes[I].InDiag); } +/// Return true if a particular error+note combination must be downgraded +/// to a warning in Microsoft mode. +static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) +{ + return (JumpDiag == diag::err_goto_into_protected_scope && + (InDiagNote == diag::note_protected_by_variable_init || + InDiagNote == diag::note_protected_by_variable_nontriv_destructor)); +} + + /// CheckJump - Validate that the specified jump statement is valid: that it is /// jumping within or out of its current scope, not into a deeper one. -void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, - SourceLocation DiagLoc, unsigned JumpDiag) { +void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, + unsigned JumpDiagError, unsigned JumpDiagWarning) { assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); unsigned FromScope = LabelAndGotoScopes[From]; @@ -679,19 +691,30 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, if (CommonScope == ToScope) return; // Pull out (and reverse) any scopes we might need to diagnose skipping. - llvm::SmallVector<unsigned, 10> ToScopes; - for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) - if (Scopes[I].InDiag) - ToScopes.push_back(I); - - // If the only scopes present are cleanup scopes, we're okay. - if (ToScopes.empty()) return; + SmallVector<unsigned, 10> ToScopesError; + SmallVector<unsigned, 10> ToScopesWarning; + for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) { + if (S.getLangOptions().MicrosoftMode && JumpDiagWarning != 0 && + IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag)) + ToScopesWarning.push_back(I); + else if (Scopes[I].InDiag) + ToScopesError.push_back(I); + } - S.Diag(DiagLoc, JumpDiag); + // Handle warnings. + if (!ToScopesWarning.empty()) { + S.Diag(DiagLoc, JumpDiagWarning); + for (unsigned i = 0, e = ToScopesWarning.size(); i != e; ++i) + S.Diag(Scopes[ToScopesWarning[i]].Loc, Scopes[ToScopesWarning[i]].InDiag); + } - // Emit diagnostics for whatever is left in ToScopes. - for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) - S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].InDiag); + // Handle errors. + if (!ToScopesError.empty()) { + S.Diag(DiagLoc, JumpDiagError); + // Emit diagnostics note for whatever is left in ToScopesError. + for (unsigned i = 0, e = ToScopesError.size(); i != e; ++i) + S.Diag(Scopes[ToScopesError[i]].Loc, Scopes[ToScopesError[i]].InDiag); + } } void Sema::DiagnoseInvalidJumps(Stmt *Body) { diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp new file mode 100644 index 0000000..8bd2213 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp @@ -0,0 +1,92 @@ +//===--- MultiInitializer.cpp - Initializer expression group ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MultiInitializer class, which can represent a list +// initializer or a parentheses-wrapped group of expressions in a C++ member +// initializer. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/MultiInitializer.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Sema.h" +#include "clang/AST/Expr.h" + +using namespace clang; + +InitListExpr *MultiInitializer::getInitList() const { + return cast<InitListExpr>(InitListOrExpressions.get<Expr*>()); +} + +SourceLocation MultiInitializer::getStartLoc() const { + return isInitializerList() ? getInitList()->getLBraceLoc() : LParenLoc; +} + +SourceLocation MultiInitializer::getEndLoc() const { + return isInitializerList() ? getInitList()->getRBraceLoc() : RParenLoc; +} + +MultiInitializer::iterator MultiInitializer::begin() const { + return isInitializerList() ? getInitList()->getInits() : getExpressions(); +} + +MultiInitializer::iterator MultiInitializer::end() const { + if (isInitializerList()) { + InitListExpr *ILE = getInitList(); + return ILE->getInits() + ILE->getNumInits(); + } + return getExpressions() + NumInitializers; +} + +bool MultiInitializer::isTypeDependent() const { + if (isInitializerList()) + return getInitList()->isTypeDependent(); + for (iterator I = begin(), E = end(); I != E; ++I) { + if ((*I)->isTypeDependent()) + return true; + } + return false; +} + +bool MultiInitializer::DiagnoseUnexpandedParameterPack(Sema &SemaRef) const { + if (isInitializerList()) + return SemaRef.DiagnoseUnexpandedParameterPack(getInitList()); + for (iterator I = begin(), E = end(); I != E; ++I) { + if (SemaRef.DiagnoseUnexpandedParameterPack(*I)) + return true; + } + return false; +} + +Expr *MultiInitializer::CreateInitExpr(ASTContext &Ctx, QualType T) const { + if (isInitializerList()) + return InitListOrExpressions.get<Expr*>(); + + return new (Ctx) ParenListExpr(Ctx, LParenLoc, getExpressions(), + NumInitializers, RParenLoc, T); +} + +ExprResult MultiInitializer::PerformInit(Sema &SemaRef, + InitializedEntity Entity, + InitializationKind Kind) const { + Expr *Single; + Expr **Args; + unsigned NumArgs; + if (isInitializerList()) { + Single = InitListOrExpressions.get<Expr*>(); + Args = &Single; + NumArgs = 1; + } else { + Args = getExpressions(); + NumArgs = NumInitializers; + } + InitializationSequence InitSeq(SemaRef, Entity, Kind, Args, NumArgs); + return InitSeq.Perform(SemaRef, Entity, Kind, + MultiExprArg(SemaRef, Args, NumArgs), 0); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index fdf3bb3..533b21c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -34,6 +34,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; @@ -54,99 +55,54 @@ void FunctionScopeInfo::Clear() { BlockScopeInfo::~BlockScopeInfo() { } +PrintingPolicy Sema::getPrintingPolicy() const { + PrintingPolicy Policy = Context.getPrintingPolicy(); + Policy.Bool = getLangOptions().Bool; + if (!Policy.Bool) { + if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) { + Policy.Bool = BoolMacro->isObjectLike() && + BoolMacro->getNumTokens() == 1 && + BoolMacro->getReplacementToken(0).is(tok::kw__Bool); + } + } + + return Policy; +} + void Sema::ActOnTranslationUnitScope(Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); VAListTagName = PP.getIdentifierInfo("__va_list_tag"); - if (!Context.isInt128Installed() && // May be set by ASTReader. - PP.getTargetInfo().getPointerWidth(0) >= 64) { - TypeSourceInfo *TInfo; - - // Install [u]int128_t for 64-bit targets. - TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty); - PushOnScopeChains(TypedefDecl::Create(Context, CurContext, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("__int128_t"), - TInfo), TUScope); - - TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty); - PushOnScopeChains(TypedefDecl::Create(Context, CurContext, - SourceLocation(), - SourceLocation(), - &Context.Idents.get("__uint128_t"), - TInfo), TUScope); - Context.setInt128Installed(); - } - - - if (!PP.getLangOptions().ObjC1) return; - - // Built-in ObjC types may already be set by ASTReader (hence isNull checks). - if (Context.getObjCSelType().isNull()) { - // Create the built-in typedef for 'SEL'. - QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); - TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT); - TypedefDecl *SelTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("SEL"), SelInfo); - PushOnScopeChains(SelTypedef, TUScope); - Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); - Context.ObjCSelRedefinitionType = Context.getObjCSelType(); - } - - // Synthesize "@class Protocol; - if (Context.getObjCProtoType().isNull()) { - ObjCInterfaceDecl *ProtocolDecl = - ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Protocol"), - SourceLocation(), true); - Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); - PushOnScopeChains(ProtocolDecl, TUScope, false); - } - // Create the built-in typedef for 'id'. - if (Context.getObjCIdType().isNull()) { - QualType T = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, 0, 0); - T = Context.getObjCObjectPointerType(T); - TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T); - TypedefDecl *IdTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("id"), IdInfo); - PushOnScopeChains(IdTypedef, TUScope); - Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); - Context.ObjCIdRedefinitionType = Context.getObjCIdType(); - } - // Create the built-in typedef for 'Class'. - if (Context.getObjCClassType().isNull()) { - QualType T = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, 0, 0); - T = Context.getObjCObjectPointerType(T); - TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T); - TypedefDecl *ClassTypedef - = TypedefDecl::Create(Context, CurContext, - SourceLocation(), SourceLocation(), - &Context.Idents.get("Class"), ClassInfo); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); - Context.ObjCClassRedefinitionType = Context.getObjCClassType(); - } + if (PP.getLangOptions().ObjC1) { + // Synthesize "@class Protocol; + if (Context.getObjCProtoType().isNull()) { + ObjCInterfaceDecl *ProtocolDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Protocol"), + SourceLocation(), true); + Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); + PushOnScopeChains(ProtocolDecl, TUScope, false); + } + } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit, + TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()), LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter), - CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0), + CurContext(0), OriginalLexicalContext(0), + PackContext(0), MSStructPragmaOn(false), VisContext(0), ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), - CompleteTranslationUnit(CompleteTranslationUnit), + ObjCShouldCallSuperDealloc(false), + ObjCShouldCallSuperFinalize(false), + TUKind(TUKind), NumSFINAEErrors(0), SuppressAccessChecking(false), AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), @@ -181,6 +137,40 @@ void Sema::Initialize() { if (ExternalSemaSource *ExternalSema = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) ExternalSema->InitializeSema(*this); + + // Initialize predefined 128-bit integer types, if needed. + if (PP.getTargetInfo().getPointerWidth(0) >= 64) { + // If either of the 128-bit integer types are unavailable to name lookup, + // define them now. + DeclarationName Int128 = &Context.Idents.get("__int128_t"); + if (IdentifierResolver::begin(Int128) == IdentifierResolver::end()) + PushOnScopeChains(Context.getInt128Decl(), TUScope); + + DeclarationName UInt128 = &Context.Idents.get("__uint128_t"); + if (IdentifierResolver::begin(UInt128) == IdentifierResolver::end()) + PushOnScopeChains(Context.getUInt128Decl(), TUScope); + } + + + // Initialize predefined Objective-C types: + if (PP.getLangOptions().ObjC1) { + // If 'SEL' does not yet refer to any declarations, make it refer to the + // predefined 'SEL'. + DeclarationName SEL = &Context.Idents.get("SEL"); + if (IdentifierResolver::begin(SEL) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCSelDecl(), TUScope); + + // If 'id' does not yet refer to any declarations, make it refer to the + // predefined 'id'. + DeclarationName Id = &Context.Idents.get("id"); + if (IdentifierResolver::begin(Id) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCIdDecl(), TUScope); + + // Create the built-in typedef for 'Class'. + DeclarationName Class = &Context.Idents.get("Class"); + if (IdentifierResolver::begin(Class) == IdentifierResolver::end()) + PushOnScopeChains(Context.getObjCClassDecl(), TUScope); + } } Sema::~Sema() { @@ -210,7 +200,7 @@ Sema::~Sema() { /// make the relevant declaration unavailable instead of erroring, do /// so and return true. bool Sema::makeUnavailableInSystemHeader(SourceLocation loc, - llvm::StringRef msg) { + StringRef msg) { // If we're not in a function, it's an error. FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext); if (!fn) return false; @@ -287,7 +277,9 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { switch (ScalarTy->getScalarTypeKind()) { case Type::STK_Bool: return CK_NoOp; - case Type::STK_Pointer: return CK_PointerToBoolean; + case Type::STK_CPointer: return CK_PointerToBoolean; + case Type::STK_BlockPointer: return CK_PointerToBoolean; + case Type::STK_ObjCObjectPointer: return CK_PointerToBoolean; case Type::STK_MemberPointer: return CK_MemberPointerToBoolean; case Type::STK_Integral: return CK_IntegralToBoolean; case Type::STK_Floating: return CK_FloatingToBoolean; @@ -297,12 +289,6 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { return CK_Invalid; } -ExprValueKind Sema::CastCategory(Expr *E) { - Expr::Classification Classification = E->Classify(Context); - return Classification.isRValue() ? VK_RValue : - (Classification.isLValue() ? VK_LValue : VK_XValue); -} - /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->isUsed()) @@ -358,7 +344,7 @@ static void checkUndefinedInternals(Sema &S) { if (S.UndefinedInternals.empty()) return; // Collect all the still-undefined entities with internal linkage. - llvm::SmallVector<UndefinedInternal, 16> undefined; + SmallVector<UndefinedInternal, 16> undefined; for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end(); i != e; ++i) { @@ -389,7 +375,7 @@ static void checkUndefinedInternals(Sema &S) { // the iteration order through an llvm::DenseMap. llvm::array_pod_sort(undefined.begin(), undefined.end()); - for (llvm::SmallVectorImpl<UndefinedInternal>::iterator + for (SmallVectorImpl<UndefinedInternal>::iterator i = undefined.begin(), e = undefined.end(); i != e; ++i) { NamedDecl *decl = i->decl; S.Diag(decl->getLocation(), diag::warn_undefined_internal) @@ -398,24 +384,41 @@ static void checkUndefinedInternals(Sema &S) { } } +void Sema::LoadExternalWeakUndeclaredIdentifiers() { + if (!ExternalSource) + return; + + SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs; + ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs); + for (unsigned I = 0, N = WeakIDs.size(); I != N; ++I) { + llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator Pos + = WeakUndeclaredIdentifiers.find(WeakIDs[I].first); + if (Pos != WeakUndeclaredIdentifiers.end()) + continue; + + WeakUndeclaredIdentifiers.insert(WeakIDs[I]); + } +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { - // At PCH writing, implicit instantiations and VTable handling info are - // stored and performed when the PCH is included. - if (CompleteTranslationUnit) { + // Only complete translation units define vtables and perform implicit + // instantiations. + if (TUKind == TU_Complete) { // If any dynamic classes have their key function defined within // this translation unit, then those vtables are considered "used" and must // be emitted. - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) { - assert(!DynamicClasses[I]->isDependentType() && + for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource), + E = DynamicClasses.end(); + I != E; ++I) { + assert(!(*I)->isDependentType() && "Should not see dependent types here!"); - if (const CXXMethodDecl *KeyFunction - = Context.getKeyFunction(DynamicClasses[I])) { + if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) { const FunctionDecl *Definition = 0; if (KeyFunction->hasBody(Definition)) - MarkVTableUsed(Definition->getLocation(), DynamicClasses[I], true); + MarkVTableUsed(Definition->getLocation(), *I, true); } } @@ -438,13 +441,15 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, + true), UnusedFileScopedDecls.end(), std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), UnusedFileScopedDecls.end()); - if (!CompleteTranslationUnit) { + if (TUKind == TU_Prefix) { + // Translation unit prefixes don't need any of the checking below. TUScope = 0; return; } @@ -452,6 +457,7 @@ void Sema::ActOnEndOfTranslationUnit() { // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. + LoadExternalWeakUndeclaredIdentifiers(); for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = WeakUndeclaredIdentifiers.begin(), E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { @@ -461,6 +467,40 @@ void Sema::ActOnEndOfTranslationUnit() { << I->first; } + if (TUKind == TU_Module) { + // Mark any macros from system headers (in /usr/include) as exported, along + // with our own Clang headers. + // FIXME: This is a gross hack to deal with the fact that system headers + // are #include'd in many places within module headers, but are not + // themselves modularized. This doesn't actually work, but it lets us + // focus on other issues for the moment. + for (Preprocessor::macro_iterator M = PP.macro_begin(false), + MEnd = PP.macro_end(false); + M != MEnd; ++M) { + if (M->second && + !M->second->isExported() && + !M->second->isBuiltinMacro()) { + SourceLocation Loc = M->second->getDefinitionLoc(); + if (SourceMgr.isInSystemHeader(Loc)) { + const FileEntry *File + = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc)); + if (File && + ((StringRef(File->getName()).find("lib/clang") + != StringRef::npos) || + (StringRef(File->getName()).find("usr/include") + != StringRef::npos) || + (StringRef(File->getName()).find("usr/local/include") + != StringRef::npos))) + M->second->setExportLocation(Loc); + } + } + } + + // Modules don't need any of the checking below. + TUScope = 0; + return; + } + // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class @@ -473,8 +513,12 @@ void Sema::ActOnEndOfTranslationUnit() { // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; - for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) { - VarDecl *VD = TentativeDefinitions[i]->getActingDefinition(); + for (TentativeDefinitionsType::iterator + T = TentativeDefinitions.begin(ExternalSource), + TEnd = TentativeDefinitions.end(); + T != TEnd; ++T) + { + VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second @@ -510,16 +554,19 @@ void Sema::ActOnEndOfTranslationUnit() { if (LangOpts.CPlusPlus0x && Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, SourceLocation()) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) CheckDelegatingCtorCycles(); // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { // Output warning for unused file scoped decls. - for (llvm::SmallVectorImpl<const DeclaratorDecl*>::iterator - I = UnusedFileScopedDecls.begin(), + for (UnusedFileScopedDeclsType::iterator + I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { + if (ShouldRemoveFromUnused(this, *I)) + continue; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) @@ -631,7 +678,7 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { // Make a copy of this suppressed diagnostic and store it with the // template-deduction information; FlushCounts(); - DiagnosticInfo DiagInfo(&SemaRef.Diags); + Diagnostic DiagInfo(&SemaRef.Diags); if (*Info) (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), @@ -646,6 +693,9 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } } + // Set up the context's printing policy based on our current state. + SemaRef.Context.setPrintingPolicy(SemaRef.getPrintingPolicy()); + // Emit the diagnostic. if (!this->Emit()) return; @@ -677,20 +727,20 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } -/// \brief Looks through the macro-instantiation chain for the given -/// location, looking for a macro instantiation with the given name. +/// \brief Looks through the macro-expansion chain for the given +/// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that -/// instantiation loc. -bool Sema::findMacroSpelling(SourceLocation &locref, llvm::StringRef name) { +/// expansion loc. +bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) { SourceLocation loc = locref; if (!loc.isMacroID()) return false; // There's no good way right now to look at the intermediate - // instantiations, so just jump to the instantiation location. - loc = getSourceManager().getInstantiationLoc(loc); + // expansions, so just jump to the expansion location. + loc = getSourceManager().getExpansionLoc(loc); // If that's written with the name, stop here. - llvm::SmallVector<char, 16> buffer; + SmallVector<char, 16> buffer; if (getPreprocessor().getSpelling(loc, buffer) == name) { locref = loc; return true; @@ -754,7 +804,7 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP, if (WP && D) AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr); else { - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = Scope->PossiblyUnreachableDiags.begin(), e = Scope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -790,10 +840,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) { } void ExternalSemaSource::ReadKnownNamespaces( - llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) { + SmallVectorImpl<NamespaceDecl *> &Namespaces) { } -void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { +void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); if (Loc.isValid()) { @@ -820,27 +870,38 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { /// \param ZeroArgCallReturnTy - If the expression can be turned into a call /// with no arguments, this parameter is set to the type returned by such a /// call; otherwise, it is set to an empty QualType. -/// \param NonTemplateOverloads - If the expression is an overloaded function +/// \param OverloadSet - If the expression is an overloaded function /// name, this parameter is populated with the decls of the various overloads. bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, - UnresolvedSetImpl &NonTemplateOverloads) { + UnresolvedSetImpl &OverloadSet) { ZeroArgCallReturnTy = QualType(); - NonTemplateOverloads.clear(); - if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) { + OverloadSet.clear(); + + if (E.getType() == Context.OverloadTy) { + OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E)); + const OverloadExpr *Overloads = FR.Expression; + for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) { - // Our overload set may include TemplateDecls, which we'll ignore for our - // present purpose. - if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { - NonTemplateOverloads.addDecl(*it); + OverloadSet.addDecl(*it); + + // Check whether the function is a non-template which takes no + // arguments. + if (const FunctionDecl *OverloadDecl + = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) { if (OverloadDecl->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = OverloadDecl->getResultType(); } } + + // Ignore overloads that are pointer-to-member constants. + if (FR.HasFormOfMemberPointer) + return false; + return true; } - if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) { + if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) { if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { if (Fun->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = Fun->getResultType(); @@ -887,8 +948,8 @@ bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, /// -fshow-overloads=best, this is the location to attach to the note about too /// many candidates. Typically this will be the location of the original /// ill-formed expression. -void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, - const SourceLocation FinalNoteLoc) { +static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, + const SourceLocation FinalNoteLoc) { int ShownOverloads = 0; int SuppressedOverloads = 0; for (UnresolvedSetImpl::iterator It = Overloads.begin(), @@ -896,15 +957,86 @@ void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads, // FIXME: Magic number for max shown overloads stolen from // OverloadCandidateSet::NoteCandidates. if (ShownOverloads >= 4 && - Diags.getShowOverloads() == Diagnostic::Ovl_Best) { + S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) { ++SuppressedOverloads; continue; } - Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(), - diag::note_member_ref_possible_intended_overload); + + NamedDecl *Fn = (*It)->getUnderlyingDecl(); + S.Diag(Fn->getLocStart(), diag::note_possible_target_of_call); ++ShownOverloads; } + if (SuppressedOverloads) - Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) - << SuppressedOverloads; + S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates) + << SuppressedOverloads; +} + +static void notePlausibleOverloads(Sema &S, SourceLocation Loc, + const UnresolvedSetImpl &Overloads, + bool (*IsPlausibleResult)(QualType)) { + if (!IsPlausibleResult) + return noteOverloads(S, Overloads, Loc); + + UnresolvedSet<2> PlausibleOverloads; + for (OverloadExpr::decls_iterator It = Overloads.begin(), + DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { + const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + QualType OverloadResultTy = OverloadDecl->getResultType(); + if (IsPlausibleResult(OverloadResultTy)) + PlausibleOverloads.addDecl(It.getDecl()); + } + noteOverloads(S, PlausibleOverloads, Loc); +} + +/// Determine whether the given expression can be called by just +/// putting parentheses after it. Notably, expressions with unary +/// operators can't be because the unary operator will start parsing +/// outside the call. +static bool IsCallableWithAppend(Expr *E) { + E = E->IgnoreImplicit(); + return (!isa<CStyleCastExpr>(E) && + !isa<UnaryOperator>(E) && + !isa<BinaryOperator>(E) && + !isa<CXXOperatorCallExpr>(E)); +} + +bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, + bool ForceComplain, + bool (*IsPlausibleResult)(QualType)) { + SourceLocation Loc = E.get()->getExprLoc(); + SourceRange Range = E.get()->getSourceRange(); + + QualType ZeroArgCallTy; + UnresolvedSet<4> Overloads; + if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) && + !ZeroArgCallTy.isNull() && + (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) { + // At this point, we know E is potentially callable with 0 + // arguments and that it returns something of a reasonable type, + // so we can emit a fixit and carry on pretending that E was + // actually a CallExpr. + SourceLocation ParenInsertionLoc = + PP.getLocForEndOfToken(Range.getEnd()); + Diag(Loc, PD) + << /*zero-arg*/ 1 << Range + << (IsCallableWithAppend(E.get()) + ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") + : FixItHint()); + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + + // FIXME: Try this before emitting the fixit, and suppress diagnostics + // while doing so. + E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, + MultiExprArg(*this, 0, 0), + ParenInsertionLoc.getLocWithOffset(1)); + return true; + } + + if (!ForceComplain) return false; + + Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + E = ExprError(); + return true; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index a26737e..6cd9230 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -103,7 +103,11 @@ struct EffectiveContext { } else if (isa<FunctionDecl>(DC)) { FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); Functions.push_back(Function); - DC = Function->getDeclContext(); + + if (Function->getFriendObjectKind()) + DC = Function->getLexicalDeclContext(); + else + DC = Function->getDeclContext(); } else if (DC->isFileContext()) { break; } else { @@ -126,11 +130,11 @@ struct EffectiveContext { return Inner; } - typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; + typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; DeclContext *Inner; - llvm::SmallVector<FunctionDecl*, 4> Functions; - llvm::SmallVector<CXXRecordDecl*, 4> Records; + SmallVector<FunctionDecl*, 4> Functions; + SmallVector<CXXRecordDecl*, 4> Records; bool Dependent; }; @@ -146,10 +150,8 @@ struct AccessTarget : public AccessedEntity { MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, - QualType BaseObjectType, - bool IsUsingDecl = false) - : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType), - IsUsingDeclaration(IsUsingDecl) { + QualType BaseObjectType) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { initialize(); } @@ -218,7 +220,6 @@ private: DeclaringClass = DeclaringClass->getCanonicalDecl(); } - bool IsUsingDeclaration : 1; bool HasInstanceContext : 1; mutable bool CalculatedInstanceContext : 1; mutable const CXXRecordDecl *InstanceContext; @@ -260,7 +261,7 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, return AR_dependent; AccessResult OnFailure = AR_inaccessible; - llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack + SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack while (true) { for (CXXRecordDecl::base_class_const_iterator @@ -421,7 +422,7 @@ static AccessResult MatchesFriend(Sema &S, // Check whether the friend is the template of a class in the // context chain. - for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + for (SmallVectorImpl<CXXRecordDecl*>::const_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { CXXRecordDecl *Record = *I; @@ -472,7 +473,7 @@ static AccessResult MatchesFriend(Sema &S, FunctionDecl *Friend) { AccessResult OnFailure = AR_inaccessible; - for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + for (SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { if (Friend == *I) return AR_accessible; @@ -493,7 +494,7 @@ static AccessResult MatchesFriend(Sema &S, AccessResult OnFailure = AR_inaccessible; - for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator + for (SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); @@ -584,7 +585,7 @@ struct ProtectedFriendContext { bool EverDependent; /// The path down to the current base class. - llvm::SmallVector<const CXXRecordDecl*, 20> CurPath; + SmallVector<const CXXRecordDecl*, 20> CurPath; ProtectedFriendContext(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *InstanceContext, @@ -1273,7 +1274,7 @@ static AccessResult CheckEffectiveAccess(Sema &S, AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); - if (S.getLangOptions().Microsoft && + if (S.getLangOptions().MicrosoftMode && IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) return AR_accessible; @@ -1554,8 +1555,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, 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"); + const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, @@ -1638,13 +1638,34 @@ void Sema::CheckLookupAccess(const LookupResult &R) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), - R.getBaseObjectType(), R.isUsingDeclaration()); + R.getBaseObjectType()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); } } } +/// Checks access to Decl from the given class. The check will take access +/// specifiers into account, but no member access expressions and such. +/// +/// \param Decl the declaration to check if it can be accessed +/// \param Class the class/context from which to start the search +/// \return true if the Decl is accessible from the Class, false otherwise. +bool Sema::IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *Class) { + if (!Class || !Decl->isCXXClassMember()) + return true; + + QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); + AccessTarget Entity(Context, AccessedEntity::Member, Class, + DeclAccessPair::make(Decl, Decl->getAccess()), + qType); + if (Entity.getAccess() == AS_public) + return true; + + EffectiveContext EC(CurContext); + return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; +} + void Sema::ActOnStartSuppressingAccessChecks() { assert(!SuppressAccessChecking && "Tried to start access check suppression when already started."); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 53dd297..77410db 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -189,7 +189,7 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, } void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, - ExprTy *alignment, SourceLocation PragmaLoc, + Expr *alignment, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { Expr *Alignment = static_cast<Expr *>(alignment); @@ -265,7 +265,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, break; default: - assert(0 && "Invalid #pragma pack kind."); + llvm_unreachable("Invalid #pragma pack kind."); } } @@ -300,6 +300,18 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context)); } +void Sema::AddCFAuditedAttribute(Decl *D) { + SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc(); + if (!Loc.isValid()) return; + + // Don't add a redundant or conflicting attribute. + if (D->hasAttr<CFAuditedTransferAttr>() || + D->hasAttr<CFUnknownTransferAttr>()) + return; + + D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context)); +} + typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack; enum { NoVisibility = (unsigned) -1 }; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index 5f8c9c6..360a040 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -137,8 +137,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - assert(false && "Dependent nested-name-specifier has no DeclContext"); - break; + llvm_unreachable("Dependent nested-name-specifier has no DeclContext"); case NestedNameSpecifier::Namespace: return NNS->getAsNamespace(); @@ -238,7 +237,7 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // until we see a definition, so awkwardly pull out this special // case. if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) { - if (!enumType->getDecl()->isDefinition()) { + if (!enumType->getDecl()->isCompleteDefinition()) { Diag(loc, diag::err_incomplete_nested_name_spec) << type << SS.getRange(); SS.SetInvalid(SS.getRange()); @@ -615,6 +614,31 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, LookupName(Found, S); } + // In Microsoft mode, if we are within a templated function and we can't + // resolve Identifier, then extend the SS with Identifier. This will have + // the effect of resolving Identifier during template instantiation. + // The goal is to be able to resolve a function call whose + // nested-name-specifier is located inside a dependent base class. + // Example: + // + // class C { + // public: + // static void foo2() { } + // }; + // template <class T> class A { public: typedef C D; }; + // + // template <class T> class B : public A<T> { + // public: + // void foo() { D::foo2(); } + // }; + if (getLangOptions().MicrosoftExt) { + DeclContext *DC = LookupCtx ? LookupCtx : CurContext; + if (DC->isDependentContext() && DC->isFunctionOrMethod()) { + SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + return false; + } + } + unsigned DiagID; if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index d053d5a..8bd9351 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp @@ -1,4 +1,4 @@ -//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===// +//===--- SemaCast.cpp - Semantic Analysis for Casts -----------------------===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,17 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for C++ named casts. +// This file implements semantic analysis for cast expressions, including +// 1) C-style casts like '(int) x' +// 2) C++ functional casts like 'int(x)' +// 3) C++ named casts like 'static_cast<int>(x)' // //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Initialization.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/Basic/PartialDiagnostic.h" @@ -39,29 +43,83 @@ enum CastType { CT_Functional ///< Type(expr) }; +namespace { + struct CastOperation { + CastOperation(Sema &S, QualType destType, ExprResult src) + : Self(S), SrcExpr(src), DestType(destType), + ResultType(destType.getNonLValueExprType(S.Context)), + ValueKind(Expr::getValueKindForType(destType)), + Kind(CK_Dependent) { + + if (const BuiltinType *placeholder = + src.get()->getType()->getAsPlaceholderType()) { + PlaceholderKind = placeholder->getKind(); + } else { + PlaceholderKind = (BuiltinType::Kind) 0; + } + } + + Sema &Self; + ExprResult SrcExpr; + QualType DestType; + QualType ResultType; + ExprValueKind ValueKind; + CastKind Kind; + BuiltinType::Kind PlaceholderKind; + CXXCastPath BasePath; + SourceRange OpRange; + SourceRange DestRange; + // Top-level semantics-checking routines. + void CheckConstCast(); + void CheckReinterpretCast(); + void CheckStaticCast(); + void CheckDynamicCast(); + void CheckCXXCStyleCast(bool FunctionalCast); + void CheckCStyleCast(); -static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange); -static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind); -static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - CastKind &Kind, - CXXCastPath &BasePath); -static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, - const SourceRange &OpRange, - const SourceRange &DestRange, - CastKind &Kind, - CXXCastPath &BasePath); + // Internal convenience methods. + + /// Try to handle the given placeholder expression kind. Return + /// true if the source expression has the appropriate placeholder + /// kind. A placeholder can only be claimed once. + bool claimPlaceholder(BuiltinType::Kind K) { + if (PlaceholderKind != K) return false; + + PlaceholderKind = (BuiltinType::Kind) 0; + return true; + } + + bool isPlaceholder() const { + return PlaceholderKind != 0; + } + bool isPlaceholder(BuiltinType::Kind K) const { + return PlaceholderKind == K; + } + + void checkCastAlign() { + Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); + } + + void checkObjCARCConversion(Sema::CheckedConversionKind CCK) { + Expr *src = SrcExpr.get(); + Self.CheckObjCARCConversion(OpRange, DestType, src, CCK); + SrcExpr = src; + } + + /// Check for and handle non-overload placeholder expressions. + void checkNonOverloadPlaceholders() { + if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload)) + return; + + SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + PlaceholderKind = (BuiltinType::Kind) 0; + } + }; +} static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, bool CheckCVR, bool CheckObjCLifetime); @@ -162,70 +220,61 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, ExprResult Ex = Owned(E); QualType DestType = DestTInfo->getType(); - SourceRange OpRange(OpLoc, Parens.getEnd()); - SourceRange DestRange = AngleBrackets; - // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent(); - ExprValueKind VK = VK_RValue; - if (TypeDependent) - VK = Expr::getValueKindForType(DestType); + CastOperation Op(*this, DestType, E); + Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); + Op.DestRange = AngleBrackets; switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: if (!TypeDependent) { - CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange); - if (Ex.isInvalid()) + Op.CheckConstCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXConstCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Ex.take(), DestTInfo, OpLoc, + return Owned(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.SrcExpr.take(), DestTInfo, OpLoc, Parens.getEnd())); case tok::kw_dynamic_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange, - Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckDynamicCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXDynamicCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, DestTInfo, - OpLoc, Parens.getEnd())); + return Owned(CXXDynamicCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, + Op.SrcExpr.take(), &Op.BasePath, + DestTInfo, OpLoc, Parens.getEnd())); } case tok::kw_reinterpret_cast: { - CastKind Kind = CK_Dependent; if (!TypeDependent) { - CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind); - if (Ex.isInvalid()) + Op.CheckReinterpretCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXReinterpretCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), 0, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXReinterpretCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, Op.Kind, + Op.SrcExpr.take(), 0, + DestTInfo, OpLoc, + Parens.getEnd())); } case tok::kw_static_cast: { - CastKind Kind = CK_Dependent; - CXXCastPath BasePath; if (!TypeDependent) { - CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath); - if (Ex.isInvalid()) + Op.CheckStaticCast(); + if (Op.SrcExpr.isInvalid()) return ExprError(); } - return Owned(CXXStaticCastExpr::Create(Context, - DestType.getNonLValueExprType(Context), - VK, Kind, Ex.take(), &BasePath, - DestTInfo, OpLoc, Parens.getEnd())); + return Owned(CXXStaticCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, DestTInfo, OpLoc, + Parens.getEnd())); } } @@ -410,7 +459,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); - llvm::SmallVector<Qualifiers, 8> cv1, cv2; + SmallVector<Qualifiers, 8> cv1, cv2; // Find the qualifiers. We only care about cvr-qualifiers for the // purpose of this check, because other qualifiers (address spaces, @@ -442,7 +491,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, QualType SrcConstruct = Self.Context.VoidTy; QualType DestConstruct = Self.Context.VoidTy; ASTContext &Context = Self.Context; - for (llvm::SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), + for (SmallVector<Qualifiers, 8>::reverse_iterator i1 = cv1.rbegin(), i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { SrcConstruct @@ -461,13 +510,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. -static void -CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind, - CXXCastPath &BasePath) { - QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType(); - DestType = Self.Context.getCanonicalType(DestType); +void CastOperation::CheckDynamicCast() { + QualType OrigSrcType = SrcExpr.get()->getType(); + QualType DestType = Self.Context.getCanonicalType(this->DestType); // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, // or "pointer to cv void". @@ -479,12 +524,9 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, DestPointee = DestPointer->getPointeeType(); } else if ((DestReference = DestType->getAs<ReferenceType>())) { DestPointee = DestReference->getPointeeType(); - VK = isa<LValueReferenceType>(DestReference) ? VK_LValue - : isa<RValueReferenceType>(DestReference) ? VK_XValue - : VK_RValue; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) - << OrigDestType << DestRange; + << this->DestType << DestRange; return; } @@ -519,7 +561,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } else if (DestReference->isLValueReferenceType()) { if (!SrcExpr.get()->isLValue()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; } SrcPointee = SrcType; } else { @@ -547,7 +589,7 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) - << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; + << CT_Dynamic << OrigSrcType << this->DestType << OpRange; return; } @@ -595,11 +637,8 @@ CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// like this: /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); -void -CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, - const SourceRange &OpRange, const SourceRange &DestRange) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckConstCast() { + if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -617,12 +656,8 @@ CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind /// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code /// like this: /// char *bytes = reinterpret_cast\<char*\>(int_ptr); -void -CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - const SourceRange &DestRange, CastKind &Kind) { - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) { +void CastOperation::CheckReinterpretCast() { + if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -647,10 +682,7 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); + checkObjCARCConversion(Sema::CCK_OtherCast); } } @@ -658,36 +690,34 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, /// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. -void -CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, - ExprValueKind &VK, const SourceRange &OpRange, - CastKind &Kind, CXXCastPath &BasePath) { +void CastOperation::CheckStaticCast() { + if (isPlaceholder()) { + checkNonOverloadPlaceholders(); + if (SrcExpr.isInvalid()) + return; + } + // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { - SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); - if (SrcExpr.isInvalid()) // if conversion failed, don't report another error - return; - if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { - ExprResult SingleFunctionExpression = - Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), + Kind = CK_ToVoid; + + if (claimPlaceholder(BuiltinType::Overload)) { + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr, false, // Decay Function to ptr true, // Complain OpRange, DestType, diag::err_bad_static_cast_overload); - if (SingleFunctionExpression.isUsable()) - { - SrcExpr = SingleFunctionExpression; - Kind = CK_ToVoid; - } + if (SrcExpr.isInvalid()) + return; } - else - Kind = CK_ToVoid; + + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); return; } - VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue && !DestType->isRecordType()) { + if (ValueKind == VK_RValue && !DestType->isRecordType() && + !isPlaceholder(BuiltinType::Overload)) { SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; @@ -711,16 +741,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, } } else if (tcr == TC_Success) { if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); - if (Self.getLangOptions().ObjCAutoRefCount) { - Expr *Exp = SrcExpr.get(); - // Note that Exp does not change with CCK_OtherCast cast type - Self.CheckObjCARCConversion(OpRange, DestType, - Exp, Sema::CCK_OtherCast); - } + checkCastAlign(); + if (Self.getLangOptions().ObjCAutoRefCount) + checkObjCARCConversion(Sema::CCK_OtherCast); + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if @@ -815,11 +841,12 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // The same goes for reverse floating point promotion/conversion and // floating-integral conversions. Again, only floating->enum is relevant. if (DestType->isEnumeralType()) { - if (SrcType->isComplexType() || SrcType->isVectorType()) { - // Fall through - these cannot be converted. - } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { + if (SrcType->isIntegralOrEnumerationType()) { Kind = CK_IntegralCast; return TC_Success; + } else if (SrcType->isRealFloatingType()) { + Kind = CK_FloatingToIntegral; + return TC_Success; } } @@ -870,7 +897,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, else if (DestType->isObjCObjectPointerType()) { // allow both c-style cast and static_cast of objective-c pointers as // they are pervasive. - Kind = CK_AnyPointerToObjCPointerCast; + Kind = CK_CPointerToObjCPointerCast; return TC_Success; } else if (CStyle && DestType->isBlockPointerType()) { @@ -1373,7 +1400,7 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, diag::warn_undefined_reinterpret_cast; if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) == - Diagnostic::Ignored) { + DiagnosticsEngine::Ignored) { return; } @@ -1430,17 +1457,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Is the source an overloaded name? (i.e. &foo) // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... if (SrcType == Self.Context.OverloadTy) { - // ... unless foo<int> resolves to an lvalue unambiguously - ExprResult SingleFunctionExpr = - Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), + // ... unless foo<int> resolves to an lvalue unambiguously. + // TODO: what if this fails because of DiagnoseUseOfDecl or something + // like it? + ExprResult SingleFunctionExpr = SrcExpr; + if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( + SingleFunctionExpr, Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr - ); - if (SingleFunctionExpr.isUsable()) { + ) && SingleFunctionExpr.isUsable()) { SrcExpr = move(SingleFunctionExpr); SrcType = SrcExpr.get()->getType(); - } - else + } else { return TC_NotApplicable; + } } if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { @@ -1592,7 +1621,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // integral type size doesn't matter. if ((Self.Context.getTypeSize(SrcType) > Self.Context.getTypeSize(DestType)) && - !Self.getLangOptions().Microsoft) { + !Self.getLangOptions().MicrosoftExt) { msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } @@ -1629,16 +1658,28 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, (DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType())) return TC_NotApplicable; + if (IsLValueCast) { + Kind = CK_LValueBitCast; + } else if (DestType->isObjCObjectPointerType()) { + Kind = Self.PrepareCastToObjCObjectPointer(SrcExpr); + } else if (DestType->isBlockPointerType()) { + if (!SrcType->isBlockPointerType()) { + Kind = CK_AnyPointerToBlockPointerCast; + } else { + Kind = CK_BitCast; + } + } else { + Kind = CK_BitCast; + } + // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; return TC_Success; } // Not casting away constness, so the only remaining check is for compatible // pointer categories. - Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { @@ -1673,65 +1714,64 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Success; } -ExprResult -Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, - Expr *CastExpr, CastKind &Kind, - CXXCastPath &BasePath, - bool FunctionalStyle) { +void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle) { + // Handle placeholders. + if (isPlaceholder()) { + // C-style casts can resolve __unknown_any types. + if (claimPlaceholder(BuiltinType::UnknownAny)) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + return; + } + + checkNonOverloadPlaceholders(); + if (SrcExpr.isInvalid()) + return; + } + + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. - // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". - if (CastTy->isVoidType()) { + if (DestType->isVoidType()) { Kind = CK_ToVoid; - ExprResult CastExprRes = IgnoredValueConversions(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); - - if (CastExpr->getType() == Context.BoundMemberTy) - return CheckPlaceholderExpr(CastExpr); // will always fail - - if (CastExpr->getType() == Context.OverloadTy) { - ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization( - CastExpr, /* Decay Function to ptr */ false, - /* Complain */ true, R, CastTy, + if (claimPlaceholder(BuiltinType::Overload)) { + Self.ResolveAndFixSingleFunctionTemplateSpecialization( + SrcExpr, /* Decay Function to ptr */ false, + /* Complain */ true, DestRange, DestType, diag::err_bad_cstyle_cast_overload); - if (SingleFunctionExpr.isInvalid()) - return ExprError(); - CastExpr = SingleFunctionExpr.take(); + if (SrcExpr.isInvalid()) + return; } - assert(!CastExpr->getType()->isPlaceholderType()); + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; - return Owned(CastExpr); + return; } - // Make sure we determine the value kind before we bail out for - // dependent types. - VK = Expr::getValueKindForType(CastTy); - // If the type is dependent, we won't do any other semantic analysis now. - if (CastTy->isDependentType() || CastExpr->isTypeDependent()) { - Kind = CK_Dependent; - return Owned(CastExpr); + if (DestType->isDependentType() || SrcExpr.get()->isTypeDependent()) { + assert(Kind == CK_Dependent); + return; } - if (VK == VK_RValue && !CastTy->isRecordType()) { - ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + if (ValueKind == VK_RValue && !DestType->isRecordType() && + !isPlaceholder(BuiltinType::Overload)) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; } // AltiVec vector initialization with a single literal. - if (const VectorType *vecTy = CastTy->getAs<VectorType>()) + if (const VectorType *vecTy = DestType->getAs<VectorType>()) if (vecTy->getVectorKind() == VectorType::AltiVecVector - && (CastExpr->getType()->isIntegerType() - || CastExpr->getType()->isFloatingType())) { + && (SrcExpr.get()->getType()->isIntegerType() + || SrcExpr.get()->getType()->isFloatingType())) { Kind = CK_VectorSplat; - return Owned(CastExpr); + return; } // C++ [expr.cast]p5: The conversions performed by @@ -1746,8 +1786,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... unsigned msg = diag::err_bad_cxx_cast_generic; - TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, - msg); + TryCastResult tcr = TryConstCast(Self, SrcExpr.get(), DestType, + /*CStyle*/true, msg); if (tcr == TC_Success) Kind = CK_NoOp; @@ -1756,47 +1796,274 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - ExprResult CastExprRes = Owned(CastExpr); - tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind, - BasePath); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, + msg, Kind, BasePath); + if (SrcExpr.isInvalid()) + return; + if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. - CastExprRes = Owned(CastExpr); - tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, - msg, Kind); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = CastExprRes.take(); + tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/true, + OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return; } } - if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success) - CheckObjCARCConversion(R, CastTy, CastExpr, CCK); + if (Self.getLangOptions().ObjCAutoRefCount && tcr == TC_Success) + checkObjCARCConversion(CCK); if (tcr != TC_Success && msg != 0) { - if (CastExpr->getType() == Context.OverloadTy) { + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, - CastTy, - /* Complain */ true, + FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), + DestType, + /*Complain*/ true, Found); assert(!Fn && "cast failed but able to resolve overload expression!!"); (void)Fn; } else { - diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), - R, CastExpr, CastTy); + diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), + OpRange, SrcExpr.get(), DestType); } + } else if (Kind == CK_BitCast) { + checkCastAlign(); } - else if (Kind == CK_BitCast) - CheckCastAlign(CastExpr, CastTy, R); + // Clear out SrcExpr if there was a fatal error. if (tcr != TC_Success) + SrcExpr = ExprError(); +} + +/// Check the semantics of a C-style cast operation, in C. +void CastOperation::CheckCStyleCast() { + assert(!Self.getLangOptions().CPlusPlus); + + // Handle placeholders. + if (isPlaceholder()) { + // C-style casts can resolve __unknown_any types. + if (claimPlaceholder(BuiltinType::UnknownAny)) { + SrcExpr = Self.checkUnknownAnyCast(DestRange, DestType, + SrcExpr.get(), Kind, + ValueKind, BasePath); + return; + } + + // We allow overloads in C, but we don't allow them to be resolved + // by anything except calls. + SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + } + + assert(!isPlaceholder()); + + // C99 6.5.4p2: the cast type needs to be void or scalar and the expression + // type needs to be scalar. + if (DestType->isVoidType()) { + // We don't necessarily do lvalue-to-rvalue conversions on this. + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + + // Cast to void allows any expr type. + Kind = CK_ToVoid; + return; + } + + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) + return; + QualType SrcType = SrcExpr.get()->getType(); + + if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + diag::err_typecheck_cast_to_incomplete)) { + SrcExpr = ExprError(); + return; + } + + if (!DestType->isScalarType() && !DestType->isVectorType()) { + const RecordType *DestRecordTy = DestType->getAs<RecordType>(); + + if (DestRecordTy && Self.Context.hasSameUnqualifiedType(DestType, SrcType)){ + // GCC struct/union extension: allow cast to self. + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar) + << DestType << SrcExpr.get()->getSourceRange(); + Kind = CK_NoOp; + return; + } + + // GCC's cast to union extension. + if (DestRecordTy && DestRecordTy->getDecl()->isUnion()) { + RecordDecl *RD = DestRecordTy->getDecl(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(), FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Self.Context.hasSameUnqualifiedType(Field->getType(), SrcType) && + !Field->isUnnamedBitfield()) { + Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_to_union) + << SrcExpr.get()->getSourceRange(); + break; + } + } + if (Field == FieldEnd) { + Self.Diag(OpRange.getBegin(), diag::err_typecheck_cast_to_union_no_type) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + Kind = CK_ToUnion; + return; + } + + // Reject any other conversions to non-scalar types. + Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar) + << DestType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + + // The type we're casting to is known to be a scalar or vector. + + // Require the operand to be a scalar or vector. + if (!SrcType->isScalarType() && !SrcType->isVectorType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::err_typecheck_expect_scalar_operand) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + + if (DestType->isExtVectorType()) { + SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.take(), Kind); + return; + } + + if (const VectorType *DestVecTy = DestType->getAs<VectorType>()) { + if (DestVecTy->getVectorKind() == VectorType::AltiVecVector && + (SrcType->isIntegerType() || SrcType->isFloatingType())) { + Kind = CK_VectorSplat; + } else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) { + SrcExpr = ExprError(); + } + return; + } + + if (SrcType->isVectorType()) { + if (Self.CheckVectorCast(OpRange, SrcType, DestType, Kind)) + SrcExpr = ExprError(); + return; + } + + // The source and target types are both scalars, i.e. + // - arithmetic types (fundamental, enum, and complex) + // - all kinds of pointers + // Note that member pointers were filtered out with C++, above. + + if (isa<ObjCSelectorExpr>(SrcExpr.get())) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_selector_expr); + SrcExpr = ExprError(); + return; + } + + // If either type is a pointer, the other type has to be either an + // integer or a pointer. + if (!DestType->isArithmeticType()) { + if (!SrcType->isIntegralType(Self.Context) && SrcType->isArithmeticType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::err_cast_pointer_from_non_pointer_int) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } else if (!SrcType->isArithmeticType()) { + if (!DestType->isIntegralType(Self.Context) && + DestType->isArithmeticType()) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_cast_pointer_to_non_pointer_int) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + + // ARC imposes extra restrictions on casts. + if (Self.getLangOptions().ObjCAutoRefCount) { + checkObjCARCConversion(Sema::CCK_CStyleCast); + if (SrcExpr.isInvalid()) + return; + + if (const PointerType *CastPtr = DestType->getAs<PointerType>()) { + if (const PointerType *ExprPtr = SrcType->getAs<PointerType>()) { + Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); + Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); + if (CastPtr->getPointeeType()->isObjCLifetimeType() && + ExprPtr->getPointeeType()->isObjCLifetimeType() && + !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_typecheck_incompatible_ownership) + << SrcType << DestType << Sema::AA_Casting + << SrcExpr.get()->getSourceRange(); + return; + } + } + } + else if (!Self.CheckObjCARCUnavailableWeakConversion(DestType, SrcType)) { + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_arc_convesion_of_weak_unavailable) + << 1 << SrcType << DestType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + + Kind = Self.PrepareScalarCast(SrcExpr, DestType); + if (SrcExpr.isInvalid()) + return; + + if (Kind == CK_BitCast) + checkCastAlign(); +} + +ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, + TypeSourceInfo *CastTypeInfo, + SourceLocation RPLoc, + Expr *CastExpr) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(LPLoc, CastExpr->getLocEnd()); + + if (getLangOptions().CPlusPlus) { + Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ false); + } else { + Op.CheckCStyleCast(); + } + + if (Op.SrcExpr.isInvalid()) + return ExprError(); + + return Owned(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, + Op.Kind, Op.SrcExpr.take(), &Op.BasePath, + CastTypeInfo, LPLoc, RPLoc)); +} + +ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, + SourceLocation LPLoc, + Expr *CastExpr, + SourceLocation RPLoc) { + CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); + Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); + Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd()); + + Op.CheckCXXCStyleCast(/*FunctionalStyle=*/ true); + if (Op.SrcExpr.isInvalid()) return ExprError(); - return Owned(CastExpr); + return Owned(CXXFunctionalCastExpr::Create(Context, Op.ResultType, + Op.ValueKind, CastTypeInfo, + Op.DestRange.getBegin(), + Op.Kind, Op.SrcExpr.take(), + &Op.BasePath, RPLoc)); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index b032b8a..eaf7bfa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -12,8 +12,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Sema/Initialization.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Analysis/Analyses/FormatString.h" #include "clang/AST/ASTContext.h" @@ -87,6 +89,19 @@ static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { << call->getArg(1)->getSourceRange(); } +/// CheckBuiltinAnnotationString - Checks that string argument to the builtin +/// annotation is a non wide string literal. +static bool CheckBuiltinAnnotationString(Sema &S, Expr *Arg) { + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); + if (!Literal || !Literal->isAscii()) { + S.Diag(Arg->getLocStart(), diag::err_builtin_annotation_not_string_constant) + << Arg->getSourceRange(); + return true; + } + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); @@ -183,12 +198,38 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_lock_release: case Builtin::BI__sync_swap: return SemaBuiltinAtomicOverloaded(move(TheCallResult)); + case Builtin::BI__atomic_load: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load); + case Builtin::BI__atomic_store: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store); + case Builtin::BI__atomic_exchange: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg); + case Builtin::BI__atomic_compare_exchange_strong: + return SemaAtomicOpsOverloaded(move(TheCallResult), + AtomicExpr::CmpXchgStrong); + case Builtin::BI__atomic_compare_exchange_weak: + return SemaAtomicOpsOverloaded(move(TheCallResult), + AtomicExpr::CmpXchgWeak); + case Builtin::BI__atomic_fetch_add: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add); + case Builtin::BI__atomic_fetch_sub: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub); + case Builtin::BI__atomic_fetch_and: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And); + case Builtin::BI__atomic_fetch_or: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or); + case Builtin::BI__atomic_fetch_xor: + return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor); + case Builtin::BI__builtin_annotation: + if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1))) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those // of the arch we are compiling for. if (BuiltinID >= Builtin::FirstTSBuiltin) { - switch (Context.Target.getTriple().getArch()) { + switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) @@ -319,7 +360,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { TheCall->getCallee()->getLocStart()); } - // Memset/memcpy/memmove handling + // Builtin handling int CMF = -1; switch (FDecl->getBuiltinID()) { case Builtin::BI__builtin_memset: @@ -339,7 +380,40 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { case Builtin::BImemmove: CMF = CMF_Memmove; break; + + case Builtin::BIstrlcpy: + case Builtin::BIstrlcat: + CheckStrlcpycatArguments(TheCall, FnInfo); + break; + case Builtin::BI__builtin_memcmp: + CMF = CMF_Memcmp; + break; + + case Builtin::BI__builtin_strncpy: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BIstrncpy: + CMF = CMF_Strncpy; + break; + + case Builtin::BI__builtin_strncmp: + CMF = CMF_Strncmp; + break; + + case Builtin::BI__builtin_strncasecmp: + CMF = CMF_Strncasecmp; + break; + + case Builtin::BI__builtin_strncat: + case Builtin::BIstrncat: + CMF = CMF_Strncat; + break; + + case Builtin::BI__builtin_strndup: + case Builtin::BIstrndup: + CMF = CMF_Strndup; + break; + default: if (FDecl->getLinkage() == ExternalLinkage && (!getLangOptions().CPlusPlus || FDecl->isExternC())) { @@ -349,12 +423,25 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { CMF = CMF_Memcpy; else if (FnInfo->isStr("memmove")) CMF = CMF_Memmove; + else if (FnInfo->isStr("memcmp")) + CMF = CMF_Memcmp; + else if (FnInfo->isStr("strncpy")) + CMF = CMF_Strncpy; + else if (FnInfo->isStr("strncmp")) + CMF = CMF_Strncmp; + else if (FnInfo->isStr("strncasecmp")) + CMF = CMF_Strncasecmp; + else if (FnInfo->isStr("strncat")) + CMF = CMF_Strncat; + else if (FnInfo->isStr("strndup")) + CMF = CMF_Strndup; } break; } + // Memset/memcpy/memmove handling if (CMF != -1) - CheckMemsetcpymoveArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo); + CheckMemaccessArguments(TheCall, CheckedMemoryFunction(CMF), FnInfo); return false; } @@ -384,6 +471,170 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { return false; } +ExprResult +Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { + CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); + DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + + // All these operations take one of the following four forms: + // T __atomic_load(_Atomic(T)*, int) (loads) + // T* __atomic_add(_Atomic(T*)*, ptrdiff_t, int) (pointer add/sub) + // int __atomic_compare_exchange_strong(_Atomic(T)*, T*, T, int, int) + // (cmpxchg) + // T __atomic_exchange(_Atomic(T)*, T, int) (everything else) + // where T is an appropriate type, and the int paremeterss are for orderings. + unsigned NumVals = 1; + unsigned NumOrders = 1; + if (Op == AtomicExpr::Load) { + NumVals = 0; + } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) { + NumVals = 2; + NumOrders = 2; + } + + if (TheCall->getNumArgs() < NumVals+NumOrders+1) { + Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) { + Diag(TheCall->getArg(NumVals+NumOrders+1)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } + + // Inspect the first argument of the atomic operation. This should always be + // a pointer to an _Atomic type. + Expr *Ptr = TheCall->getArg(0); + Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get(); + const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); + if (!pointerType) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + QualType AtomTy = pointerType->getPointeeType(); + if (!AtomTy->isAtomicType()) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + QualType ValType = AtomTy->getAs<AtomicType>()->getValueType(); + + if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) && + !ValType->isIntegerType() && !ValType->isPointerType()) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + if (!ValType->isIntegerType() && + (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){ + Diag(DRE->getLocStart(), diag::err_atomic_op_logical_needs_atomic_int) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + + switch (ValType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + // okay + break; + + case Qualifiers::OCL_Weak: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Autoreleasing: + Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) + << ValType << Ptr->getSourceRange(); + return ExprError(); + } + + QualType ResultType = ValType; + if (Op == AtomicExpr::Store) + ResultType = Context.VoidTy; + else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) + ResultType = Context.BoolTy; + + // The first argument --- the pointer --- has a fixed type; we + // deduce the types of the rest of the arguments accordingly. Walk + // the remaining arguments, converting them to the deduced value type. + for (unsigned i = 1; i != NumVals+NumOrders+1; ++i) { + ExprResult Arg = TheCall->getArg(i); + QualType Ty; + if (i < NumVals+1) { + // The second argument to a cmpxchg is a pointer to the data which will + // be exchanged. The second argument to a pointer add/subtract is the + // amount to add/subtract, which must be a ptrdiff_t. The third + // argument to a cmpxchg and the second argument in all other cases + // is the type of the value. + if (i == 1 && (Op == AtomicExpr::CmpXchgWeak || + Op == AtomicExpr::CmpXchgStrong)) + Ty = Context.getPointerType(ValType.getUnqualifiedType()); + else if (!ValType->isIntegerType() && + (Op == AtomicExpr::Add || Op == AtomicExpr::Sub)) + Ty = Context.getPointerDiffType(); + else + Ty = ValType; + } else { + // The order(s) are always converted to int. + Ty = Context.IntTy; + } + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, Ty, false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + } + + SmallVector<Expr*, 5> SubExprs; + SubExprs.push_back(Ptr); + if (Op == AtomicExpr::Load) { + SubExprs.push_back(TheCall->getArg(1)); // Order + } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) { + SubExprs.push_back(TheCall->getArg(2)); // Order + SubExprs.push_back(TheCall->getArg(1)); // Val1 + } else { + SubExprs.push_back(TheCall->getArg(3)); // Order + SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(TheCall->getArg(4)); // OrderFail + } + + return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), + SubExprs.data(), SubExprs.size(), + ResultType, Op, + TheCall->getRParenLoc())); +} + + +/// checkBuiltinArgument - Given a call to a builtin function, perform +/// normal type-checking on the given argument, updating the call in +/// place. This is useful when a builtin function requires custom +/// type-checking for some of its arguments but not necessarily all of +/// them. +/// +/// Returns true on error. +static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { + FunctionDecl *Fn = E->getDirectCallee(); + assert(Fn && "builtin call without direct callee!"); + + ParmVarDecl *Param = Fn->getParamDecl(ArgIndex); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, Param); + + ExprResult Arg = E->getArg(0); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + + E->setArg(ArgIndex, Arg.take()); + return false; +} + /// SemaBuiltinAtomicOverloaded - We have a call to a function like /// __sync_fetch_and_add, which is an overloaded function based on the pointer /// type of its first argument. The main ActOnCallExpr routines have already @@ -441,6 +692,9 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + // Strip any qualifiers off ValType. + ValType = ValType.getUnqualifiedType(); + // The majority of builtins return a value, but a few have special return // types, so allow them to override appropriately below. QualType ResultType = ValType; @@ -494,7 +748,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; switch (BuiltinID) { - default: assert(0 && "Unknown overloaded atomic builtin!"); + default: llvm_unreachable("Unknown overloaded atomic builtin!"); case Builtin::BI__sync_fetch_and_add: BuiltinIndex = 0; break; case Builtin::BI__sync_fetch_and_sub: BuiltinIndex = 1; break; case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break; @@ -559,11 +813,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(), - ValType, Arg.take(), Kind, VK, BasePath); + // Initialize the argument. + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + ValType, /*consume*/ false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return ExprError(); @@ -573,17 +826,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - Arg = ImpCastExprToType(Arg.take(), ValType, Kind, VK, &BasePath); - TheCall->setArg(i+1, Arg.get()); + TheCall->setArg(i+1, Arg.take()); } - // Switch the DeclRefExpr to refer to the new decl. - DRE->setDecl(NewBuiltinDecl); - DRE->setType(NewBuiltinDecl->getType()); + ASTContext& Context = this->getASTContext(); + + // Create a new DeclRefExpr to refer to the new decl. + DeclRefExpr* NewDRE = DeclRefExpr::Create( + Context, + DRE->getQualifierLoc(), + NewBuiltinDecl, + DRE->getLocation(), + NewBuiltinDecl->getType(), + DRE->getValueKind()); // Set the callee in the CallExpr. // FIXME: This leaks the original parens and implicit casts. - ExprResult PromotedCall = UsualUnaryConversions(DRE); + ExprResult PromotedCall = UsualUnaryConversions(NewDRE); if (PromotedCall.isInvalid()) return ExprError(); TheCall->setCallee(PromotedCall.take()); @@ -596,7 +855,6 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return move(TheCallResult); } - /// CheckObjCString - Checks that the argument to the builtin /// CFString constructor is correct /// Note: It might also make sense to do the UTF-16 conversion here (would @@ -605,16 +863,16 @@ bool Sema::CheckObjCString(Expr *Arg) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); - if (!Literal || Literal->isWide()) { + if (!Literal || !Literal->isAscii()) { Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant) << Arg->getSourceRange(); return true; } if (Literal->containsNonAsciiOrNull()) { - llvm::StringRef String = Literal->getString(); + StringRef String = Literal->getString(); unsigned NumBytes = String.size(); - llvm::SmallVector<UTF16, 128> ToBuf(NumBytes); + SmallVector<UTF16, 128> ToBuf(NumBytes); const UTF8 *FromPtr = (UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; @@ -649,6 +907,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, TheCall, 0)) + return true; + // Determine whether the current function is variadic or not. BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; @@ -844,7 +1106,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << TheCall->getArg(i)->getSourceRange()); } - llvm::SmallVector<Expr*, 32> exprs; + SmallVector<Expr*, 32> exprs; for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { exprs.push_back(TheCall->getArg(i)); @@ -1238,7 +1500,7 @@ getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1); // Advance the end SourceLocation by one due to half-open ranges. - End = End.getFileLocWithOffset(1); + End = End.getLocWithOffset(1); return CharSourceRange::getCharRange(Start, End); } @@ -1322,7 +1584,7 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, } S.Diag(Loc, diag::warn_format_invalid_conversion) - << llvm::StringRef(csStart, csLen) + << StringRef(csStart, csLen) << getSpecifierRange(startSpec, specifierLen); return keepGoing; @@ -1838,7 +2100,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, bool isPrintf) { // CHECK: is the format string a wide literal? - if (FExpr->isWide()) { + if (!FExpr->isAscii()) { Diag(FExpr->getLocStart(), diag::warn_format_string_is_wide_literal) << OrigFormatExpr->getSourceRange(); @@ -1846,12 +2108,13 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } // Str - The format string. NOTE: this is NOT null-terminated! - llvm::StringRef StrRef = FExpr->getString(); + StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); unsigned StrLen = StrRef.size(); + const unsigned numDataArgs = TheCall->getNumArgs() - firstDataArg; // CHECK: empty format string? - if (StrLen == 0) { + if (StrLen == 0 && numDataArgs > 0) { Diag(FExpr->getLocStart(), diag::warn_empty_format_string) << OrigFormatExpr->getSourceRange(); return; @@ -1859,9 +2122,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, if (isPrintf) { CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - TheCall->getNumArgs() - firstDataArg, - isa<ObjCStringLiteral>(OrigFormatExpr), Str, - HasVAListArg, TheCall, format_idx); + numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr), + Str, HasVAListArg, TheCall, format_idx); bool FormatExtensions = getLangOptions().FormatExtensions; if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, @@ -1870,9 +2132,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } else { CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - TheCall->getNumArgs() - firstDataArg, - isa<ObjCStringLiteral>(OrigFormatExpr), Str, - HasVAListArg, TheCall, format_idx); + numDataArgs, isa<ObjCStringLiteral>(OrigFormatExpr), + Str, HasVAListArg, TheCall, format_idx); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen)) H.DoneProcessing(); @@ -1916,19 +2177,22 @@ static QualType getSizeOfArgType(const Expr* E) { /// \brief Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified -/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls. +/// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' +/// function calls. /// /// \param Call The call expression to diagnose. -void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, - CheckedMemoryFunction CMF, - IdentifierInfo *FnName) { +void Sema::CheckMemaccessArguments(const CallExpr *Call, + CheckedMemoryFunction CMF, + IdentifierInfo *FnName) { // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - if (Call->getNumArgs() < 3) + unsigned ExpectedNumArgs = (CMF == CMF_Strndup ? 2 : 3); + if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (CMF == CMF_Memset? 1 : 2); - const Expr *LenExpr = Call->getArg(2)->IgnoreParenImpCasts(); + unsigned LastArg = (CMF == CMF_Memset || CMF == CMF_Strndup ? 1 : 2); + unsigned LenArg = (CMF == CMF_Strndup ? 1 : 2); + const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); @@ -1962,6 +2226,8 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, llvm::FoldingSetNodeID DestID; Dest->Profile(DestID, Context, true); if (DestID == SizeOfArgID) { + // TODO: For strncpy() and friends, this could suggest sizeof(dst) + // over sizeof(src) as well. unsigned ActionIdx = 0; // Default is to suggest dereferencing. if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest)) if (UnaryOp->getOpcode() == UO_AddrOf) @@ -1969,9 +2235,10 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, if (Context.getTypeSize(PointeeTy) == Context.getCharWidth()) ActionIdx = 2; // If the pointee's size is sizeof(char), // suggest an explicit length. + unsigned DestSrcSelect = (CMF == CMF_Strndup ? 1 : ArgIdx); DiagRuntimeBehavior(SizeOfArg->getExprLoc(), Dest, PDiag(diag::warn_sizeof_pointer_expr_memaccess) - << FnName << ArgIdx << ActionIdx + << FnName << DestSrcSelect << ActionIdx << Dest->getSourceRange() << SizeOfArg->getSourceRange()); break; @@ -1993,24 +2260,27 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, } } - unsigned DiagID; - // Always complain about dynamic classes. if (isDynamicClassType(PointeeTy)) - DiagID = diag::warn_dyn_class_memaccess; + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_dyn_class_memaccess) + << (CMF == CMF_Memcmp ? ArgIdx + 2 : ArgIdx) << FnName << PointeeTy + // "overwritten" if we're warning about the destination for any call + // but memcmp; otherwise a verb appropriate to the call. + << (ArgIdx == 0 && CMF != CMF_Memcmp ? 0 : (unsigned)CMF) + << Call->getCallee()->getSourceRange()); else if (PointeeTy.hasNonTrivialObjCLifetime() && CMF != CMF_Memset) - DiagID = diag::warn_arc_object_memaccess; + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_arc_object_memaccess) + << ArgIdx << FnName << PointeeTy + << Call->getCallee()->getSourceRange()); else continue; DiagRuntimeBehavior( Dest->getExprLoc(), Dest, - PDiag(DiagID) - << ArgIdx << FnName << PointeeTy - << Call->getCallee()->getSourceRange()); - - DiagRuntimeBehavior( - Dest->getExprLoc(), Dest, PDiag(diag::note_bad_memaccess_silence) << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); break; @@ -2018,10 +2288,107 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call, } } +// A little helper routine: ignore addition and subtraction of integer literals. +// This intentionally does not ignore all integer constant expressions because +// we don't want to remove sizeof(). +static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { + Ex = Ex->IgnoreParenCasts(); + + for (;;) { + const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex); + if (!BO || !BO->isAdditiveOp()) + break; + + const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); + const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); + + if (isa<IntegerLiteral>(RHS)) + Ex = LHS; + else if (isa<IntegerLiteral>(LHS)) + Ex = RHS; + else + break; + } + + return Ex; +} + +// Warn if the user has made the 'size' argument to strlcpy or strlcat +// be the size of the source, instead of the destination. +void Sema::CheckStrlcpycatArguments(const CallExpr *Call, + IdentifierInfo *FnName) { + + // Don't crash if the user has the wrong number of arguments + if (Call->getNumArgs() != 3) + return; + + const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context); + const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context); + const Expr *CompareWithSrc = NULL; + + // Look for 'strlcpy(dst, x, sizeof(x))' + if (const Expr *Ex = getSizeOfExprArg(SizeArg)) + CompareWithSrc = Ex; + else { + // Look for 'strlcpy(dst, x, strlen(x))' + if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) { + if (SizeCall->isBuiltinCall(Context) == Builtin::BIstrlen + && SizeCall->getNumArgs() == 1) + CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context); + } + } + + if (!CompareWithSrc) + return; + + // Determine if the argument to sizeof/strlen is equal to the source + // argument. In principle there's all kinds of things you could do + // here, for instance creating an == expression and evaluating it with + // EvaluateAsBooleanCondition, but this uses a more direct technique: + const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg); + if (!SrcArgDRE) + return; + + const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc); + if (!CompareWithSrcDRE || + SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) + return; + + const Expr *OriginalSizeArg = Call->getArg(2); + Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size) + << OriginalSizeArg->getSourceRange() << FnName; + + // Output a FIXIT hint if the destination is an array (rather than a + // pointer to an array). This could be enhanced to handle some + // pointers if we know the actual size, like if DstArg is 'array+2' + // we could say 'sizeof(array)-2'. + const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts(); + QualType DstArgTy = DstArg->getType(); + + // Only handle constant-sized or VLAs, but not flexible members. + if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(DstArgTy)) { + // Only issue the FIXIT for arrays of size > 1. + if (CAT->getSize().getSExtValue() <= 1) + return; + } else if (!DstArgTy->isVariableArrayType()) { + return; + } + + llvm::SmallString<128> sizeString; + llvm::raw_svector_ostream OS(sizeString); + OS << "sizeof("; + DstArg->printPretty(OS, Context, 0, getPrintingPolicy()); + OS << ")"; + + Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) + << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), + OS.str()); +} + //===--- CHECK: Return Address of Stack Variable --------------------------===// -static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); -static Expr *EvalAddr(Expr* E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); +static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars); +static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -2030,7 +2397,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { Expr *stackE = 0; - llvm::SmallVector<DeclRefExpr *, 8> refVars; + SmallVector<DeclRefExpr *, 8> refVars; // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. @@ -2112,7 +2479,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { +static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) { if (E->isTypeDependent()) return NULL; @@ -2257,7 +2624,7 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { +static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) { do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead @@ -2374,11 +2741,11 @@ do { /// Check for comparisons of floating point operands using != and ==. /// Issue a warning if these are no self-comparisons, as they are not likely /// to do what the programmer intended. -void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { +void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { bool EmitWarning = true; - Expr* LeftExprSansParen = lex->IgnoreParenImpCasts(); - Expr* RightExprSansParen = rex->IgnoreParenImpCasts(); + Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts(); + Expr* RightExprSansParen = RHS->IgnoreParenImpCasts(); // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. @@ -2417,8 +2784,8 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { // Emit the diagnostic. if (EmitWarning) - Diag(loc, diag::warn_floatingpoint_eq) - << lex->getSourceRange() << rex->getSourceRange(); + Diag(Loc, diag::warn_floatingpoint_eq) + << LHS->getSourceRange() << RHS->getSourceRange(); } //===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// @@ -2462,7 +2829,7 @@ struct IntRange { // For enum types, use the known bit width of the enumerators. if (const EnumType *ET = dyn_cast<EnumType>(T)) { EnumDecl *Enum = ET->getDecl(); - if (!Enum->isDefinition()) + if (!Enum->isCompleteDefinition()) return IntRange(C.getIntWidth(QualType(T, 0)), false); unsigned NumPositive = Enum->getNumPositiveBits(); @@ -2490,7 +2857,7 @@ struct IntRange { if (const ComplexType *CT = dyn_cast<ComplexType>(T)) T = CT->getElementType().getTypePtr(); if (const EnumType *ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr(); const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -2767,14 +3134,9 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { IntRange::forValueOfType(C, E->getType()); } - FieldDecl *BitField = E->getBitField(); - if (BitField) { - llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); - unsigned BitWidth = BitWidthAP.getZExtValue(); - - return IntRange(BitWidth, + if (FieldDecl *BitField = E->getBitField()) + return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); - } return IntRange::forValueOfType(C, E->getType()); } @@ -2883,10 +3245,7 @@ void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// -/// \param lex the left-hand expression -/// \param rex the right-hand expression -/// \param OpLoc the location of the joining operator -/// \param BinOpc binary opcode or 0 +/// \param E the binary operator to check for warnings void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -2903,20 +3262,20 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { || E->isValueDependent() || E->isIntegerConstantExpr(S.Context)) return AnalyzeImpConvsInComparison(S, E); - Expr *lex = E->getLHS()->IgnoreParenImpCasts(); - Expr *rex = E->getRHS()->IgnoreParenImpCasts(); + Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); + Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; - if (lex->getType()->hasSignedIntegerRepresentation()) { - assert(!rex->getType()->hasSignedIntegerRepresentation() && + if (LHS->getType()->hasSignedIntegerRepresentation()) { + assert(!RHS->getType()->hasSignedIntegerRepresentation() && "unsigned comparison between two signed integer expressions?"); - signedOperand = lex; - unsignedOperand = rex; - } else if (rex->getType()->hasSignedIntegerRepresentation()) { - signedOperand = rex; - unsignedOperand = lex; + signedOperand = LHS; + unsignedOperand = RHS; + } else if (RHS->getType()->hasSignedIntegerRepresentation()) { + signedOperand = RHS; + unsignedOperand = LHS; } else { CheckTrivialUnsignedComparison(S, E); return AnalyzeImpConvsInComparison(S, E); @@ -2927,8 +3286,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. - AnalyzeImplicitConversions(S, lex, E->getOperatorLoc()); - AnalyzeImplicitConversions(S, rex, E->getOperatorLoc()); + AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); + AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); // If the signed range is non-negative, -Wsign-compare won't fire, // but we should still check for comparisons which are always true @@ -2953,8 +3312,8 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { } S.Diag(E->getOperatorLoc(), diag::warn_mixed_sign_comparison) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange(); } /// Analyzes an attempt to assign the given value to a bitfield. @@ -2979,16 +3338,14 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, Expr *OriginalInit = Init->IgnoreParenImpCasts(); - llvm::APSInt Width(32); Expr::EvalResult InitValue; - if (!Bitfield->getBitWidth()->isIntegerConstantExpr(Width, S.Context) || - !OriginalInit->Evaluate(InitValue, S.Context) || + if (!OriginalInit->Evaluate(InitValue, S.Context) || !InitValue.Val.isInt()) return false; const llvm::APSInt &Value = InitValue.Val.getInt(); unsigned OriginalWidth = Value.getBitWidth(); - unsigned FieldWidth = Width.getZExtValue(); + unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); if (OriginalWidth <= FieldWidth) return false; @@ -3049,34 +3406,22 @@ void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag); } -/// Diagnose an implicit cast from a literal expression. Also attemps to supply -/// fixit hints when the cast wouldn't lose information to simply write the -/// expression with the expected type. +/// Diagnose an implicit cast from a literal expression. Does not warn when the +/// cast wouldn't lose information. void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, SourceLocation CContext) { - // Emit the primary warning first, then try to emit a fixit hint note if - // reasonable. - S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) - << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext); - - const llvm::APFloat &Value = FL->getValue(); - - // Don't attempt to fix PPC double double literals. - if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble) - return; - - // Try to convert this exactly to an integer. + // Try to convert the literal exactly to an integer. If we can, don't warn. bool isExact = false; + const llvm::APFloat &Value = FL->getValue(); llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, &isExact) - != llvm::APFloat::opOK || !isExact) + == llvm::APFloat::opOK && isExact) return; - std::string LiteralValue = IntegerValue.toString(10); - S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer) - << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue); + S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) + << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext); } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -3102,17 +3447,24 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Source == Target) return; if (Target->isDependentType()) return; - // If the conversion context location is invalid don't complain. - // We also don't want to emit a warning if the issue occurs from the - // instantiation of a system macro. The problem is that 'getSpellingLoc()' - // is slow, so we delay this check as long as possible. Once we detect - // we are in that scenario, we just return. + // If the conversion context location is invalid don't complain. We also + // don't want to emit a warning if the issue occurs from the expansion of + // a system macro. The problem is that 'getSpellingLoc()' is slow, so we + // delay this check as long as possible. Once we detect we are in that + // scenario, we just return. if (CC.isInvalid()) return; - // Never diagnose implicit casts to bool. - if (Target->isSpecificBuiltinType(BuiltinType::Bool)) - return; + // Diagnose implicit casts to bool. + if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { + if (isa<StringLiteral>(E)) + // Warn on string literal to bool. Checks for string literals in logical + // expressions, for instances, assert(0 && "error here"), is prevented + // by a check in AnalyzeImplicitConversions(). + return DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_string_literal_to_bool); + return; // Other casts to bool are not checked. + } // Strip vector types. if (isa<VectorType>(Source)) { @@ -3180,6 +3532,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; Expr *InnerE = E->IgnoreParenImpCasts(); + // We also want to warn on, e.g., "int i = -1.234" + if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) + if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) + InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); + if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { DiagnoseFloatingLiteralImpCast(S, FL, T, CC); } else { @@ -3314,29 +3671,16 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { CC)) return; - // ...and -Wsign-compare isn't... - if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional, CC)) - return; - // ...then check whether it would have warned about either of the // candidates for a signedness conversion to the condition type. - if (E->getType() != T) { - Suspicious = false; - CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + if (E->getType() == T) return; + + Suspicious = false; + CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + E->getType(), CC, &Suspicious); + if (!Suspicious) + CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); - if (!Suspicious) - CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), - E->getType(), CC, &Suspicious); - if (!Suspicious) - return; - } - - // If so, emit a diagnostic under -Wsign-compare. - Expr *lex = E->getTrueExpr()->IgnoreParenImpCasts(); - Expr *rex = E->getFalseExpr()->IgnoreParenImpCasts(); - S.Diag(E->getQuestionLoc(), diag::warn_mixed_sign_conditional) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); } /// AnalyzeImplicitConversions - Find and report any interesting @@ -3346,6 +3690,9 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); + if (E->isTypeDependent() || E->isValueDependent()) + return; + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -3389,8 +3736,16 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { // Now just recurse over the expression's children. CC = E->getExprLoc(); - for (Stmt::child_range I = E->children(); I; ++I) - AnalyzeImplicitConversions(S, cast<Expr>(*I), CC); + BinaryOperator *BO = dyn_cast<BinaryOperator>(E); + bool IsLogicalOperator = BO && BO->isLogicalOp(); + for (Stmt::child_range I = E->children(); I; ++I) { + Expr *ChildExpr = cast<Expr>(*I); + if (IsLogicalOperator && + isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts())) + // Ignore checking string literals that are in logical operators. + continue; + AnalyzeImplicitConversions(S, ChildExpr, CC); + } } } // end anonymous namespace @@ -3411,6 +3766,11 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { if (E->isTypeDependent() || E->isValueDependent()) return; + // Check for array bounds violations in cases where the check isn't triggered + // elsewhere for other Expr types (like BinaryOperators), e.g. when an + // ArraySubscriptExpr is on the RHS of a variable initialization. + CheckArrayAccess(E); + // This is not the right CC for (e.g.) a variable initialization. AnalyzeImplicitConversions(*this, E, CC); } @@ -3477,7 +3837,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { // cast; don't do it if we're ignoring -Wcast_align (as is the default). if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align, TRange.getBegin()) - == Diagnostic::Ignored) + == DiagnosticsEngine::Ignored) return; // Ignore dependent types. @@ -3515,63 +3875,164 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -static void CheckArrayAccess_Check(Sema &S, - const clang::ArraySubscriptExpr *E) { - const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts(); +static const Type* getElementType(const Expr *BaseExpr) { + const Type* EltType = BaseExpr->getType().getTypePtr(); + if (EltType->isAnyPointerType()) + return EltType->getPointeeType().getTypePtr(); + else if (EltType->isArrayType()) + return EltType->getBaseElementTypeUnsafe(); + return EltType; +} + +/// \brief Check whether this array fits the idiom of a size-one tail padded +/// array member of a struct. +/// +/// We avoid emitting out-of-bounds access warnings for such arrays as they are +/// commonly used to emulate flexible arrays in C89 code. +static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size, + const NamedDecl *ND) { + if (Size != 1 || !ND) return false; + + const FieldDecl *FD = dyn_cast<FieldDecl>(ND); + if (!FD) return false; + + // Don't consider sizes resulting from macro expansions or template argument + // substitution to form C89 tail-padded arrays. + ConstantArrayTypeLoc TL = + cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc()); + const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr()); + if (!SizeExpr || SizeExpr->getExprLoc().isMacroID()) + return false; + + const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext()); + if (!RD || !RD->isStruct()) + return false; + + // See if this is the last field decl in the record. + const Decl *D = FD; + while ((D = D->getNextDeclInContext())) + if (isa<FieldDecl>(D)) + return false; + return true; +} + +void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, + bool isSubscript, bool AllowOnePastEnd) { + const Type* EffectiveType = getElementType(BaseExpr); + BaseExpr = BaseExpr->IgnoreParenCasts(); + IndexExpr = IndexExpr->IgnoreParenCasts(); + const ConstantArrayType *ArrayTy = - S.Context.getAsConstantArrayType(BaseExpr->getType()); + Context.getAsConstantArrayType(BaseExpr->getType()); if (!ArrayTy) return; - const Expr *IndexExpr = E->getIdx(); if (IndexExpr->isValueDependent()) return; llvm::APSInt index; - if (!IndexExpr->isIntegerConstantExpr(index, S.Context)) + if (!IndexExpr->isIntegerConstantExpr(index, Context)) return; + const NamedDecl *ND = NULL; + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(DRE->getDecl()); + if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) + ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); if (!size.isStrictlyPositive()) return; + + const Type* BaseType = getElementType(BaseExpr); + if (BaseType != EffectiveType) { + // Make sure we're comparing apples to apples when comparing index to size + uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); + uint64_t array_typesize = Context.getTypeSize(BaseType); + // Handle ptrarith_typesize being zero, such as when casting to void* + if (!ptrarith_typesize) ptrarith_typesize = 1; + if (ptrarith_typesize != array_typesize) { + // There's a cast to a different size type involved + uint64_t ratio = array_typesize / ptrarith_typesize; + // TODO: Be smarter about handling cases where array_typesize is not a + // multiple of ptrarith_typesize + if (ptrarith_typesize * ratio == array_typesize) + size *= llvm::APInt(size.getBitWidth(), ratio); + } + } + if (size.getBitWidth() > index.getBitWidth()) index = index.sext(size.getBitWidth()); else if (size.getBitWidth() < index.getBitWidth()) size = size.sext(index.getBitWidth()); - if (index.slt(size)) + // For array subscripting the index must be less than size, but for pointer + // arithmetic also allow the index (offset) to be equal to size since + // computing the next address after the end of the array is legal and + // commonly done e.g. in C++ iterators and range-based for loops. + if (AllowOnePastEnd ? index.sle(size) : index.slt(size)) + return; + + // Also don't warn for arrays of size 1 which are members of some + // structure. These are often used to approximate flexible arrays in C89 + // code. + if (IsTailPaddedMemberArray(*this, size, ND)) return; - S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - S.PDiag(diag::warn_array_index_exceeds_bounds) - << index.toString(10, true) - << size.toString(10, true) - << IndexExpr->getSourceRange()); + unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds; + if (isSubscript) + DiagID = diag::warn_array_index_exceeds_bounds; + + DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, + PDiag(DiagID) << index.toString(10, true) + << size.toString(10, true) + << (unsigned)size.getLimitedValue(~0U) + << IndexExpr->getSourceRange()); } else { - S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - S.PDiag(diag::warn_array_index_precedes_bounds) - << index.toString(10, true) - << IndexExpr->getSourceRange()); + unsigned DiagID = diag::warn_array_index_precedes_bounds; + if (!isSubscript) { + DiagID = diag::warn_ptr_arith_precedes_bounds; + if (index.isNegative()) index = -index; + } + + DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, + PDiag(DiagID) << index.toString(10, true) + << IndexExpr->getSourceRange()); } - const NamedDecl *ND = NULL; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); - if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); if (ND) - S.DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, - S.PDiag(diag::note_array_index_out_of_bounds) - << ND->getDeclName()); + DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, + PDiag(diag::note_array_index_out_of_bounds) + << ND->getDeclName()); } void Sema::CheckArrayAccess(const Expr *expr) { - while (true) { - expr = expr->IgnoreParens(); + int AllowOnePastEnd = 0; + while (expr) { + expr = expr->IgnoreParenImpCasts(); switch (expr->getStmtClass()) { - case Stmt::ArraySubscriptExprClass: - CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr)); + case Stmt::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); + CheckArrayAccess(ASE->getBase(), ASE->getIdx(), true, + AllowOnePastEnd > 0); return; + } + case Stmt::UnaryOperatorClass: { + // Only unwrap the * and & unary operators + const UnaryOperator *UO = cast<UnaryOperator>(expr); + expr = UO->getSubExpr(); + switch (UO->getOpcode()) { + case UO_AddrOf: + AllowOnePastEnd++; + break; + case UO_Deref: + AllowOnePastEnd--; + break; + default: + return; + } + break; + } case Stmt::ConditionalOperatorClass: { const ConditionalOperator *cond = cast<ConditionalOperator>(expr); if (const Expr *lhs = cond->getLHS()) @@ -3625,7 +4086,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) { case CK_BitCast: case CK_LValueBitCast: case CK_LValueToRValue: - case CK_ObjCReclaimReturnedObject: + case CK_ARCReclaimReturnedObject: e = cast->getSubExpr(); continue; @@ -3634,10 +4095,7 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) { const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty(); if (pre->isImplicitProperty()) return false; ObjCPropertyDecl *property = pre->getExplicitProperty(); - if (!(property->getPropertyAttributes() & - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_strong)) && + if (!property->isRetaining() && !(property->getPropertyIvarDecl() && property->getPropertyIvarDecl()->getType() .getObjCLifetime() == Qualifiers::OCL_Strong)) @@ -3758,7 +4216,7 @@ static void diagnoseRetainCycle(Sema &S, Expr *capturer, static bool isSetterLikeSelector(Selector sel) { if (sel.isUnarySelector()) return false; - llvm::StringRef str = sel.getNameForSlot(0); + StringRef str = sel.getNameForSlot(0); while (!str.empty() && str.front() == '_') str = str.substr(1); if (str.startswith("set") || str.startswith("add")) str = str.substr(3); @@ -3810,7 +4268,7 @@ bool Sema::checkUnsafeAssigns(SourceLocation Loc, return false; // strip off any implicit cast added to get to the one arc-specific while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { - if (cast->getCastKind() == CK_ObjCConsumeObject) { + if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_assign) << (LT == Qualifiers::OCL_ExplicitNone) << RHS->getSourceRange(); @@ -3841,7 +4299,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, unsigned Attributes = PD->getPropertyAttributes(); if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) { - if (cast->getCastKind() == CK_ObjCConsumeObject) { + if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_property_assign) << RHS->getSourceRange(); return; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index b555c8a..405d626 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -61,7 +61,7 @@ namespace { /// a single (declaration, index) mapping (the common case) but /// can also store a list of (declaration, index) mappings. class ShadowMapEntry { - typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector; + typedef SmallVector<DeclIndexPair, 4> DeclIndexPairVector; /// \brief Contains either the solitary NamedDecl * or a vector /// of (declaration, index) pairs. @@ -434,7 +434,7 @@ static NestedNameSpecifier * getRequiredQualification(ASTContext &Context, DeclContext *CurContext, DeclContext *TargetContext) { - llvm::SmallVector<DeclContext *, 4> TargetParents; + SmallVector<DeclContext *, 4> TargetParents; for (DeclContext *CommonAncestor = TargetContext; CommonAncestor && !CommonAncestor->Encloses(CurContext); @@ -990,9 +990,6 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { else if (SemaRef.getLangOptions().ObjC1) { if (isa<ObjCIvarDecl>(ND)) return true; - if (isa<ObjCPropertyDecl>(ND) && - SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) - return true; } return ND->getIdentifierNamespace() & IDNS; @@ -1011,9 +1008,6 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const { else if (SemaRef.getLangOptions().ObjC1) { if (isa<ObjCIvarDecl>(ND)) return true; - if (isa<ObjCPropertyDecl>(ND) && - SemaRef.canSynthesizeProvisionalIvar(cast<ObjCPropertyDecl>(ND))) - return true; } return ND->getIdentifierNamespace() & IDNS; @@ -1192,8 +1186,16 @@ namespace { CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) : Results(Results), CurContext(CurContext) { } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { - Results.AddResult(ND, CurContext, Hiding, InBaseClass); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) { + bool Accessible = true; + if (Ctx) { + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) + Accessible = Results.getSema().IsSimplyAccessible(ND, Class); + // FIXME: ObjC access checks are missing. + } + ResultBuilder::Result Result(ND, 0, false, Accessible); + Results.AddResult(Result, CurContext, Hiding, InBaseClass); } }; } @@ -1846,6 +1848,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("operator")); } +/// \brief Retrieve a printing policy suitable for code completion. +static PrintingPolicy getCompletionPrintingPolicy(Sema &S) { + PrintingPolicy Policy = S.getPrintingPolicy(); + Policy.AnonymousTagLocations = false; + Policy.SuppressStrongLifetime = true; + return Policy; +} + /// \brief Retrieve the string representation of the given type as a string /// that has the appropriate lifetime for code completion. /// @@ -1853,15 +1863,12 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, /// common type names. static const char *GetCompletionTypeString(QualType T, ASTContext &Context, + const PrintingPolicy &Policy, CodeCompletionAllocator &Allocator) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - if (!T.getLocalQualifiers()) { // Built-in type names are constant strings. if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) - return BT->getName(Context.getLangOptions()); + return BT->getName(Policy); // Anonymous tag types are constant strings. if (const TagType *TagT = dyn_cast<TagType>(T)) @@ -1885,6 +1892,7 @@ static const char *GetCompletionTypeString(QualType T, /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, + const PrintingPolicy &Policy, NamedDecl *ND, CodeCompletionBuilder &Result) { if (!ND) @@ -1915,7 +1923,7 @@ static void AddResultTypeChunk(ASTContext &Context, if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; - Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, + Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, Policy, Result.getAllocator())); } @@ -1933,13 +1941,32 @@ static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod, } } +static void appendWithSpace(std::string &Result, StringRef Text) { + if (!Result.empty()) + Result += ' '; + Result += Text.str(); +} +static std::string formatObjCParamQualifiers(unsigned ObjCQuals) { + std::string Result; + if (ObjCQuals & Decl::OBJC_TQ_In) + appendWithSpace(Result, "in"); + else if (ObjCQuals & Decl::OBJC_TQ_Inout) + appendWithSpace(Result, "inout"); + else if (ObjCQuals & Decl::OBJC_TQ_Out) + appendWithSpace(Result, "out"); + if (ObjCQuals & Decl::OBJC_TQ_Bycopy) + appendWithSpace(Result, "bycopy"); + else if (ObjCQuals & Decl::OBJC_TQ_Byref) + appendWithSpace(Result, "byref"); + if (ObjCQuals & Decl::OBJC_TQ_Oneway) + appendWithSpace(Result, "oneway"); + return Result; +} + static std::string FormatFunctionParameter(ASTContext &Context, + const PrintingPolicy &Policy, ParmVarDecl *Param, bool SuppressName = false) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { @@ -1953,8 +1980,8 @@ static std::string FormatFunctionParameter(ASTContext &Context, Param->getType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { - Result = "(" + Result; - Result += ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) + + Result + ")"; if (Param->getIdentifier() && !SuppressName) Result += Param->getIdentifier()->getName(); } @@ -2003,8 +2030,8 @@ static std::string FormatFunctionParameter(ASTContext &Context, Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy); if (ObjCMethodParam) { - Result = "(" + Result; - Result += ")"; + Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier()) + + Result + ")"; if (Param->getIdentifier()) Result += Param->getIdentifier()->getName(); } @@ -2030,7 +2057,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { if (I) Result += ", "; - Result += FormatFunctionParameter(Context, Block->getArg(I)); + Result += FormatFunctionParameter(Context, Policy, Block->getArg(I)); if (I == N - 1 && BlockProto->getTypePtr()->isVariadic()) Result += ", ..."; @@ -2046,6 +2073,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(ASTContext &Context, + const PrintingPolicy &Policy, FunctionDecl *Function, CodeCompletionBuilder &Result, unsigned Start = 0, @@ -2062,7 +2090,7 @@ static void AddFunctionParameterChunks(ASTContext &Context, CodeCompletionBuilder Opt(Result.getAllocator()); if (!FirstParameter) Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - AddFunctionParameterChunks(Context, Function, Opt, P, true); + AddFunctionParameterChunks(Context, Policy, Function, Opt, P, true); Result.AddOptionalChunk(Opt.TakeString()); break; } @@ -2075,7 +2103,8 @@ static void AddFunctionParameterChunks(ASTContext &Context, InOptional = false; // Format the placeholder string. - std::string PlaceholderStr = FormatFunctionParameter(Context, Param); + std::string PlaceholderStr = FormatFunctionParameter(Context, Policy, + Param); if (Function->isVariadic() && P == N - 1) PlaceholderStr += ", ..."; @@ -2097,14 +2126,12 @@ static void AddFunctionParameterChunks(ASTContext &Context, /// \brief Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks(ASTContext &Context, + const PrintingPolicy &Policy, TemplateDecl *Template, CodeCompletionBuilder &Result, unsigned MaxParameters = 0, unsigned Start = 0, bool InDefaultArg = false) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - typedef CodeCompletionString::Chunk Chunk; bool FirstParameter = true; @@ -2155,7 +2182,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, CodeCompletionBuilder Opt(Result.getAllocator()); if (!FirstParameter) Opt.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - AddTemplateParameterChunks(Context, Template, Opt, MaxParameters, + AddTemplateParameterChunks(Context, Policy, Template, Opt, MaxParameters, P - Params->begin(), true); Result.AddOptionalChunk(Opt.TakeString()); break; @@ -2180,14 +2207,15 @@ static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, NestedNameSpecifier *Qualifier, bool QualifierIsInformative, - ASTContext &Context) { + ASTContext &Context, + const PrintingPolicy &Policy) { if (!Qualifier) return; std::string PrintedNNS; { llvm::raw_string_ostream OS(PrintedNNS); - Qualifier->print(OS, Context.PrintingPolicy); + Qualifier->print(OS, Policy); } if (QualifierIsInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(PrintedNNS)); @@ -2233,8 +2261,8 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, } /// \brief Add the name of the given declaration -static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND, - CodeCompletionBuilder &Result) { +static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, + NamedDecl *ND, CodeCompletionBuilder &Result) { typedef CodeCompletionString::Chunk Chunk; DeclarationName Name = ND->getDeclName(); @@ -2299,7 +2327,7 @@ static void AddTypedNameChunk(ASTContext &Context, NamedDecl *ND, Result.getAllocator().CopyString(Record->getNameAsString())); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(Context, Template, Result); + AddTemplateParameterChunks(Context, Policy, Template, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } break; @@ -2319,10 +2347,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, typedef CodeCompletionString::Chunk Chunk; CodeCompletionBuilder Result(Allocator, Priority, Availability); - PrintingPolicy Policy(S.Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - + PrintingPolicy Policy = getCompletionPrintingPolicy(S); if (Kind == RK_Pattern) { Pattern->Priority = Priority; Pattern->Availability = Availability; @@ -2346,19 +2371,24 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // Format a function-like macro with placeholders for the arguments. Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); - A != AEnd; ++A) { + bool CombineVariadicArgument = false; + MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); + if (MI->isVariadic() && AEnd - A > 1) { + AEnd -= 2; + CombineVariadicArgument = true; + } + for (MacroInfo::arg_iterator A = MI->arg_begin(); A != AEnd; ++A) { if (A != MI->arg_begin()) Result.AddChunk(Chunk(CodeCompletionString::CK_Comma)); - if (!MI->isVariadic() || A != AEnd - 1) { + if (!MI->isVariadic() || A + 1 != AEnd) { // Non-variadic argument. Result.AddPlaceholderChunk( Result.getAllocator().CopyString((*A)->getName())); continue; } - // Variadic argument; cope with the different between GNU and C99 + // Variadic argument; cope with the difference between GNU and C99 // variadic macros, providing a single placeholder for the rest of the // arguments. if ((*A)->isStr("__VA_ARGS__")) @@ -2369,6 +2399,18 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); } } + + if (CombineVariadicArgument) { + // Handle the next-to-last argument, combining it with the variadic + // argument. + std::string LastArg = (*A)->getName(); + ++A; + if ((*A)->isStr("__VA_ARGS__")) + LastArg += ", ..."; + else + LastArg += ", " + (*A)->getName().str() + "..."; + Result.AddPlaceholderChunk(Result.getAllocator().CopyString(LastArg)); + } Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result.TakeString(); } @@ -2382,15 +2424,21 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, Result.AddTextChunk("::"); return Result.TakeString(); } + + for (Decl::attr_iterator i = ND->attr_begin(); i != ND->attr_end(); ++i) { + if (AnnotateAttr *Attr = dyn_cast_or_null<AnnotateAttr>(*i)) { + Result.AddAnnotation(Result.getAllocator().CopyString(Attr->getAnnotation())); + } + } - AddResultTypeChunk(S.Context, ND, Result); + AddResultTypeChunk(S.Context, Policy, ND, Result); if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); - AddTypedNameChunk(S.Context, ND, Result); + S.Context, Policy); + AddTypedNameChunk(S.Context, Policy, ND, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - AddFunctionParameterChunks(S.Context, Function, Result); + AddFunctionParameterChunks(S.Context, Policy, Function, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); @@ -2398,13 +2446,13 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - AddTypedNameChunk(S.Context, Function, Result); + AddTypedNameChunk(S.Context, Policy, Function, Result); // Figure out which template parameters are deduced (or have default // arguments). - llvm::SmallVector<bool, 16> Deduced; + SmallVector<bool, 16> Deduced; S.MarkDeducedTemplateParameters(FunTmpl, Deduced); unsigned LastDeducibleArgument; for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; @@ -2437,14 +2485,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(S.Context, FunTmpl, Result, + AddTemplateParameterChunks(S.Context, Policy, FunTmpl, Result, LastDeducibleArgument); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } // Add the function parameters Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); - AddFunctionParameterChunks(S.Context, Function, Result); + AddFunctionParameterChunks(S.Context, Policy, Function, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightParen)); AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); @@ -2452,11 +2500,11 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Template->getNameAsString())); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); - AddTemplateParameterChunks(S.Context, Template, Result); + AddTemplateParameterChunks(S.Context, Policy, Template, Result); Result.AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); return Result.TakeString(); } @@ -2490,7 +2538,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (Idx > StartParameter) Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) - Keyword += II->getName().str(); + Keyword += II->getName(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword)); @@ -2505,13 +2553,14 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, std::string Arg; if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) - Arg = FormatFunctionParameter(S.Context, *P, true); + Arg = FormatFunctionParameter(S.Context, Policy, *P, true); else { (*P)->getType().getAsStringInternal(Arg, Policy); - Arg = "(" + Arg + ")"; + Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier()) + + Arg + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) - Arg += II->getName().str(); + Arg += II->getName(); } if (Method->isVariadic() && (P + 1) == PEnd) @@ -2543,7 +2592,7 @@ CodeCompletionResult::CreateCodeCompletionString(Sema &S, if (Qualifier) AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, - S.Context); + S.Context, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); @@ -2556,14 +2605,12 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Sema &S, CodeCompletionAllocator &Allocator) const { typedef CodeCompletionString::Chunk Chunk; - PrintingPolicy Policy(S.Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; + PrintingPolicy Policy = getCompletionPrintingPolicy(S); // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available); FunctionDecl *FDecl = getFunction(); - AddResultTypeChunk(S.Context, FDecl, Result); + AddResultTypeChunk(S.Context, Policy, FDecl, Result); const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(getFunctionType()); if (!FDecl && !Proto) { @@ -2571,7 +2618,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( // highlighted ellipsis. const FunctionType *FT = getFunctionType(); Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(), - S.Context, + S.Context, Policy, Result.getAllocator())); Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); @@ -2624,7 +2671,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( return Result.TakeString(); } -unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName, +unsigned clang::getMacroUsagePriority(StringRef MacroName, const LangOptions &LangOpts, bool PreferredTypeIsPointer) { unsigned Priority = CCP_Macro; @@ -2689,6 +2736,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case Decl::TemplateTemplateParm:return CXCursor_TemplateTemplateParameter; case Decl::FunctionTemplate: return CXCursor_FunctionTemplate; case Decl::ClassTemplate: return CXCursor_ClassTemplate; + case Decl::AccessSpec: return CXCursor_CXXAccessSpecifier; case Decl::ClassTemplatePartialSpecialization: return CXCursor_ClassTemplatePartialSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; @@ -2850,6 +2898,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, return; } + PrintingPolicy Policy = getCompletionPrintingPolicy(S); for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), MEnd = Method->end_overridden_methods(); M != MEnd; ++M) { @@ -2866,7 +2915,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, if (NNS) { std::string Str; llvm::raw_string_ostream OS(Str); - NNS->print(OS, S.Context.PrintingPolicy); + NNS->print(OS, Policy); Builder.AddTextChunk(Results.getAllocator().CopyString(OS.str())); } } else if (!InContext->Equals(Overridden->getDeclContext())) @@ -3059,7 +3108,7 @@ struct Sema::CodeCompleteExpressionData { QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; - llvm::SmallVector<Decl *, 4> IgnoreDecls; + SmallVector<Decl *, 4> IgnoreDecls; }; /// \brief Perform code-completion in an expression context when we know what @@ -3146,6 +3195,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, // Add nullary methods if (AllowNullaryMethods) { ASTContext &Context = Container->getASTContext(); + PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), MEnd = Container->meth_end(); M != MEnd; ++M) { @@ -3153,7 +3203,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) if (AddedProperties.insert(Name)) { CodeCompletionBuilder Builder(Results.getAllocator()); - AddResultTypeChunk(Context, *M, Builder); + AddResultTypeChunk(Context, Policy, *M, Builder); Builder.AddTypedTextChunk( Results.getAllocator().CopyString(Name->getName())); @@ -3224,7 +3274,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, } } -void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, +void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *BaseE, SourceLocation OpLoc, bool IsArrow) { if (!BaseE || !CodeCompleter) @@ -3366,8 +3416,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { break; default: - assert(false && "Unknown type specifier kind in CodeCompleteTag"); - return; + llvm_unreachable("Unknown type specifier kind in CodeCompleteTag"); } ResultBuilder Results(*this, CodeCompleter->getAllocator(), ContextKind); @@ -3408,10 +3457,11 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { void Sema::CodeCompleteCase(Scope *S) { if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; - + SwitchStmt *Switch = getCurFunction()->SwitchStack.back(); - if (!Switch->getCond()->getType()->isEnumeralType()) { - CodeCompleteExpressionData Data(Switch->getCond()->getType()); + QualType type = Switch->getCond()->IgnoreImplicit()->getType(); + if (!type->isEnumeralType()) { + CodeCompleteExpressionData Data(type); Data.IntegralConstantExpression = true; CodeCompleteExpression(S, Data); return; @@ -3419,7 +3469,7 @@ void Sema::CodeCompleteCase(Scope *S) { // Code-complete the cases of a switch statement over an enumeration type // by providing the list of - EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl(); + EnumDecl *Enum = type->castAs<EnumType>()->getDecl(); // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion @@ -3527,8 +3577,8 @@ static bool anyNullArguments(Expr **Args, unsigned NumArgs) { return false; } -void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, - ExprTy **ArgsIn, unsigned NumArgs) { +void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, + Expr **ArgsIn, unsigned NumArgs) { if (!CodeCompleter) return; @@ -3556,7 +3606,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: What if we're calling a member function? typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; - llvm::SmallVector<ResultCandidate, 8> Results; + SmallVector<ResultCandidate, 8> Results; Expr *NakedFn = Fn->IgnoreParenCasts(); if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) @@ -3662,7 +3712,62 @@ void Sema::CodeCompleteReturn(Scope *S) { CodeCompleteExpression(S, ResultType); } -void Sema::CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) { +void Sema::CodeCompleteAfterIf(Scope *S) { + typedef CodeCompletionResult Result; + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + mapCodeCompletionContext(*this, PCC_Statement)); + Results.setFilter(&ResultBuilder::IsOrdinaryName); + Results.EnterNewScope(); + + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); + + AddOrdinaryNameResults(PCC_Statement, S, *this, Results); + + // "else" block + CodeCompletionBuilder Builder(Results.getAllocator()); + Builder.AddTypedTextChunk("else"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Builder.TakeString()); + + // "else if" block + Builder.AddTypedTextChunk("else"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTextChunk("if"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + if (getLangOptions().CPlusPlus) + Builder.AddPlaceholderChunk("condition"); + else + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Builder.TakeString()); + + Results.ExitScope(); + + if (S->getFnParent()) + AddPrettyFunctionResults(PP.getLangOptions(), Results); + + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, Results); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(),Results.size()); +} + +void Sema::CodeCompleteAssignmentRHS(Scope *S, Expr *LHS) { if (LHS) CodeCompleteExpression(S, static_cast<Expr *>(LHS)->getType()); else @@ -3706,7 +3811,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Name, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -3848,10 +3953,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) { void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, CXXCtorInitializer** Initializers, unsigned NumInitializers) { - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; - + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); CXXConstructorDecl *Constructor = static_cast<CXXConstructorDecl *>(ConstructorD); if (!Constructor) @@ -4045,15 +4147,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { Results.AddResult(Result(Builder.TakeString())); } -void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, - bool InInterface) { +void Sema::CodeCompleteObjCAtDirective(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - if (ObjCImpDecl) + if (isa<ObjCImplDecl>(CurContext)) AddObjCImplementationResults(getLangOptions(), Results, false); - else if (InInterface) + else if (CurContext->isObjCContainer()) AddObjCInterfaceResults(getLangOptions(), Results, false); else AddObjCTopLevelResults(Results, false); @@ -4425,14 +4526,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container, } -void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) { +void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { typedef CodeCompletionResult Result; // Try to find the interface where getters might live. - ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(ClassDecl); + ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null<ObjCCategoryDecl>(ClassDecl)) + = dyn_cast_or_null<ObjCCategoryDecl>(CurContext)) Class = Category->getClassInterface(); if (!Class) @@ -4453,15 +4554,15 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl) { Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl) { +void Sema::CodeCompleteObjCPropertySetter(Scope *S) { typedef CodeCompletionResult Result; // Try to find the interface where setters might live. ObjCInterfaceDecl *Class - = dyn_cast_or_null<ObjCInterfaceDecl>(ObjCImplDecl); + = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null<ObjCCategoryDecl>(ObjCImplDecl)) + = dyn_cast_or_null<ObjCCategoryDecl>(CurContext)) Class = Category->getClassInterface(); if (!Class) @@ -4694,7 +4795,8 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, CodeCompletionBuilder Builder(Results.getAllocator()); // Give this completion a return type. - AddResultTypeChunk(S.Context, SuperMethod, Builder); + AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, + Builder); // If we need the "super" keyword, add it (plus some spacing). if (NeedSuperKeyword) { @@ -4955,8 +5057,13 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, unsigned NumSelIdents, bool AtArgumentExpression, bool IsSuper) { + + QualType T = this->GetTypeFromParser(Receiver); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCClassMessage); + CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, + T, SelIdents, NumSelIdents)); + AddClassMessageCompletions(*this, S, Receiver, SelIdents, NumSelIdents, AtArgumentExpression, IsSuper, Results); @@ -4967,7 +5074,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, // our preferred type, improving completion results. if (AtArgumentExpression) { QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, - NumSelIdents); + NumSelIdents); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); else @@ -4976,11 +5083,11 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCClassMessage, + Results.getCompletionContext(), Results.data(), Results.size()); } -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, +void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents, bool AtArgumentExpression, @@ -5019,7 +5126,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // Build the set of methods we can see. ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCInstanceMessage); + CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage, + ReceiverType, SelIdents, NumSelIdents)); + Results.EnterNewScope(); // If this is a send-to-super, try to add the special "super" send @@ -5132,7 +5241,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCInstanceMessage, + Results.getCompletionContext(), Results.data(),Results.size()); } @@ -5196,7 +5305,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, } } - Accumulator += Sel.getNameForSlot(I).str(); + Accumulator += Sel.getNameForSlot(I); Accumulator += ':'; } Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Accumulator)); @@ -5303,12 +5412,11 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, // Record any forward-declared interfaces we find. if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) { - for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end(); - C != CEnd; ++C) - if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && - (!OnlyUnimplemented || !C->getInterface()->getImplementation())) - Results.AddResult(Result(C->getInterface(), 0), CurContext, - 0, false); + ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl(); + if ((!OnlyForwardDeclarations || IDecl->isForwardDecl()) && + (!OnlyUnimplemented || !IDecl->getImplementation())) + Results.AddResult(Result(IDecl, 0), CurContext, + 0, false); } } } @@ -5318,21 +5426,23 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // Add all classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, true, - false, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompletionContext::CCC_ObjCSuperclass); + CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. @@ -5341,14 +5451,16 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, if (CurClass && isa<ObjCInterfaceDecl>(CurClass)) Results.Ignore(CurClass); - // Add all classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, - false, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCSuperclass, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } @@ -5357,14 +5469,16 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - // Add all unimplemented classes. - AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, - true, Results); - + if (CodeCompleter->includeGlobals()) { + // Add all unimplemented classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + true, Results); + } + Results.ExitScope(); - // FIXME: Use cached global completion results. + HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, + CodeCompletionContext::CCC_ObjCInterfaceName, Results.data(),Results.size()); } @@ -5442,14 +5556,14 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { +void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl); + = dyn_cast_or_null<ObjCContainerDecl>(CurContext); if (!Container || (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) @@ -5482,15 +5596,14 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { } void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, - IdentifierInfo *PropertyName, - Decl *ObjCImpDecl) { + IdentifierInfo *PropertyName) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null<ObjCContainerDecl>(ObjCImpDecl); + = dyn_cast_or_null<ObjCContainerDecl>(CurContext); if (!Container || (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) @@ -5523,7 +5636,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, bool SawSimilarlyNamedIvar = false; std::string NameWithPrefix; NameWithPrefix += '_'; - NameWithPrefix += PropertyName->getName().str(); + NameWithPrefix += PropertyName->getName(); std::string NameWithSuffix = PropertyName->getName().str(); NameWithSuffix += '_'; for(; Class; Class = Class->getSuperClass()) { @@ -5557,8 +5670,9 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available); + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context, - Allocator)); + Policy, Allocator)); Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix)); Results.AddResult(Result(Builder.TakeString(), Priority, CXCursor_ObjCIvarDecl)); @@ -5658,9 +5772,10 @@ static void FindImplementableMethods(ASTContext &Context, /// completion string. static void AddObjCPassingTypeChunk(QualType Type, ASTContext &Context, + const PrintingPolicy &Policy, CodeCompletionBuilder &Builder) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); - Builder.AddTextChunk(GetCompletionTypeString(Type, Context, + Builder.AddTextChunk(GetCompletionTypeString(Type, Context, Policy, Builder.getAllocator())); Builder.AddChunk(CodeCompletionString::CK_RightParen); } @@ -5668,7 +5783,7 @@ static void AddObjCPassingTypeChunk(QualType Type, /// \brief Determine whether the given class is or inherits from a class by /// the given name. static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, - llvm::StringRef Name) { + StringRef Name) { if (!Class) return false; @@ -5690,7 +5805,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (!PropName || PropName->getLength() == 0) return; - + PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); + // Builder that will create each code completion. typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); @@ -5703,10 +5819,10 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // on demand. struct KeyHolder { CodeCompletionAllocator &Allocator; - llvm::StringRef Key; + StringRef Key; const char *CopiedKey; - KeyHolder(CodeCompletionAllocator &Allocator, llvm::StringRef Key) + KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key) : Allocator(Allocator), Key(Key), CopiedKey(0) { } operator const char *() { @@ -5733,7 +5849,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, KnownSelectors.insert(Selectors.getNullarySelector(PropName)) && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder); Builder.AddTypedTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, @@ -5748,7 +5864,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() && (Property->getType()->isIntegerType() || Property->getType()->isBooleanType())))) { - std::string SelectorName = (llvm::Twine("is") + UpperKey).str(); + std::string SelectorName = (Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5767,7 +5883,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add the normal mutator. if (IsInstanceMethod && ReturnTypeMatchesVoid && !Property->getSetterMethodDecl()) { - std::string SelectorName = (llvm::Twine("set") + UpperKey).str(); + std::string SelectorName = (Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5779,7 +5895,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName())); Builder.AddTypedTextChunk(":"); - AddObjCPassingTypeChunk(Property->getType(), Context, Builder); + AddObjCPassingTypeChunk(Property->getType(), Context, Policy, Builder); Builder.AddTextChunk(Key); Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); @@ -5818,7 +5934,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(NSUInteger)countOf<key> if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isIntegerType())) { - std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str(); + std::string SelectorName = (Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5841,7 +5957,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName - = (llvm::Twine("objectIn") + UpperKey + "AtIndex").str(); + = (Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5868,7 +5984,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSArray"))) { std::string SelectorName - = (llvm::Twine(Property->getName()) + "AtIndexes").str(); + = (Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -5889,7 +6005,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("get") + UpperKey).str(); + std::string SelectorName = (Twine("get") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("range") @@ -5923,7 +6039,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("in") + UpperKey + "AtIndex").str(); + std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get("insertObject"), &Context.Idents.get(SelectorName) @@ -5955,7 +6071,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("insert") + UpperKey).str(); + std::string SelectorName = (Twine("insert") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("atIndexes") @@ -5987,7 +6103,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); + = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6009,7 +6125,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("remove") + UpperKey + "AtIndexes").str(); + = (Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6031,7 +6147,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); + = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName), &Context.Idents.get("withObject") @@ -6063,8 +6179,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName1 - = (llvm::Twine("replace") + UpperKey + "AtIndexes").str(); - std::string SelectorName2 = (llvm::Twine("with") + UpperKey).str(); + = (Twine("replace") + UpperKey + "AtIndexes").str(); + std::string SelectorName2 = (Twine("with") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName1), &Context.Idents.get(SelectorName2) @@ -6101,7 +6217,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSEnumerator"))) { - std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str(); + std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6119,7 +6235,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (type *)memberOfKey:(type *)object if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { - std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str(); + std::string SelectorName = (Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6136,6 +6252,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk(" *"); } else { Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, + Policy, Builder.getAllocator())); } Builder.AddChunk(CodeCompletionString::CK_RightParen); @@ -6149,7 +6266,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str(); + = (Twine("add") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6171,7 +6288,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("add") + UpperKey).str(); + std::string SelectorName = (Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6193,7 +6310,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName - = (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str(); + = (Twine("remove") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6215,7 +6332,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("remove") + UpperKey).str(); + std::string SelectorName = (Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6236,7 +6353,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str(); + std::string SelectorName = (Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6264,7 +6381,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSSet"))) { std::string SelectorName - = (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str(); + = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6285,7 +6402,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->isIntegerType() || ReturnType->isBooleanType())) { std::string SelectorName - = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); + = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { if (ReturnType.isNull()) { @@ -6303,12 +6420,15 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, void Sema::CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, - ParsedType ReturnTy, - Decl *IDecl) { + ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); - + Decl *IDecl = 0; + if (CurContext->isObjCContainer()) { + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + IDecl = cast<Decl>(OCD); + } // Determine where we should start searching for methods. ObjCContainerDecl *SearchDecl = 0; bool IsInImplementation = false; @@ -6346,9 +6466,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - PrintingPolicy Policy(Context.PrintingPolicy); - Policy.AnonymousTagLocations = false; - Policy.SuppressStrongLifetime = true; + PrintingPolicy Policy = getCompletionPrintingPolicy(*this); for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { @@ -6358,7 +6476,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) - AddObjCPassingTypeChunk(Method->getResultType(), Context, Builder); + AddObjCPassingTypeChunk(Method->getResultType(), Context, Policy, + Builder); Selector Sel = Method->getSelector(); @@ -6382,7 +6501,8 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, break; // Add the parameter type. - AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Builder); + AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Policy, + Builder); if (IdentifierInfo *Id = (*P)->getIdentifier()) Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); @@ -6425,7 +6545,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of // the properties in this class and its categories. if (Context.getLangOptions().ObjC2) { - llvm::SmallVector<ObjCContainerDecl *, 4> Containers; + SmallVector<ObjCContainerDecl *, 4> Containers; Containers.push_back(SearchDecl); VisitedSelectorSet KnownSelectors; @@ -6748,9 +6868,8 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, // FIXME: In the future, we could provide "overload" results, much like we // do for function calls. - CodeCompleteOrdinaryName(S, - S->getFnParent()? Sema::PCC_RecoveryInFunction - : Sema::PCC_Namespace); + // Now just ignore this. There will be another code-completion callback + // for the expanded tokens. } void Sema::CodeCompleteNaturalLanguage() { @@ -6760,7 +6879,7 @@ void Sema::CodeCompleteNaturalLanguage() { } void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, - llvm::SmallVectorImpl<CodeCompletionResult> &Results) { + SmallVectorImpl<CodeCompletionResult> &Results) { ResultBuilder Builder(*this, Allocator, CodeCompletionContext::CCC_Recovery); if (!CodeCompleter || CodeCompleter->includeGlobals()) { CodeCompletionDeclConsumer Consumer(Builder, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index 9d91a48..8d993ef 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -33,11 +33,13 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/ModuleLoader.h" #include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> @@ -69,7 +71,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, - bool WantNontrivialTypeSourceInfo) { + bool WantNontrivialTypeSourceInfo, + IdentifierInfo **CorrectedII) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; if (ObjectTypePtr) { @@ -144,6 +147,51 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: + if (CorrectedII) { + TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), + Kind, S, SS, 0, false, + Sema::CTC_Type); + IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); + TemplateTy Template; + bool MemberOfUnknownSpecialization; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(NewII, NameLoc); + NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); + CXXScopeSpec NewSS, *NewSSPtr = SS; + if (SS && NNS) { + NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); + NewSSPtr = &NewSS; + } + if (Correction && (NNS || NewII != &II) && + // Ignore a correction to a template type as the to-be-corrected + // identifier is not a template (typo correction for template names + // is handled elsewhere). + !(getLangOptions().CPlusPlus && NewSSPtr && + isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(), + false, Template, MemberOfUnknownSpecialization))) { + ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, + isClassName, HasTrailingDot, ObjectTypePtr, + WantNontrivialTypeSourceInfo); + if (Ty) { + std::string CorrectedStr(Correction.getAsString(getLangOptions())); + std::string CorrectedQuotedStr( + Correction.getQuoted(getLangOptions())); + Diag(NameLoc, diag::err_unknown_typename_suggest) + << Result.getLookupName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(SourceRange(NameLoc), + CorrectedStr); + if (NamedDecl *FirstDecl = Correction.getCorrectionDecl()) + Diag(FirstDecl->getLocation(), diag::note_previous_decl) + << CorrectedQuotedStr; + + if (SS && NNS) + SS->MakeTrivial(Context, NNS, SourceRange(NameLoc)); + *CorrectedII = NewII; + return Ty; + } + } + } + // If typo correction failed or was not performed, fall through case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); @@ -269,7 +317,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { /// A<T>::TYPE a; // no typename required because A<T> is a base class. /// }; /// @endcode -bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) { +bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { const Type *Ty = SS->getScopeRep()->getAsType(); @@ -278,8 +326,9 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) { BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType())) return true; + return S->isFunctionPrototypeScope(); } - return false; + return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, @@ -361,7 +410,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; - if (getLangOptions().Microsoft && isMicrosoftMissingTypename(SS)) + if (getLangOptions().MicrosoftMode && isMicrosoftMissingTypename(SS, S)) DiagID = diag::warn_typename_missing; Diag(SS->getRange().getBegin(), DiagID) @@ -419,24 +468,6 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, ExprResult E = LookupInObjCMethod(Result, S, Name, true); if (E.get() || E.isInvalid()) return E; - - // Synthesize ivars lazily. - if (getLangOptions().ObjCDefaultSynthProperties && - getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) { - if (const ObjCPropertyDecl *Property = - canSynthesizeProvisionalIvar(Name)) { - Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name; - Diag(Property->getLocation(), diag::note_property_declare); - } - - // FIXME: This is strange. Shouldn't we just take the ivar returned - // from SynthesizeProvisionalIvar and continue with that? - E = LookupInObjCMethod(Result, S, Name, true); - if (E.get() || E.isInvalid()) - return E; - } - } } bool SecondTry = false; @@ -737,11 +768,6 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC; } - // ObjCMethodDecls are parsed (for some reason) outside the context - // of the class. - if (isa<ObjCMethodDecl>(DC)) - return DC->getLexicalParent()->getLexicalParent(); - return DC->getLexicalParent(); } @@ -804,6 +830,29 @@ void Sema::ExitDeclaratorContext(Scope *S) { // disappear. } + +void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FunctionTemplateDecl *TFD = dyn_cast_or_null<FunctionTemplateDecl>(D)) { + // We assume that the caller has already called + // ActOnReenterTemplateScope + FD = TFD->getTemplatedDecl(); + } + if (!FD) + return; + + PushDeclContext(S, FD); + for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) { + ParmVarDecl *Param = FD->getParamDecl(P); + // If the parameter has an identifier, then add it to the scope + if (Param->getIdentifier()) { + S->AddDecl(Param); + IdResolver.AddDecl(Param); + } + } +} + + /// \brief Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// @@ -843,7 +892,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Out-of-line definitions shouldn't be pushed into scope in C++. // Out-of-line variable and function definitions shouldn't even in C. if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) && - D->isOutOfLine()) + D->isOutOfLine() && + !D->getDeclContext()->getRedeclContext()->Equals( + D->getLexicalDeclContext()->getRedeclContext())) return; // Template instantiations should also not be pushed into scope. @@ -1086,12 +1137,28 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return true; } +static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, + FixItHint &Hint) { + if (isa<LabelDecl>(D)) { + SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(), + tok::colon, Ctx.getSourceManager(), Ctx.getLangOptions(), true); + if (AfterColon.isInvalid()) + return; + Hint = FixItHint::CreateRemoval(CharSourceRange:: + getCharRange(D->getLocStart(), AfterColon)); + } + return; +} + /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { + FixItHint Hint; if (!ShouldDiagnoseUnusedDecl(D)) return; + GenerateFixForUnusedDecl(D, Context, Hint); + unsigned DiagID; if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) DiagID = diag::warn_unused_exception_param; @@ -1100,7 +1167,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { else DiagID = diag::warn_unused_variable; - Diag(D->getLocation(), DiagID) << D->getDeclName(); + Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint; } static void CheckPoppedLabel(LabelDecl *L, Sema &S) { @@ -1246,7 +1313,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, << R; if (Context.BuiltinInfo.getHeaderName(BID) && Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) Diag(Loc, diag::note_please_include_header) << Context.BuiltinInfo.getHeaderName(BID) << Context.BuiltinInfo.GetName(BID); @@ -1263,7 +1330,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // Create Decl objects for each parameter, adding them to the // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { ParmVarDecl *parm = ParmVarDecl::Create(Context, New, SourceLocation(), @@ -1273,7 +1340,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, parm->setScopeInfo(0, i); Params.push_back(parm); } - New->setParams(Params.data(), Params.size()); + New->setParams(Params); } AddKnownFunctionAttributes(New); @@ -1308,29 +1375,24 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { case 2: if (!TypeID->isStr("id")) break; - Context.ObjCIdRedefinitionType = New->getUnderlyingType(); + Context.setObjCIdRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'id', ignoring the current definition. New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); return; case 5: if (!TypeID->isStr("Class")) break; - Context.ObjCClassRedefinitionType = New->getUnderlyingType(); + Context.setObjCClassRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'Class', ignoring the current definition. New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) break; - Context.ObjCSelRedefinitionType = New->getUnderlyingType(); + Context.setObjCSelRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'SEL', ignoring the current definition. New->setTypeForDecl(Context.getObjCSelType().getTypePtr()); return; - case 8: - if (!TypeID->isStr("Protocol")) - break; - Context.setObjCProtoType(New->getUnderlyingType()); - return; } // Fall through - the typedef name was not a builtin type. } @@ -1382,7 +1444,13 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old)) New->setPreviousDeclaration(Typedef); - if (getLangOptions().Microsoft) + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + + if (getLangOptions().MicrosoftExt) return; if (getLangOptions().CPlusPlus) { @@ -1443,8 +1511,14 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { static bool DeclHasAttr(const Decl *D, const Attr *A) { const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A); + const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A); for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) if ((*i)->getKind() == A->getKind()) { + if (Ann) { + if (Ann->getAnnotation() == cast<AnnotateAttr>(*i)->getAnnotation()) + return true; + continue; + } // FIXME: Don't hardcode this check if (OA && isa<OwnershipAttr>(*i)) return OA->getOwnKind() == cast<OwnershipAttr>(*i)->getOwnKind(); @@ -1456,7 +1530,7 @@ DeclHasAttr(const Decl *D, const Attr *A) { /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl, - ASTContext &C) { + ASTContext &C, bool mergeDeprecation = true) { if (!oldDecl->hasAttrs()) return; @@ -1469,6 +1543,13 @@ static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl, for (specific_attr_iterator<InheritableAttr> i = oldDecl->specific_attr_begin<InheritableAttr>(), e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) { + // Ignore deprecated/unavailable/availability attributes if requested. + if (!mergeDeprecation && + (isa<DeprecatedAttr>(*i) || + isa<UnavailableAttr>(*i) || + isa<AvailabilityAttr>(*i))) + continue; + if (!DeclHasAttr(newDecl, *i)) { InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C)); newAttr->setInherited(true); @@ -1535,6 +1616,8 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { return Sema::CXXDestructor; } else if (MD->isCopyAssignmentOperator()) { return Sema::CXXCopyAssignment; + } else if (MD->isMoveAssignmentOperator()) { + return Sema::CXXMoveAssignment; } return Sema::CXXInvalid; @@ -1605,7 +1688,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->getStorageClass() == SC_Static && Old->getStorageClass() != SC_Static && !canRedefineFunction(Old, getLangOptions())) { - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { Diag(New->getLocation(), diag::warn_static_non_static) << New; Diag(Old->getLocation(), PrevDiag); } else { @@ -1669,6 +1752,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { RequiresAdjustment = true; } + // Merge ns_returns_retained attribute. + if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) { + if (NewTypeInfo.getProducesResult()) { + Diag(New->getLocation(), diag::err_returns_retained_mismatch); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; + } + + NewTypeInfo = NewTypeInfo.withProducesResult(true); + RequiresAdjustment = true; + } + if (RequiresAdjustment) { NewType = Context.adjustFunctionType(NewType, NewTypeInfo); New->setType(QualType(NewType, 0)); @@ -1706,9 +1801,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); + // MSVC allows explicit template specialization at class scope: + // 2 CXMethodDecls referring to the same function will be injected. + // We don't want a redeclartion error. + bool IsClassScopeExplicitSpecialization = + OldMethod->isFunctionTemplateSpecialization() && + NewMethod->isFunctionTemplateSpecialization(); bool isFriend = NewMethod->getFriendObjectKind(); - if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) { + if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() && + !IsClassScopeExplicitSpecialization) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. @@ -1790,7 +1892,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); - llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), + SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), OldProto->arg_type_end()); NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), @@ -1799,7 +1901,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->setHasInheritedPrototype(); // Synthesize a parameter for each argument type. - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (FunctionProtoType::arg_type_iterator ParamType = OldProto->arg_type_begin(), ParamEnd = OldProto->arg_type_end(); @@ -1815,7 +1917,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Params.push_back(Param); } - New->setParams(Params.data(), Params.size()); + New->setParams(Params); } return MergeCompatibleFunctionDecls(New, Old); @@ -1836,8 +1938,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Old->hasPrototype() && !New->hasPrototype() && New->getType()->getAs<FunctionProtoType>() && Old->getNumParams() == New->getNumParams()) { - llvm::SmallVector<QualType, 16> ArgTypes; - llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings; + SmallVector<QualType, 16> ArgTypes; + SmallVector<GNUCompatibleParamWarning, 16> Warnings; const FunctionProtoType *OldProto = Old->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *NewProto @@ -1933,6 +2035,12 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { if (Old->isPure()) New->setPure(); + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) @@ -1949,15 +2057,20 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, const ObjCMethodDecl *oldMethod) { + // We don't want to merge unavailable and deprecated attributes + // except from interface to implementation. + bool mergeDeprecation = isa<ObjCImplDecl>(newMethod->getDeclContext()); + // Merge the attributes. - mergeDeclAttributes(newMethod, oldMethod, Context); + mergeDeclAttributes(newMethod, oldMethod, Context, mergeDeprecation); // Merge attributes from the parameters. - for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(), + ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(); + for (ObjCMethodDecl::param_iterator ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, Context); - + CheckObjCMethodOverride(newMethod, oldMethod, true); } @@ -2111,6 +2224,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + // __module_private__ is propagated to later declarations. + if (Old->isModulePrivate()) + New->setModulePrivate(); + else if (New->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, Old); + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still @@ -2193,6 +2312,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Tag = dyn_cast<TagDecl>(TagD); } + if (Tag) + Tag->setFreeStanding(); + if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." @@ -2202,6 +2324,20 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << DS.getSourceRange(); } + if (DS.isConstexprSpecified()) { + // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations + // and definitions of functions and variables. + if (Tag) + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) + << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : + DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + else + Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); + // Don't emit warnings after this error. + return TagD; + } + if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. @@ -2217,7 +2353,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); - if (!Record->getDeclName() && Record->isDefinition() && + if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || Record->getDeclContext()->isRecord()) @@ -2230,7 +2366,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } // Check for Microsoft C extension: anonymous struct. - if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus && + if (getLangOptions().MicrosoftExt && !getLangOptions().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Handle 2 kinds of anonymous struct: @@ -2238,7 +2374,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); - if ((Record && Record->getDeclName() && !Record->isDefinition()) || + if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || (DS.getTypeSpecType() == DeclSpec::TST_typename && DS.getRepAsType().get()->isStructureType())) { Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct) @@ -2305,6 +2441,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; + if (DS.isModulePrivateSpecified() && + Tag && Tag->getDeclContext()->isFunctionOrMethod()) + Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) + << Tag->getTagKind() + << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); + // FIXME: Warn on useless attributes return TagD; @@ -2379,7 +2521,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, AccessSpecifier AS, - llvm::SmallVector<NamedDecl*, 2> &Chaining, + SmallVector<NamedDecl*, 2> &Chaining, bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl @@ -2511,8 +2653,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; // Recover by adding 'static'. - DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), - PrevSpec, DiagID, getLangOptions()); + DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(), + PrevSpec, DiagID); } // C++ [class.union]p3: // A storage class is not allowed in a declaration of an @@ -2524,8 +2666,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Invalid = true; // Recover by removing the storage specifier. - DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), - PrevSpec, DiagID, getLangOptions()); + DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(), + PrevSpec, DiagID); } // Ignore const/volatile/restrict qualifiers. @@ -2582,7 +2724,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { // Visual C++ allows type definition in anonymous struct or union. - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); else { @@ -2606,7 +2748,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DK = diag::err_anonymous_record_with_static; // Visual C++ allows type definition in anonymous struct or union. - if (getLangOptions().Microsoft && + if (getLangOptions().MicrosoftExt && DK == diag::err_anonymous_record_with_type) Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); @@ -2665,6 +2807,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, SC, SCAsWritten); + + // Default-initialize the implicit variable. This initialization will be + // trivial in almost all cases, except if a union member has an in-class + // initializer: + // union { int n = 0; }; + ActOnUninitializedDecl(Anon, /*TypeMayContainAuto=*/false); } Anon->setImplicit(); @@ -2676,7 +2824,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - llvm::SmallVector<NamedDecl*, 2> Chain; + SmallVector<NamedDecl*, 2> Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, @@ -2740,7 +2888,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct into the current // context and into the identifier resolver chain for name lookup // purposes. - llvm::SmallVector<NamedDecl*, 2> Chain; + SmallVector<NamedDecl*, 2> Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext, @@ -2855,26 +3003,51 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { } // switch (Name.getKind()) - assert(false && "Unknown name kind"); - return DeclarationNameInfo(); + llvm_unreachable("Unknown name kind"); +} + +static QualType getCoreType(QualType Ty) { + do { + if (Ty->isPointerType() || Ty->isReferenceType()) + Ty = Ty->getPointeeType(); + else if (Ty->isArrayType()) + Ty = Ty->castAsArrayTypeUnsafe()->getElementType(); + else + return Ty.withoutLocalFastQualifiers(); + } while (true); } -/// isNearlyMatchingFunction - Determine whether the C++ functions -/// Declaration and Definition are "nearly" matching. This heuristic -/// is used to improve diagnostics in the case where an out-of-line -/// function definition doesn't match any declaration within -/// the class or namespace. -static bool isNearlyMatchingFunction(ASTContext &Context, +/// hasSimilarParameters - Determine whether the C++ functions Declaration +/// and Definition have "nearly" matching parameters. This heuristic is +/// used to improve diagnostics in the case where an out-of-line function +/// definition doesn't match any declaration within the class or namespace. +/// Also sets Params to the list of indices to the parameters that differ +/// between the declaration and the definition. If hasSimilarParameters +/// returns true and Params is empty, then all of the parameters match. +static bool hasSimilarParameters(ASTContext &Context, FunctionDecl *Declaration, - FunctionDecl *Definition) { + FunctionDecl *Definition, + llvm::SmallVectorImpl<unsigned> &Params) { + Params.clear(); if (Declaration->param_size() != Definition->param_size()) return false; for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); - if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(), - DefParamTy.getNonReferenceType())) + // The parameter types are identical + if (Context.hasSameType(DefParamTy, DeclParamTy)) + continue; + + QualType DeclParamBaseTy = getCoreType(DeclParamTy); + QualType DefParamBaseTy = getCoreType(DefParamTy); + const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier(); + const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier(); + + if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) || + (DeclTyName && DeclTyName == DefTyName)) + Params.push_back(Idx); + else // The two parameters aren't even close return false; } @@ -2900,7 +3073,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_decltype: - case DeclSpec::TST_underlyingType: { + case DeclSpec::TST_underlyingType: + case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); @@ -2955,8 +3129,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, } Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { - return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), - /*IsFunctionDefinition=*/false); + D.setFunctionDefinition(false); + return HandleDeclarator(S, D, MultiTemplateParamsArg(*this)); } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: @@ -2980,8 +3154,7 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, } Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition) { + MultiTemplateParamsArg TemplateParamLists) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -3180,22 +3353,21 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) Previous.clear(); - bool Redeclaration = false; + bool AddToScope = true; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return 0; } - New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, + New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, move(TemplateParamLists), - IsFunctionDefinition, Redeclaration); + AddToScope); } else { - New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, - move(TemplateParamLists), - Redeclaration); + New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, + move(TemplateParamLists)); } if (New == 0) @@ -3203,7 +3375,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. - if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl())) + if (New->getDeclName() && AddToScope && + !(D.isRedeclaration() && New->isInvalidDecl())) PushOnScopeChains(New, S); return New; @@ -3321,6 +3494,23 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, } } +llvm::DenseMap<DeclarationName, NamedDecl *>::iterator +Sema::findLocallyScopedExternalDecl(DeclarationName Name) { + if (ExternalSource) { + // Load locally-scoped external decls from the external source. + SmallVector<NamedDecl *, 4> Decls; + ExternalSource->ReadLocallyScopedExternalDecls(Decls); + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(Decls[I]->getDeclName()); + if (Pos == LocallyScopedExternalDecls.end()) + LocallyScopedExternalDecls[Decls[I]->getDeclName()] = Decls[I]; + } + } + + return LocallyScopedExternalDecls.find(Name); +} + /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { @@ -3341,8 +3531,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, bool &Redeclaration) { + TypeSourceInfo *TInfo, LookupResult &Previous) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) @@ -3362,6 +3551,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 1; if (D.getName().Kind != UnqualifiedId::IK_Identifier) { Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) @@ -3369,7 +3561,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, return 0; } - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo); if (!NewTD) return 0; // Handle attributes prior to checking for duplicates in MergeVarDecl @@ -3377,7 +3569,10 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckTypedefForVariablyModifiedType(S, NewTD); - return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); + bool Redeclaration = D.isRedeclaration(); + NamedDecl *ND = ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); + D.setRedeclaration(Redeclaration); + return ND; } void @@ -3557,10 +3752,9 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { NamedDecl* Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool &Redeclaration) { + TypeSourceInfo *TInfo, LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists) { + QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); // Check that there are no default arguments (C++ only). @@ -3585,7 +3779,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) - << Name.getAsString(); + << Name; return 0; } @@ -3606,6 +3800,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + if (getLangOptions().OpenCL) { + // Set up the special work-group-local storage class for variables in the + // OpenCL __local address space. + if (R.getAddressSpace() == LangAS::opencl_local) + SC = SC_OpenCLWorkGroupLocal; + } + bool isExplicitSpecialization = false; VarDecl *NewVD; if (!getLangOptions().CPlusPlus) { @@ -3695,20 +3896,67 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.size(), TemplateParamLists.release()); } + + if (D.getDeclSpec().isConstexprSpecified()) { + // FIXME: once we know whether there's an initializer, apply this to + // static data members too. + if (!NewVD->isStaticDataMember() && + !NewVD->isThisDeclarationADefinition()) { + // 'constexpr' is redundant and ill-formed on a non-defining declaration + // of a variable. Suggest replacing it with 'const' if appropriate. + SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc(); + SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc); + // If the declarator is complex, we need to move the keyword to the + // innermost chunk as we switch it from 'constexpr' to 'const'. + int Kind = DeclaratorChunk::Paren; + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + Kind = D.getTypeObject(I).Kind; + if (Kind != DeclaratorChunk::Paren) + break; + } + if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) || + Kind == DeclaratorChunk::Reference) + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateRemoval(ConstexprRange); + else if (Kind == DeclaratorChunk::Paren) + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateReplacement(ConstexprRange, "const"); + else + Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl) + << FixItHint::CreateRemoval(ConstexprRange) + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const "); + } else { + NewVD->setConstexpr(true); + } + } } + // Set the lexical context. If the declarator has a C++ scope specifier, the + // lexical context will be different from the semantic context. + NewVD->setLexicalDeclContext(CurContext); + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); - else if (!Context.Target.isTLSSupported()) + else if (!Context.getTargetInfo().isTLSSupported()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); else NewVD->setThreadSpecified(true); } - // Set the lexical context. If the declarator has a C++ scope specifier, the - // lexical context will be different from the semantic context. - NewVD->setLexicalDeclContext(CurContext); + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (isExplicitSpecialization) + Diag(NewVD->getLocation(), diag::err_module_private_specialization) + << 2 + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else if (NewVD->hasLocalStorage()) + Diag(NewVD->getLocation(), diag::err_module_private_local) + << 0 << NewVD->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else + NewVD->setModulePrivate(); + } // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -3722,7 +3970,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - llvm::StringRef Label = SE->getString(); + StringRef Label = SE->getString(); if (S->getFnParent() != 0) { switch (SC) { case SC_None: @@ -3730,12 +3978,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; break; case SC_Register: - if (!Context.Target.isValidGCCRegisterName(Label)) + if (!Context.getTargetInfo().isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; break; case SC_Static: case SC_Extern: case SC_PrivateExtern: + case SC_OpenCLWorkGroupLocal: break; } } @@ -3754,9 +4003,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); - if (!getLangOptions().CPlusPlus) - CheckVariableDeclaration(NewVD, Previous, Redeclaration); - else { + if (!getLangOptions().CPlusPlus) { + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + } else { // Merge the decl with the existing one if appropriate. if (!Previous.empty()) { if (Previous.isSingleResult() && @@ -3777,7 +4026,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setInvalidDecl(); } - CheckVariableDeclaration(NewVD, Previous, Redeclaration); + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); // This is an explicit specialization of a static data member. Check it. if (isExplicitSpecialization && !NewVD->isInvalidDecl() && @@ -3825,7 +4074,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) == - Diagnostic::Ignored) + DiagnosticsEngine::Ignored) return; // Don't diagnose declarations at file scope. @@ -3899,7 +4148,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) == - Diagnostic::Ignored) + DiagnosticsEngine::Ignored) return; LookupResult R(*this, D->getDeclName(), D->getLocation(), @@ -3918,18 +4167,21 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { /// that have been instantiated from a template. /// /// Sets NewVD->isInvalidDecl() if an error was encountered. -void Sema::CheckVariableDeclaration(VarDecl *NewVD, - LookupResult &Previous, - bool &Redeclaration) { +/// +/// Returns true if the variable declaration is a redeclaration. +bool Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) - return; + return false; QualType T = NewVD->getType(); if (T->isObjCObjectType()) { - Diag(NewVD->getLocation(), diag::err_statically_allocated_object); - return NewVD->setInvalidDecl(); + Diag(NewVD->getLocation(), diag::err_statically_allocated_object) + << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); + T = Context.getObjCObjectPointerType(T); + NewVD->setType(T); } // Emit an error if an address space was applied to decl with local storage. @@ -3938,12 +4190,13 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // ISO/IEC TR 18037 S5.1.2 if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr<BlocksAttr>()) { - if (getLangOptions().getGCMode() != LangOptions::NonGC) + if (getLangOptions().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); else Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); @@ -3977,7 +4230,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, else Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (FixedTy.isNull()) { @@ -3985,7 +4239,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); @@ -3997,7 +4252,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, // an extern "C" variable, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(NewVD->getDeclName()); + = findLocallyScopedExternalDecl(NewVD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } @@ -4005,17 +4260,20 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if (T->isVoidType() && !NewVD->hasExternalStorage()) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (isVM && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } // Function pointers and references cannot have qualified function type, only @@ -4032,13 +4290,15 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) { Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer) << PtrOrRef; - return NewVD->setInvalidDecl(); + NewVD->setInvalidDecl(); + return false; } if (!Previous.empty()) { - Redeclaration = true; MergeVarDecl(NewVD, Previous); + return true; } + return false; } /// \brief Data used with FindOverriddenMethod @@ -4108,233 +4368,397 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { return AddedAny; } -static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { - LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(), +namespace { + // Struct for holding all of the extra arguments needed by + // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator. + struct ActOnFDArgs { + Scope *S; + Declarator &D; + MultiTemplateParamsArg TemplateParamLists; + bool AddToScope; + }; +} + +/// \brief Generate diagnostics for an invalid function redeclaration. +/// +/// This routine handles generating the diagnostic messages for an invalid +/// function redeclaration, including finding possible similar declarations +/// or performing typo correction if there are no previous declarations with +/// the same name. +/// +/// Returns a NamedDecl iff typo correction was performed and substituting in +/// the new declaration name does not cause new errors. +static NamedDecl* DiagnoseInvalidRedeclaration( + Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD, + ActOnFDArgs &ExtraArgs) { + NamedDecl *Result = NULL; + DeclarationName Name = NewFD->getDeclName(); + DeclContext *NewDC = NewFD->getDeclContext(); + LookupResult Prev(SemaRef, Name, NewFD->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - S.LookupQualifiedName(Prev, NewFD->getDeclContext()); + llvm::SmallVector<unsigned, 1> MismatchedParams; + llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches; + TypoCorrection Correction; + bool isFriendDecl = (SemaRef.getLangOptions().CPlusPlus && + ExtraArgs.D.getDeclSpec().isFriendSpecified()); + unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend + : diag::err_member_def_does_not_match; + + NewFD->setInvalidDecl(); + SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - if (isa<FunctionDecl>(*Func) && - isNearlyMatchingFunction(S.Context, cast<FunctionDecl>(*Func), NewFD)) - S.Diag((*Func)->getLocation(), diag::note_member_def_close_match); + if (!Prev.empty()) { + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func); + if (FD && + hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { + // Add 1 to the index so that 0 can mean the mismatch didn't + // involve a parameter + unsigned ParamNum = + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; + NearMatches.push_back(std::make_pair(FD, ParamNum)); + } + } + // If the qualified name lookup yielded nothing, try typo correction + } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(), + Prev.getLookupKind(), 0, 0, NewDC)) && + Correction.getCorrection() != Name) { + // Trap errors. + Sema::SFINAETrap Trap(SemaRef); + + // Set up everything for the call to ActOnFunctionDeclarator + ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), + ExtraArgs.D.getIdentifierLoc()); + Previous.clear(); + Previous.setLookupName(Correction.getCorrection()); + for (TypoCorrection::decl_iterator CDecl = Correction.begin(), + CDeclEnd = Correction.end(); + CDecl != CDeclEnd; ++CDecl) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl); + if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD, + MismatchedParams)) { + Previous.addDecl(FD); + } + } + bool wasRedeclaration = ExtraArgs.D.isRedeclaration(); + // TODO: Refactor ActOnFunctionDeclarator so that we can call only the + // pieces need to verify the typo-corrected C++ declaraction and hopefully + // eliminate the need for the parameter pack ExtraArgs. + Result = SemaRef.ActOnFunctionDeclarator(ExtraArgs.S, ExtraArgs.D, + NewFD->getDeclContext(), + NewFD->getTypeSourceInfo(), + Previous, + ExtraArgs.TemplateParamLists, + ExtraArgs.AddToScope); + if (Trap.hasErrorOccurred()) { + // Pretend the typo correction never occurred + ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(), + ExtraArgs.D.getIdentifierLoc()); + ExtraArgs.D.setRedeclaration(wasRedeclaration); + Previous.clear(); + Previous.setLookupName(Name); + Result = NULL; + } else { + for (LookupResult::iterator Func = Previous.begin(), + FuncEnd = Previous.end(); + Func != FuncEnd; ++Func) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func)) + NearMatches.push_back(std::make_pair(FD, 0)); + } + } + if (NearMatches.empty()) { + // Ignore the correction if it didn't yield any close FunctionDecl matches + Correction = TypoCorrection(); + } else { + DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest + : diag::err_member_def_does_not_match_suggest; + } } -} -NamedDecl* -Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition, bool &Redeclaration) { - assert(R.getTypePtr()->isFunctionType()); + if (Correction) + SemaRef.Diag(NewFD->getLocation(), DiagMsg) + << Name << NewDC << Correction.getQuoted(SemaRef.getLangOptions()) + << FixItHint::CreateReplacement( + NewFD->getLocation(), + Correction.getAsString(SemaRef.getLangOptions())); + else + SemaRef.Diag(NewFD->getLocation(), DiagMsg) + << Name << NewDC << NewFD->getLocation(); + + bool NewFDisConst = false; + if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) + NewFDisConst = NewMD->getTypeQualifiers() & Qualifiers::Const; + + for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator + NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); + NearMatch != NearMatchEnd; ++NearMatch) { + FunctionDecl *FD = NearMatch->first; + bool FDisConst = false; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + FDisConst = MD->getTypeQualifiers() & Qualifiers::Const; + + if (unsigned Idx = NearMatch->second) { + ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); + SemaRef.Diag(FDParam->getTypeSpecStartLoc(), + diag::note_member_def_close_param_match) + << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType(); + } else if (Correction) { + SemaRef.Diag(FD->getLocation(), diag::note_previous_decl) + << Correction.getQuoted(SemaRef.getLangOptions()); + } else if (FDisConst != NewFDisConst) { + SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match) + << NewFDisConst << FD->getSourceRange().getEnd(); + } else + SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_match); + } + return Result; +} - // TODO: consider using NameInfo for diagnostic. - DeclarationNameInfo NameInfo = GetNameForDeclarator(D); - DeclarationName Name = NameInfo.getName(); - FunctionDecl::StorageClass SC = SC_None; +static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); + default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_typecheck_sclass_func); + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_typecheck_sclass_func); D.setInvalidType(); break; - case DeclSpec::SCS_unspecified: SC = SC_None; break; - case DeclSpec::SCS_extern: SC = SC_Extern; break; + case DeclSpec::SCS_unspecified: break; + case DeclSpec::SCS_extern: return SC_Extern; case DeclSpec::SCS_static: { - if (CurContext->getRedeclContext()->isFunctionOrMethod()) { + if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). - Diag(D.getDeclSpec().getStorageClassSpecLoc(), - diag::err_static_block_func); - SC = SC_None; + SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_block_func); + break; } else - SC = SC_Static; - break; + return SC_Static; } - case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern; break; + case DeclSpec::SCS_private_extern: return SC_PrivateExtern; } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + // No explicit storage class has already been returned + return SC_None; +} - // Do not allow returning a objc interface by-value. - if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { - Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs<FunctionType>()->getResultType(); - D.setInvalidType(); - } - - FunctionDecl *NewFD; +static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, + DeclContext *DC, QualType &R, + TypeSourceInfo *TInfo, + FunctionDecl::StorageClass SC, + bool &IsVirtualOkay) { + DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + + FunctionDecl *NewFD = 0; bool isInline = D.getDeclSpec().isInlineSpecified(); - bool isFriend = false; DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); FunctionDecl::StorageClass SCAsWritten = StorageClassSpecToFunctionDeclStorageClass(SCSpec); - FunctionTemplateDecl *FunctionTemplate = 0; - bool isExplicitSpecialization = false; - bool isFunctionTemplateSpecialization = false; - if (!getLangOptions().CPlusPlus) { + if (!SemaRef.getLangOptions().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other reference // to a type name (which eventually refers to a function type). bool HasPrototype = - (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || - (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); + + NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); if (D.isInvalidType()) NewFD->setInvalidDecl(); - + // Set the lexical context. - NewFD->setLexicalDeclContext(CurContext); - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - /*ExplicitInstantiationOrSpecialization=*/false); - } else { - isFriend = D.getDeclSpec().isFriendSpecified(); - bool isVirtual = D.getDeclSpec().isVirtualSpecified(); - bool isExplicit = D.getDeclSpec().isExplicitSpecified(); - bool isVirtualOkay = false; - - // Check that the return type is not an abstract class type. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!DC->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), - R->getAs<FunctionType>()->getResultType(), - diag::err_abstract_type_in_decl, - AbstractReturnType)) - D.setInvalidType(); + NewFD->setLexicalDeclContext(SemaRef.CurContext); - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { - // This is a C++ constructor declaration. - assert(DC->isRecord() && - "Constructors can only be declared in a member context"); - - R = CheckConstructorDeclarator(D, R, SC); - - // Create the new declaration - CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( - Context, - cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isExplicit, isInline, - /*isImplicitlyDeclared=*/false); - - NewFD = NewCD; - } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { - // This is a C++ destructor declaration. - if (DC->isRecord()) { - R = CheckDestructorDeclarator(D, R, SC); - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - - CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record, - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, - /*isImplicitlyDeclared=*/false); - NewFD = NewDD; - isVirtualOkay = true; - - // If the class is complete, then we now create the implicit exception - // specification. If the class is incomplete or dependent, we can't do - // it yet. - if (getLangOptions().CPlusPlus0x && !Record->isDependentType() && - Record->getDefinition() && !Record->isBeingDefined() && - R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { - AdjustDestructorExceptionSpec(Record, NewDD); - } + return NewFD; + } - } else { - Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); - - // Create a FunctionDecl to satisfy the function definition parsing - // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - D.getIdentifierLoc(), Name, R, TInfo, - SC, SCAsWritten, isInline, - /*hasPrototype=*/true); - D.setInvalidType(); - } - } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { - if (!DC->isRecord()) { - Diag(D.getIdentifierLoc(), - diag::err_conv_function_not_member); - return 0; - } + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); + + // Check that the return type is not an abstract class type. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + SemaRef.RequireNonAbstractType(D.getIdentifierLoc(), + R->getAs<FunctionType>()->getResultType(), + diag::err_abstract_type_in_decl, + SemaRef.AbstractReturnType)) + D.setInvalidType(); - CheckConversionDeclarator(D, R, SC); - NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = SemaRef.CheckConstructorDeclarator(D, R, SC); + return CXXConstructorDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isExplicit, isInline, + /*isImplicitlyDeclared=*/false, + isConstexpr); + + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = SemaRef.CheckDestructorDeclarator(D, R, SC); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( + SemaRef.Context, Record, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isInline, isExplicit, - SourceLocation()); - - isVirtualOkay = true; - } else if (DC->isRecord()) { - // If the of the function is the same as the name of the record, then this - // must be an invalid constructor that has a return type. - // (The parser checks for a return type and makes the declarator a - // constructor if it has no return type). - // must have an invalid constructor that has a return type - if (Name.getAsIdentifierInfo() && - Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ - Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) - << SourceRange(D.getIdentifierLoc()); - return 0; + NameInfo, R, TInfo, isInline, + /*isImplicitlyDeclared=*/false); + + // If the class is complete, then we now create the implicit exception + // specification. If the class is incomplete or dependent, we can't do + // it yet. + if (SemaRef.getLangOptions().CPlusPlus0x && !Record->isDependentType() && + Record->getDefinition() && !Record->isBeingDefined() && + R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) { + SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); } - bool isStatic = SC == SC_Static; - - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - isStatic = true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - isStatic = true; - - // This is a C++ method declaration. - CXXMethodDecl *NewMD = CXXMethodDecl::Create( - Context, cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); - NewFD = NewMD; - - isVirtualOkay = !isStatic; + IsVirtualOkay = true; + return NewDD; + } else { - // Determine whether the function was written with a - // prototype. This true when: - // - we're in C++ (where every function has a prototype), - NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), - NameInfo, R, TInfo, SC, SCAsWritten, isInline, - true/*HasPrototype*/); + SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); + D.setInvalidType(); + + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), Name, R, TInfo, + SC, SCAsWritten, isInline, + /*hasPrototype=*/true, isConstexpr); + } + + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { + if (!DC->isRecord()) { + SemaRef.Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } + + SemaRef.CheckConversionDeclarator(D, R, SC); + IsVirtualOkay = true; + return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, + R, TInfo, isInline, isExplicit, + isConstexpr, SourceLocation()); + + } else if (DC->isRecord()) { + // If the name of the function is the same as the name of the record, + // then this must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a + // constructor if it has no return type). + if (Name.getAsIdentifierInfo() && + Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + return 0; + } + + bool isStatic = SC == SC_Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + + IsVirtualOkay = !isStatic; + + // This is a C++ method declaration. + return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, + TInfo, isStatic, SCAsWritten, isInline, + isConstexpr, SourceLocation()); + + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + return FunctionDecl::Create(SemaRef.Context, DC, + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, SC, SCAsWritten, isInline, + true/*HasPrototype*/, isConstexpr); + } +} + +NamedDecl* +Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, + TypeSourceInfo *TInfo, LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope) { + QualType R = TInfo->getType(); + + assert(R.getTypePtr()->isFunctionType()); + + // TODO: consider using NameInfo for diagnostic. + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + // Do not allow returning a objc interface by-value. + if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { + Diag(D.getIdentifierLoc(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 + << R->getAs<FunctionType>()->getResultType() + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); + + QualType T = R->getAs<FunctionType>()->getResultType(); + T = Context.getObjCObjectPointerType(T); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + R = Context.getFunctionType(T, FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); } + else if (isa<FunctionNoProtoType>(R)) + R = Context.getFunctionNoProtoType(T); + } + + bool isFriend = false; + FunctionTemplateDecl *FunctionTemplate = 0; + bool isExplicitSpecialization = false; + bool isFunctionTemplateSpecialization = false; + bool isDependentClassScopeExplicitSpecialization = false; + bool isVirtualOkay = false; - if (isFriend && !isInline && IsFunctionDefinition) { + FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, + isVirtualOkay); + if (!NewFD) return 0; + + if (getLangOptions().CPlusPlus) { + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); + isFriend = D.getDeclSpec().isFriendSpecified(); + if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. @@ -4377,6 +4801,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(NewFD->getLocation(), diag::err_destructor_template); return 0; } + + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (DC->isDependentContext()) { + ContextRAII SavedContext(*this, DC); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), @@ -4437,7 +4871,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } - + // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a @@ -4474,7 +4908,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } } - + // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; see 12.3.1 @@ -4495,10 +4929,32 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // Filter out previous declarations that don't match the scope. - FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), - isExplicitSpecialization || - isFunctionTemplateSpecialization); + if (isConstexpr) { + // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors + // are implicitly inline. + NewFD->setImplicitlyInline(); + + // C++0x [dcl.constexpr]p3: functions declared constexpr are required to + // be either constructors or to return a literal type. Therefore, + // destructors cannot be declared constexpr. + if (isa<CXXDestructorDecl>(NewFD)) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor); + } + + // If __module_private__ was specified, mark the function accordingly. + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (isFunctionTemplateSpecialization) { + SourceLocation ModulePrivateLoc + = D.getDeclSpec().getModulePrivateSpecLoc(); + Diag(ModulePrivateLoc, diag::err_module_private_specialization) + << 0 + << FixItHint::CreateRemoval(ModulePrivateLoc); + } else { + NewFD->setModulePrivate(); + if (FunctionTemplate) + FunctionTemplate->setModulePrivate(); + } + } if (isFriend) { // For now, claim that the objects have no previous declaration. @@ -4510,7 +4966,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setAccess(AS_public); } - if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && IsFunctionDefinition) { + if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && + D.isFunctionDefinition()) { // A method is implicitly inline if it's defined in its class // definition. NewFD->setImplicitlyInline(); @@ -4530,6 +4987,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } } + + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), + isExplicitSpecialization || + isFunctionTemplateSpecialization); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { @@ -4541,7 +5003,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; if (D.isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); @@ -4603,8 +5065,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && "Should not need args for typedef of non-prototype fn"); } + // Finally, we know we have the right number of parameters, install them. - NewFD->setParams(Params.data(), Params.size()); + NewFD->setParams(Params); // Process the non-inheritable attributes on this declaration. ProcessDeclAttributes(S, NewFD, D, @@ -4613,9 +5076,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!getLangOptions().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplicitSpecialization=false; - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration); - assert((NewFD->isInvalidDecl() || !Redeclaration || + if (!NewFD->isInvalidDecl()) { + if (NewFD->getResultType()->isVariablyModifiedType()) { + // Functions returning a variably modified type violate C99 6.7.5.2p2 + // because all functions have linkage. + Diag(NewFD->getLocation(), diag::err_vm_func_decl); + NewFD->setInvalidDecl(); + } else { + if (NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isExplicitSpecialization)); + } + } + assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); } else { @@ -4676,8 +5150,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // that either the specialized function type or the specialized // template is dependent, and therefore matching will fail. In // this case, don't check the specialization yet. + bool InstantiationDependent = false; if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + (NewFD->getType()->isDependentType() || DC->isDependentContext() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs.getArgumentArray(), TemplateArgs.size(), + InstantiationDependent))) { assert(HasExplicitTemplateArgs && "friend function specialization without template args"); if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, @@ -4686,10 +5164,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } else if (isFunctionTemplateSpecialization) { if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { - Diag(NewFD->getLocation(), diag::err_function_specialization_in_class) + isDependentClassScopeExplicitSpecialization = true; + Diag(NewFD->getLocation(), getLangOptions().MicrosoftExt ? + diag::ext_function_specialization_in_class : + diag::err_function_specialization_in_class) << NewFD->getDeclName(); - NewFD->setInvalidDecl(); - return 0; } else if (CheckFunctionTemplateSpecialization(NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : 0), Previous)) @@ -4719,18 +5198,33 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Perform semantic checking on the function declaration. - CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, - Redeclaration); + if (!isDependentClassScopeExplicitSpecialization) { + if (NewFD->isInvalidDecl()) { + // If this is a class member, mark the class invalid immediately. + // This avoids some consistency errors later. + if (CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(NewFD)) + methodDecl->getParent()->setInvalidDecl(); + } else { + if (NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isExplicitSpecialization)); + } + } - assert((NewFD->isInvalidDecl() || !Redeclaration || + assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() && + !CheckConstexprFunctionDecl(NewFD, CCK_Declaration)) + NewFD->setInvalidDecl(); + NamedDecl *PrincipalDecl = (FunctionTemplate ? cast<NamedDecl>(FunctionTemplate) : NewFD); - if (isFriend && Redeclaration) { + if (isFriend && D.isRedeclaration()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDeclaration()->getAccess(); @@ -4752,7 +5246,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), PrevTemplate? PrevTemplate->getTemplateParameters() : 0, D.getDeclSpec().isFriendSpecified() - ? (IsFunctionDefinition + ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition : TPC_FriendFunctionTemplate) : (D.getCXXScopeSpec().isSet() && @@ -4764,7 +5258,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewFD->isInvalidDecl()) { // Ignore all the rest of this. - } else if (!Redeclaration) { + } else if (!D.isRedeclaration()) { + struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, + AddToScope }; // Fake up an access specifier if it's supposed to be a class member. if (isa<CXXRecordDecl>(NewFD->getDeclContext())) NewFD->setAccess(AS_public); @@ -4784,38 +5280,43 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, (TemplateParamLists.size() || D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { - // ignore these - } else { - // The user tried to provide an out-of-line definition for a - // function that is a member of a class or namespace, but there - // was no such member function declared (C++ [class.mfct]p2, - // C++ [namespace.memdef]p2). For example: - // - // class X { - // void f() const; - // }; - // - // void X::f() { } // ill-formed - // - // Complain about this problem, and attempt to suggest close - // matches (e.g., those that differ only in cv-qualifiers and - // whether the parameter types are references). - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << Name << DC << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - - DiagnoseInvalidRedeclaration(*this, NewFD); - } + // ignore these + } else { + // The user tried to provide an out-of-line definition for a + // function that is a member of a class or namespace, but there + // was no such member function declared (C++ [class.mfct]p2, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // matches (e.g., those that differ only in cv-qualifiers and + // whether the parameter types are references). + + if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous, + NewFD, + ExtraArgs)) { + AddToScope = ExtraArgs.AddToScope; + return Result; + } + } // Unqualified local friend declarations are required to resolve // to something. - } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { - Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend); - NewFD->setInvalidDecl(); - DiagnoseInvalidRedeclaration(*this, NewFD); + } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) { + if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous, + NewFD, + ExtraArgs)) { + AddToScope = ExtraArgs.AddToScope; + return Result; } + } - } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && + } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { // An out-of-line member function declaration must also be a @@ -4839,7 +5340,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // attributes declared post-definition are currently ignored // FIXME: This should happen during attribute merging - if (Redeclaration && Previous.isSingleResult()) { + if (D.isRedeclaration() && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl()); if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) { @@ -4871,6 +5372,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewFD); + // If there's a #pragma clang arc_cf_code_audited in scope, consider + // marking the function. + AddCFAuditedAttribute(NewFD); + // If this is a locally-scoped extern C function, update the // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC() @@ -4901,6 +5406,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Context.setcudaConfigureCallDecl(NewFD); } } + + // Here we have an function template explicit specialization at class scope. + // The actually specialization will be postponed to template instatiation + // time via the ClassScopeFunctionSpecializationDecl node. + if (isDependentClassScopeExplicitSpecialization) { + ClassScopeFunctionSpecializationDecl *NewSpec = + ClassScopeFunctionSpecializationDecl::Create( + Context, CurContext, SourceLocation(), + cast<CXXMethodDecl>(NewFD)); + CurContext->addDecl(NewSpec); + AddToScope = false; + } return NewFD; } @@ -4919,29 +5436,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, +/// +/// Returns true if the function declaration is a redeclaration. +bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, - bool IsExplicitSpecialization, - bool &Redeclaration) { - // If NewFD is already known erroneous, don't do any of this checking. - if (NewFD->isInvalidDecl()) { - // If this is a class member, mark the class invalid immediately. - // This avoids some consistency errors later. - if (isa<CXXMethodDecl>(NewFD)) - cast<CXXMethodDecl>(NewFD)->getParent()->setInvalidDecl(); - - return; - } - - if (NewFD->getResultType()->isVariablyModifiedType()) { - // Functions returning a variably modified type violate C99 6.7.5.2p2 - // because all functions have linkage. - Diag(NewFD->getLocation(), diag::err_vm_func_decl); - return NewFD->setInvalidDecl(); - } - - if (NewFD->isMain()) - CheckMain(NewFD); + bool IsExplicitSpecialization) { + assert(!NewFD->getResultType()->isVariablyModifiedType() + && "Variably modified return types are not handled here"); // Check for a previous declaration of this name. if (Previous.empty() && NewFD->isExternC()) { @@ -4949,11 +5450,13 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // an extern "C" function, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(NewFD->getDeclName()); + = findLocallyScopedExternalDecl(NewFD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) Previous.addDecl(Pos->second); } + bool Redeclaration = false; + // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. if (!Previous.empty()) { @@ -5003,8 +5506,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. - if (MergeFunctionDecl(NewFD, OldDecl)) - return NewFD->setInvalidDecl(); + if (MergeFunctionDecl(NewFD, OldDecl)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } Previous.clear(); Previous.addDecl(OldDecl); @@ -5028,6 +5533,10 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); } + + if (OldTemplateDecl->isModulePrivate()) + NewTemplateDecl->setModulePrivate(); + } else { if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions NewFD->setAccess(OldDecl->getAccess()); @@ -5054,7 +5563,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Context.getCanonicalType(ClassType)); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); - return NewFD->setInvalidDecl(); + NewFD->setInvalidDecl(); + return Redeclaration; } } } else if (CXXConversionDecl *Conversion @@ -5086,13 +5596,17 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && - CheckOverloadedOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); + CheckOverloadedOperatorDeclaration(NewFD)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } // Extra checking for C++0x literal operators (C++0x [over.literal]). if (NewFD->getLiteralIdentifier() && - CheckLiteralOperatorDeclaration(NewFD)) - return NewFD->setInvalidDecl(); + CheckLiteralOperatorDeclaration(NewFD)) { + NewFD->setInvalidDecl(); + return Redeclaration; + } // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done @@ -5112,24 +5626,22 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + return Redeclaration; } -void Sema::CheckMain(FunctionDecl* FD) { +void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // C++ [basic.start.main]p3: A program that declares main to be inline // or static is ill-formed. // C99 6.7.4p4: In a hosted environment, the inline function specifier // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. - bool isInline = FD->isInlineSpecified(); - bool isStatic = FD->getStorageClass() == SC_Static; - if (isInline || isStatic) { - unsigned diagID = diag::warn_unusual_main_decl; - if (isInline || getLangOptions().CPlusPlus) - diagID = diag::err_unusual_main_decl; - - int which = isStatic + (isInline << 1) - 1; - Diag(FD->getLocation(), diagID) << which; - } + if (FD->getStorageClass() == SC_Static) + Diag(DS.getStorageClassSpecLoc(), getLangOptions().CPlusPlus + ? diag::err_static_main : diag::warn_static_main) + << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); + if (FD->isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_main) + << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); @@ -5152,7 +5664,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // Darwin passes an undocumented fourth argument of type char**. If // other platforms start sprouting these, the logic below will start // getting shifty. - if (nparams == 4 && Context.Target.getTriple().isOSDarwin()) + if (nparams == 4 && Context.getTargetInfo().getTriple().isOSDarwin()) HasExtraParameters = false; if (HasExtraParameters) { @@ -5231,41 +5743,89 @@ namespace { : public EvaluatedExprVisitor<SelfReferenceChecker> { Sema &S; Decl *OrigDecl; + bool isRecordType; + bool isPODType; public: typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), - S(S), OrigDecl(OrigDecl) { } + S(S), OrigDecl(OrigDecl) { + isPODType = false; + isRecordType = false; + if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) { + isPODType = VD->getType().isPODType(S.Context); + isRecordType = VD->getType()->isRecordType(); + } + } void VisitExpr(Expr *E) { if (isa<ObjCMessageExpr>(*E)) return; + if (isRecordType) { + Expr *expr = E; + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + ValueDecl *VD = ME->getMemberDecl(); + if (isa<EnumConstantDecl>(VD) || isa<VarDecl>(VD)) return; + expr = ME->getBase(); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(expr)) { + HandleDeclRefExpr(DRE); + return; + } + } Inherited::VisitExpr(E); } + void VisitMemberExpr(MemberExpr *E) { + if (E->getType()->canDecayToPointerType()) return; + if (isa<FieldDecl>(E->getMemberDecl())) + if (DeclRefExpr *DRE + = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) { + HandleDeclRefExpr(DRE); + return; + } + Inherited::VisitMemberExpr(E); + } + void VisitImplicitCastExpr(ImplicitCastExpr *E) { - CheckForSelfReference(E); + if ((!isRecordType &&E->getCastKind() == CK_LValueToRValue) || + (isRecordType && E->getCastKind() == CK_NoOp)) { + Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr)) + SubExpr = ME->getBase()->IgnoreParenImpCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + HandleDeclRefExpr(DRE); + return; + } + } Inherited::VisitImplicitCastExpr(E); } - void CheckForSelfReference(ImplicitCastExpr *E) { - if (E->getCastKind() != CK_LValueToRValue) return; - Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr); - if (!DRE) return; - Decl* ReferenceDecl = DRE->getDecl(); + void VisitUnaryOperator(UnaryOperator *E) { + // For POD record types, addresses of its own members are well-defined. + if (isRecordType && isPODType) return; + Inherited::VisitUnaryOperator(E); + } + + void HandleDeclRefExpr(DeclRefExpr *DRE) { + Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, Sema::NotForRedeclaration); - S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr, + S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() + << Result.getLookupName() << OrigDecl->getLocation() - << SubExpr->getSourceRange()); + << DRE->getSourceRange()); } }; } +/// CheckSelfReference - Warns if OrigDecl is used in expression E. +void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { + SelfReferenceChecker(*this, OrigDecl).VisitExpr(E); +} + /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -5281,10 +5841,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Variables declared within a function/method body are handled // by a dataflow analysis. if (!vd->hasLocalStorage() && !vd->isStaticLocal()) - SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + CheckSelfReference(RealDecl, Init); } else { - SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + CheckSelfReference(RealDecl, Init); } if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { @@ -5392,6 +5952,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } } + // OpenCL 1.1 6.5.2: "Variables allocated in the __local address space inside + // a kernel function cannot be initialized." + if (VDecl->getStorageClass() == SC_OpenCLWorkGroupLocal) { + Diag(VDecl->getLocation(), diag::err_local_cant_init); + VDecl->setInvalidDecl(); + return; + } + // Capture the variable that is being initialized and the style of // initialization. InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); @@ -5456,11 +6024,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // A member-declarator can contain a constant-initializer only // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. + // + // C++0x [class.static.data]p3: + // If a non-volatile const static data member is of integral or + // enumeration type, its declaration in the class definition can + // specify a brace-or-equal-initializer in which every initalizer-clause + // that is an assignment-expression is a constant expression. A static + // data member of literal type can be declared in the class definition + // with the constexpr specifier; if so, its declaration shall specify a + // brace-or-equal-initializer in which every initializer-clause that is + // an assignment-expression is a constant expression. QualType T = VDecl->getType(); // Do nothing on dependent types. if (T->isDependentType()) { + // Allow any 'static constexpr' members, whether or not they are of literal + // type. We separately check that the initializer is a constant expression, + // which implicitly requires the member to be of literal type. + } else if (VDecl->isConstexpr()) { + // Require constness. } else if (!T.isConstQualified()) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) @@ -5471,7 +6054,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } else if (T->isIntegralOrEnumerationType()) { // Check whether the expression is a constant expression. SourceLocation Loc; - if (Init->isValueDependent()) + if (getLangOptions().CPlusPlus0x && T.isVolatileQualified()) + // In C++0x, a non-constexpr const static data member with an + // in-class initializer cannot be volatile. + Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile); + else if (Init->isValueDependent()) ; // Nothing to check. else if (Init->isIntegerConstantExpr(Context, &Loc)) ; // Ok, it's an ICE! @@ -5488,31 +6075,33 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); } - // We allow floating-point constants as an extension in C++03, and - // C++0x has far more complicated rules that we don't really - // implement fully. - } else { - bool Allowed = false; - if (getLangOptions().CPlusPlus0x) { - Allowed = T->isLiteralType(); - } else if (T->isFloatingType()) { // also permits complex, which is ok - Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) - << T << Init->getSourceRange(); - Allowed = true; - } - - if (!Allowed) { - Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) - << T << Init->getSourceRange(); - VDecl->setInvalidDecl(); - - // TODO: there are probably expressions that pass here that shouldn't. - } else if (!Init->isValueDependent() && - !Init->isConstantInitializer(Context, false)) { + // We allow floating-point constants as an extension. + } else if (T->isFloatingType()) { // also permits complex, which is ok + Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) + << T << Init->getSourceRange(); + if (getLangOptions().CPlusPlus0x) + Diag(VDecl->getLocation(), + diag::note_in_class_initializer_float_type_constexpr) + << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); + + if (!Init->isValueDependent() && + !Init->isConstantInitializer(Context, false)) { Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } + + // Suggest adding 'constexpr' in C++0x for literal types. + } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) + << T << Init->getSourceRange() + << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); + VDecl->setConstexpr(true); + + } else { + Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) + << T << Init->getSourceRange(); + VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { if (VDecl->getStorageClassAsWritten() == SC_Extern && @@ -5547,33 +6136,23 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setType(DclT); Init->setType(DclT); } - - - // If this variable is a local declaration with record type, make sure it - // doesn't have a flexible member initialization. We only support this as a - // global/static definition. - if (VDecl->hasLocalStorage()) - if (const RecordType *RT = VDecl->getType()->getAs<RecordType>()) - if (RT->getDecl()->hasFlexibleArrayMember()) { - // Check whether the initializer tries to initialize the flexible - // array member itself to anything other than an empty initializer list. - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - unsigned Index = std::distance(RT->getDecl()->field_begin(), - RT->getDecl()->field_end()) - 1; - if (Index < ILE->getNumInits() && - !(isa<InitListExpr>(ILE->getInit(Index)) && - cast<InitListExpr>(ILE->getInit(Index))->getNumInits() == 0)) { - Diag(VDecl->getLocation(), diag::err_nonstatic_flexible_variable); - VDecl->setInvalidDecl(); - } - } - } // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); if (!VDecl->isInvalidDecl()) checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + + if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() && + !VDecl->getType()->isDependentType() && + !Init->isTypeDependent() && !Init->isValueDependent() && + !Init->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) { + // FIXME: Improve this diagnostic to explain why the initializer is not + // a constant expression. + Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init) + << VDecl << Init->getSourceRange(); + } Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. @@ -5639,6 +6218,21 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } + // C++0x [dcl.constexpr]p9: An object or reference declared constexpr must + // have an initializer. + // C++0x [class.static.data]p3: A static data member can be declared with + // the constexpr specifier; if so, its declaration shall specify + // a brace-or-equal-initializer. + // + // A static data member's definition may inherit an initializer from an + // in-class declaration. + if (Var->isConstexpr() && !Var->getAnyInitializer()) { + Diag(Var->getLocation(), diag::err_constexpr_var_requires_init) + << Var->getDeclName(); + Var->setInvalidDecl(); + return; + } + switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) @@ -5829,10 +6423,11 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) { case SC_Register: Error = 4; break; + case SC_OpenCLWorkGroupLocal: + llvm_unreachable("Unexpected storage class"); } - // FIXME: constexpr isn't allowed here. - //if (DS.isConstexprSpecified()) - // Error = 5; + if (VD->isConstexpr()) + Error = 5; if (Error != -1) { Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) << VD->getDeclName() << Error; @@ -5916,7 +6511,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decl **Group, unsigned NumDecls) { - llvm::SmallVector<Decl*, 8> Decls; + SmallVector<Decl*, 8> Decls; if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); @@ -5996,6 +6591,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 0; DiagnoseFunctionSpecifiers(D); @@ -6074,6 +6672,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ProcessDeclAttributes(S, New, D); + if (D.getDeclSpec().isModulePrivateSpecified()) + Diag(New->getLocation(), diag::err_module_private_local) + << 1 << New->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + if (New->hasAttr<BlocksAttr>()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } @@ -6157,8 +6761,9 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // - otherwise, it's an error if (T->isArrayType()) { if (!T.isConstQualified()) { - Diag(NameLoc, diag::err_arc_array_param_no_ownership) - << TSInfo->getTypeLoc().getSourceRange(); + DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType( + NameLoc, diag::err_arc_array_param_no_ownership, T, false)); } lifetime = Qualifiers::OCL_ExplicitNone; } else { @@ -6185,8 +6790,10 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // passed by reference. if (T->isObjCObjectType()) { Diag(NameLoc, - diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; - New->setInvalidDecl(); + diag::err_object_cannot_be_passed_returned_by_value) << 1 << T + << FixItHint::CreateInsertion(NameLoc, "*"); + T = Context.getObjCObjectPointerType(T); + New->setType(T); } // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage @@ -6241,9 +6848,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); + D.setFunctionDefinition(true); Decl *DP = HandleDeclarator(ParentScope, D, - MultiTemplateParamsArg(*this), - /*IsFunctionDefinition=*/true); + MultiTemplateParamsArg(*this)); return ActOnStartOfFunctionDef(FnBodyScope, DP); } @@ -6379,7 +6986,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // dllimport attribute cannot be directly applied to definition. // Microsoft accepts dllimport for functions defined within class scope. if (!DA->isInherited() && - !(LangOpts.Microsoft && FD->getLexicalDeclContext()->isRecord())) { + !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) << "dllimport"; @@ -6389,7 +6996,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Visual C++ appears to not think this is an issue, so only issue // a warning when Microsoft extensions are disabled. - if (!LangOpts.Microsoft) { + if (!LangOpts.MicrosoftExt) { // If a symbol previously declared dllimport is later defined, the // attribute is ignored in subsequent references, and a warning is // emitted. @@ -6417,7 +7024,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { /// FIXME: Employ a smarter algorithm that accounts for multiple return /// statements and the lifetimes of the NRVO candidates. We should be able to /// find a maximal set of NRVO variables. -static void ComputeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { +void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { ReturnStmt **Returns = Scope->Returns.data(); const VarDecl *NRVOCandidate = 0; @@ -6466,7 +7073,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // MSVC permits the use of pure specifier (=0) on function definition, // defined at class scope, warn about this non standard construct. - if (getLangOptions().Microsoft && FD->isPure()) + if (getLangOptions().MicrosoftExt && FD->isPure()) Diag(FD->getLocation(), diag::warn_pure_function_definition); if (!FD->isInvalidDecl()) { @@ -6478,7 +7085,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - ComputeNRVO(Body, getCurFunction()); + computeNRVO(Body, getCurFunction()); } assert(FD == getCurFunctionDecl() && "Function parsing confused"); @@ -6491,11 +7098,27 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), MD->getResultType(), MD); + + if (Body) + computeNRVO(Body, getCurFunction()); + } + if (ObjCShouldCallSuperDealloc) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); + ObjCShouldCallSuperDealloc = false; + } + if (ObjCShouldCallSuperFinalize) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize); + ObjCShouldCallSuperFinalize = false; } } else { return 0; } + assert(!ObjCShouldCallSuperDealloc && "This should only be set for " + "ObjC methods, which should have been handled in the block above."); + assert(!ObjCShouldCallSuperFinalize && "This should only be set for " + "ObjC methods, which should have been handled in the block above."); + // Verify and clean out per-function state. if (Body) { // C++ constructors that have function-try-blocks can't have return @@ -6504,8 +7127,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, 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 gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !dcl->isInvalidDecl() && !hasAnyUnrecoverableErrorsInThisFunction()) @@ -6532,6 +7154,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, ActivePolicy = &WP; } + if (FD && FD->isConstexpr() && !FD->isInvalidDecl() && + !CheckConstexprFunctionBody(FD, Body)) + FD->setInvalidDecl(); + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); } @@ -6552,6 +7178,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, return dcl; } + +/// When we finish delayed parsing of an attribute, we must attach it to the +/// relevant Decl. +void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, + ParsedAttributes &Attrs) { + ProcessDeclAttributeList(S, D, Attrs.getList()); +} + + /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, @@ -6561,7 +7196,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos - = LocallyScopedExternalDecls.find(&II); + = findLocallyScopedExternalDecl(&II); if (Pos != LocallyScopedExternalDecls.end()) { Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; Diag(Pos->second->getLocation(), diag::note_previous_declaration); @@ -6651,6 +7286,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } + if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && + !FD->getAttr<ReturnsTwiceAttr>()) + FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>()) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>()) @@ -6712,6 +7350,16 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } + if (D.getDeclSpec().isModulePrivateSpecified()) { + if (CurContext->isFunctionOrMethod()) + Diag(NewTD->getLocation(), diag::err_module_private_local) + << 2 << NewTD->getDeclName() + << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) + << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); + else + NewTD->setModulePrivate(); + } + // C++ [dcl.typedef]p8: // If the typedef declaration defines an unnamed class (or // enum), the first typedef-name declared by the declaration @@ -6853,6 +7501,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, bool ScopedEnum, bool ScopedEnumUsesClassTag, @@ -6892,6 +7541,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, TemplateParams, AS, + ModulePrivateLoc, TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); return Result.get(); @@ -6934,7 +7584,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); - } else if (getLangOptions().Microsoft) + } else if (getLangOptions().MicrosoftExt) // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); } @@ -7233,7 +7883,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || - getLangOptions().Microsoft)) || TUK == TUK_Friend) + getLangOptions().MicrosoftExt)) || TUK == TUK_Friend) return PrevTagDecl; // Diagnose attempts to redefine a tag. @@ -7385,7 +8035,7 @@ CreateNewDecl: Diag(Def->getLocation(), diag::note_previous_definition); } else { unsigned DiagID = diag::ext_forward_ref_enum; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::ext_ms_forward_ref_enum; else if (getLangOptions().CPlusPlus) DiagID = diag::err_forward_ref_enum; @@ -7454,6 +8104,23 @@ CreateNewDecl: AddMsStructLayoutForRecord(RD); } + if (PrevDecl && PrevDecl->isModulePrivate()) + New->setModulePrivate(); + else if (ModulePrivateLoc.isValid()) { + if (isExplicitSpecialization) + Diag(New->getLocation(), diag::err_module_private_specialization) + << 2 + << FixItHint::CreateRemoval(ModulePrivateLoc); + else if (PrevDecl && !PrevDecl->isModulePrivate()) + diagnoseModulePrivateRedeclaration(New, PrevDecl, ModulePrivateLoc); + // __module_private__ does not apply to local classes. However, we only + // diagnose this as an error when the declaration specifiers are + // freestanding. Here, we just ignore the __module_private__. + // foobar + else if (!SearchDC->isFunctionOrMethod()) + New->setModulePrivate(); + } + // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) @@ -7480,7 +8147,7 @@ CreateNewDecl: // the tag name visible. if (TUK == TUK_Friend) New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() || - getLangOptions().Microsoft); + getLangOptions().MicrosoftExt); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) @@ -7530,6 +8197,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { PushDeclContext(S, Tag); } +Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { + assert(isa<ObjCContainerDecl>(IDecl) && + "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); + DeclContext *OCD = cast<DeclContext>(IDecl); + assert(getContainingDC(OCD) == CurContext && + "The next DeclContext should be lexically contained in the current one."); + CurContext = OCD; + return IDecl; +} + void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation FinalLoc, SourceLocation LBraceLoc) { @@ -7581,6 +8258,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, Consumer.HandleTagDeclDefinition(Tag); } +void Sema::ActOnObjCContainerFinishDefinition() { + // Exit this scope of this interface definition. + PopDeclContext(); +} + +void Sema::ActOnObjCTemporaryExitContainerContext() { + OriginalLexicalContext = CurContext; + ActOnObjCContainerFinishDefinition(); +} + +void Sema::ActOnObjCReenterContainerContext() { + ActOnObjCContainerStartDefinition(cast<Decl>(OriginalLexicalContext)); + OriginalLexicalContext = 0; +} + void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD); @@ -7669,7 +8361,7 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { + Declarator &D, Expr *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD), DeclStart, D, static_cast<Expr*>(BitfieldWidth), /*HasInit=*/false, AS_public); @@ -7703,6 +8395,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (D.getDeclSpec().isConstexprSpecified()) + Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + << 2; // Check to see if this name was declared as a member previously LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); @@ -7735,6 +8430,9 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); + if (D.getDeclSpec().isModulePrivateSpecified()) + NewFD->setModulePrivate(); + if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -7968,8 +8666,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } } - assert(0 && "found no user-declared constructors"); - return; + llvm_unreachable("found no user-declared constructors"); } break; @@ -8054,7 +8751,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXDestructor: hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break; default: - assert(0 && "unexpected special member"); return; + llvm_unreachable("unexpected special member"); } // Check for nontrivial bases (and recurse). @@ -8102,7 +8799,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { } } - assert(0 && "found no explanation for non-trivial member"); + llvm_unreachable("found no explanation for non-trivial member"); } /// TranslateIvarVisibility - Translate visibility from a token ID to an @@ -8110,7 +8807,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { static ObjCIvarDecl::AccessControl TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { switch (ivarVisibility) { - default: assert(0 && "Unknown visitibility kind"); + default: llvm_unreachable("Unknown visitibility kind"); case tok::objc_private: return ObjCIvarDecl::Private; case tok::objc_public: return ObjCIvarDecl::Public; case tok::objc_protected: return ObjCIvarDecl::Protected; @@ -8122,8 +8819,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { /// in order to create an IvarDecl object for it. Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, - Decl *IntfDecl, - Declarator &D, ExprTy *BitfieldWidth, + Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind Visibility) { IdentifierInfo *II = D.getIdentifier(); @@ -8165,7 +8861,7 @@ Decl *Sema::ActOnIvar(Scope *S, Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. - ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(IntfDecl); + ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(CurContext); ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { @@ -8213,6 +8909,9 @@ Decl *Sema::ActOnIvar(Scope *S, if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID)) NewID->setInvalidDecl(); + if (D.getDeclSpec().isModulePrivateSpecified()) + NewID->setModulePrivate(); + if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. @@ -8227,23 +8926,19 @@ Decl *Sema::ActOnIvar(Scope *S, /// class and class extensions. For every class @interface and class /// extension @interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. -void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, - llvm::SmallVectorImpl<Decl *> &AllIvarDecls) { +void Sema::ActOnLastBitfield(SourceLocation DeclLoc, + SmallVectorImpl<Decl *> &AllIvarDecls) { if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty()) return; Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl); - if (!Ivar->isBitField()) - return; - uint64_t BitFieldSize = - Ivar->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); - if (BitFieldSize == 0) + if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) return; - ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl); + ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext); if (!ID) { - if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CurContext)) { if (!CD->IsClassExtension()) return; } @@ -8252,13 +8947,14 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, return; } // All conditions are met. Add a new bitfield to the tail end of ivars. - llvm::APInt Zero(Context.getTypeSize(Context.CharTy), 0); - Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc); + llvm::APInt Zero(Context.getTypeSize(Context.IntTy), 0); + Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc); - Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl), + Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext), DeclLoc, DeclLoc, 0, Context.CharTy, - Context.CreateTypeSourceInfo(Context.CharTy), + Context.getTrivialTypeSourceInfo(Context.CharTy, + DeclLoc), ObjCIvarDecl::Private, BW, true); AllIvarDecls.push_back(Ivar); @@ -8266,27 +8962,25 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, void Sema::ActOnFields(Scope* S, SourceLocation RecLoc, Decl *EnclosingDecl, - Decl **Fields, unsigned NumFields, + llvm::ArrayRef<Decl *> Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { assert(EnclosingDecl && "missing record or interface decl"); // If the decl this is being inserted into is invalid, then it may be a // redeclaration or some other bogus case. Don't try to add fields to it. - if (EnclosingDecl->isInvalidDecl()) { - // FIXME: Deallocate fields? + if (EnclosingDecl->isInvalidDecl()) return; - } - // Verify that all the fields are okay. unsigned NumNamedMembers = 0; - llvm::SmallVector<FieldDecl*, 32> RecFields; + SmallVector<FieldDecl*, 32> RecFields; RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); bool ARCErrReported = false; - for (unsigned i = 0; i != NumFields; ++i) { - FieldDecl *FD = cast<FieldDecl>(Fields[i]); + for (llvm::ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end(); + i != end; ++i) { + FieldDecl *FD = cast<FieldDecl>(*i); // Get the type for the field. const Type *FDTy = FD->getType().getTypePtr(); @@ -8321,25 +9015,26 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } else if (FDTy->isIncompleteArrayType() && Record && - ((i == NumFields - 1 && !Record->isUnion()) || - ((getLangOptions().Microsoft || getLangOptions().CPlusPlus) && - (i == NumFields - 1 || Record->isUnion())))) { + ((i + 1 == Fields.end() && !Record->isUnion()) || + ((getLangOptions().MicrosoftExt || + getLangOptions().CPlusPlus) && + (i + 1 == Fields.end() || Record->isUnion())))) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. // It will accept flexible array in union and also // as the sole element of a struct/class. - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_ms) << FD->getDeclName(); - else if (NumFields == 1) + else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms) << FD->getDeclName() << Record->getTagKind(); } else if (getLangOptions().CPlusPlus) { if (Record->isUnion()) Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu) << FD->getDeclName(); - else if (NumFields == 1) + else if (Fields.size() == 1) Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu) << FD->getDeclName() << Record->getTagKind(); } else if (NumNamedMembers < 1) { @@ -8376,7 +9071,7 @@ void Sema::ActOnFields(Scope* S, // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. - if (i != NumFields-1) + if (i + 1 != Fields.end()) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { @@ -8393,10 +9088,10 @@ void Sema::ActOnFields(Scope* S, Record->setHasObjectMember(true); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object - Diag(FD->getLocation(), diag::err_statically_allocated_object); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; + Diag(FD->getLocation(), diag::err_statically_allocated_object) + << FixItHint::CreateInsertion(FD->getLocation(), "*"); + QualType T = Context.getObjCObjectPointerType(FD->getType()); + FD->setType(T); } else if (!getLangOptions().CPlusPlus) { if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) { @@ -8421,7 +9116,7 @@ void Sema::ActOnFields(Scope* S, } } else if (getLangOptions().ObjC1 && - getLangOptions().getGCMode() != LangOptions::NonGC && + getLangOptions().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { if (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong()) @@ -8650,7 +9345,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, SourceLocation IdLoc, IdentifierInfo *Id, Expr *Val) { - unsigned IntWidth = Context.Target.getIntWidth(); + unsigned IntWidth = Context.getTargetInfo().getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; @@ -8691,7 +9386,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // ... if the initializing value of an enumerator cannot be // represented by the underlying type, the program is ill-formed. if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } else @@ -8806,7 +9501,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attr, - SourceLocation EqualLoc, ExprTy *val) { + SourceLocation EqualLoc, Expr *val) { EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null<EnumConstantDecl>(lastEnumConst); @@ -8894,9 +9589,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. - unsigned IntWidth = Context.Target.getIntWidth(); - unsigned CharWidth = Context.Target.getCharWidth(); - unsigned ShortWidth = Context.Target.getShortWidth(); + unsigned IntWidth = Context.getTargetInfo().getIntWidth(); + unsigned CharWidth = Context.getTargetInfo().getCharWidth(); + unsigned ShortWidth = Context.getTargetInfo().getShortWidth(); // Verify that all the values are okay, compute the size of the values, and // reverse the list. @@ -8969,12 +9664,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.IntTy; BestWidth = IntWidth; } else { - BestWidth = Context.Target.getLongWidth(); + BestWidth = Context.getTargetInfo().getLongWidth(); if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; } else { - BestWidth = Context.Target.getLongLongWidth(); + BestWidth = Context.getTargetInfo().getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) Diag(Enum->getLocation(), diag::warn_enum_too_large); @@ -9001,13 +9696,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) ? Context.UnsignedIntTy : Context.IntTy; } else if (NumPositiveBits <= - (BestWidth = Context.Target.getLongWidth())) { + (BestWidth = Context.getTargetInfo().getLongWidth())) { BestType = Context.UnsignedLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOptions().CPlusPlus) ? Context.UnsignedLongTy : Context.LongTy; } else { - BestWidth = Context.Target.getLongLongWidth(); + BestWidth = Context.getTargetInfo().getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; @@ -9094,6 +9789,33 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, return New; } +DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc, + IdentifierInfo &ModuleName, + SourceLocation ModuleNameLoc) { + ModuleKey Module = PP.getModuleLoader().loadModule(ImportLoc, + ModuleName, ModuleNameLoc); + if (!Module) + return true; + + // FIXME: Actually create a declaration to describe the module import. + (void)Module; + return DeclResult((Decl *)0); +} + +void +Sema::diagnoseModulePrivateRedeclaration(NamedDecl *New, NamedDecl *Old, + SourceLocation ModulePrivateKeyword) { + assert(!Old->isModulePrivate() && "Old is module-private!"); + + Diag(New->getLocation(), diag::err_module_private_follows_public) + << New->getDeclName() << SourceRange(ModulePrivateKeyword); + Diag(Old->getLocation(), diag::note_previous_declaration) + << Old->getDeclName(); + + // Drop the __module_private__ from the new declaration, since it's invalid. + New->setModulePrivate(false); +} + void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { @@ -9126,3 +9848,16 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, std::pair<IdentifierInfo*,WeakInfo>(AliasName, W)); } } + +Decl *Sema::getObjCDeclContext() const { + return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); +} + +AvailabilityResult Sema::getCurContextAvailability() const { + const Decl *D = cast<Decl>(getCurLexicalContext()); + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + D = CatD->getClassInterface(); + + return D->getAvailability(); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 61b7b3e..69baf79 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -15,19 +15,21 @@ #include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace sema; /// These constants match the enumerated choices of /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. -enum { +enum AttributeDeclKind { ExpectedFunction, ExpectedUnion, ExpectedVariableOrFunction, @@ -42,7 +44,8 @@ enum { ExpectedClassMember, ExpectedVariable, ExpectedMethod, - ExpectedVariableFunctionOrLabel + ExpectedVariableFunctionOrLabel, + ExpectedFieldOrGlobalVar }; //===----------------------------------------------------------------------===// @@ -194,6 +197,8 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } +/// \brief Check if the attribute has exactly as many args as Num. May +/// output an error. static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, unsigned int Num) { if (Attr.getNumArgs() != Num) { @@ -204,6 +209,140 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, return true; } + +/// \brief Check if the attribute has at least as many args as Num. May +/// output an error. +static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, + unsigned int Num) { + if (Attr.getNumArgs() < Num) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num; + return false; + } + + return true; +} + +/// +/// \brief Check if passed in Decl is a field or potentially shared global var +/// \return true if the Decl is a field or potentially shared global variable +/// +static bool mayBeSharedVariable(const Decl *D) { + if (isa<FieldDecl>(D)) + return true; + if (const VarDecl *vd = dyn_cast<VarDecl>(D)) + return (vd->hasGlobalStorage() && !(vd->isThreadSpecified())); + + return false; +} + +/// \brief Check if the passed-in expression is of type int or bool. +static bool isIntOrBool(Expr *Exp) { + QualType QT = Exp->getType(); + return QT->isBooleanType() || QT->isIntegerType(); +} + +/// +/// \brief Check if passed in Decl is a pointer type. +/// Note that this function may produce an error message. +/// \return true if the Decl is a pointer type; false otherwise +/// +static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) { + if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) { + QualType QT = vd->getType(); + if (QT->isAnyPointerType()) + return true; + S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type) + << Attr.getName()->getName() << QT; + } else { + S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl) + << Attr.getName(); + } + return false; +} + +/// \brief Checks that the passed in QualType either is of RecordType or points +/// to RecordType. Returns the relevant RecordType, null if it does not exit. +static const RecordType *getRecordType(QualType QT) { + if (const RecordType *RT = QT->getAs<RecordType>()) + return RT; + + // Now check if we point to record type. + if (const PointerType *PT = QT->getAs<PointerType>()) + return PT->getPointeeType()->getAs<RecordType>(); + + return 0; +} + +/// \brief Thread Safety Analysis: Checks that the passed in RecordType +/// resolves to a lockable object. May flag an error. +static bool checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr, + const RecordType *RT) { + // Flag error if could not get record type for this argument. + if (!RT) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class) + << Attr.getName(); + return false; + } + // Flag error if the type is not lockable. + if (!RT->getDecl()->getAttr<LockableAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable) + << Attr.getName(); + return false; + } + return true; +} + +/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting +/// from Sidx, resolve to a lockable object. May flag an error. +/// \param Sidx The attribute argument index to start checking with. +/// \param ParamIdxOk Whether an argument can be indexing into a function +/// parameter list. +static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D, + const AttributeList &Attr, + SmallVectorImpl<Expr*> &Args, + int Sidx = 0, + bool ParamIdxOk = false) { + for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { + Expr *ArgExp = Attr.getArg(Idx); + + if (ArgExp->isTypeDependent()) { + // FIXME -- need to processs this again on template instantiation + Args.push_back(ArgExp); + continue; + } + + QualType ArgTy = ArgExp->getType(); + + // First see if we can just cast to record type, or point to record type. + const RecordType *RT = getRecordType(ArgTy); + + // Now check if we index into a record type function param. + if(!RT && ParamIdxOk) { + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp); + if(FD && IL) { + unsigned int NumParams = FD->getNumParams(); + llvm::APInt ArgValue = IL->getValue(); + uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); + uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; + if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) + << Attr.getName() << Idx + 1 << NumParams; + return false; + } + ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); + RT = getRecordType(ArgTy); + } + } + + if (!checkForLockableRecord(S, D, Attr, RT)) + return false; + + Args.push_back(ArgExp); + } + return true; +} + //===----------------------------------------------------------------------===// // Attribute Implementations //===----------------------------------------------------------------------===// @@ -212,6 +351,324 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr, // least add some helper functions to check most argument patterns (# // and types of args). +static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool pointer = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + if (pointer && !checkIsPointer(S, D, Attr)) + return; + + if (pointer) + D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context)); + else + D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context)); +} + +static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool pointer = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + + Expr *Arg = Attr.getArg(0); + + // D must be either a member field or global (potentially shared) variable. + if (!mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + if (pointer && !checkIsPointer(S, D, Attr)) + return; + + if (Arg->isTypeDependent()) + // FIXME: handle attributes with dependent types + return; + + // check that the argument is lockable object + if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType()))) + return; + + if (pointer) + D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), + S.Context, Arg)); + else + D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg)); +} + + +static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool scoped = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + // FIXME: Lockable structs for C code. + if (!isa<CXXRecordDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedClass; + return; + } + + if (scoped) + D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context)); + else + D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context)); +} + +static void handleNoThreadSafetyAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getRange(), + S.Context)); +} + +static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool before) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // D must be either a member field or global (potentially shared) variable. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD || !mayBeSharedVariable(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFieldOrGlobalVar; + return; + } + + // Check that this attribute only applies to lockable types + QualType QT = VD->getType(); + if (!QT->isDependentType()) { + const RecordType *RT = getRecordType(QT); + if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attribute_decl_not_lockable) + << Attr.getName(); + return; + } + } + + SmallVector<Expr*, 1> Args; + // check that all arguments are lockable objects + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (before) + D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context, + StartArg, Size)); + else + D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + +static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + // check that the attribute is applied to a function + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(), + S.Context, StartArg, + Size)); + else + D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(), + S.Context, StartArg, + Size)); +} + +static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (!isIntOrBool(Attr.getArg(0))) { + S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool) + << Attr.getName(); + return; + } + + SmallVector<Expr*, 2> Args; + // check that all arguments are lockable objects + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1)) + return; + + unsigned Size = Args.size(); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(), + S.Context, + Attr.getArg(0), + StartArg, Size)); + else + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(), + S.Context, + Attr.getArg(0), + StartArg, Size)); +} + +static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr, + bool exclusive = false) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + if (exclusive) + D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(), + S.Context, StartArg, + Size)); + else + D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(), + S.Context, StartArg, + Size)); +} + +static void handleUnlockFunAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + // zero or more arguments ok + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + +static void handleLockReturnedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + Expr *Arg = Attr.getArg(0); + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + if (Arg->isTypeDependent()) + return; + + // check that the argument is lockable object + if (!checkForLockableRecord(S, D, Attr, getRecordType(Arg->getType()))) + return; + + D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context, Arg)); +} + +static void handleLocksExcludedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + assert(!Attr.isInvalid()); + + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + // check that all arguments are lockable objects + SmallVector<Expr*, 1> Args; + if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args)) + return; + + unsigned Size = Args.size(); + assert(Size == Attr.getNumArgs()); + Expr **StartArg = Size == 0 ? 0 : &Args[0]; + + D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context, + StartArg, Size)); +} + + static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D); @@ -261,7 +718,7 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); + TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. @@ -270,14 +727,14 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << Attr.getName() << FD->getType(); else - FD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); + FD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context)); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context)); + TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -290,26 +747,48 @@ static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) { // The IBAction attributes only apply to instance methods. if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->isInstanceMethod()) { - D->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context)); return; } S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName(); } +static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { + // The IBOutlet/IBOutletCollection attributes only apply to instance + // variables or properties of Objective-C classes. The outlet must also + // have an object reference type. + if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) { + if (!VD->getType()->getAs<ObjCObjectPointerType>()) { + S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type) + << Attr.getName() << VD->getType() << 0; + return false; + } + } + else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + if (!PD->getType()->getAs<ObjCObjectPointerType>()) { + S.Diag(Attr.getLoc(), diag::err_iboutlet_object_type) + << Attr.getName() << PD->getType() << 1; + return false; + } + } + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + return false; + } + + return true; +} + static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (!checkAttributeNumArgs(S, Attr, 0)) return; - - // The IBOutlet attributes only apply to instance variables of - // Objective-C classes. - if (isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D)) { - D->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context)); + + if (!checkIBOutletCommon(S, D, Attr)) return; - } - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + D->addAttr(::new (S.Context) IBOutletAttr(Attr.getRange(), S.Context)); } static void handleIBOutletCollection(Sema &S, Decl *D, @@ -321,25 +800,9 @@ static void handleIBOutletCollection(Sema &S, Decl *D, return; } - // The IBOutletCollection attributes only apply to instance variables of - // Objective-C classes. - if (!(isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + if (!checkIBOutletCommon(S, D, Attr)) return; - } - if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) - if (!VD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) - << VD->getType() << 0; - return; - } - if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - if (!PD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) - << PD->getType() << 1; - return; - } - + IdentifierInfo *II = Attr.getParameterName(); if (!II) II = &S.Context.Idents.get("id"); @@ -360,8 +823,8 @@ static void handleIBOutletCollection(Sema &S, Decl *D, S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; return; } - D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context, - QT)); + D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getRange(),S.Context, + QT, Attr.getParameterLoc())); } static void possibleTransparentUnionPointerType(QualType &T) { @@ -394,7 +857,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; // The nonnull attribute only applies to pointers. - llvm::SmallVector<unsigned, 10> NonNullArgs; + SmallVector<unsigned, 10> NonNullArgs; for (AttributeList::arg_iterator I=Attr.arg_begin(), E=Attr.arg_end(); I!=E; ++I) { @@ -466,7 +929,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned* start = &NonNullArgs[0]; unsigned size = NonNullArgs.size(); llvm::array_pod_sort(start, start + size); - D->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start, + D->addAttr(::new (S.Context) NonNullAttr(Attr.getRange(), S.Context, start, size)); } @@ -526,13 +989,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { bool HasImplicitThisParam = isInstanceMethod(D); unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; - llvm::StringRef Module = AL.getParameterName()->getName(); + StringRef Module = AL.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. if (Module.startswith("__") && Module.endswith("__")) Module = Module.substr(2, Module.size() - 4); - llvm::SmallVector<unsigned, 10> OwnershipArgs; + SmallVector<unsigned, 10> OwnershipArgs; for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E; ++I) { @@ -712,18 +1175,18 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "weakref" << 1; return; } // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str->getString())); } - D->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WeakRefAttr(Attr.getRange(), S.Context)); } static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -737,20 +1200,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "alias" << 1; return; } - if (S.Context.Target.getTriple().isOSDarwin()) { + if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); return; } // FIXME: check if target symbol exists in current file - D->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str->getString())); } @@ -765,7 +1228,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NakedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context)); } static void handleAlwaysInlineAttr(Sema &S, Decl *D, @@ -782,7 +1245,7 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context)); } static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -795,7 +1258,7 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { QualType RetTy = FD->getResultType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { - D->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context)); return; } } @@ -808,13 +1271,13 @@ static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 0)) return; - D->addAttr(::new (S.Context) MayAliasAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) MayAliasAttr(Attr.getRange(), S.Context)); } static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { assert(!Attr.isInvalid()); if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoCommonAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -823,7 +1286,7 @@ static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { assert(!Attr.isInvalid()); if (isa<VarDecl>(D)) - D->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedVariable; @@ -840,7 +1303,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { return; } - D->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoReturnAttr(attr.getRange(), S.Context)); } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { @@ -874,7 +1337,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, } } - D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context)); } // PS3 PPU-specific. @@ -935,7 +1398,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { count++; } - D->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) VecReturnAttr(Attr.getRange(), S.Context)); } static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -961,7 +1424,24 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UnusedAttr(Attr.getRange(), S.Context)); +} + +static void handleReturnsTwiceAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // check the attribute arguments. + if (Attr.hasParameterOrArguments()) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunction; + return; + } + + D->addAttr(::new (S.Context) ReturnsTwiceAttr(Attr.getRange(), S.Context)); } static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -982,7 +1462,7 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) UsedAttr(Attr.getRange(), S.Context)); } static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1011,7 +1491,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context, priority)); } @@ -1041,7 +1521,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context, priority)); } @@ -1053,7 +1533,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // Handle the case where deprecated attribute has a text message. - llvm::StringRef Str; + StringRef Str; if (NumArgs == 1) { StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0)); if (!SE) { @@ -1064,7 +1544,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Str = SE->getString(); } - D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str)); } static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1075,7 +1555,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // Handle the case where unavailable attribute has a text message. - llvm::StringRef Str; + StringRef Str; if (NumArgs == 1) { StringLiteral *SE = dyn_cast<StringLiteral>(Attr.getArg(0)); if (!SE) { @@ -1085,7 +1565,7 @@ static void handleUnavailableAttr(Sema &S, Decl *D, const AttributeList &Attr) { } Str = SE->getString(); } - D->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); + D->addAttr(::new (S.Context) UnavailableAttr(Attr.getRange(), S.Context, Str)); } static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, @@ -1097,7 +1577,7 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr( - Attr.getLoc(), S.Context)); + Attr.getRange(), S.Context)); } static void handleAvailabilityAttr(Sema &S, Decl *D, @@ -1105,7 +1585,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, IdentifierInfo *Platform = Attr.getParameterName(); SourceLocation PlatformLoc = Attr.getParameterLoc(); - llvm::StringRef PlatformName + StringRef PlatformName = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); if (PlatformName.empty()) { S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) @@ -1119,10 +1599,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); bool IsUnavailable = Attr.getUnavailableLoc().isValid(); - // Ensure that Introduced < Deprecated < Obsoleted (although not all + // Ensure that Introduced <= Deprecated <= Obsoleted (although not all // of these steps are needed). if (Introduced.isValid() && Deprecated.isValid() && - !(Introduced.Version < Deprecated.Version)) { + !(Introduced.Version <= Deprecated.Version)) { S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) << 1 << PlatformName << Deprecated.Version.getAsString() << 0 << Introduced.Version.getAsString(); @@ -1130,7 +1610,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } if (Introduced.isValid() && Obsoleted.isValid() && - !(Introduced.Version < Obsoleted.Version)) { + !(Introduced.Version <= Obsoleted.Version)) { S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) << 2 << PlatformName << Obsoleted.Version.getAsString() << 0 << Introduced.Version.getAsString(); @@ -1138,14 +1618,14 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } if (Deprecated.isValid() && Obsoleted.isValid() && - !(Deprecated.Version < Obsoleted.Version)) { + !(Deprecated.Version <= Obsoleted.Version)) { S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering) << 2 << PlatformName << Obsoleted.Version.getAsString() << 1 << Deprecated.Version.getAsString(); return; } - D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) AvailabilityAttr(Attr.getRange(), S.Context, Platform, Introduced.Version, Deprecated.Version, @@ -1162,13 +1642,13 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "visibility" << 1; return; } - llvm::StringRef TypeStr = Str->getString(); + StringRef TypeStr = Str->getString(); VisibilityAttr::VisibilityType type; if (TypeStr == "default") @@ -1184,7 +1664,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) VisibilityAttr(Attr.getRange(), S.Context, type)); } static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, @@ -1207,7 +1687,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, return; } - llvm::StringRef param = Attr.getParameterName()->getName(); + StringRef param = Attr.getParameterName()->getName(); ObjCMethodFamilyAttr::FamilyKind family; if (param == "none") family = ObjCMethodFamilyAttr::OMF_None; @@ -1236,7 +1716,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, return; } - method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getLoc(), + method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), S.Context, family)); } @@ -1251,7 +1731,7 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getRange(), S.Context)); } static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1267,7 +1747,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { return; } } - D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context)); } static void @@ -1282,7 +1762,7 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) OverloadableAttr(Attr.getRange(), S.Context)); } static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1306,7 +1786,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type)); + D->addAttr(::new (S.Context) BlocksAttr(Attr.getRange(), S.Context, type)); } static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1316,7 +1796,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - int sentinel = 0; + unsigned sentinel = 0; if (Attr.getNumArgs() > 0) { Expr *E = Attr.getArg(0); llvm::APSInt Idx(32); @@ -1326,16 +1806,17 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { << "sentinel" << 1 << E->getSourceRange(); return; } - sentinel = Idx.getZExtValue(); - if (sentinel < 0) { + if (Idx.isSigned() && Idx.isNegative()) { S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } + + sentinel = Idx.getZExtValue(); } - int nullPos = 0; + unsigned nullPos = 0; if (Attr.getNumArgs() > 1) { Expr *E = Attr.getArg(1); llvm::APSInt Idx(32); @@ -1347,7 +1828,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } nullPos = Idx.getZExtValue(); - if (nullPos > 1 || nullPos < 0) { + if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) @@ -1357,9 +1838,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - const FunctionType *FT = FD->getType()->getAs<FunctionType>(); - assert(FT && "FunctionDecl has non-function type?"); - + const FunctionType *FT = FD->getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) { S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; @@ -1398,7 +1877,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } - D->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, + D->addAttr(::new (S.Context) SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos)); } @@ -1425,7 +1904,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) return; } - D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context)); } static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1449,7 +1928,7 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - nd->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context)); + nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context)); } static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1466,7 +1945,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { diag::warn_attribute_weak_import_invalid_on_definition) << "weak_import" << 2 /*variable and function*/; else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || - (S.Context.Target.getTriple().isOSDarwin() && + (S.Context.getTargetInfo().getTriple().isOSDarwin() && isa<ObjCInterfaceDecl>(D))) { // Nothing to warn about here. } else @@ -1476,7 +1955,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context)); } static void handleReqdWorkGroupSize(Sema &S, Decl *D, @@ -1497,7 +1976,7 @@ static void handleReqdWorkGroupSize(Sema &S, Decl *D, } WGSize[i] = (unsigned) ArgNum.getZExtValue(); } - D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2])); } @@ -1517,7 +1996,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { } // If the target wants to validate the section specifier, make it happen. - std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString()); + std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(SE->getString()); if (!Error.empty()) { S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) << Error; @@ -1530,7 +2009,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) SectionAttr(Attr.getRange(), S.Context, SE->getString())); } @@ -1544,9 +2023,9 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) { if (Existing->getLocation().isInvalid()) - Existing->setLocation(Attr.getLoc()); + Existing->setRange(Attr.getRange()); } else { - D->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoThrowAttr(Attr.getRange(), S.Context)); } } @@ -1559,9 +2038,9 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (ConstAttr *Existing = D->getAttr<ConstAttr>()) { if (Existing->getLocation().isInvalid()) - Existing->setLocation(Attr.getLoc()); + Existing->setRange(Attr.getRange()); } else { - D->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ConstAttr(Attr.getRange(), S.Context)); } } @@ -1570,7 +2049,7 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeNumArgs(S, Attr, 0)) return; - D->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PureAttr(Attr.getRange(), S.Context)); } static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1629,7 +2108,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); + D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD)); S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD); } @@ -1704,7 +2183,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) FormatArgAttr(Attr.getRange(), S.Context, Idx.getZExtValue())); } @@ -1719,7 +2198,7 @@ enum FormatAttrKind { /// getFormatAttrKind - Map from format attribute names to supported format /// types. -static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { +static FormatAttrKind getFormatAttrKind(StringRef Format) { // Check for formats that get handled specially. if (Format == "NSString") return NSStringFormat; @@ -1788,7 +2267,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, Attr.setInvalid(); return; } - D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getRange(), S.Context, prioritynum)); } @@ -1819,7 +2298,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam; unsigned FirstIdx = 1; - llvm::StringRef Format = Attr.getParameterName()->getName(); + StringRef Format = Attr.getParameterName()->getName(); // Normalize the argument, __foo__ becomes foo. if (Format.startswith("__") && Format.endswith("__")) @@ -1939,12 +2418,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // If we don't have a valid location for this attribute, adopt the // location. if (f->getLocation().isInvalid()) - f->setLocation(Attr.getLoc()); + f->setRange(Attr.getRange()); return; } } - D->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format, + D->addAttr(::new (S.Context) FormatAttr(Attr.getRange(), S.Context, Format, Idx.getZExtValue(), FirstArg.getZExtValue())); } @@ -1970,7 +2449,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, return; } - if (!RD->isDefinition()) { + if (!RD->isCompleteDefinition()) { S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; @@ -2013,7 +2492,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } } - RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context)); + RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getRange(), S.Context)); } static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2030,7 +2509,15 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - D->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, + + // Don't duplicate annotations that are already set. + for (specific_attr_iterator<AnnotateAttr> + i = D->specific_attr_begin<AnnotateAttr>(), + e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) { + if ((*i)->getAnnotation() == SE->getString()) + return; + } + D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context, SE->getString())); } @@ -2046,20 +2533,21 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // weaker alignment, rather than being silently ignored. if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getLoc(), S.Context, true, 0)); + D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, true, 0)); return; } - S.AddAlignedAttr(Attr.getLoc(), D, Attr.getArg(0)); + S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0)); } -void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E) { if (E->isTypeDependent() || E->isValueDependent()) { // Save dependent expressions in the AST to be instantiated. - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E)); return; } + SourceLocation AttrLoc = AttrRange.getBegin(); // FIXME: Cache the number on the Attr object? llvm::APSInt Alignment(32); if (!E->isIntegerConstantExpr(Alignment, Context)) { @@ -2073,13 +2561,13 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { return; } - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E)); } -void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) { +void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS) { // FIXME: Cache the number on the Attr object if non-dependent? // FIXME: Perform checking of type validity - D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, false, TS)); + D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS)); return; } @@ -2104,7 +2592,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - llvm::StringRef Str = Attr.getParameterName()->getName(); + StringRef Str = Attr.getParameterName()->getName(); // Normalize the attribute name, __foo__ becomes foo. if (Str.startswith("__") && Str.endswith("__")) @@ -2136,13 +2624,13 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. if (Str == "word") - DestWidth = S.Context.Target.getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(0); else if (Str == "byte") - DestWidth = S.Context.Target.getCharWidth(); + DestWidth = S.Context.getTargetInfo().getCharWidth(); break; case 7: if (Str == "pointer") - DestWidth = S.Context.Target.getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(0); break; } @@ -2153,7 +2641,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { OldTy = VD->getType(); else { S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc()); + << "mode" << Attr.getRange(); return; } @@ -2216,12 +2704,12 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!IntegerMode) NewTy = S.Context.DoubleTy; else if (OldTy->isSignedIntegerType()) - if (S.Context.Target.getLongWidth() == 64) + if (S.Context.getTargetInfo().getLongWidth() == 64) NewTy = S.Context.LongTy; else NewTy = S.Context.LongLongTy; else - if (S.Context.Target.getLongWidth() == 64) + if (S.Context.getTargetInfo().getLongWidth() == 64) NewTy = S.Context.UnsignedLongTy; else NewTy = S.Context.UnsignedLongLongTy; @@ -2264,7 +2752,7 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context)); } static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2279,7 +2767,7 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NoInlineAttr(Attr.getRange(), S.Context)); } static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, @@ -2295,7 +2783,7 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getRange(), S.Context)); } @@ -2313,7 +2801,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant"; } @@ -2333,7 +2821,7 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device"; } @@ -2366,7 +2854,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global"; } @@ -2385,7 +2873,7 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host"; } @@ -2404,7 +2892,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getRange(), S.Context)); } else { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared"; } @@ -2427,7 +2915,7 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getRange(), S.Context)); } static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -2447,31 +2935,31 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { switch (Attr.getKind()) { case AttributeList::AT_fastcall: - D->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_stdcall: - D->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_thiscall: - D->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cdecl: - D->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_pascal: - D->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_pcs: { Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "pcs" << 1; Attr.setInvalid(); return; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); PcsAttr::PCSType PCS; if (StrRef == "aapcs") PCS = PcsAttr::AAPCS; @@ -2483,7 +2971,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) PcsAttr(Attr.getLoc(), S.Context, PCS)); + D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS)); } default: llvm_unreachable("unexpected attribute kind"); @@ -2493,7 +2981,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ assert(!Attr.isInvalid()); - D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); } bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { @@ -2519,14 +3007,14 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { case AttributeList::AT_pcs: { Expr *Arg = attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) << "pcs" << 1; attr.setInvalid(); return true; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); if (StrRef == "aapcs") { CC = CC_AAPCS; break; @@ -2555,7 +3043,7 @@ static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - D->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, numParams)); + D->addAttr(::new (S.Context) RegparmAttr(Attr.getRange(), S.Context, numParams)); } /// Checks a regparm attribute, returning true if it is ill-formed and @@ -2580,7 +3068,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return true; } - if (Context.Target.getRegParmMax() == 0) { + if (Context.getTargetInfo().getRegParmMax() == 0) { Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); Attr.setInvalid(); @@ -2588,9 +3076,9 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { } numParams = NumParams.getZExtValue(); - if (numParams > Context.Target.getRegParmMax()) { + if (numParams > Context.getTargetInfo().getRegParmMax()) { Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) - << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); + << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); Attr.setInvalid(); return true; } @@ -2635,7 +3123,7 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ } } - D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getRange(), S.Context, MaxThreads.getZExtValue(), MinBlocks.getZExtValue())); } else { @@ -2648,17 +3136,21 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){ //===----------------------------------------------------------------------===// static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); + return type->isDependentType() || + type->isObjCObjectPointerType() || + S.Context.isObjCNSObjectType(type); } static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isPointerType() || isValidSubjectOfNSAttribute(S, type); + return type->isDependentType() || + type->isPointerType() || + isValidSubjectOfNSAttribute(S, type); } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { ParmVarDecl *param = dyn_cast<ParmVarDecl>(D); if (!param) { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedParameter; + << Attr.getRange() << Attr.getName() << ExpectedParameter; return; } @@ -2673,25 +3165,25 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!typeOK) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << cf; + << Attr.getRange() << Attr.getName() << cf; return; } if (cf) - param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getRange(), S.Context)); else - param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getLoc(), S.Context)); + param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getRange(), S.Context)); } static void handleNSConsumesSelfAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() << ExpectedMethod; + << Attr.getRange() << Attr.getName() << ExpectedMethod; return; } - D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getRange(), S.Context)); } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, @@ -2710,7 +3202,7 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, returnType = FD->getResultType(); else { S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(Attr.getLoc()) << Attr.getName() + << Attr.getRange() << Attr.getName() << ExpectedFunctionOrMethod; return; } @@ -2735,53 +3227,143 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, if (!typeOK) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << SourceRange(Attr.getLoc()) - << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; + << Attr.getRange() << Attr.getName() << isa<ObjCMethodDecl>(D) << cf; return; } switch (Attr.getKind()) { default: - assert(0 && "invalid ownership attribute"); - return; + llvm_unreachable("invalid ownership attribute"); case AttributeList::AT_ns_returns_autoreleased: - D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cf_returns_not_retained: - D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_cf_returns_retained: - D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(), S.Context)); return; case AttributeList::AT_ns_returns_retained: - D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), + D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(), S.Context)); return; }; } +static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, + const AttributeList &attr) { + SourceLocation loc = attr.getLoc(); + + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); + + if (!isa<ObjCMethodDecl>(method)) { + S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(loc, loc) << attr.getName() << 13 /* methods */; + return; + } + + // Check that the method returns a normal pointer. + QualType resultType = method->getResultType(); + + if (!resultType->isReferenceType() && + (!resultType->isPointerType() || resultType->isObjCRetainableType())) { + S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type) + << SourceRange(loc) + << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2; + + // Drop the attribute. + return; + } + + method->addAttr( + ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context)); +} + +/// Handle cf_audited_transfer and cf_unknown_transfer. +static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) { + if (!isa<FunctionDecl>(D)) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << A.getRange() << A.getName() << 0 /*function*/; + return; + } + + bool IsAudited = (A.getKind() == AttributeList::AT_cf_audited_transfer); + + // Check whether there's a conflicting attribute already present. + Attr *Existing; + if (IsAudited) { + Existing = D->getAttr<CFUnknownTransferAttr>(); + } else { + Existing = D->getAttr<CFAuditedTransferAttr>(); + } + if (Existing) { + S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible) + << A.getName() + << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer") + << A.getRange() << Existing->getRange(); + return; + } + + // All clear; add the attribute. + if (IsAudited) { + D->addAttr( + ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context)); + } else { + D->addAttr( + ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context)); + } +} + +static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D, + const AttributeList &Attr) { + RecordDecl *RD = dyn_cast<RecordDecl>(D); + if (!RD || RD->isUnion()) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << Attr.getRange() << Attr.getName() << 14 /*struct */; + } + + IdentifierInfo *ParmName = Attr.getParameterName(); + + // In Objective-C, verify that the type names an Objective-C type. + // We don't want to check this outside of ObjC because people sometimes + // do crazy C declarations of Objective-C types. + if (ParmName && S.getLangOptions().ObjC1) { + // Check for an existing type with this name. + LookupResult R(S, DeclarationName(ParmName), Attr.getParameterLoc(), + Sema::LookupOrdinaryName); + if (S.LookupName(R, Sc)) { + NamedDecl *Target = R.getFoundDecl(); + if (Target && !isa<ObjCInterfaceDecl>(Target)) { + S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface); + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + } + } + + D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context, + ParmName)); +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; - SourceLocation L = Attr.getLoc(); S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 12 /* variable */; + << Attr.getRange() << Attr.getName() << 12 /* variable */; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) { - SourceLocation L = Attr.getLoc(); S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << SourceRange(L, L) << Attr.getName() << 12 /* variable */; + << Attr.getRange() << Attr.getName() << 12 /* variable */; return; } @@ -2820,7 +3402,7 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(Attr.getLoc(), S.Context)); + ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context)); } static bool isKnownDeclSpecAttr(const AttributeList &Attr) { @@ -2834,20 +3416,20 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) { //===----------------------------------------------------------------------===// static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.Microsoft || S.LangOpts.Borland) { + if (S.LangOpts.MicrosoftExt || S.LangOpts.Borland) { // check the attribute arguments. if (!checkAttributeNumArgs(S, Attr, 1)) return; Expr *Arg = Attr.getArg(0); StringLiteral *Str = dyn_cast<StringLiteral>(Arg); - if (Str == 0 || Str->isWide()) { + if (!Str || !Str->isAscii()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "uuid" << 1; return; } - llvm::StringRef StrRef = Str->getString(); + StringRef StrRef = Str->getString(); bool IsCurly = StrRef.size() > 1 && StrRef.front() == '{' && StrRef.back() == '}'; @@ -2864,7 +3446,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" - llvm::StringRef::iterator I = StrRef.begin(); + StringRef::iterator I = StrRef.begin(); if (IsCurly) // Skip the optional '{' ++I; @@ -2881,7 +3463,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { I++; } - D->addAttr(::new (S.Context) UuidAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context, Str->getString())); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid"; @@ -2969,6 +3551,16 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_objc_precise_lifetime: handleObjCPreciseLifetimeAttr(S, D, Attr); break; + case AttributeList::AT_objc_returns_inner_pointer: + handleObjCReturnsInnerPointerAttr(S, D, Attr); break; + + case AttributeList::AT_ns_bridged: + handleNSBridgedAttr(S, scope, D, Attr); break; + + case AttributeList::AT_cf_audited_transfer: + case AttributeList::AT_cf_unknown_transfer: + handleCFTransferAttr(S, D, Attr); break; + // Checker-specific. case AttributeList::AT_cf_consumed: case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break; @@ -2996,6 +3588,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, handleArcWeakrefUnavailableAttr (S, D, Attr); break; case AttributeList::AT_unused: handleUnusedAttr (S, D, Attr); break; + case AttributeList::AT_returns_twice: + handleReturnsTwiceAttr(S, D, Attr); + break; case AttributeList::AT_used: handleUsedAttr (S, D, Attr); break; case AttributeList::AT_visibility: handleVisibilityAttr (S, D, Attr); break; case AttributeList::AT_warn_unused_result: handleWarnUnusedResult(S, D, Attr); @@ -3041,6 +3636,63 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_uuid: handleUuidAttr(S, D, Attr); break; + + // Thread safety attributes: + case AttributeList::AT_guarded_var: + handleGuardedVarAttr(S, D, Attr); + break; + case AttributeList::AT_pt_guarded_var: + handleGuardedVarAttr(S, D, Attr, /*pointer = */true); + break; + case AttributeList::AT_scoped_lockable: + handleLockableAttr(S, D, Attr, /*scoped = */true); + break; + case AttributeList::AT_no_thread_safety_analysis: + handleNoThreadSafetyAttr(S, D, Attr); + break; + case AttributeList::AT_lockable: + handleLockableAttr(S, D, Attr); + break; + case AttributeList::AT_guarded_by: + handleGuardedByAttr(S, D, Attr); + break; + case AttributeList::AT_pt_guarded_by: + handleGuardedByAttr(S, D, Attr, /*pointer = */true); + break; + case AttributeList::AT_exclusive_lock_function: + handleLockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_locks_required: + handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_exclusive_trylock_function: + handleTrylockFunAttr(S, D, Attr, /*exclusive = */true); + break; + case AttributeList::AT_lock_returned: + handleLockReturnedAttr(S, D, Attr); + break; + case AttributeList::AT_locks_excluded: + handleLocksExcludedAttr(S, D, Attr); + break; + case AttributeList::AT_shared_lock_function: + handleLockFunAttr(S, D, Attr); + break; + case AttributeList::AT_shared_locks_required: + handleLocksRequiredAttr(S, D, Attr); + break; + case AttributeList::AT_shared_trylock_function: + handleTrylockFunAttr(S, D, Attr); + break; + case AttributeList::AT_unlock_function: + handleUnlockFunAttr(S, D, Attr); + break; + case AttributeList::AT_acquired_before: + handleAcquireOrderAttr(S, D, Attr, /*before = */true); + break; + case AttributeList::AT_acquired_after: + handleAcquireOrderAttr(S, D, Attr, /*before = */false); + break; + default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); @@ -3091,19 +3743,86 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } +// Annotation attributes are the only attributes allowed after an access +// specifier. +bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList) { + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (l->getKind() == AttributeList::AT_annotate) { + handleAnnotateAttr(*this, ASDecl, *l); + } else { + Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + return true; + } + } + + return false; +} + +/// checkUnusedDeclAttributes - Check a list of attributes to see if it +/// contains any decl attributes that we should warn about. +static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { + for ( ; A; A = A->getNext()) { + // Only warn if the attribute is an unignored, non-type attribute. + if (A->isUsedAsTypeAttr()) continue; + if (A->getKind() == AttributeList::IgnoredAttribute) continue; + + if (A->getKind() == AttributeList::UnknownAttribute) { + S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored) + << A->getName() << A->getRange(); + } else { + S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl) + << A->getName() << A->getRange(); + } + } +} + +/// checkUnusedDeclAttributes - Given a declarator which is not being +/// used to build a declaration, complain about any decl attributes +/// which might be lying around on it. +void Sema::checkUnusedDeclAttributes(Declarator &D) { + ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList()); + ::checkUnusedDeclAttributes(*this, D.getAttributes()); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) + ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); +} + /// DeclClonePragmaWeak - clone existing decl (maybe definition), /// #pragma weak needs a non-definition decl and source may not have one -NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { +NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); NamedDecl *NewD = 0; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), - FD->getInnerLocStart(), - FD->getLocation(), DeclarationName(II), - FD->getType(), FD->getTypeSourceInfo()); - if (FD->getQualifier()) { - FunctionDecl *NewFD = cast<FunctionDecl>(NewD); + FunctionDecl *NewFD; + // FIXME: Missing call to CheckFunctionDeclaration(). + // FIXME: Mangling? + // FIXME: Is the qualifier info correct? + // FIXME: Is the DeclContext correct? + NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), + Loc, Loc, DeclarationName(II), + FD->getType(), FD->getTypeSourceInfo(), + SC_None, SC_None, + false/*isInlineSpecified*/, + FD->hasPrototype(), + false/*isConstexprSpecified*/); + NewD = NewFD; + + if (FD->getQualifier()) NewFD->setQualifierInfo(FD->getQualifierLoc()); + + // Fake up parameter variables; they are declared as if this were + // a typedef. + QualType FDTy = FD->getType(); + if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { + SmallVector<ParmVarDecl*, 16> Params; + for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), + AE = FT->arg_type_end(); AI != AE; ++AI) { + ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, *AI); + Param->setScopeInfo(0, Params.size()); + Params.push_back(Param); + } + NewFD->setParams(Params); } } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), @@ -3126,7 +3845,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { W.setUsed(true); if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); - NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias()); + NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context, NDId->getName())); NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); @@ -3149,15 +3868,18 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, bool NonInheritable, bool Inheritable) { // It's valid to "forward-declare" #pragma weak, in which case we // have to do this. - if (Inheritable && !WeakUndeclaredIdentifiers.empty()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { - if (IdentifierInfo *Id = ND->getIdentifier()) { - llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I - = WeakUndeclaredIdentifiers.find(Id); - if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) { - WeakInfo W = I->second; - DeclApplyPragmaWeak(S, ND, W); - WeakUndeclaredIdentifiers[Id] = W; + if (Inheritable) { + LoadExternalWeakUndeclaredIdentifiers(); + if (!WeakUndeclaredIdentifiers.empty()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + if (IdentifierInfo *Id = ND->getIdentifier()) { + llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I + = WeakUndeclaredIdentifiers.find(Id); + if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) { + WeakInfo W = I->second; + DeclApplyPragmaWeak(S, ND, W); + WeakUndeclaredIdentifiers[Id] = W; + } } } } @@ -3185,7 +3907,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl)) + // Function declarations in sys headers will be marked unavailable. + if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && + !isa<FunctionDecl>(decl)) return false; // Require it to be declared in a system header. @@ -3200,6 +3924,17 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, "this system declaration uses an unsupported type")); return; } + if (S.getLangOptions().ObjCAutoRefCount) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { + // FIXME. we may want to supress diagnostics for all + // kind of forbidden type messages on unavailable functions. + if (FD->hasAttr<UnavailableAttr>() && + diag.getForbiddenTypeDiagnostic() == + diag::err_arc_array_param_no_ownership) { + diag.Triggered = true; + return; + } + } S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); @@ -3287,6 +4022,9 @@ static bool isDeclDeprecated(Decl *D) { do { if (D->isDeprecated()) return true; + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + return CatD->getClassInterface()->isDeprecated(); } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; } @@ -3306,7 +4044,7 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, << DD.getDeprecationDecl()->getDeclName(); } -void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, +void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass) { // Delay if we're currently parsing a declaration. @@ -3316,7 +4054,7 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, } // Otherwise, don't warn if our current context is deprecated. - if (isDeclDeprecated(cast<Decl>(CurContext))) + if (isDeclDeprecated(cast<Decl>(getCurLexicalContext()))) return; if (!Message.empty()) Diag(Loc, diag::warn_deprecated_message) << D->getDeclName() diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index d793daf..a39584a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -392,7 +392,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { // MSVC accepts that default parameters be redefined for member functions // of template class. The new default parameter's value is ignored. Invalid = true; - if (getLangOptions().Microsoft) { + if (getLangOptions().MicrosoftExt) { CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New); if (MD && MD->getParent()->getDescribedClassTemplate()) { // Merge the old default argument into the new parameter. @@ -502,6 +502,20 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { } } + // C++0x [dcl.constexpr]p1: If any declaration of a function or function + // template has a constexpr specifier then all its declarations shall + // contain the constexpr specifier. [Note: An explicit specialization can + // differ from the template declaration with respect to the constexpr + // specifier. -- end note] + // + // FIXME: Don't reject changes in constexpr in explicit specializations. + if (New->isConstexpr() != Old->isConstexpr()) { + Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) + << New << New->isConstexpr(); + Diag(Old->getLocation(), diag::note_previous_declaration); + Invalid = true; + } + if (CheckEquivalentExceptionSpec(Old, New)) Invalid = true; @@ -602,6 +616,363 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { } } +// CheckConstexprParameterTypes - Check whether a function's parameter types +// are all literal types. If so, return true. If not, produce a suitable +// diagnostic depending on @p CCK and return false. +static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD, + Sema::CheckConstexprKind CCK) { + unsigned ArgIndex = 0; + const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>(); + for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(), + e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) { + const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); + SourceLocation ParamLoc = PD->getLocation(); + if (!(*i)->isDependentType() && + SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ? + SemaRef.PDiag(diag::err_constexpr_non_literal_param) + << ArgIndex+1 << PD->getSourceRange() + << isa<CXXConstructorDecl>(FD) : + SemaRef.PDiag(), + /*AllowIncompleteType*/ true)) { + if (CCK == Sema::CCK_NoteNonConstexprInstantiation) + SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param) + << ArgIndex+1 << PD->getSourceRange() + << isa<CXXConstructorDecl>(FD) << *i; + return false; + } + } + return true; +} + +// CheckConstexprFunctionDecl - Check whether a function declaration satisfies +// the requirements of a constexpr function declaration or a constexpr +// constructor declaration. Return true if it does, false if not. +// +// This implements C++0x [dcl.constexpr]p3,4, as amended by N3308. +// +// \param CCK Specifies whether to produce diagnostics if the function does not +// satisfy the requirements. +bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD, + CheckConstexprKind CCK) { + assert((CCK != CCK_NoteNonConstexprInstantiation || + (NewFD->getTemplateInstantiationPattern() && + NewFD->getTemplateInstantiationPattern()->isConstexpr())) && + "only constexpr templates can be instantiated non-constexpr"); + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(NewFD)) { + // C++0x [dcl.constexpr]p4: + // In the definition of a constexpr constructor, each of the parameter + // types shall be a literal type. + if (!CheckConstexprParameterTypes(*this, NewFD, CCK)) + return false; + + // In addition, either its function-body shall be = delete or = default or + // it shall satisfy the following constraints: + // - the class shall not have any virtual base classes; + const CXXRecordDecl *RD = CD->getParent(); + if (RD->getNumVBases()) { + // Note, this is still illegal if the body is = default, since the + // implicit body does not satisfy the requirements of a constexpr + // constructor. We also reject cases where the body is = delete, as + // required by N3308. + if (CCK != CCK_Instantiation) { + Diag(NewFD->getLocation(), + CCK == CCK_Declaration ? diag::err_constexpr_virtual_base + : diag::note_constexpr_tmpl_virtual_base) + << RD->isStruct() << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getSourceRange().getBegin(), + diag::note_constexpr_virtual_base_here) << I->getSourceRange(); + } + return false; + } + } else { + // C++0x [dcl.constexpr]p3: + // The definition of a constexpr function shall satisfy the following + // constraints: + // - it shall not be virtual; + const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); + if (Method && Method->isVirtual()) { + if (CCK != CCK_Instantiation) { + Diag(NewFD->getLocation(), + CCK == CCK_Declaration ? diag::err_constexpr_virtual + : diag::note_constexpr_tmpl_virtual); + + // If it's not obvious why this function is virtual, find an overridden + // function which uses the 'virtual' keyword. + const CXXMethodDecl *WrittenVirtual = Method; + while (!WrittenVirtual->isVirtualAsWritten()) + WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); + if (WrittenVirtual != Method) + Diag(WrittenVirtual->getLocation(), + diag::note_overridden_virtual_function); + } + return false; + } + + // - its return type shall be a literal type; + QualType RT = NewFD->getResultType(); + if (!RT->isDependentType() && + RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ? + PDiag(diag::err_constexpr_non_literal_return) : + PDiag(), + /*AllowIncompleteType*/ true)) { + if (CCK == CCK_NoteNonConstexprInstantiation) + Diag(NewFD->getLocation(), + diag::note_constexpr_tmpl_non_literal_return) << RT; + return false; + } + + // - each of its parameter types shall be a literal type; + if (!CheckConstexprParameterTypes(*this, NewFD, CCK)) + return false; + } + + return true; +} + +/// Check the given declaration statement is legal within a constexpr function +/// body. C++0x [dcl.constexpr]p3,p4. +/// +/// \return true if the body is OK, false if we have diagnosed a problem. +static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, + DeclStmt *DS) { + // C++0x [dcl.constexpr]p3 and p4: + // The definition of a constexpr function(p3) or constructor(p4) [...] shall + // contain only + for (DeclStmt::decl_iterator DclIt = DS->decl_begin(), + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) { + switch ((*DclIt)->getKind()) { + case Decl::StaticAssert: + case Decl::Using: + case Decl::UsingShadow: + case Decl::UsingDirective: + case Decl::UnresolvedUsingTypename: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + continue; + + case Decl::Typedef: + case Decl::TypeAlias: { + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt); + if (TN->getUnderlyingType()->isVariablyModifiedType()) { + // Don't allow variably-modified types in constexpr functions. + TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc(); + SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla) + << TL.getSourceRange() << TL.getType() + << isa<CXXConstructorDecl>(Dcl); + return false; + } + continue; + } + + case Decl::Enum: + case Decl::CXXRecord: + // As an extension, we allow the declaration (but not the definition) of + // classes and enumerations in all declarations, not just in typedef and + // alias declarations. + if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) { + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + continue; + + case Decl::Var: + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration) + << isa<CXXConstructorDecl>(Dcl); + return false; + + default: + SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + } + + return true; +} + +/// Check that the given field is initialized within a constexpr constructor. +/// +/// \param Dcl The constexpr constructor being checked. +/// \param Field The field being checked. This may be a member of an anonymous +/// struct or union nested within the class being checked. +/// \param Inits All declarations, including anonymous struct/union members and +/// indirect members, for which any initialization was provided. +/// \param Diagnosed Set to true if an error is produced. +static void CheckConstexprCtorInitializer(Sema &SemaRef, + const FunctionDecl *Dcl, + FieldDecl *Field, + llvm::SmallSet<Decl*, 16> &Inits, + bool &Diagnosed) { + if (Field->isUnnamedBitfield()) + return; + + if (!Inits.count(Field)) { + if (!Diagnosed) { + SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init); + Diagnosed = true; + } + SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); + } else if (Field->isAnonymousStructOrUnion()) { + const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) + // If an anonymous union contains an anonymous struct of which any member + // is initialized, all members must be initialized. + if (!RD->isUnion() || Inits.count(*I)) + CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed); + } +} + +/// Check the body for the given constexpr function declaration only contains +/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. +/// +/// \return true if the body is OK, false if we have diagnosed a problem. +bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { + if (isa<CXXTryStmt>(Body)) { + // C++0x [dcl.constexpr]p3: + // The definition of a constexpr function shall satisfy the following + // constraints: [...] + // - its function-body shall be = delete, = default, or a + // compound-statement + // + // C++0x [dcl.constexpr]p4: + // In the definition of a constexpr constructor, [...] + // - its function-body shall not be a function-try-block; + Diag(Body->getLocStart(), diag::err_constexpr_function_try_block) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + + // - its function-body shall be [...] a compound-statement that contains only + CompoundStmt *CompBody = cast<CompoundStmt>(Body); + + llvm::SmallVector<SourceLocation, 4> ReturnStmts; + for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(), + BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) { + switch ((*BodyIt)->getStmtClass()) { + case Stmt::NullStmtClass: + // - null statements, + continue; + + case Stmt::DeclStmtClass: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt))) + return false; + continue; + + case Stmt::ReturnStmtClass: + // - and exactly one return statement; + if (isa<CXXConstructorDecl>(Dcl)) + break; + + ReturnStmts.push_back((*BodyIt)->getLocStart()); + // FIXME + // - every constructor call and implicit conversion used in initializing + // the return value shall be one of those allowed in a constant + // expression. + // Deal with this as part of a general check that the function can produce + // a constant expression (for [dcl.constexpr]p5). + continue; + + default: + break; + } + + Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + + if (const CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(Dcl)) { + const CXXRecordDecl *RD = Constructor->getParent(); + // - every non-static data member and base class sub-object shall be + // initialized; + if (RD->isUnion()) { + // DR1359: Exactly one member of a union shall be initialized. + if (Constructor->getNumCtorInitializers() == 0) { + Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init); + return false; + } + } else if (!Constructor->isDependentContext() && + !Constructor->isDelegatingConstructor()) { + assert(RD->getNumVBases() == 0 && "constexpr ctor with virtual bases"); + + // Skip detailed checking if we have enough initializers, and we would + // allow at most one initializer per member. + bool AnyAnonStructUnionMembers = false; + unsigned Fields = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++Fields) { + if ((*I)->isAnonymousStructOrUnion()) { + AnyAnonStructUnionMembers = true; + break; + } + } + if (AnyAnonStructUnionMembers || + Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) { + // Check initialization of non-static data members. Base classes are + // always initialized so do not need to be checked. Dependent bases + // might not have initializers in the member initializer list. + llvm::SmallSet<Decl*, 16> Inits; + for (CXXConstructorDecl::init_const_iterator + I = Constructor->init_begin(), E = Constructor->init_end(); + I != E; ++I) { + if (FieldDecl *FD = (*I)->getMember()) + Inits.insert(FD); + else if (IndirectFieldDecl *ID = (*I)->getIndirectMember()) + Inits.insert(ID->chain_begin(), ID->chain_end()); + } + + bool Diagnosed = false; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) + CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed); + if (Diagnosed) + return false; + } + } + + // FIXME + // - every constructor involved in initializing non-static data members + // and base class sub-objects shall be a constexpr constructor; + // - every assignment-expression that is an initializer-clause appearing + // directly or indirectly within a brace-or-equal-initializer for + // a non-static data member that is not named by a mem-initializer-id + // shall be a constant expression; and + // - every implicit conversion used in converting a constructor argument + // to the corresponding parameter type and converting + // a full-expression to the corresponding member type shall be one of + // those allowed in a constant expression. + // Deal with these as part of a general check that the function can produce + // a constant expression (for [dcl.constexpr]p5). + } else { + if (ReturnStmts.empty()) { + Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return); + return false; + } + if (ReturnStmts.size() > 1) { + Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return); + for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) + Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); + return false; + } + } + + return true; +} + /// isCurrentClassName - Determine whether the identifier II is the /// name of the class type currently being defined. In the case of /// nested classes, this will only return true if II is the name of @@ -797,7 +1168,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, /// ActOnBaseSpecifiers - Attach the given base specifiers to the /// class, after checking whether there are any duplicate base /// classes. -void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, BaseTy **Bases, +void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, unsigned NumBases) { if (!ClassDecl || !Bases || !NumBases) return; @@ -1005,19 +1376,20 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. -Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, - SourceLocation ColonLoc) { +bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); CurContext->addHiddenDecl(ASDecl); - return ASDecl; + return ProcessAccessDeclAttributeList(ASDecl, Attrs); } /// CheckOverrideControl - Check C++0x override control semantics. void Sema::CheckOverrideControl(const Decl *D) { - const CXXMethodDecl *MD = llvm::dyn_cast<CXXMethodDecl>(D); + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); if (!MD || !MD->isVirtual()) return; @@ -1060,9 +1432,8 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - ExprTy *BW, const VirtSpecifiers &VS, - ExprTy *InitExpr, bool HasDeferredInit, - bool IsDefinition) { + Expr *BW, const VirtSpecifiers &VS, + bool HasDeferredInit) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1073,11 +1444,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Loc = D.getSourceRange().getBegin(); Expr *BitWidth = static_cast<Expr*>(BW); - Expr *Init = static_cast<Expr*>(InitExpr); assert(isa<CXXRecordDecl>(CurContext)); assert(!DS.isFriendSpecified()); - assert(!Init || !HasDeferredInit); bool isFunc = D.isDeclarationOfFunction(); @@ -1120,7 +1489,37 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Decl *Member; if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); + + // Data members must have identifiers for names. + if (Name.getNameKind() != DeclarationName::Identifier) { + Diag(Loc, diag::err_bad_variable_name) + << Name; + return 0; + } + IdentifierInfo *II = Name.getAsIdentifierInfo(); + + // Member field could not be with "template" keyword. + // So TemplateParameterLists should be empty in this case. + if (TemplateParameterLists.size()) { + TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0]; + if (TemplateParams->size()) { + // There is no such thing as a member field template. + Diag(D.getIdentifierLoc(), diag::err_template_member) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + } else { + // There is an extraneous 'template<>' for this member. + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_member_noparams) + << II + << SourceRange(TemplateParams->getTemplateLoc(), + TemplateParams->getRAngleLoc()); + } + return 0; + } + if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class // definition: @@ -1138,16 +1537,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, SS.clear(); } - - // FIXME: Check for template parameters! - // FIXME: Check that the name is an identifier! + Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, HasDeferredInit, AS); assert(Member && "HandleField never returns null"); } else { assert(!HasDeferredInit); - Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); + Member = HandleDeclarator(S, D, move(TemplateParameterLists)); if (!Member) { return 0; } @@ -1214,28 +1611,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert((Name || isInstField) && "No identifier for non-field ?"); - if (Init) - AddInitializerToDecl(Member, Init, false, - DS.getTypeSpecType() == DeclSpec::TST_auto); - else if (DS.getTypeSpecType() == DeclSpec::TST_auto && - DS.getStorageClassSpec() == DeclSpec::SCS_static) { - // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static - // data member if a brace-or-equal-initializer is provided. - Diag(Loc, diag::err_auto_var_requires_init) - << Name << cast<ValueDecl>(Member)->getType(); - Member->setInvalidDecl(); - } - - FinalizeDeclaration(Member); - if (isInstField) FieldCollector->Add(cast<FieldDecl>(Member)); return Member; } /// ActOnCXXInClassMemberInitializer - This is invoked after parsing an -/// in-class initializer for a non-static C++ class member. Such parsing -/// is deferred until the class is complete. +/// in-class initializer for a non-static C++ class member, and after +/// instantiating an in-class initializer in a class template. Such actions +/// are deferred until the class is complete. void Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc, Expr *InitExpr) { @@ -1319,7 +1703,21 @@ static bool FindBaseInitializer(Sema &SemaRef, return DirectBaseSpec || VirtualBaseSpec; } -/// ActOnMemInitializer - Handle a C++ member initializer. +/// \brief Handle a C++ member initializer using braced-init-list syntax. +MemInitResult +Sema::ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + SourceLocation IdLoc, + Expr *InitList, + SourceLocation EllipsisLoc) { + return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, + IdLoc, MultiInitializer(InitList), EllipsisLoc); +} + +/// \brief Handle a C++ member initializer using parentheses syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, @@ -1328,9 +1726,25 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, ParsedType TemplateTypeTy, SourceLocation IdLoc, SourceLocation LParenLoc, - ExprTy **Args, unsigned NumArgs, + Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { + return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, + IdLoc, MultiInitializer(LParenLoc, Args, NumArgs, + RParenLoc), + EllipsisLoc); +} + +/// \brief Handle a C++ member initializer. +MemInitResult +Sema::BuildMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + SourceLocation IdLoc, + const MultiInitializer &Args, + SourceLocation EllipsisLoc) { if (!ConstructorD) return true; @@ -1365,26 +1779,23 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, = ClassDecl->lookup(MemberOrBase); if (Result.first != Result.second) { Member = dyn_cast<FieldDecl>(*Result.first); - + if (Member) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); - - return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - LParenLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); + + return BuildMemberInitializer(Member, Args, IdLoc); } - + // Handle anonymous union case. if (IndirectFieldDecl* IndirectField = dyn_cast<IndirectFieldDecl>(*Result.first)) { if (EllipsisLoc.isValid()) Diag(EllipsisLoc, diag::err_pack_expansion_member_init) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); - return BuildMemberInitializer(IndirectField, (Expr**)Args, - NumArgs, IdLoc, - LParenLoc, RParenLoc); + return BuildMemberInitializer(IndirectField, Args, IdLoc); } } } @@ -1443,8 +1854,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, Diag(Member->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; - return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - LParenLoc, RParenLoc); + return BuildMemberInitializer(Member, Args, IdLoc); } } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) { const CXXBaseSpecifier *DirectBaseSpec; @@ -1473,7 +1883,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) - << MemberOrBase << SourceRange(IdLoc, RParenLoc); + << MemberOrBase << SourceRange(IdLoc, Args.getEndLoc()); return true; } } @@ -1493,8 +1903,62 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs, - LParenLoc, RParenLoc, ClassDecl, EllipsisLoc); + return BuildBaseInitializer(BaseType, TInfo, Args, ClassDecl, EllipsisLoc); +} + +/// Checks a member initializer expression for cases where reference (or +/// pointer) members are bound to by-value parameters (or their addresses). +static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, + Expr *Init, + SourceLocation IdLoc) { + QualType MemberTy = Member->getType(); + + // We only handle pointers and references currently. + // FIXME: Would this be relevant for ObjC object pointers? Or block pointers? + if (!MemberTy->isReferenceType() && !MemberTy->isPointerType()) + return; + + const bool IsPointer = MemberTy->isPointerType(); + if (IsPointer) { + if (const UnaryOperator *Op + = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) { + // The only case we're worried about with pointers requires taking the + // address. + if (Op->getOpcode() != UO_AddrOf) + return; + + Init = Op->getSubExpr(); + } else { + // We only handle address-of expression initializers for pointers. + return; + } + } + + if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) { + // Taking the address of a temporary will be diagnosed as a hard error. + if (IsPointer) + return; + + S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary) + << Member << Init->getSourceRange(); + } else if (const DeclRefExpr *DRE + = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { + // We only warn when referring to a non-reference parameter declaration. + const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl()); + if (!Parameter || Parameter->getType()->isReferenceType()) + return; + + S.Diag(Init->getExprLoc(), + IsPointer ? diag::warn_init_ptr_member_to_parameter_addr + : diag::warn_bind_ref_member_to_parameter) + << Member << Parameter << Init->getSourceRange(); + } else { + // Other initializers are fine. + return; + } + + S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) + << (unsigned)IsPointer; } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1566,10 +2030,9 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, } MemInitResult -Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { +Sema::BuildMemberInitializer(ValueDecl *Member, + const MultiInitializer &Args, + SourceLocation IdLoc) { FieldDecl *DirectMember = dyn_cast<FieldDecl>(Member); IndirectFieldDecl *IndirectMember = dyn_cast<IndirectFieldDecl>(Member); assert((DirectMember || IndirectMember) && @@ -1582,9 +2045,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. - for (unsigned i = 0; i < NumArgs; ++i) { + for (MultiInitializer::iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { SourceLocation L; - if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { + Expr *Arg = *I; + if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Arg)) + Arg = DIE->getInit(); + if (InitExprContainsUninitializedFields(Arg, Member, &L)) { // FIXME: Return true in the case when other fields are used before being // uninitialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th @@ -1595,17 +2062,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, } } - bool HasDependentArg = false; - for (unsigned i = 0; i < NumArgs; i++) - HasDependentArg |= Args[i]->isTypeDependent(); + bool HasDependentArg = Args.isTypeDependent(); Expr *Init; if (Member->getType()->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. - Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, - Member->getType().getNonReferenceType()); + Init = Args.CreateInitExpr(Context,Member->getType().getNonReferenceType()); DiscardCleanupsInEvaluationContext(); } else { @@ -1614,17 +2077,14 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0) : InitializedEntity::InitializeMember(IndirectMember, 0); InitializationKind Kind = - InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc); + InitializationKind::CreateDirect(IdLoc, Args.getStartLoc(), + Args.getEndLoc()); - InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - - ExprResult MemberInit = - InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + ExprResult MemberInit = Args.PerformInit(*this, MemberEntity, Kind); if (MemberInit.isInvalid()) return true; - CheckImplicitConversions(MemberInit.get(), LParenLoc); + CheckImplicitConversions(MemberInit.get(), Args.getStartLoc()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -1640,31 +2100,30 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, // of the information that we have about the member // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - Init = new (Context) ParenListExpr( - Context, LParenLoc, Args, NumArgs, RParenLoc, - Member->getType().getNonReferenceType()); - else + if (CurContext->isDependentContext()) { + Init = Args.CreateInitExpr(Context, + Member->getType().getNonReferenceType()); + } else { Init = MemberInit.get(); + CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc); + } } if (DirectMember) { return new (Context) CXXCtorInitializer(Context, DirectMember, - IdLoc, LParenLoc, Init, - RParenLoc); + IdLoc, Args.getStartLoc(), + Init, Args.getEndLoc()); } else { return new (Context) CXXCtorInitializer(Context, IndirectMember, - IdLoc, LParenLoc, Init, - RParenLoc); + IdLoc, Args.getStartLoc(), + Init, Args.getEndLoc()); } } MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, - Expr **Args, unsigned NumArgs, + const MultiInitializer &Args, SourceLocation NameLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) @@ -1675,13 +2134,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = - InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc); + InitializationKind::CreateDirect(NameLoc, Args.getStartLoc(), + Args.getEndLoc()); - InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); - - ExprResult DelegationInit = - InitSeq.Perform(*this, DelegationEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + ExprResult DelegationInit = Args.PerformInit(*this, DelegationEntity, Kind); if (DelegationInit.isInvalid()) return true; @@ -1690,7 +2146,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, = ConExpr->getConstructor(); assert(Constructor && "Delegating constructor with no target?"); - CheckImplicitConversions(DelegationInit.get(), LParenLoc); + CheckImplicitConversions(DelegationInit.get(), Args.getStartLoc()); // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a @@ -1700,24 +2156,22 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, return true; assert(!CurContext->isDependentContext()); - return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, + return new (Context) CXXCtorInitializer(Context, Loc, Args.getStartLoc(), + Constructor, DelegationInit.takeAs<Expr>(), - RParenLoc); + Args.getEndLoc()); } MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, - Expr **Args, unsigned NumArgs, - SourceLocation LParenLoc, SourceLocation RParenLoc, + const MultiInitializer &Args, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { - bool HasDependentArg = false; - for (unsigned i = 0; i < NumArgs; i++) - HasDependentArg |= Args[i]->isTypeDependent(); + bool HasDependentArg = Args.isTypeDependent(); SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); - + if (!BaseType->isDependentType() && !BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); @@ -1734,28 +2188,26 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // This is a pack expansion. if (!BaseType->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << SourceRange(BaseLoc, RParenLoc); - + << SourceRange(BaseLoc, Args.getEndLoc()); + EllipsisLoc = SourceLocation(); } } else { // Check for any unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer)) return true; - - for (unsigned I = 0; I != NumArgs; ++I) - if (DiagnoseUnexpandedParameterPack(Args[I])) - return true; + + if (Args.DiagnoseUnexpandedParameterPack(*this)) + return true; } - + // Check for direct and virtual base classes. const CXXBaseSpecifier *DirectBaseSpec = 0; const CXXBaseSpecifier *VirtualBaseSpec = 0; if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) - return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc, - LParenLoc, RParenLoc, ClassDecl); + return BuildDelegatingInitializer(BaseTInfo, Args, BaseLoc, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -1782,18 +2234,14 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (Dependent) { // Can't check initialization for a base of dependent type or when // any of the arguments are type-dependent expressions. - ExprResult BaseInit - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, BaseType)); + Expr *BaseInit = Args.CreateInitExpr(Context, BaseType); DiscardCleanupsInEvaluationContext(); - return new (Context) CXXCtorInitializer(Context, BaseTInfo, - /*IsVirtual=*/false, - LParenLoc, - BaseInit.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); + return new (Context) CXXCtorInitializer(Context, BaseTInfo, + /*IsVirtual=*/false, + Args.getStartLoc(), BaseInit, + Args.getEndLoc(), EllipsisLoc); } // C++ [base.class.init]p2: @@ -1813,18 +2261,15 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = - InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); - - InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); - - ExprResult BaseInit = - InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(*this, Args, NumArgs), 0); + InitializationKind::CreateDirect(BaseLoc, Args.getStartLoc(), + Args.getEndLoc()); + + ExprResult BaseInit = Args.PerformInit(*this, BaseEntity, Kind); if (BaseInit.isInvalid()) return true; - CheckImplicitConversions(BaseInit.get(), LParenLoc); - + CheckImplicitConversions(BaseInit.get(), Args.getStartLoc()); + // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. @@ -1839,24 +2284,27 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // of the information that we have about the base // initializer. However, deconstructing the ASTs is a dicey process, // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) { - ExprResult Init - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc, BaseType)); - return new (Context) CXXCtorInitializer(Context, BaseTInfo, - BaseSpec->isVirtual(), - LParenLoc, - Init.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); - } + if (CurContext->isDependentContext()) + BaseInit = Owned(Args.CreateInitExpr(Context, BaseType)); return new (Context) CXXCtorInitializer(Context, BaseTInfo, - BaseSpec->isVirtual(), - LParenLoc, - BaseInit.takeAs<Expr>(), - RParenLoc, - EllipsisLoc); + BaseSpec->isVirtual(), + Args.getStartLoc(), + BaseInit.takeAs<Expr>(), + Args.getEndLoc(), EllipsisLoc); +} + +// Create a static_cast\<T&&>(expr). +static Expr *CastForMoving(Sema &SemaRef, Expr *E) { + QualType ExprType = E->getType(); + QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType); + SourceLocation ExprLoc = E->getLocStart(); + TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( + TargetType, ExprLoc); + + return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E, + SourceRange(ExprLoc, ExprLoc), + E->getSourceRange()).take(); } /// ImplicitInitializerKind - How an implicit base or member initializer should @@ -1889,7 +2337,9 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, break; } + case IIK_Move: case IIK_Copy: { + bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); @@ -1897,17 +2347,22 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Constructor->getLocation(), ParamType, VK_LValue, 0); - + // Cast to the base class to avoid ambiguities. QualType ArgTy = SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), ParamType.getQualifiers()); + if (Moving) { + CopyCtorArg = CastForMoving(SemaRef, CopyCtorArg); + } + CXXCastPath BasePath; BasePath.push_back(BaseSpec); CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, CK_UncheckedDerivedToBase, - VK_LValue, &BasePath).take(); + Moving ? VK_XValue : VK_LValue, + &BasePath).take(); InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), @@ -1918,9 +2373,6 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, MultiExprArg(&CopyCtorArg, 1)); break; } - - case IIK_Move: - assert(false && "Unhandled initializer kind!"); } BaseInit = SemaRef.MaybeCreateExprWithCleanups(BaseInit); @@ -1940,36 +2392,46 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, return false; } +static bool RefersToRValueRef(Expr *MemRef) { + ValueDecl *Referenced = cast<MemberExpr>(MemRef)->getMemberDecl(); + return Referenced->getType()->isRValueReferenceType(); +} + static bool BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ImplicitInitializerKind ImplicitInitKind, - FieldDecl *Field, + FieldDecl *Field, IndirectFieldDecl *Indirect, CXXCtorInitializer *&CXXMemberInit) { if (Field->isInvalidDecl()) return true; SourceLocation Loc = Constructor->getLocation(); - if (ImplicitInitKind == IIK_Copy) { + if (ImplicitInitKind == IIK_Copy || ImplicitInitKind == IIK_Move) { + bool Moving = ImplicitInitKind == IIK_Move; ParmVarDecl *Param = Constructor->getParamDecl(0); QualType ParamType = Param->getType().getNonReferenceType(); // Suppress copying zero-width bitfields. - if (const Expr *Width = Field->getBitWidth()) - if (Width->EvaluateAsInt(SemaRef.Context) == 0) - return false; + if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0) + return false; Expr *MemberExprBase = DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Loc, ParamType, VK_LValue, 0); + if (Moving) { + MemberExprBase = CastForMoving(SemaRef, MemberExprBase); + } + // Build a reference to this field within the parameter. CXXScopeSpec SS; LookupResult MemberLookup(SemaRef, Field->getDeclName(), Loc, Sema::LookupMemberName); - MemberLookup.addDecl(Field, AS_public); + MemberLookup.addDecl(Indirect ? cast<ValueDecl>(Indirect) + : cast<ValueDecl>(Field), AS_public); MemberLookup.resolveKind(); - ExprResult CopyCtorArg + ExprResult CtorArg = SemaRef.BuildMemberReferenceExpr(MemberExprBase, ParamType, Loc, /*IsArrow=*/false, @@ -1977,18 +2439,27 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, /*FirstQualifierInScope=*/0, MemberLookup, /*TemplateArgs=*/0); - if (CopyCtorArg.isInvalid()) + if (CtorArg.isInvalid()) return true; - + + // C++11 [class.copy]p15: + // - if a member m has rvalue reference type T&&, it is direct-initialized + // with static_cast<T&&>(x.m); + if (RefersToRValueRef(CtorArg.get())) { + CtorArg = CastForMoving(SemaRef, CtorArg.take()); + } + // When the field we are copying is an array, create index variables for // each dimension of the array. We use these index variables to subscript // the source array, and other clients (e.g., CodeGen) will perform the // necessary iteration with these index variables. - llvm::SmallVector<VarDecl *, 4> IndexVariables; + SmallVector<VarDecl *, 4> IndexVariables; QualType BaseType = Field->getType(); QualType SizeType = SemaRef.Context.getSizeType(); + bool InitializingArray = false; while (const ConstantArrayType *Array = SemaRef.Context.getAsConstantArrayType(BaseType)) { + InitializingArray = true; // Create the iteration variable for this array index. IdentifierInfo *IterationVarName = 0; { @@ -2009,24 +2480,30 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_RValue, Loc); assert(!IterationVarRef.isInvalid() && "Reference to invented variable cannot fail!"); - + // Subscript the array with this iteration variable. - CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CopyCtorArg.take(), - Loc, + CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc, IterationVarRef.take(), - Loc); - if (CopyCtorArg.isInvalid()) + Loc); + if (CtorArg.isInvalid()) return true; - + BaseType = Array->getElementType(); } - + + // The array subscript expression is an lvalue, which is wrong for moving. + if (Moving && InitializingArray) + CtorArg = CastForMoving(SemaRef, CtorArg.take()); + // Construct the entity that we will be initializing. For an array, this // will be first element in the array, which may require several levels // of array-subscript entities. - llvm::SmallVector<InitializedEntity, 4> Entities; + SmallVector<InitializedEntity, 4> Entities; Entities.reserve(1 + IndexVariables.size()); - Entities.push_back(InitializedEntity::InitializeMember(Field)); + if (Indirect) + Entities.push_back(InitializedEntity::InitializeMember(Indirect)); + else + Entities.push_back(InitializedEntity::InitializeMember(Field)); for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, 0, @@ -2036,22 +2513,31 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); - Expr *CopyCtorArgE = CopyCtorArg.takeAs<Expr>(); + Expr *CtorArgE = CtorArg.takeAs<Expr>(); InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, - &CopyCtorArgE, 1); + &CtorArgE, 1); ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, - MultiExprArg(&CopyCtorArgE, 1)); + MultiExprArg(&CtorArgE, 1)); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; - CXXMemberInit - = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, Loc, - MemberInit.takeAs<Expr>(), Loc, - IndexVariables.data(), - IndexVariables.size()); + if (Indirect) { + assert(IndexVariables.size() == 0 && + "Indirect field improperly initialized"); + CXXMemberInit + = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, + Loc, Loc, + MemberInit.takeAs<Expr>(), + Loc); + } else + CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, + Loc, MemberInit.takeAs<Expr>(), + Loc, + IndexVariables.data(), + IndexVariables.size()); return false; } @@ -2061,7 +2547,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, SemaRef.Context.getBaseElementType(Field->getType()); if (FieldBaseElementType->isRecordType()) { - InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializedEntity InitEntity + = Indirect? InitializedEntity::InitializeMember(Indirect) + : InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); @@ -2073,11 +2561,17 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, if (MemberInit.isInvalid()) return true; - CXXMemberInit = - new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, - Field, Loc, Loc, - MemberInit.get(), - Loc); + if (Indirect) + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, + Indirect, Loc, + Loc, + MemberInit.get(), + Loc); + else + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, + Field, Loc, Loc, + MemberInit.get(), + Loc); return false; } @@ -2129,21 +2623,37 @@ struct BaseAndFieldInfo { bool AnyErrorsInInits; ImplicitInitializerKind IIK; llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields; - llvm::SmallVector<CXXCtorInitializer*, 8> AllToInit; + SmallVector<CXXCtorInitializer*, 8> AllToInit; BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { - // FIXME: Handle implicit move constructors. - if (Ctor->isImplicit() && Ctor->isCopyConstructor()) + bool Generated = Ctor->isImplicit() || Ctor->isDefaulted(); + if (Generated && Ctor->isCopyConstructor()) IIK = IIK_Copy; + else if (Generated && Ctor->isMoveConstructor()) + IIK = IIK_Move; else IIK = IIK_Default; } }; } +/// \brief Determine whether the given indirect field declaration is somewhere +/// within an anonymous union. +static bool isWithinAnonymousUnion(IndirectFieldDecl *F) { + for (IndirectFieldDecl::chain_iterator C = F->chain_begin(), + CEnd = F->chain_end(); + C != CEnd; ++C) + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((*C)->getDeclContext())) + if (Record->isUnion()) + return true; + + return false; +} + static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, - FieldDecl *Top, FieldDecl *Field) { + FieldDecl *Field, + IndirectFieldDecl *Indirect = 0) { // Overwhelmingly common case: we have a direct initializer for this field. if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field)) { @@ -2155,53 +2665,26 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer()) { - Info.AllToInit.push_back( - new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, - SourceLocation(), - SourceLocation(), 0, - SourceLocation())); + CXXCtorInitializer *Init; + if (Indirect) + Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, + SourceLocation(), + SourceLocation(), 0, + SourceLocation()); + else + Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, + SourceLocation(), + SourceLocation(), 0, + SourceLocation()); + Info.AllToInit.push_back(Init); return false; } - if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) { - const RecordType *FieldClassType = Field->getType()->getAs<RecordType>(); - assert(FieldClassType && "anonymous struct/union without record type"); - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - - // Even though union members never have non-trivial default - // constructions in C++03, we still build member initializers for aggregate - // record types which can be union members, and C++0x allows non-trivial - // default constructors for union members, so we ensure that only one - // member is initialized for these. - if (FieldClassDecl->isUnion()) { - // First check for an explicit initializer for one field. - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(*FA)) { - Info.AllToInit.push_back(Init); - - // Once we've initialized a field of an anonymous union, the union - // field in the class is also initialized, so exit immediately. - return false; - } else if ((*FA)->isAnonymousStructOrUnion()) { - if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) - return true; - } - } - - // FIXME: C++0x unrestricted unions might call a default constructor here. - return false; - } else { - // For structs, we simply descend through to initialize all members where - // necessary. - for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), - EA = FieldClassDecl->field_end(); FA != EA; FA++) { - if (CollectFieldInitializer(SemaRef, Info, Top, *FA)) - return true; - } - } - } + // Don't build an implicit initializer for union members if none was + // explicitly specified. + if (Field->getParent()->isUnion() || + (Indirect && isWithinAnonymousUnion(Indirect))) + return false; // Don't try to build an implicit initializer if there were semantic // errors in any of the initializers (and therefore we might be @@ -2210,7 +2693,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, return false; CXXCtorInitializer *Init = 0; - if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, Init)) + if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field, + Indirect, Init)) return true; if (Init) @@ -2238,12 +2722,12 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, return false; } - + bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, CXXCtorInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { - if (Constructor->getDeclContext()->isDependentContext()) { + if (Constructor->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { @@ -2330,15 +2814,51 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, } // Fields. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - if ((*Field)->getType()->isIncompleteArrayType()) { - assert(ClassDecl->hasFlexibleArrayMember() && - "Incomplete array type is not valid"); + for (DeclContext::decl_iterator Mem = ClassDecl->decls_begin(), + MemEnd = ClassDecl->decls_end(); + Mem != MemEnd; ++Mem) { + if (FieldDecl *F = dyn_cast<FieldDecl>(*Mem)) { + // C++ [class.bit]p2: + // A declaration for a bit-field that omits the identifier declares an + // unnamed bit-field. Unnamed bit-fields are not members and cannot be + // initialized. + if (F->isUnnamedBitfield()) + continue; + + if (F->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // If we're not generating the implicit copy/move constructor, then we'll + // handle anonymous struct/union fields based on their individual + // indirect fields. + if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default) + continue; + + if (CollectFieldInitializer(*this, Info, F)) + HadError = true; continue; } - if (CollectFieldInitializer(*this, Info, *Field, *Field)) - HadError = true; + + // Beyond this point, we only consider default initialization. + if (Info.IIK != IIK_Default) + continue; + + if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) { + if (F->getType()->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // Initialize each field of an anonymous struct individually. + if (CollectFieldInitializer(*this, Info, F->getAnonField(), F)) + HadError = true; + + continue; + } } NumInitializers = Info.AllToInit.size(); @@ -2414,7 +2934,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, CXXCtorInitializer *Init = Inits[InitIndex]; if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order, Init->getSourceLocation()) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { ShouldCheckOrder = true; break; } @@ -2425,7 +2945,7 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // Build the list of bases and members in the order that they'll // actually be initialized. The explicit initializers should be in // this same order but may be missing things. - llvm::SmallVector<const void*, 32> IdealInitKeys; + SmallVector<const void*, 32> IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); @@ -2445,9 +2965,13 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) + E = ClassDecl->field_end(); Field != E; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - + } + unsigned NumIdealInits = IdealInitKeys.size(); unsigned IdealIndex = 0; @@ -2561,7 +3085,8 @@ bool CheckRedundantUnionInit(Sema &S, /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, - MemInitTy **meminits, unsigned NumMemInits, + CXXCtorInitializer **meminits, + unsigned NumMemInits, bool AnyErrors) { if (!ConstructorDecl) return; @@ -2630,8 +3155,9 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXRecordDecl *ClassDecl) { - // Ignore dependent contexts. - if (ClassDecl->isDependentContext()) + // Ignore dependent contexts. Also ignore unions, since their members never + // have destructors implicitly called. + if (ClassDecl->isDependentContext() || ClassDecl->isUnion()) return; // FIXME: all the access-control diagnostics are positioned on the @@ -2903,6 +3429,7 @@ struct CheckAbstractUsage { CheckPolymorphic(ReferenceTypeLoc) CheckPolymorphic(MemberPointerTypeLoc) CheckPolymorphic(BlockPointerTypeLoc) + CheckPolymorphic(AtomicTypeLoc) /// Handle all the types we haven't given a more specific /// implementation for above. @@ -3016,7 +3543,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (RecordDecl::field_iterator F = Record->field_begin(), FEnd = Record->field_end(); F != FEnd; ++F) { - if (F->hasInClassInitializer()) + if (F->hasInClassInitializer() || F->isUnnamedBitfield()) continue; if (F->getType()->isReferenceType() || @@ -3077,6 +3604,47 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that member function to be + // const. [...] The class of which that function is a member shall be + // a literal type. + // + // It's fine to diagnose constructors here too: such constructors cannot + // produce a constant expression, so are ill-formed (no diagnostic required). + // + // If the class has virtual bases, any constexpr members will already have + // been diagnosed by the checks performed on the member declaration, so + // suppress this (less useful) diagnostic. + if (LangOpts.CPlusPlus0x && !Record->isDependentType() && + !Record->isLiteral() && !Record->getNumVBases()) { + for (CXXRecordDecl::method_iterator M = Record->method_begin(), + MEnd = Record->method_end(); + M != MEnd; ++M) { + if ((*M)->isConstexpr()) { + switch (Record->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // If a template instantiates to a non-literal type, but its members + // instantiate to constexpr functions, the template is technically + // ill-formed, but we allow it for sanity. Such members are treated as + // non-constexpr. + (*M)->setConstexpr(false); + continue; + + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + RequireLiteralType((*M)->getLocation(), Context.getRecordType(Record), + PDiag(diag::err_constexpr_method_non_literal)); + break; + } + + // Only produce one error per class. + break; + } + } + } + // Declare inherited constructors. We do this eagerly here because: // - The standard requires an eager diagnostic for conflicting inherited // constructors from different classes. @@ -3114,12 +3682,14 @@ void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { break; case CXXMoveConstructor: + CheckExplicitlyDefaultedMoveConstructor(cast<CXXConstructorDecl>(*MI)); + break; + case CXXMoveAssignment: - Diag(MI->getLocation(), diag::err_defaulted_move_unsupported); + CheckExplicitlyDefaultedMoveAssignment(*MI); break; - default: - // FIXME: Do moves once they exist + case CXXInvalid: llvm_unreachable("non-special member explicitly defaulted!"); } } @@ -3176,7 +3746,7 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) { return; } - if (ShouldDeleteDefaultConstructor(CD)) { + if (ShouldDeleteSpecialMember(CD, CXXDefaultConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { @@ -3243,7 +3813,7 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) { return; } - if (ShouldDeleteCopyConstructor(CD)) { + if (ShouldDeleteSpecialMember(CD, CXXCopyConstructor)) { if (First) { CD->setDeletedAsWritten(); } else { @@ -3288,7 +3858,7 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); QualType ArgType = OperType->getArgType(0); - if (!ArgType->isReferenceType()) { + if (!ArgType->isLValueReferenceType()) { Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); HadError = true; } else { @@ -3340,6 +3910,155 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) { } } +void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) { + assert(CD->isExplicitlyDefaulted() && CD->isMoveConstructor()); + + // Whether this was the first-declared instance of the constructor. + bool First = CD == CD->getCanonicalDecl(); + + bool HadError = false; + if (CD->getNumParams() != 1) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_params) + << CD->getSourceRange(); + HadError = true; + } + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(CD->getParent())); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + // Check for parameter type matching. + // This is a move ctor so we know it's a cv-qualified rvalue reference to T. + QualType ArgType = CtorType->getArgType(0); + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified()) { + Diag(CD->getLocation(), diag::err_defaulted_move_ctor_const_param); + HadError = true; + } + + if (CtorType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXMoveConstructor, + PDiag(), + ExceptionType, SourceLocation(), + CtorType, CD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.ExtInfo = CtorType->getExtInfo(); + CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI)); + } + + if (HadError) { + CD->setInvalidDecl(); + return; + } + + if (ShouldDeleteSpecialMember(CD, CXXMoveConstructor)) { + if (First) { + CD->setDeletedAsWritten(); + } else { + Diag(CD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXMoveConstructor; + CD->setInvalidDecl(); + } + } +} + +void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) { + assert(MD->isExplicitlyDefaulted()); + + // Whether this was the first-declared instance of the operator + bool First = MD == MD->getCanonicalDecl(); + + bool HadError = false; + if (MD->getNumParams() != 1) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_params) + << MD->getSourceRange(); + HadError = true; + } + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + if (!ReturnType->isLValueReferenceType() || + !Context.hasSameType( + Context.getCanonicalType(ReturnType->getPointeeType()), + Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_return_type); + HadError = true; + } + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(MD->getParent())); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(), + *ExceptionType = Context.getFunctionType( + Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>(); + + QualType ArgType = OperType->getArgType(0); + if (!ArgType->isRValueReferenceType()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_not_ref); + HadError = true; + } else { + if (ArgType->getPointeeType().isVolatileQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_volatile_param); + HadError = true; + } + if (ArgType->getPointeeType().isConstQualified()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_const_param); + HadError = true; + } + } + + if (OperType->getTypeQuals()) { + Diag(MD->getLocation(), diag::err_defaulted_move_assign_quals); + HadError = true; + } + + if (OperType->hasExceptionSpec()) { + if (CheckEquivalentExceptionSpec( + PDiag(diag::err_incorrect_defaulted_exception_spec) + << CXXMoveAssignment, + PDiag(), + ExceptionType, SourceLocation(), + OperType, MD->getLocation())) { + HadError = true; + } + } else if (First) { + // We set the declaration to have the computed exception spec here. + // We duplicate the one parameter type. + EPI.RefQualifier = OperType->getRefQualifier(); + EPI.ExtInfo = OperType->getExtInfo(); + MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI)); + } + + if (HadError) { + MD->setInvalidDecl(); + return; + } + + if (ShouldDeleteMoveAssignmentOperator(MD)) { + if (First) { + MD->setDeletedAsWritten(); + } else { + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) + << CXXMoveAssignment; + MD->setInvalidDecl(); + } + } +} + void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { assert(DD->isExplicitlyDefaulted()); @@ -3381,30 +4100,53 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) { } } -bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { - CXXRecordDecl *RD = CD->getParent(); +/// This function implements the following C++0x paragraphs: +/// - [class.ctor]/5 +/// - [class.copy]/11 +bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) { + assert(!MD->isInvalidDecl()); + CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; - SourceLocation Loc = CD->getLocation(); + bool IsUnion = RD->isUnion(); + bool IsConstructor = false; + bool IsAssignment = false; + bool IsMove = false; + + bool ConstArg = false; - // Do access control from the constructor - ContextRAII CtorContext(*this, CD); + switch (CSM) { + case CXXDefaultConstructor: + IsConstructor = true; + break; + case CXXCopyConstructor: + IsConstructor = true; + ConstArg = MD->getParamDecl(0)->getType().isConstQualified(); + break; + case CXXMoveConstructor: + IsConstructor = true; + IsMove = true; + break; + default: + llvm_unreachable("function only currently implemented for default ctors"); + } + + SourceLocation Loc = MD->getLocation(); + + // Do access control from the special member function + ContextRAII MethodContext(*this, MD); - bool Union = RD->isUnion(); bool AllConst = true; // We do this because we should never actually use an anonymous // union's constructor. - if (Union && RD->isAnonymousStructOrUnion()) + if (IsUnion && RD->isAnonymousStructOrUnion()) return false; // FIXME: We should put some diagnostic logic right into this function. - // C++0x [class.ctor]/5 - // A defaulted default constructor for class X is defined as deleted if: - for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) { @@ -3415,26 +4157,41 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [direct base class] has a type with a destructor that is - // deleted or inaccessible from the defaulted default constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; + // Unless we have an assignment operator, the base's destructor must + // be accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } - // -- any [direct base class either] has no default constructor or - // overload resolution as applied to [its] default constructor - // results in an ambiguity or in a function that is deleted or - // inaccessible from the defaulted default constructor - CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); - if (!BaseDefault || BaseDefault->isDeleted()) - return true; + // Finding the corresponding member in the base should lead to a + // unique, accessible, non-deleted function. If we are doing + // a destructor, we have already checked this case. + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + CXXMethodDecl *BaseMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember); + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), + PDiag()) != AR_accessible) + return true; - if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), - PDiag()) != AR_accessible) - return true; + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !BaseCtor->isMoveConstructor() && + !BaseDecl->isTriviallyCopyable()) + return true; + } + } } for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), @@ -3443,69 +4200,76 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [virtual base class] has a type with a destructor that is - // delete or inaccessible from the defaulted default constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; + // Unless we have an assignment operator, the base's destructor must + // be accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); + if (BaseDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != + AR_accessible) + return true; + } - // -- any [virtual base class either] has no default constructor or - // overload resolution as applied to [its] default constructor - // results in an ambiguity or in a function that is deleted or - // inaccessible from the defaulted default constructor - CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl); - if (!BaseDefault || BaseDefault->isDeleted()) - return true; + // Finding the corresponding member in the base should lead to a + // unique, accessible, non-deleted function. + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(BaseDecl, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + CXXMethodDecl *BaseMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *BaseCtor = cast<CXXConstructorDecl>(BaseMember); + if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), + PDiag()) != AR_accessible) + return true; - if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(), - PDiag()) != AR_accessible) - return true; + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !BaseCtor->isMoveConstructor() && + !BaseDecl->isTriviallyCopyable()) + return true; + } + } } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { - if (FI->isInvalidDecl()) + if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) continue; QualType FieldType = Context.getBaseElementType(FI->getType()); CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); - // -- any non-static data member with no brace-or-equal-initializer is of - // reference type - if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) - return true; - - // -- X is a union and all its variant members are of const-qualified type - // (or array thereof) - if (Union && !FieldType.isConstQualified()) - AllConst = false; - - if (FieldRecord) { - // -- X is a union-like class that has a variant member with a non-trivial - // default constructor - if (Union && !FieldRecord->hasTrivialDefaultConstructor()) + // For a default constructor, all references must be initialized in-class + // and, if a union, it must have a non-const member. + if (CSM == CXXDefaultConstructor) { + if (FieldType->isReferenceType() && !FI->hasInClassInitializer()) return true; - CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); - if (FieldDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != - AR_accessible) + if (IsUnion && !FieldType.isConstQualified()) + AllConst = false; + // For a copy constructor, data members must not be of rvalue reference + // type. + } else if (CSM == CXXCopyConstructor) { + if (FieldType->isRValueReferenceType()) return true; + } - // -- any non-variant non-static data member of const-qualified type (or - // array thereof) with no brace-or-equal-initializer does not have a - // user-provided default constructor - if (FieldType.isConstQualified() && + if (FieldRecord) { + // For a default constructor, a const member must have a user-provided + // default constructor or else be explicitly initialized. + if (CSM == CXXDefaultConstructor && FieldType.isConstQualified() && !FI->hasInClassInitializer() && !FieldRecord->hasUserProvidedDefaultConstructor()) return true; - if (!Union && FieldRecord->isUnion() && + // Some additional restrictions exist on the variant members. + if (!IsUnion && FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) { // We're okay to reuse AllConst here since we only care about the // value otherwise if we're in a union. @@ -3521,12 +4285,49 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { if (!UnionFieldType.isConstQualified()) AllConst = false; - if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialDefaultConstructor()) - return true; + if (UnionFieldRecord) { + // FIXME: Checking for accessibility and validity of this + // destructor is technically going beyond the + // standard, but this is believed to be a defect. + if (!IsAssignment) { + CXXDestructorDecl *FieldDtor = LookupDestructor(UnionFieldRecord); + if (FieldDtor->isDeleted()) + return true; + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + if (!FieldDtor->isTrivial()) + return true; + } + + if (CSM != CXXDestructor) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(UnionFieldRecord, CSM, ConstArg, false, + false, false, false); + // FIXME: Checking for accessibility and validity of this + // corresponding member is technically going beyond the + // standard, but this is believed to be a defect. + if (!SMOR->hasSuccess()) + return true; + + CXXMethodDecl *FieldMember = SMOR->getMethod(); + // A member of a union must have a trivial corresponding + // constructor. + if (!FieldMember->isTrivial()) + return true; + + if (IsConstructor) { + CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember); + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + } + } + } } - if (AllConst) + // At least one member in each anonymous union must be non-const + if (CSM == CXXDefaultConstructor && AllConst) return true; // Don't try to initialize the anonymous union @@ -3534,51 +4335,81 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) { continue; } - // -- any non-static data member with no brace-or-equal-initializer has - // class type M (or array thereof) and either M has no default - // constructor or overload resolution as applied to M's default - // constructor results in an ambiguity or in a function that is deleted - // or inaccessible from the defaulted default constructor. - if (!FI->hasInClassInitializer()) { - CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord); - if (!FieldDefault || FieldDefault->isDeleted()) + // Unless we're doing assignment, the field's destructor must be + // accessible and not deleted. + if (!IsAssignment) { + CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); + if (FieldDtor->isDeleted()) return true; - if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(), - PDiag()) != AR_accessible) + if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != + AR_accessible) + return true; + } + + // Check that the corresponding member of the field is accessible, + // unique, and non-deleted. We don't do this if it has an explicit + // initialization when default-constructing. + if (CSM != CXXDestructor && + (CSM != CXXDefaultConstructor || !FI->hasInClassInitializer())) { + SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(FieldRecord, CSM, ConstArg, false, false, false, + false); + if (!SMOR->hasSuccess()) + return true; + + CXXMethodDecl *FieldMember = SMOR->getMethod(); + if (IsConstructor) { + CXXConstructorDecl *FieldCtor = cast<CXXConstructorDecl>(FieldMember); + if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), + PDiag()) != AR_accessible) + return true; + + // For a move operation, the corresponding operation must actually + // be a move operation (and not a copy selected by overload + // resolution) unless we are working on a trivially copyable class. + if (IsMove && !FieldCtor->isMoveConstructor() && + !FieldRecord->isTriviallyCopyable()) + return true; + } + + // We need the corresponding member of a union to be trivial so that + // we can safely copy them all simultaneously. + // FIXME: Note that performing the check here (where we rely on the lack + // of an in-class initializer) is technically ill-formed. However, this + // seems most obviously to be a bug in the standard. + if (IsUnion && !FieldMember->isTrivial()) return true; } - } else if (!Union && FieldType.isConstQualified() && - !FI->hasInClassInitializer()) { - // -- any non-variant non-static data member of const-qualified type (or - // array thereof) with no brace-or-equal-initializer does not have a - // user-provided default constructor + } else if (CSM == CXXDefaultConstructor && !IsUnion && + FieldType.isConstQualified() && !FI->hasInClassInitializer()) { + // We can't initialize a const member of non-class type to any value. return true; } } - if (Union && AllConst) + // We can't have all const members in a union when default-constructing, + // or else they're all nonsensical garbage values that can't be changed. + if (CSM == CXXDefaultConstructor && IsUnion && AllConst) return true; return false; } -bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { - CXXRecordDecl *RD = CD->getParent(); +bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; - SourceLocation Loc = CD->getLocation(); + SourceLocation Loc = MD->getLocation(); // Do access control from the constructor - ContextRAII CtorContext(*this, CD); + ContextRAII MethodContext(*this, MD); bool Union = RD->isUnion(); - assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() && - "copy assignment arg has no pointee type"); unsigned ArgQuals = - CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? + MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? Qualifiers::Const : 0; // We do this because we should never actually use an anonymous @@ -3588,8 +4419,9 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { // FIXME: We should put some diagnostic logic right into this function. - // C++0x [class.copy]/11 - // A defaulted [copy] constructor for class X is defined as delete if X has: + // C++0x [class.copy]/20 + // A defaulted [copy] assignment operator for class X is defined as deleted + // if X has: for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); @@ -3602,24 +4434,15 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [direct base class] of a type with a destructor that is deleted or - // inaccessible from the defaulted constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; - // -- a [direct base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] constructor, results in an - // ambiguity or a function that is deleted or inaccessible from the - // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); - if (!BaseCtor || BaseCtor->isDeleted()) + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != - AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } @@ -3630,35 +4453,32 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- any [virtual base class] of a type with a destructor that is deleted or - // inaccessible from the defaulted constructor - CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl); - if (BaseDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) != - AR_accessible) - return true; - // -- a [virtual base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] constructor, results in an - // ambiguity or a function that is deleted or inaccessible from the - // defaulted constructor - CXXConstructorDecl *BaseCtor = LookupCopyingConstructor(BaseDecl, ArgQuals); - if (!BaseCtor || BaseCtor->isDeleted()) + // resolution, as applied to B's [copy] assignment operator, results in + // an ambiguity or a function that is deleted or inaccessible from the + // assignment operator + CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, + 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) != - AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); - // -- for a copy constructor, a non-static data member of rvalue reference - // type - if (FieldType->isRValueReferenceType()) + // -- a non-static data member of reference type + if (FieldType->isReferenceType()) + return true; + + // -- a non-static data member of const non-class type (or array thereof) + if (FieldType.isConstQualified() && !FieldType->isRecordType()) return true; CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); @@ -3675,42 +4495,27 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); - // -- a variant member with a non-trivial [copy] constructor and X - // is a union-like class + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialCopyConstructor()) + !UnionFieldRecord->hasTrivialCopyAssignment()) return true; } } // Don't try to initalize an anonymous union continue; - } else { - // -- a variant member with a non-trivial [copy] constructor and X is a - // union-like class - if (Union && !FieldRecord->hasTrivialCopyConstructor()) - return true; - - // -- any [non-static data member] of a type with a destructor that is - // deleted or inaccessible from the defaulted constructor - CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord); - if (FieldDtor->isDeleted()) - return true; - if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) != - AR_accessible) + // -- a variant member with a non-trivial [copy] assignment operator + // and X is a union-like class + } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { return true; } - // -- a [non-static data member of class type (or array thereof)] B that - // cannot be [copied] because overload resolution, as applied to B's - // [copy] constructor, results in an ambiguity or a function that is - // deleted or inaccessible from the defaulted constructor - CXXConstructorDecl *FieldCtor = LookupCopyingConstructor(FieldRecord, - ArgQuals); - if (!FieldCtor || FieldCtor->isDeleted()) + CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals, + false, 0); + if (!CopyOper || CopyOper->isDeleted()) return true; - if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(), - PDiag()) != AR_accessible) + if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) return true; } } @@ -3718,7 +4523,7 @@ bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) { return false; } -bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { +bool Sema::ShouldDeleteMoveAssignmentOperator(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) @@ -3731,66 +4536,52 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { bool Union = RD->isUnion(); - unsigned ArgQuals = - MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ? - Qualifiers::Const : 0; - // We do this because we should never actually use an anonymous // union's constructor. if (Union && RD->isAnonymousStructOrUnion()) return false; - // FIXME: We should put some diagnostic logic right into this function. - - // C++0x [class.copy]/11 - // A defaulted [copy] assignment operator for class X is defined as deleted + // C++0x [class.copy]/20 + // A defaulted [move] assignment operator for class X is defined as deleted // if X has: + // -- for the move constructor, [...] any direct or indirect virtual base + // class. + if (RD->getNumVBases() != 0) + return true; + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) { - // We'll handle this one later - if (BI->isVirtual()) - continue; QualType BaseType = BI->getType(); CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); assert(BaseDecl && "base isn't a CXXRecordDecl"); - // -- a [direct base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] assignment operator, results in + // -- a [direct base class] B that cannot be [moved] because overload + // resolution, as applied to B's [move] assignment operator, results in // an ambiguity or a function that is deleted or inaccessible from the // assignment operator - CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, - 0); - if (!CopyOper || CopyOper->isDeleted()) + CXXMethodDecl *MoveOper = LookupMovingAssignment(BaseDecl, false, 0); + if (!MoveOper || MoveOper->isDeleted()) return true; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) + if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible) return true; - } - for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), - BE = RD->vbases_end(); - BI != BE; ++BI) { - QualType BaseType = BI->getType(); - CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl(); - assert(BaseDecl && "base isn't a CXXRecordDecl"); - - // -- a [virtual base class] B that cannot be [copied] because overload - // resolution, as applied to B's [copy] assignment operator, results in - // an ambiguity or a function that is deleted or inaccessible from the - // assignment operator - CXXMethodDecl *CopyOper = LookupCopyingAssignment(BaseDecl, ArgQuals, false, - 0); - if (!CopyOper || CopyOper->isDeleted()) - return true; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) + // -- for the move assignment operator, a [direct base class] with a type + // that does not have a move assignment operator and is not trivially + // copyable. + if (!MoveOper->isMoveAssignmentOperator() && + !BaseDecl->isTriviallyCopyable()) return true; } for (CXXRecordDecl::field_iterator FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isUnnamedBitfield()) + continue; + QualType FieldType = Context.getBaseElementType(FI->getType()); // -- a non-static data member of reference type @@ -3800,7 +4591,7 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { // -- a non-static data member of const non-class type (or array thereof) if (FieldType.isConstQualified() && !FieldType->isRecordType()) return true; - + CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl(); if (FieldRecord) { @@ -3815,28 +4606,34 @@ bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) { CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl(); - // -- a variant member with a non-trivial [copy] assignment operator + // -- a variant member with a non-trivial [move] assignment operator // and X is a union-like class if (UnionFieldRecord && - !UnionFieldRecord->hasTrivialCopyAssignment()) + !UnionFieldRecord->hasTrivialMoveAssignment()) return true; } } // Don't try to initalize an anonymous union continue; - // -- a variant member with a non-trivial [copy] assignment operator + // -- a variant member with a non-trivial [move] assignment operator // and X is a union-like class - } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) { + } else if (Union && !FieldRecord->hasTrivialMoveAssignment()) { return true; } - CXXMethodDecl *CopyOper = LookupCopyingAssignment(FieldRecord, ArgQuals, - false, 0); - if (!CopyOper || CopyOper->isDeleted()) - return false; - if (CheckDirectMemberAccess(Loc, CopyOper, PDiag()) != AR_accessible) - return false; + CXXMethodDecl *MoveOper = LookupMovingAssignment(FieldRecord, false, 0); + if (!MoveOper || MoveOper->isDeleted()) + return true; + if (CheckDirectMemberAccess(Loc, MoveOper, PDiag()) != AR_accessible) + return true; + + // -- for the move assignment operator, a [non-static data member] with a + // type that does not have a move assignment operator and is not + // trivially copyable. + if (!MoveOper->isMoveAssignmentOperator() && + !FieldRecord->isTriviallyCopyable()) + return true; } } @@ -3959,7 +4756,7 @@ namespace { Sema *S; CXXMethodDecl *Method; llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; - llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods; + SmallVector<CXXMethodDecl *, 8> OverloadedMethods; }; } @@ -3978,7 +4775,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, assert(Name.getNameKind() == DeclarationName::Identifier); bool foundSameNameMethod = false; - llvm::SmallVector<CXXMethodDecl *, 8> overloadedMethods; + SmallVector<CXXMethodDecl *, 8> overloadedMethods; for (Path.Decls = BaseRecord->lookup(Name); Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { @@ -4009,7 +4806,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, /// overriding any. void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual, - MD->getLocation()) == Diagnostic::Ignored) + MD->getLocation()) == DiagnosticsEngine::Ignored) return; if (MD->getDeclName().getNameKind() != DeclarationName::Identifier) return; @@ -4058,10 +4855,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, AdjustDeclIfTemplate(TagDecl); - ActOnFields(S, RLoc, TagDecl, + ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( // strict aliasing violation! reinterpret_cast<Decl**>(FieldCollector->getCurFields()), - FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); + FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); CheckCompletedCXXClass( dyn_cast_or_null<CXXRecordDecl>(TagDecl)); @@ -4946,7 +5743,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, IdentLoc, Named, CommonAncestor); if (IsUsingDirectiveInToplevelContext(CurContext) && - !SourceMgr.isFromMainFile(SourceMgr.getInstantiationLoc(IdentLoc))) { + !SourceMgr.isFromMainFile(SourceMgr.getExpansionLoc(IdentLoc))) { Diag(IdentLoc, diag::warn_using_directive_in_header); } @@ -5361,7 +6158,6 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Otherwise, look up the target name. LookupResult R(*this, NameInfo, LookupOrdinaryName); - R.setUsingDeclaration(true); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration @@ -5968,7 +6764,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); @@ -5981,7 +6779,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); - if (ShouldDeleteDefaultConstructor(DefaultCon)) + if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) DefaultCon->setDeletedAsWritten(); return DefaultCon; @@ -6075,7 +6873,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // We start with an initial pass over the base classes to collect those that // inherit constructors from. If there are none, we can forgo all further // processing. - typedef llvm::SmallVector<const RecordType *, 4> BasesVector; + typedef SmallVector<const RecordType *, 4> BasesVector; BasesVector BasesToInheritFrom; for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), BaseE = ClassDecl->bases_end(); @@ -6171,7 +6969,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { if (params == maxParams) NewCtorType = BaseCtorType; else { - llvm::SmallVector<QualType, 16> Args; + SmallVector<QualType, 16> Args; for (unsigned i = 0; i < params; ++i) { Args.push_back(BaseCtorType->getArgType(i)); } @@ -6219,16 +7017,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // OK, we're there, now add the constructor. // C++0x [class.inhctor]p8: [...] that would be performed by a - // user-writtern inline constructor [...] + // user-written inline constructor [...] DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true); + /*ImplicitlyDeclared=*/true, + // FIXME: Due to a defect in the standard, we treat inherited + // constructors as constexpr even if that makes them ill-formed. + /*Constexpr=*/BaseCtor->isConstexpr()); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. - llvm::SmallVector<ParmVarDecl *, 16> ParamDecls; + SmallVector<ParmVarDecl *, 16> ParamDecls; for (unsigned i = 0; i < params; ++i) { ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc, UsingLoc, @@ -6237,7 +7038,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { /*TInfo=*/0, SC_None, SC_None, /*DefaultArg=*/0)); } - NewCtor->setParams(ParamDecls.data(), ParamDecls.size()); + NewCtor->setParams(ParamDecls); NewCtor->setInheritedConstructor(BaseCtor); PushOnScopeChains(NewCtor, S, false); @@ -6365,7 +7166,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, SourceLocation Loc = Destructor->getLocation(); Destructor->setBody(new (Context) CompoundStmt(Context, 0, 0, Loc, Loc)); - + Destructor->setImplicitlyDefined(true); Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -6388,8 +7189,10 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, ImplicitExceptionSpecification exceptSpec = ComputeDefaultedDtorExceptionSpec(classDecl); - // Replace the destructor's type. - FunctionProtoType::ExtProtoInfo epi; + // Replace the destructor's type, building off the existing one. Fortunately, + // the only thing of interest in the destructor type is its extended info. + // The return and arguments are fixed. + FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); epi.NumExceptions = exceptSpec.size(); epi.Exceptions = exceptSpec.data(); @@ -6403,41 +7206,45 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, // However, we don't have a body yet, so it needs to be done somewhere else. } -/// \brief Builds a statement that copies the given entity from \p From to +/// \brief Builds a statement that copies/moves the given entity from \p From to /// \c To. /// -/// This routine is used to copy the members of a class with an -/// implicitly-declared copy assignment operator. When the entities being +/// This routine is used to copy/move the members of a class with an +/// implicitly-declared copy/move assignment operator. When the entities being /// copied are arrays, this routine builds for loops to copy them. /// /// \param S The Sema object used for type-checking. /// -/// \param Loc The location where the implicit copy is being generated. +/// \param Loc The location where the implicit copy/move is being generated. /// -/// \param T The type of the expressions being copied. Both expressions must -/// have this type. +/// \param T The type of the expressions being copied/moved. Both expressions +/// must have this type. /// -/// \param To The expression we are copying to. +/// \param To The expression we are copying/moving to. /// -/// \param From The expression we are copying from. +/// \param From The expression we are copying/moving from. /// -/// \param CopyingBaseSubobject Whether we're copying a base subobject. +/// \param CopyingBaseSubobject Whether we're copying/moving a base subobject. /// Otherwise, it's a non-static member subobject. /// +/// \param Copying Whether we're copying or moving. +/// /// \param Depth Internal parameter recording the depth of the recursion. /// /// \returns A statement or a loop that copies the expressions. static StmtResult BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Expr *To, Expr *From, - bool CopyingBaseSubobject, unsigned Depth = 0) { - // C++0x [class.copy]p30: + bool CopyingBaseSubobject, bool Copying, + unsigned Depth = 0) { + // C++0x [class.copy]p28: // Each subobject is assigned in the manner appropriate to its type: // - // - if the subobject is of class type, the copy assignment operator - // for the class is used (as if by explicit qualification; that is, - // ignoring any possible virtual overriding functions in more derived - // classes); + // - if the subobject is of class type, as if by a call to operator= with + // the subobject as the object expression and the corresponding + // subobject of x as a single function argument (as if by explicit + // qualification; that is, ignoring any possible virtual overriding + // functions in more derived classes); if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -6447,14 +7254,15 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(OpLookup, ClassDecl, false); - // Filter out any result that isn't a copy-assignment operator. + // Filter out any result that isn't a copy/move-assignment operator. LookupResult::Filter F = OpLookup.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - if (Method->isCopyAssignmentOperator()) + if (Copying ? Method->isCopyAssignmentOperator() : + Method->isMoveAssignmentOperator()) continue; - + F.erase(); } F.done(); @@ -6573,11 +7381,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, IterationVarRef, Loc)); To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc, IterationVarRef, Loc)); - - // Build the copy for an individual element of the array. + if (!Copying) // Cast to rvalue + From = CastForMoving(S, From); + + // Build the copy/move for an individual element of the array. StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), To, From, CopyingBaseSubobject, - Depth + 1); + Copying, Depth + 1); if (Copy.isInvalid()) return StmtError(); @@ -6733,7 +7543,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, - /*isInline=*/true, + /*isInline=*/true, /*isConstexpr=*/false, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); @@ -6746,7 +7556,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ArgType, /*TInfo=*/0, SC_None, SC_None, 0); - CopyAssignment->setParams(&FromParam, 1); + CopyAssignment->setParams(FromParam); // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; @@ -6857,7 +7667,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, To.get(), From, - /*CopyingBaseSubobject=*/true); + /*CopyingBaseSubobject=*/true, + /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); @@ -6878,6 +7689,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + // Check for members of reference type; we can't copy those. if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) @@ -6902,9 +7716,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } // Suppress assigning zero-width bitfields. - if (const Expr *Width = Field->getBitWidth()) - if (Width->EvaluateAsInt(Context) == 0) - continue; + if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + continue; QualType FieldType = Field->getType().getNonReferenceType(); if (FieldType->isIncompleteArrayType()) { @@ -6932,8 +7745,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // explicit assignments, do so. This optimization only applies for arrays // of scalars and arrays of class type with trivial copy-assignment // operators. - if (FieldType->isArrayType() && - BaseType.hasTrivialCopyAssignment(Context)) { + if (FieldType->isArrayType() && !FieldType.isVolatileQualified() + && BaseType.hasTrivialAssignment(Context, /*Copying=*/true)) { // Compute the size of the memory buffer to be copied. QualType SizeType = Context.getSizeType(); llvm::APInt Size(Context.getTypeSize(SizeType), @@ -7020,8 +7833,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy of this field. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, - To.get(), From.get(), - /*CopyingBaseSubobject=*/false); + To.get(), From.get(), + /*CopyingBaseSubobject=*/false, + /*Copying=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); @@ -7066,6 +7880,436 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) { + ImplicitExceptionSpecification ExceptSpec(Context); + + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // C++0x [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + + // It is unspecified whether or not an implicit move assignment operator + // attempts to deduplicate calls to assignment operators of virtual bases are + // made. As such, this exception specification is effectively unspecified. + // Based on a similar decision made for constness in C++0x, we're erring on + // the side of assuming such calls to be made regardless of whether they + // actually happen. + // Note that a move constructor is not implicitly declared when there are + // virtual bases, but it can still be user-declared and explicitly defaulted. + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + BaseEnd = ClassDecl->bases_end(); + Base != BaseEnd; ++Base) { + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + Base != BaseEnd; ++Base) { + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; + ++Field) { + QualType FieldType = Context.getBaseElementType((*Field)->getType()); + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) { + if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl, + false, 0)) + ExceptSpec.CalledDecl(MoveAssign); + } + } + + return ExceptSpec; +} + +CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { + // Note: The following rules are largely analoguous to the move + // constructor rules. + + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl)); + + QualType ArgType = Context.getTypeDeclType(ClassDecl); + QualType RetType = Context.getLValueReferenceType(ArgType); + ArgType = Context.getRValueReferenceType(ArgType); + + // An implicitly-declared move assignment operator is an inline public + // member of its class. + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); + CXXMethodDecl *MoveAssignment + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(RetType, &ArgType, 1, EPI), + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/SC_None, + /*isInline=*/true, + /*isConstexpr=*/false, + SourceLocation()); + MoveAssignment->setAccess(AS_public); + MoveAssignment->setDefaulted(); + MoveAssignment->setImplicit(); + MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment()); + + // Add the parameter to the operator. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, + ClassLoc, ClassLoc, /*Id=*/0, + ArgType, /*TInfo=*/0, + SC_None, + SC_None, 0); + MoveAssignment->setParams(FromParam); + + // Note that we have added this copy-assignment operator. + ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + + // C++0x [class.copy]p9: + // If the definition of a class X does not explicitly declare a move + // assignment operator, one will be implicitly declared as defaulted if and + // only if: + // [...] + // - the move assignment operator would not be implicitly defined as + // deleted. + if (ShouldDeleteMoveAssignmentOperator(MoveAssignment)) { + // Cache this result so that we don't try to generate this over and over + // on every lookup, leaking memory and wasting time. + ClassDecl->setFailedImplicitMoveAssignment(); + return 0; + } + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(MoveAssignment, S, false); + ClassDecl->addDecl(MoveAssignment); + + AddOverriddenMethods(ClassDecl, MoveAssignment); + return MoveAssignment; +} + +void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MoveAssignOperator) { + assert((MoveAssignOperator->isDefaulted() && + MoveAssignOperator->isOverloadedOperator() && + MoveAssignOperator->getOverloadedOperator() == OO_Equal && + !MoveAssignOperator->doesThisDeclarationHaveABody()) && + "DefineImplicitMoveAssignment called for wrong function"); + + CXXRecordDecl *ClassDecl = MoveAssignOperator->getParent(); + + if (ClassDecl->isInvalidDecl() || MoveAssignOperator->isInvalidDecl()) { + MoveAssignOperator->setInvalidDecl(); + return; + } + + MoveAssignOperator->setUsed(); + + ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator); + DiagnosticErrorTrap Trap(Diags); + + // C++0x [class.copy]p28: + // The implicitly-defined or move assignment operator for a non-union class + // X performs memberwise move assignment of its subobjects. The direct base + // classes of X are assigned first, in the order of their declaration in the + // base-specifier-list, and then the immediate non-static data members of X + // are assigned, in the order in which they were declared in the class + // definition. + + // The statements that form the synthesized function body. + ASTOwningVector<Stmt*> Statements(*this); + + // The parameter for the "other" object, which we are move from. + ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); + QualType OtherRefType = Other->getType()-> + getAs<RValueReferenceType>()->getPointeeType(); + assert(OtherRefType.getQualifiers() == 0 && + "Bad argument type of defaulted move assignment"); + + // Our location for everything implicitly-generated. + SourceLocation Loc = MoveAssignOperator->getLocation(); + + // Construct a reference to the "other" object. We'll be using this + // throughout the generated ASTs. + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); + assert(OtherRef && "Reference to parameter cannot fail!"); + // Cast to rvalue. + OtherRef = CastForMoving(*this, OtherRef); + + // Construct the "this" pointer. We'll be using this throughout the generated + // ASTs. + Expr *This = ActOnCXXThis(Loc).takeAs<Expr>(); + assert(This && "Reference to this cannot fail!"); + + // Assign base classes. + bool Invalid = false; + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Form the assignment: + // static_cast<Base*>(this)->Base::operator=(static_cast<Base&&>(other)); + QualType BaseType = Base->getType().getUnqualifiedType(); + if (!BaseType->isRecordType()) { + Invalid = true; + continue; + } + + CXXCastPath BasePath; + BasePath.push_back(Base); + + // Construct the "from" expression, which is an implicit cast to the + // appropriately-qualified base type. + Expr *From = OtherRef; + From = ImpCastExprToType(From, BaseType, CK_UncheckedDerivedToBase, + VK_XValue, &BasePath).take(); + + // Dereference "this". + ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); + + // Implicitly cast "this" to the appropriately-qualified base type. + To = ImpCastExprToType(To.take(), + Context.getCVRQualifiedType(BaseType, + MoveAssignOperator->getTypeQualifiers()), + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); + + // Build the move. + StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType, + To.get(), From, + /*CopyingBaseSubobject=*/true, + /*Copying=*/false); + if (Move.isInvalid()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + MoveAssignOperator->setInvalidDecl(); + return; + } + + // Success! Record the move. + Statements.push_back(Move.takeAs<Expr>()); + } + + // \brief Reference to the __builtin_memcpy function. + Expr *BuiltinMemCpyRef = 0; + // \brief Reference to the __builtin_objc_memmove_collectable function. + Expr *CollectableMemCpyRef = 0; + + // Assign non-static members. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + // Check for members of reference type; we can't move those. + if (Field->getType()->isReferenceType()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + continue; + } + + // Check for members of const-qualified, non-class type. + QualType BaseType = Context.getBaseElementType(Field->getType()); + if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { + Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + Diag(Field->getLocation(), diag::note_declared_at); + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + continue; + } + + // Suppress assigning zero-width bitfields. + if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + continue; + + QualType FieldType = Field->getType().getNonReferenceType(); + if (FieldType->isIncompleteArrayType()) { + assert(ClassDecl->hasFlexibleArrayMember() && + "Incomplete array type is not valid"); + continue; + } + + // Build references to the field in the object we're copying from and to. + CXXScopeSpec SS; // Intentionally empty + LookupResult MemberLookup(*this, Field->getDeclName(), Loc, + LookupMemberName); + MemberLookup.addDecl(*Field); + MemberLookup.resolveKind(); + ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); + ExprResult To = BuildMemberReferenceExpr(This, This->getType(), + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); + assert(!From.isInvalid() && "Implicit field reference cannot fail"); + assert(!To.isInvalid() && "Implicit field reference cannot fail"); + + assert(!From.get()->isLValue() && // could be xvalue or prvalue + "Member reference with rvalue base must be rvalue except for reference " + "members, which aren't allowed for move assignment."); + + // If the field should be copied with __builtin_memcpy rather than via + // explicit assignments, do so. This optimization only applies for arrays + // of scalars and arrays of class type with trivial move-assignment + // operators. + if (FieldType->isArrayType() && !FieldType.isVolatileQualified() + && BaseType.hasTrivialAssignment(Context, /*Copying=*/false)) { + // Compute the size of the memory buffer to be copied. + QualType SizeType = Context.getSizeType(); + llvm::APInt Size(Context.getTypeSize(SizeType), + Context.getTypeSizeInChars(BaseType).getQuantity()); + for (const ConstantArrayType *Array + = Context.getAsConstantArrayType(FieldType); + Array; + Array = Context.getAsConstantArrayType(Array->getElementType())) { + llvm::APInt ArraySize + = Array->getSize().zextOrTrunc(Size.getBitWidth()); + Size *= ArraySize; + } + + // Take the address of the field references for "from" and "to". We + // directly construct UnaryOperators here because semantic analysis + // does not permit us to take the address of an xvalue. + From = new (Context) UnaryOperator(From.get(), UO_AddrOf, + Context.getPointerType(From.get()->getType()), + VK_RValue, OK_Ordinary, Loc); + To = new (Context) UnaryOperator(To.get(), UO_AddrOf, + Context.getPointerType(To.get()->getType()), + VK_RValue, OK_Ordinary, Loc); + + bool NeedsCollectableMemCpy = + (BaseType->isRecordType() && + BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()); + + if (NeedsCollectableMemCpy) { + if (!CollectableMemCpyRef) { + // Create a reference to the __builtin_objc_memmove_collectable function. + LookupResult R(*this, + &Context.Idents.get("__builtin_objc_memmove_collectable"), + Loc, LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>(); + if (!CollectableMemCpy) { + // Something went horribly wrong earlier, and we will have + // complained about it. + Invalid = true; + continue; + } + + CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, + CollectableMemCpy->getType(), + VK_LValue, Loc, 0).take(); + assert(CollectableMemCpyRef && "Builtin reference cannot fail"); + } + } + // Create a reference to the __builtin_memcpy builtin function. + else if (!BuiltinMemCpyRef) { + LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, + LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>(); + if (!BuiltinMemCpy) { + // Something went horribly wrong earlier, and we will have complained + // about it. + Invalid = true; + continue; + } + + BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, + BuiltinMemCpy->getType(), + VK_LValue, Loc, 0).take(); + assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); + } + + ASTOwningVector<Expr*> CallArgs(*this); + CallArgs.push_back(To.takeAs<Expr>()); + CallArgs.push_back(From.takeAs<Expr>()); + CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); + ExprResult Call = ExprError(); + if (NeedsCollectableMemCpy) + Call = ActOnCallExpr(/*Scope=*/0, + CollectableMemCpyRef, + Loc, move_arg(CallArgs), + Loc); + else + Call = ActOnCallExpr(/*Scope=*/0, + BuiltinMemCpyRef, + Loc, move_arg(CallArgs), + Loc); + + assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); + Statements.push_back(Call.takeAs<Expr>()); + continue; + } + + // Build the move of this field. + StmtResult Move = BuildSingleCopyAssign(*this, Loc, FieldType, + To.get(), From.get(), + /*CopyingBaseSubobject=*/false, + /*Copying=*/false); + if (Move.isInvalid()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + MoveAssignOperator->setInvalidDecl(); + return; + } + + // Success! Record the copy. + Statements.push_back(Move.takeAs<Stmt>()); + } + + if (!Invalid) { + // Add a "return *this;" + ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This); + + StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get()); + if (Return.isInvalid()) + Invalid = true; + else { + Statements.push_back(Return.takeAs<Stmt>()); + + if (Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveAssignment << Context.getTagDeclType(ClassDecl); + Invalid = true; + } + } + } + + if (Invalid) { + MoveAssignOperator->setInvalidDecl(); + return; + } + + StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + /*isStmtExpr=*/false); + assert(!Body.isInvalid() && "Compound statement creation cannot fail"); + MoveAssignOperator->setBody(Body.takeAs<Stmt>()); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(MoveAssignOperator); + } +} + std::pair<Sema::ImplicitExceptionSpecification, bool> Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) { if (ClassDecl->isInvalidDecl()) @@ -7205,7 +8449,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); @@ -7220,7 +8466,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ArgType, /*TInfo=*/0, SC_None, SC_None, 0); - CopyConstructor->setParams(&FromParam, 1); + CopyConstructor->setParams(FromParam); if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); @@ -7232,7 +8478,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // deleted; ... if (ClassDecl->hasUserDeclaredMoveConstructor() || ClassDecl->hasUserDeclaredMoveAssignment() || - ShouldDeleteCopyConstructor(CopyConstructor)) + ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) CopyConstructor->setDeletedAsWritten(); return CopyConstructor; @@ -7262,19 +8508,184 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, MultiStmtArg(*this, 0, 0), /*isStmtExpr=*/false) .takeAs<Stmt>()); + CopyConstructor->setImplicitlyDefined(true); } CopyConstructor->setUsed(); - if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(CopyConstructor); } } +Sema::ImplicitExceptionSpecification +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) { + // C++ [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + ImplicitExceptionSpecification ExceptSpec(Context); + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // Direct base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), + BEnd = ClassDecl->bases_end(); + B != BEnd; ++B) { + if (B->isVirtual()) // Handled below. + continue; + + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + // Virtual base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), + BEnd = ClassDecl->vbases_end(); + B != BEnd; ++B) { + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(BaseClassDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + // Field constructors. + for (RecordDecl::field_iterator F = ClassDecl->field_begin(), + FEnd = ClassDecl->field_end(); + F != FEnd; ++F) { + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + ExceptSpec.SetDelayed(); + } else if (const RecordType *RecordTy + = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupMovingConstructor(FieldRecDecl); + // If this is a deleted function, add it anyway. This might be conformant + // with the standard. This might not. I'm not sure. It might not matter. + // In particular, the problem is that this function never gets called. It + // might just be ill-formed because this function attempts to refer to + // a deleted function here. + if (Constructor) + ExceptSpec.CalledDecl(Constructor); + } + } + + return ExceptSpec; +} + +CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( + CXXRecordDecl *ClassDecl) { + ImplicitExceptionSpecification Spec( + ComputeDefaultedMoveCtorExceptionSpec(ClassDecl)); + + QualType ClassType = Context.getTypeDeclType(ClassDecl); + QualType ArgType = Context.getRValueReferenceType(ClassType); + + FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); + + DeclarationName Name + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType)); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); + + // C++0x [class.copy]p11: + // An implicitly-declared copy/move constructor is an inline public + // member of its class. + CXXConstructorDecl *MoveConstructor + = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + Context.getFunctionType(Context.VoidTy, + &ArgType, 1, EPI), + /*TInfo=*/0, + /*isExplicit=*/false, + /*isInline=*/true, + /*isImplicitlyDeclared=*/true, + // FIXME: apply the rules for definitions here + /*isConstexpr=*/false); + MoveConstructor->setAccess(AS_public); + MoveConstructor->setDefaulted(); + MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor()); + + // Add the parameter to the constructor. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, + ClassLoc, ClassLoc, + /*IdentifierInfo=*/0, + ArgType, /*TInfo=*/0, + SC_None, + SC_None, 0); + MoveConstructor->setParams(FromParam); + + // C++0x [class.copy]p9: + // If the definition of a class X does not explicitly declare a move + // constructor, one will be implicitly declared as defaulted if and only if: + // [...] + // - the move constructor would not be implicitly defined as deleted. + if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) { + // Cache this result so that we don't try to generate this over and over + // on every lookup, leaking memory and wasting time. + ClassDecl->setFailedImplicitMoveConstructor(); + return 0; + } + + // Note that we have declared this constructor. + ++ASTContext::NumImplicitMoveConstructorsDeclared; + + if (Scope *S = getScopeForContext(ClassDecl)) + PushOnScopeChains(MoveConstructor, S, false); + ClassDecl->addDecl(MoveConstructor); + + return MoveConstructor; +} + +void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *MoveConstructor) { + assert((MoveConstructor->isDefaulted() && + MoveConstructor->isMoveConstructor() && + !MoveConstructor->doesThisDeclarationHaveABody()) && + "DefineImplicitMoveConstructor - call it for implicit move ctor"); + + CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); + assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); + + ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor); + DiagnosticErrorTrap Trap(Diags); + + if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) || + Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXMoveConstructor << Context.getTagDeclType(ClassDecl); + MoveConstructor->setInvalidDecl(); + } else { + MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(), + MoveConstructor->getLocation(), + MultiStmtArg(*this, 0, 0), + /*isStmtExpr=*/false) + .takeAs<Stmt>()); + MoveConstructor->setImplicitlyDefined(true); + } + + MoveConstructor->setUsed(); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(MoveConstructor); + } +} + ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, + bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { @@ -7297,8 +8708,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, - Elidable, move(ExprArgs), RequiresZeroInit, - ConstructKind, ParenRange); + Elidable, move(ExprArgs), HadMultipleCandidates, + RequiresZeroInit, ConstructKind, ParenRange); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -7307,6 +8718,7 @@ ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, + bool HadMultipleCandidates, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { @@ -7322,20 +8734,21 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, - Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, + Constructor, Elidable, Exprs, NumExprs, + HadMultipleCandidates, RequiresZeroInit, static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), ParenRange)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - MultiExprArg Exprs) { + MultiExprArg Exprs, + bool HadMultipleCandidates) { // FIXME: Provide the correct paren SourceRange when available. ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, - move(Exprs), false, CXXConstructExpr::CK_Complete, - SourceRange()); + move(Exprs), HadMultipleCandidates, false, + CXXConstructExpr::CK_Complete, SourceRange()); if (TempResult.isInvalid()) return true; @@ -7447,6 +8860,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, // class type. if (!VDecl->getType()->isDependentType() && + !VDecl->getType()->isIncompleteArrayType() && RequireCompleteType(VDecl->getLocation(), VDecl->getType(), diag::err_typecheck_decl_incomplete_type)) { VDecl->setInvalidDecl(); @@ -7522,18 +8936,34 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, = InitializationKind::CreateDirect(VDecl->getLocation(), LParenLoc, RParenLoc); + QualType T = VDecl->getType(); InitializationSequence InitSeq(*this, Entity, Kind, Exprs.get(), Exprs.size()); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs), &T); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; + } else if (T != VDecl->getType()) { + VDecl->setType(T); + Result.get()->setType(T); } - CheckImplicitConversions(Result.get(), LParenLoc); - Result = MaybeCreateExprWithCleanups(Result); - VDecl->setInit(Result.takeAs<Expr>()); + Expr *Init = Result.get(); + CheckImplicitConversions(Init, LParenLoc); + + if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() && + !Init->isValueDependent() && + !Init->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) { + // FIXME: Improve this diagnostic to explain why the initializer is not + // a constant expression. + Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init) + << VDecl << Init->getSourceRange(); + } + + Init = MaybeCreateExprWithCleanups(Init); + VDecl->setInit(Init); VDecl->setCXXDirectInitializer(true); CheckCompleteVariableDeclaration(VDecl); @@ -7566,7 +8996,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; - llvm::SmallVector<Expr *, 8> AllArgs; + SmallVector<Expr *, 8> AllArgs; bool Invalid = GatherArgumentsForCall(Loc, Constructor, Proto, 0, Args, NumArgs, AllArgs, CallType); @@ -7928,6 +9358,30 @@ FinishedParams: return true; } + StringRef LiteralName + = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); + if (LiteralName[0] != '_') { + // C++0x [usrlit.suffix]p1: + // Literal suffix identifiers that do not start with an underscore are + // reserved for future standardization. + bool IsHexFloat = true; + if (LiteralName.size() > 1 && + (LiteralName[0] == 'P' || LiteralName[0] == 'p')) { + for (unsigned I = 1, N = LiteralName.size(); I < N; ++I) { + if (!isdigit(LiteralName[I])) { + IsHexFloat = false; + break; + } + } + } + + if (IsHexFloat) + Diag(FnDecl->getLocation(), diag::warn_user_literal_hexfloat) + << LiteralName; + else + Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved); + } + return false; } @@ -7940,7 +9394,7 @@ FinishedParams: /// have any braces. Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - llvm::StringRef Lang, + StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; if (Lang == "\"C\"") @@ -8265,6 +9719,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, + /*ModulePrivateLoc=*/SourceLocation(), TempParamLists.size() - 1, (TemplateParameterList**) TempParamLists.release()).take(); } else { @@ -8427,7 +9882,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, return D; } -Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, +Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams) { const DeclSpec &DS = D.getDeclSpec(); @@ -8436,7 +9891,6 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, SourceLocation Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType T = TInfo->getType(); // C++ [class.friend]p1 // A friend of a class is a function or class.... @@ -8448,7 +9902,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // a declaration that does not use the syntactic form of a // function declarator to have a function type, the program // is ill-formed. - if (!T->isFunctionType()) { + if (!TInfo->getType()->isFunctionType()) { Diag(Loc, diag::err_unexpected_friend); // It might be worthwhile to try to recover by creating an @@ -8551,6 +10005,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, DCScope = getScopeForDeclContext(S, DC); + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + if (isLocal && D.isFunctionDefinition()) { + Diag(NameInfo.getBeginLoc(), diag::err_friend_def_in_local_class); + } + // - There's a non-dependent scope specifier, in which case we // compute it and do a previous lookup there for a function // or function template. @@ -8576,7 +10038,8 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, if (Previous.empty()) { D.setInvalidType(); - Diag(Loc, diag::err_qualified_friend_not_found) << Name << T; + Diag(Loc, diag::err_qualified_friend_not_found) + << Name << TInfo->getType(); return 0; } @@ -8584,6 +10047,20 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // class that is not a member of the class . . . if (DC->Equals(CurContext)) Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + + if (D.isFunctionDefinition()) { + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + SemaDiagnosticBuilder DB + = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); + + DB << SS.getScopeRep(); + if (DC->isFileContext()) + DB << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } // - There's a scope specifier that does not match any template // parameter lists, in which case we use some arbitrary context, @@ -8591,10 +10068,19 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, // - There's a scope specifier that does match some template // parameter lists, which we don't handle right now. } else { + if (D.isFunctionDefinition()) { + // C++ [class.friend]p6: + // A function can be defined in a friend declaration of a class if and + // only if the class is a non-local class (9.8), the function name is + // unqualified, and the function has namespace scope. + Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def) + << SS.getScopeRep(); + } + DC = CurContext; assert(isa<CXXRecordDecl>(DC) && "friend declaration not in class?"); } - + if (!DC->isRecord()) { // This implies that it has to be an operator or function. if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || @@ -8607,11 +10093,9 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, } } - bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous, - move(TemplateParams), - IsDefinition, - Redeclaration); + bool AddToScope = true; + NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous, + move(TemplateParams), AddToScope); if (!ND) return 0; assert(ND->getDeclContext() == DC); @@ -8732,15 +10216,24 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { break; } - case CXXMoveConstructor: - case CXXMoveAssignment: - Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported); + case CXXMoveConstructor: { + CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD); + CheckExplicitlyDefaultedMoveConstructor(CD); + if (!CD->isInvalidDecl()) + DefineImplicitMoveConstructor(DefaultLoc, CD); break; + } - default: - // FIXME: Do the rest once we have move functions + case CXXMoveAssignment: { + CheckExplicitlyDefaultedMoveAssignment(MD); + if (!MD->isInvalidDecl()) + DefineImplicitMoveAssignment(DefaultLoc, MD); break; } + + case CXXInvalid: + llvm_unreachable("Invalid special member."); + } } else { Diag(DefaultLoc, diag::err_default_special_members); } @@ -8934,6 +10427,30 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } +void Sema::LoadExternalVTableUses() { + if (!ExternalSource) + return; + + SmallVector<ExternalVTableUse, 4> VTables; + ExternalSource->ReadUsedVTables(VTables); + SmallVector<VTableUse, 4> NewUses; + for (unsigned I = 0, N = VTables.size(); I != N; ++I) { + llvm::DenseMap<CXXRecordDecl *, bool>::iterator Pos + = VTablesUsed.find(VTables[I].Record); + // Even if a definition wasn't required before, it may be required now. + if (Pos != VTablesUsed.end()) { + if (!Pos->second && VTables[I].DefinitionRequired) + Pos->second = true; + continue; + } + + VTablesUsed[VTables[I].Record] = VTables[I].DefinitionRequired; + NewUses.push_back(VTableUse(VTables[I].Record, VTables[I].Location)); + } + + VTableUses.insert(VTableUses.begin(), NewUses.begin(), NewUses.end()); +} + void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired) { // Ignore any vtable uses in unevaluated operands or for classes that do @@ -8944,6 +10461,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Try to insert this class into the map. + LoadExternalVTableUses(); Class = cast<CXXRecordDecl>(Class->getCanonicalDecl()); std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool> Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); @@ -8969,6 +10487,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, } bool Sema::DefineUsedVTables() { + LoadExternalVTableUses(); if (VTableUses.empty()) return false; @@ -9037,7 +10556,10 @@ bool Sema::DefineUsedVTables() { // Optionally warn if we're emitting a weak vtable. if (Class->getLinkage() == ExternalLinkage && Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { - if (!KeyFunction || (KeyFunction->hasBody() && KeyFunction->isInlined())) + const FunctionDecl *KeyFunctionDef = 0; + if (!KeyFunction || + (KeyFunction->hasBody(KeyFunctionDef) && + KeyFunctionDef->isInlined())) Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; } } @@ -9078,11 +10600,11 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { if (!getLangOptions().CPlusPlus) return; if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { - llvm::SmallVector<ObjCIvarDecl*, 8> ivars; + SmallVector<ObjCIvarDecl*, 8> ivars; CollectIvarsToConstructOrDestruct(OID, ivars); if (ivars.empty()) return; - llvm::SmallVector<CXXCtorInitializer*, 32> AllToInit; + SmallVector<CXXCtorInitializer*, 32> AllToInit; for (unsigned i = 0; i < ivars.size(); i++) { FieldDecl *Field = ivars[i]; if (Field->isInvalidDecl()) @@ -9199,8 +10721,8 @@ void Sema::CheckDelegatingCtorCycles() { llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(), CE = Current.end(); - for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator - I = DelegatingCtorDecls.begin(), + for (DelegatingCtorDeclsType::iterator + I = DelegatingCtorDecls.begin(ExternalSource), E = DelegatingCtorDecls.end(); I != E; ++I) { DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); @@ -9209,3 +10731,44 @@ void Sema::CheckDelegatingCtorCycles() { for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) (*CI)->setInvalidDecl(); } + +/// IdentifyCUDATarget - Determine the CUDA compilation target for this function +Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { + // Implicitly declared functions (e.g. copy constructors) are + // __host__ __device__ + if (D->isImplicit()) + return CFT_HostDevice; + + if (D->hasAttr<CUDAGlobalAttr>()) + return CFT_Global; + + if (D->hasAttr<CUDADeviceAttr>()) { + if (D->hasAttr<CUDAHostAttr>()) + return CFT_HostDevice; + else + return CFT_Device; + } + + return CFT_Host; +} + +bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, + CUDAFunctionTarget CalleeTarget) { + // CUDA B.1.1 "The __device__ qualifier declares a function that is... + // Callable from the device only." + if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) + return true; + + // CUDA B.1.2 "The __global__ qualifier declares a function that is... + // Callable from the host only." + // CUDA B.1.3 "The __host__ qualifier declares a function that is... + // Callable from the host only." + if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && + (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) + return true; + + if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) + return true; + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index aa8152b..62b4a7c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -106,7 +106,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method, return true; } -bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, +void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden, bool IsImplementation) { if (Overridden->hasRelatedResultType() && @@ -148,105 +148,44 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, << ResultTypeRange; } - Diag(Overridden->getLocation(), diag::note_related_result_type_overridden) - << Overridden->getMethodFamily(); + if (ObjCMethodFamily Family = Overridden->getMethodFamily()) + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden_family) + << Family; + else + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden); } - - return false; -} - -/// \brief Check for consistency between a given method declaration and the -/// methods it overrides within the class hierarchy. -/// -/// This method walks the inheritance hierarchy starting at the given -/// declaration context (\p DC), invoking Sema::CheckObjCMethodOverride() with -/// the given new method (\p NewMethod) and any method it directly overrides -/// in the hierarchy. Sema::CheckObjCMethodOverride() is responsible for -/// checking consistency, e.g., among return types for methods that return a -/// related result type. -static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod, - DeclContext *DC, - bool SkipCurrent = true) { - if (!DC) - return false; - - if (!SkipCurrent) { - // Look for this method. If we find it, we're done. - Selector Sel = NewMethod->getSelector(); - bool IsInstance = NewMethod->isInstanceMethod(); - DeclContext::lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isInstanceMethod() == IsInstance) - return S.CheckObjCMethodOverride(NewMethod, MD, false); + if (getLangOptions().ObjCAutoRefCount) { + if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() != + Overridden->hasAttr<NSReturnsRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::err_nsreturns_retained_attribute_mismatch) << 1; + Diag(Overridden->getLocation(), diag::note_previous_decl) + << "method"; } - } - - if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) { - // Look through categories. - for (ObjCCategoryDecl *Category = Class->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - if (CheckObjCMethodOverrides(S, NewMethod, Category, false)) - return true; + if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() != + Overridden->hasAttr<NSReturnsNotRetainedAttr>())) { + Diag(NewMethod->getLocation(), + diag::err_nsreturns_retained_attribute_mismatch) << 0; + Diag(Overridden->getLocation(), diag::note_previous_decl) + << "method"; + } + ObjCMethodDecl::param_const_iterator oi = Overridden->param_begin(); + for (ObjCMethodDecl::param_iterator + ni = NewMethod->param_begin(), ne = NewMethod->param_end(); + ni != ne; ++ni, ++oi) { + const ParmVarDecl *oldDecl = (*oi); + ParmVarDecl *newDecl = (*ni); + if (newDecl->hasAttr<NSConsumedAttr>() != + oldDecl->hasAttr<NSConsumedAttr>()) { + Diag(newDecl->getLocation(), + diag::err_nsconsumed_attribute_mismatch); + Diag(oldDecl->getLocation(), diag::note_previous_decl) + << "parameter"; + } } - - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(), - IEnd = Class->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - // Look in our superclass. - return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(), - false); - } - - if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) { - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(), - IEnd = Category->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - return false; - } - - if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) { - // Look through protocols. - for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(), - IEnd = Protocol->protocol_end(); - I != IEnd; ++I) - if (CheckObjCMethodOverrides(S, NewMethod, *I, false)) - return true; - - return false; } - - return false; -} - -bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, - DeclContext *DC) { - if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Class); - - if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Category); - - if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol); - - if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, - Impl->getClassInterface()); - - if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC)) - return ::CheckObjCMethodOverrides(*this, NewMethod, - CatImpl->getClassInterface()); - - return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext); } /// \brief Check a method declaration for compatibility with the Objective-C @@ -256,11 +195,13 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { switch (family) { case OMF_None: case OMF_dealloc: + case OMF_finalize: case OMF_retain: case OMF_release: case OMF_autorelease: case OMF_retainCount: case OMF_self: + case OMF_performSelector: return false; case OMF_init: @@ -286,11 +227,6 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) { method->hasAttr<NSReturnsAutoreleasedAttr>()) return false; break; - - case OMF_performSelector: - // we don't annotate performSelector's - return true; - } method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(), @@ -311,6 +247,20 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, } } +/// AddAnyMethodToGlobalPool - Add any method, instance or factory to global +/// pool. +void Sema::AddAnyMethodToGlobalPool(Decl *D) { + ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D); + + // If we don't have a valid method decl, simply return. + if (!MDecl) + return; + if (MDecl->isInstanceMethod()) + AddInstanceMethodToGlobalPool(MDecl, true); + else + AddFactoryMethodToGlobalPool(MDecl, true); +} + /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { @@ -321,12 +271,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { if (!MDecl) return; - // Allow the rest of sema to find private method decl implementations. - if (MDecl->isInstanceMethod()) - AddInstanceMethodToGlobalPool(MDecl, true); - else - AddFactoryMethodToGlobalPool(MDecl, true); - // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); PushFunctionScope(); @@ -365,6 +309,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { case OMF_None: case OMF_dealloc: + case OMF_finalize: case OMF_alloc: case OMF_init: case OMF_mutableCopy: @@ -376,14 +321,29 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { } } - // Warn on implementating deprecated methods under - // -Wdeprecated-implementations flag. - if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) + // Warn on deprecated methods under -Wdeprecated-implementations, + // and prepare for warning on missing super calls. + if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) { if (ObjCMethodDecl *IMD = IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod())) DiagnoseObjCImplementedDeprecations(*this, dyn_cast<NamedDecl>(IMD), MDecl->getLocation(), 0); + + // If this is "dealloc" or "finalize", set some bit here. + // Then in ActOnSuperMessage() (SemaExprObjC), set it back to false. + // Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set. + // Only do this if the current class actually has a superclass. + if (IC->getSuperClass()) { + ObjCShouldCallSuperDealloc = + !(Context.getLangOptions().ObjCAutoRefCount || + Context.getLangOptions().getGC() == LangOptions::GCOnly) && + MDecl->getMethodFamily() == OMF_dealloc; + ObjCShouldCallSuperFinalize = + Context.getLangOptions().getGC() != LangOptions::NonGC && + MDecl->getMethodFamily() == OMF_finalize; + } + } } Decl *Sema:: @@ -414,11 +374,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Return the previous class interface. // FIXME: don't leak the objects passed in! - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } else { - IDecl->setLocation(AtInterfaceLoc); + IDecl->setLocation(ClassLoc); IDecl->setForwardDecl(false); - IDecl->setClassLoc(ClassLoc); + IDecl->setAtStartLoc(AtInterfaceLoc); // If the forward decl was in a PCH, we need to write it again in a // dependent AST file. IDecl->setChangedSinceDeserialization(true); @@ -522,7 +482,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(IDecl); - return IDecl; + return ActOnObjCContainerStartDefinition(IDecl); } /// ActOnCompatiblityAlias - this action is called after complete parsing of @@ -618,7 +578,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, Diag(PDecl->getLocation(), diag::note_previous_definition); // Just return the protocol we already had. // FIXME: don't leak the objects passed in! - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } ObjCList<ObjCProtocolDecl> PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); @@ -626,14 +586,18 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); // Make sure the cached decl gets a valid start location. - PDecl->setLocation(AtProtoInterfaceLoc); + PDecl->setAtStartLoc(AtProtoInterfaceLoc); + PDecl->setLocation(ProtocolLoc); PDecl->setForwardDecl(false); + // Since this ObjCProtocolDecl was created by a forward declaration, + // we now add it to the DeclContext since it wasn't added before + PDecl->setLexicalDeclContext(CurContext); CurContext->addDecl(PDecl); // Repeat in dependent AST files. PDecl->setChangedSinceDeserialization(true); } else { - PDecl = ObjCProtocolDecl::Create(Context, CurContext, - AtProtoInterfaceLoc,ProtocolName); + PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, + ProtocolLoc, AtProtoInterfaceLoc); PushOnScopeChains(PDecl, TUScope); PDecl->setForwardDecl(false); } @@ -647,7 +611,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } CheckObjCDeclScope(PDecl); - return PDecl; + return ActOnObjCContainerStartDefinition(PDecl); } /// FindProtocolDeclaration - This routine looks up protocols and @@ -657,7 +621,7 @@ void Sema::FindProtocolDeclaration(bool WarnOnDeclarations, const IdentifierLocPair *ProtocolId, unsigned NumProtocols, - llvm::SmallVectorImpl<Decl *> &Protocols) { + SmallVectorImpl<Decl *> &Protocols) { for (unsigned i = 0; i != NumProtocols; ++i) { ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); @@ -725,16 +689,16 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, const IdentifierLocPair *IdentList, unsigned NumElts, AttributeList *attrList) { - llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; - llvm::SmallVector<SourceLocation, 8> ProtoLocs; + SmallVector<ObjCProtocolDecl*, 32> Protocols; + SmallVector<SourceLocation, 8> ProtoLocs; for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); bool isNew = false; if (PDecl == 0) { // Not already seen? - PDecl = ObjCProtocolDecl::Create(Context, CurContext, - IdentList[i].second, Ident); + PDecl = ObjCProtocolDecl::Create(Context, CurContext, Ident, + IdentList[i].second, AtProtocolLoc); PushOnScopeChains(PDecl, TUScope, false); isNew = true; } @@ -774,10 +738,10 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // the enclosing method declarations. We mark the decl invalid // to make it clear that this isn't a valid AST. CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName); + ClassLoc, CategoryLoc, CategoryName,IDecl); CDecl->setInvalidDecl(); Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } if (!CategoryName && IDecl->getImplementation()) { @@ -786,19 +750,6 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, diag::note_implementation_declared); } - CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, - ClassLoc, CategoryLoc, CategoryName); - // FIXME: PushOnScopeChains? - CurContext->addDecl(CDecl); - - CDecl->setClassInterface(IDecl); - // Insert class extension to the list of class's categories. - if (!CategoryName) - CDecl->insertNextClassCategory(); - - // If the interface is deprecated, warn about it. - (void)DiagnoseUseOfDecl(IDecl, ClassLoc); - if (CategoryName) { /// Check for duplicate interface declaration for this category ObjCCategoryDecl *CDeclChain; @@ -812,10 +763,13 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, break; } } - if (!CDeclChain) - CDecl->insertNextClassCategory(); } + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName, IDecl); + // FIXME: PushOnScopeChains? + CurContext->addDecl(CDecl); + if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -826,7 +780,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } /// ActOnStartCategoryImplementation - Perform semantic checks on the @@ -845,22 +799,26 @@ Decl *Sema::ActOnStartCategoryImplementation( // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), SourceLocation(), SourceLocation(), - CatName); - CatIDecl->setClassInterface(IDecl); - CatIDecl->insertNextClassCategory(); + CatName, IDecl); } } ObjCCategoryImplDecl *CDecl = - ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName, - IDecl); + ObjCCategoryImplDecl::Create(Context, CurContext, CatName, IDecl, + ClassLoc, AtCatImplLoc); /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) + if (!IDecl || IDecl->isForwardDecl()) { Diag(ClassLoc, diag::err_undef_interface) << ClassName; + CDecl->setInvalidDecl(); + } // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); + // If the interface is deprecated/unavailable, warn/error about it. + if (IDecl) + DiagnoseUseOfDecl(IDecl, ClassLoc); + /// Check that CatName, category name, is not used in another implementation. if (CatIDecl) { if (CatIDecl->getImplementation()) { @@ -879,7 +837,7 @@ Decl *Sema::ActOnStartCategoryImplementation( } CheckObjCDeclScope(CDecl); - return CDecl; + return ActOnObjCContainerStartDefinition(CDecl); } Decl *Sema::ActOnStartClassImplementation( @@ -969,11 +927,11 @@ Decl *Sema::ActOnStartClassImplementation( } ObjCImplementationDecl* IMPDecl = - ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc, - IDecl, SDecl); + ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, + ClassLoc, AtClassImplLoc); if (CheckObjCDeclScope(IMPDecl)) - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); // Check that there is no duplicate implementation of this class. if (IDecl->getImplementation()) { @@ -990,7 +948,7 @@ Decl *Sema::ActOnStartClassImplementation( dyn_cast<NamedDecl>(IDecl), IMPDecl->getLocation(), 1); } - return IMPDecl; + return ActOnObjCContainerStartDefinition(IMPDecl); } void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, @@ -1050,21 +1008,18 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, assert (ClsIvar && "missing class ivar"); // First, make sure the types match. - if (Context.getCanonicalType(ImplIvar->getType()) != - Context.getCanonicalType(ClsIvar->getType())) { + if (!Context.hasSameType(ImplIvar->getType(), ClsIvar->getType())) { Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type) << ImplIvar->getIdentifier() << ImplIvar->getType() << ClsIvar->getType(); Diag(ClsIvar->getLocation(), diag::note_previous_definition); - } else if (ImplIvar->isBitField() && ClsIvar->isBitField()) { - Expr *ImplBitWidth = ImplIvar->getBitWidth(); - Expr *ClsBitWidth = ClsIvar->getBitWidth(); - if (ImplBitWidth->EvaluateAsInt(Context).getZExtValue() != - ClsBitWidth->EvaluateAsInt(Context).getZExtValue()) { - Diag(ImplBitWidth->getLocStart(), diag::err_conflicting_ivar_bitwidth) - << ImplIvar->getIdentifier(); - Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition); - } + } else if (ImplIvar->isBitField() && ClsIvar->isBitField() && + ImplIvar->getBitWidthValue(Context) != + ClsIvar->getBitWidthValue(Context)) { + Diag(ImplIvar->getBitWidth()->getLocStart(), + diag::err_conflicting_ivar_bitwidth) << ImplIvar->getIdentifier(); + Diag(ClsIvar->getBitWidth()->getLocStart(), + diag::note_previous_definition); } // Make sure the names are identical. if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { @@ -1167,26 +1122,38 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) { return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange()); } -static void CheckMethodOverrideReturn(Sema &S, +static bool CheckMethodOverrideReturn(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsOverridingMode, + bool Warn) { if (IsProtocolMethodDecl && (MethodDecl->getObjCDeclQualifier() != MethodImpl->getObjCDeclQualifier())) { - S.Diag(MethodImpl->getLocation(), - diag::warn_conflicting_ret_type_modifiers) - << MethodImpl->getDeclName() - << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) - << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + if (Warn) { + S.Diag(MethodImpl->getLocation(), + (IsOverridingMode ? + diag::warn_conflicting_overriding_ret_type_modifiers + : diag::warn_conflicting_ret_type_modifiers)) + << MethodImpl->getDeclName() + << getTypeRange(MethodImpl->getResultTypeSourceInfo()); + S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) + << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + } + else + return false; } if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(), MethodDecl->getResultType())) - return; + return true; + if (!Warn) + return false; - unsigned DiagID = diag::warn_conflicting_ret_types; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_ret_types + : diag::warn_conflicting_ret_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1199,9 +1166,11 @@ static void CheckMethodOverrideReturn(Sema &S, // return types that are subclasses of the declared return type, // or that are more-qualified versions of the declared type. if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false)) - return; + return false; - DiagID = diag::warn_non_covariant_ret_types; + DiagID = + IsOverridingMode ? diag::warn_non_covariant_overriding_ret_types + : diag::warn_non_covariant_ret_types; } } @@ -1210,34 +1179,52 @@ static void CheckMethodOverrideReturn(Sema &S, << MethodDecl->getResultType() << MethodImpl->getResultType() << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_definition) + S.Diag(MethodDecl->getLocation(), + IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); + return false; } -static void CheckMethodOverrideParam(Sema &S, +static bool CheckMethodOverrideParam(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, ParmVarDecl *ImplVar, ParmVarDecl *IfaceVar, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsOverridingMode, + bool Warn) { if (IsProtocolMethodDecl && (ImplVar->getObjCDeclQualifier() != IfaceVar->getObjCDeclQualifier())) { - S.Diag(ImplVar->getLocation(), - diag::warn_conflicting_param_modifiers) - << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName(); - S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) - << getTypeRange(IfaceVar->getTypeSourceInfo()); + if (Warn) { + if (IsOverridingMode) + S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_overriding_param_modifiers) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName(); + else S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_param_modifiers) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName(); + S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) + << getTypeRange(IfaceVar->getTypeSourceInfo()); + } + else + return false; } QualType ImplTy = ImplVar->getType(); QualType IfaceTy = IfaceVar->getType(); if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) - return; - - unsigned DiagID = diag::warn_conflicting_param_types; + return true; + + if (!Warn) + return false; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_param_types + : diag::warn_conflicting_param_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1250,17 +1237,22 @@ static void CheckMethodOverrideParam(Sema &S, // implementation must accept any objects that the superclass // accepts, however it may also accept others. if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true)) - return; + return false; - DiagID = diag::warn_non_contravariant_param_types; + DiagID = + IsOverridingMode ? diag::warn_non_contravariant_overriding_param_types + : diag::warn_non_contravariant_param_types; } } S.Diag(ImplVar->getLocation(), DiagID) << getTypeRange(ImplVar->getTypeSourceInfo()) << MethodImpl->getDeclName() << IfaceTy << ImplTy; - S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) + S.Diag(IfaceVar->getLocation(), + (IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition)) << getTypeRange(IfaceVar->getTypeSourceInfo()); + return false; } /// In ARC, check whether the conventional meanings of the two methods @@ -1302,6 +1294,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, case OMF_release: case OMF_autorelease: case OMF_dealloc: + case OMF_finalize: case OMF_retainCount: case OMF_self: case OMF_performSelector: @@ -1341,20 +1334,86 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, return; CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, - IsProtocolMethodDecl); + IsProtocolMethodDecl, false, + true); for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); - IM != EM; ++IM, ++IF) + IM != EM; ++IM, ++IF) { CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF, - IsProtocolMethodDecl); + IsProtocolMethodDecl, false, true); + } if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); + Diag(ImpMethodDecl->getLocation(), + diag::warn_conflicting_variadic); Diag(MethodDecl->getLocation(), diag::note_previous_declaration); } } +void Sema::CheckConflictingOverridingMethod(ObjCMethodDecl *Method, + ObjCMethodDecl *Overridden, + bool IsProtocolMethodDecl) { + + CheckMethodOverrideReturn(*this, Method, Overridden, + IsProtocolMethodDecl, true, + true); + + for (ObjCMethodDecl::param_iterator IM = Method->param_begin(), + IF = Overridden->param_begin(), EM = Method->param_end(); + IM != EM; ++IM, ++IF) { + CheckMethodOverrideParam(*this, Method, Overridden, *IM, *IF, + IsProtocolMethodDecl, true, true); + } + + if (Method->isVariadic() != Overridden->isVariadic()) { + Diag(Method->getLocation(), + diag::warn_conflicting_overriding_variadic); + Diag(Overridden->getLocation(), diag::note_previous_declaration); + } +} + +/// WarnExactTypedMethods - This routine issues a warning if method +/// implementation declaration matches exactly that of its declaration. +void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl) { + // don't issue warning when protocol method is optional because primary + // class is not required to implement it and it is safe for protocol + // to implement it. + if (MethodDecl->getImplementationControl() == ObjCMethodDecl::Optional) + return; + // don't issue warning when primary class's method is + // depecated/unavailable. + if (MethodDecl->hasAttr<UnavailableAttr>() || + MethodDecl->hasAttr<DeprecatedAttr>()) + return; + + bool match = CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, + IsProtocolMethodDecl, false, false); + if (match) + for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), + IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); + IM != EM; ++IM, ++IF) { + match = CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, + *IM, *IF, + IsProtocolMethodDecl, false, false); + if (!match) + break; + } + if (match) + match = (ImpMethodDecl->isVariadic() == MethodDecl->isVariadic()); + if (match) + match = !(MethodDecl->isClassMethod() && + MethodDecl->getSelector() == GetNullarySelector("load", Context)); + + if (match) { + Diag(ImpMethodDecl->getLocation(), + diag::warn_category_method_impl_match); + Diag(MethodDecl->getLocation(), diag::note_method_declared_at); + } +} + /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely /// improve the efficiency of selector lookups and type checking by associating /// with each protocol / interface / category the flattened instance tables. If @@ -1416,7 +1475,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, if (!MethodInClass || !MethodInClass->isSynthesized()) { unsigned DIAG = diag::warn_unimplemented_protocol_method; if (Diags.getDiagnosticLevel(DIAG, ImpLoc) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); Diag(method->getLocation(), diag::note_method_declared_at); Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) @@ -1434,7 +1493,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, !ClsMap.count(method->getSelector()) && (!Super || !Super->lookupClassMethod(method->getSelector()))) { unsigned DIAG = diag::warn_unimplemented_protocol_method; - if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != Diagnostic::Ignored) { + if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != + DiagnosticsEngine::Ignored) { WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); Diag(method->getLocation(), diag::note_method_declared_at); Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << @@ -1458,7 +1518,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool &IncompleteImpl, - bool ImmediateClass) { + bool ImmediateClass, + bool WarnExactMatch) { // Check and see if instance methods in class interface have been // implemented in the implementation class. If so, their types match. for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(), @@ -1474,15 +1535,19 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, continue; } else { ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getInstanceMethod((*I)->getSelector()); - ObjCMethodDecl *MethodDecl = - CDecl->getInstanceMethod((*I)->getSelector()); - assert(MethodDecl && - "MethodDecl is null in ImplMethodsVsClassMethods"); + IMPDecl->getInstanceMethod((*I)->getSelector()); + assert(CDecl->getInstanceMethod((*I)->getSelector()) && + "Expected to find the method through lookup as well"); + ObjCMethodDecl *MethodDecl = *I; // ImpMethodDecl may be null as in a @dynamic property. - if (ImpMethodDecl) - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, - isa<ObjCProtocolDecl>(CDecl)); + if (ImpMethodDecl) { + if (!WarnExactMatch) + WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + else if (!MethodDecl->isSynthesized()) + WarnExactTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + } } } @@ -1500,10 +1565,15 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); - ObjCMethodDecl *MethodDecl = - CDecl->getClassMethod((*I)->getSelector()); - WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, - isa<ObjCProtocolDecl>(CDecl)); + assert(CDecl->getClassMethod((*I)->getSelector()) && + "Expected to find the method through lookup as well"); + ObjCMethodDecl *MethodDecl = *I; + if (!WarnExactMatch) + WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); + else + WarnExactTypedMethods(ImpMethodDecl, MethodDecl, + isa<ObjCProtocolDecl>(CDecl)); } } @@ -1514,7 +1584,7 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, const_cast<ObjCCategoryDecl *>(ClsExtDecl), - IncompleteImpl, false); + IncompleteImpl, false, WarnExactMatch); // Check for any implementation of a methods declared in protocol. for (ObjCInterfaceDecl::all_protocol_iterator @@ -1522,14 +1592,50 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, E = I->all_referenced_protocol_end(); PI != E; ++PI) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, - (*PI), IncompleteImpl, false); - if (I->getSuperClass()) + (*PI), IncompleteImpl, false, WarnExactMatch); + + // FIXME. For now, we are not checking for extact match of methods + // in category implementation and its primary class's super class. + if (!WarnExactMatch && I->getSuperClass()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, I->getSuperClass(), IncompleteImpl, false); } } +/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in +/// category matches with those implemented in its primary class and +/// warns each time an exact match is found. +void Sema::CheckCategoryVsClassMethodMatches( + ObjCCategoryImplDecl *CatIMPDecl) { + llvm::DenseSet<Selector> InsMap, ClsMap; + + for (ObjCImplementationDecl::instmeth_iterator + I = CatIMPDecl->instmeth_begin(), + E = CatIMPDecl->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + + for (ObjCImplementationDecl::classmeth_iterator + I = CatIMPDecl->classmeth_begin(), + E = CatIMPDecl->classmeth_end(); I != E; ++I) + ClsMap.insert((*I)->getSelector()); + if (InsMap.empty() && ClsMap.empty()) + return; + + // Get category's primary class. + ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl(); + if (!CatDecl) + return; + ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface(); + if (!IDecl) + return; + llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen; + bool IncompleteImpl = false; + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + CatIMPDecl, IDecl, + IncompleteImpl, false, true /*WarnExactMatch*/); +} + void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1559,6 +1665,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, CDecl, IncompleteImpl, true); + + // check all methods implemented in category against those declared + // in its primary class. + if (ObjCCategoryImplDecl *CatDecl = + dyn_cast<ObjCCategoryImplDecl>(IMPDecl)) + CheckCategoryVsClassMethodMatches(CatDecl); // Check the protocol list for unimplemented methods in the @implementation // class. @@ -1598,17 +1710,16 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); } } else - assert(false && "invalid ObjCContainerDecl type."); + llvm_unreachable("invalid ObjCContainerDecl type."); } /// ActOnForwardClassDeclaration - -Decl * +Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, unsigned NumElts) { - llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces; - + SmallVector<Decl *, 8> DeclsInGroup; for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. NamedDecl *PrevDecl @@ -1653,17 +1764,14 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, PushOnScopeChains(IDecl, TUScope, false); CurContext->makeDeclVisibleInContext(IDecl, true); } - - Interfaces.push_back(IDecl); + ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, + IDecl, IdentLocs[i]); + CurContext->addDecl(CDecl); + CheckObjCDeclScope(CDecl); + DeclsInGroup.push_back(CDecl); } - - assert(Interfaces.size() == NumElts); - ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, - Interfaces.data(), IdentLocs, - Interfaces.size()); - CurContext->addDecl(CDecl); - CheckObjCDeclScope(CDecl); - return CDecl; + + return BuildDeclaratorGroup(DeclsInGroup.data(), DeclsInGroup.size(), false); } static bool tryMatchRecordTypes(ASTContext &Context, @@ -1705,11 +1813,16 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy, if (!left->isScalarType() || !right->isScalarType()) return tryMatchRecordTypes(Context, strategy, left, right); - // Make scalars agree in kind, except count bools as chars. + // Make scalars agree in kind, except count bools as chars, and group + // all non-member pointers together. Type::ScalarTypeKind leftSK = left->getScalarTypeKind(); Type::ScalarTypeKind rightSK = right->getScalarTypeKind(); if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral; if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral; + if (leftSK == Type::STK_CPointer || leftSK == Type::STK_BlockPointer) + leftSK = Type::STK_ObjCObjectPointer; + if (rightSK == Type::STK_CPointer || rightSK == Type::STK_BlockPointer) + rightSK = Type::STK_ObjCObjectPointer; // Note that data member pointers and function member pointers don't // intermix because of the size differences. @@ -1764,12 +1877,12 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, != right->hasAttr<NSConsumesSelfAttr>())) return false; - ObjCMethodDecl::param_iterator + ObjCMethodDecl::param_const_iterator li = left->param_begin(), le = left->param_end(), ri = right->param_begin(); for (; li != le; ++li, ++ri) { assert(ri != right->param_end() && "Param mismatch"); - ParmVarDecl *lparm = *li, *rparm = *ri; + const ParmVarDecl *lparm = *li, *rparm = *ri; if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType())) return false; @@ -1887,7 +2000,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, (receiverIdOrClass && warn && (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, R.getBegin()) != - Diagnostic::Ignored)); + DiagnosticsEngine::Ignored)); if (strictSelectorMatch) for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, @@ -2010,15 +2123,14 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, - Decl *ClassDecl, Decl **allMethods, unsigned allNum, Decl **allProperties, unsigned pNum, DeclGroupPtrTy *allTUVars, unsigned tuvNum) { - // FIXME: If we don't have a ClassDecl, we have an error. We should consider - // always passing in a decl. If the decl has an error, isInvalidDecl() - // should be true. - if (!ClassDecl) + + if (!CurContext->isObjCContainer()) return; + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + Decl *ClassDecl = cast<Decl>(OCD); bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) @@ -2055,6 +2167,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(PrevMethod->getLocation(), diag::note_previous_declaration); Method->setInvalidDecl(); } else { + if (PrevMethod) + Method->setAsRedeclaration(PrevMethod); InsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "id". AddInstanceMethodToGlobalPool(Method); @@ -2074,6 +2188,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, Diag(PrevMethod->getLocation(), diag::note_previous_declaration); Method->setInvalidDecl(); } else { + if (PrevMethod) + Method->setAsRedeclaration(PrevMethod); ClsMap[Method->getSelector()] = Method; /// The following allows us to typecheck messages to "Class". AddFactoryMethodToGlobalPool(Method); @@ -2145,10 +2261,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } } } - - if (LangOpts.ObjCDefaultSynthProperties && - LangOpts.ObjCNonFragileABI2) - DefaultSynthesizeProperties(S, IC, IDecl); ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); DiagnoseOwningPropertyGetterSynthesis(IC); @@ -2187,6 +2299,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, } } } + ActOnObjCContainerFinishDefinition(); } @@ -2208,16 +2321,22 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { return false; } +namespace { + /// \brief Describes the compatibility of a result type with its method. + enum ResultTypeCompatibilityKind { + RTC_Compatible, + RTC_Incompatible, + RTC_Unknown + }; +} + /// \brief Check whether the declared result type of the given Objective-C /// method declaration is compatible with the method's class. /// -static bool +static ResultTypeCompatibilityKind CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, ObjCInterfaceDecl *CurrentClass) { QualType ResultType = Method->getResultType(); - SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo()) - ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); // If an Objective-C method inherits its related result type, then its // declared result type must be compatible with its own class type. The @@ -2227,52 +2346,171 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, // - it is id or qualified id, or if (ResultObjectType->isObjCIdType() || ResultObjectType->isObjCQualifiedIdType()) - return false; + return RTC_Compatible; if (CurrentClass) { if (ObjCInterfaceDecl *ResultClass = ResultObjectType->getInterfaceDecl()) { // - it is the same as the method's class type, or if (CurrentClass == ResultClass) - return false; + return RTC_Compatible; // - it is a superclass of the method's class type if (ResultClass->isSuperClassOf(CurrentClass)) - return false; + return RTC_Compatible; } + } else { + // Any Objective-C pointer type might be acceptable for a protocol + // method; we just don't know. + return RTC_Unknown; } } - return true; + return RTC_Incompatible; } -/// \brief Determine if any method in the global method pool has an inferred -/// result type. -static bool -anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) { - Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel); - if (Pos == S.MethodPool.end()) { - if (S.ExternalSource) - Pos = S.ReadMethodPool(Sel); - else - return 0; +namespace { +/// A helper class for searching for methods which a particular method +/// overrides. +class OverrideSearch { + Sema &S; + ObjCMethodDecl *Method; + llvm::SmallPtrSet<ObjCContainerDecl*, 8> Searched; + llvm::SmallPtrSet<ObjCMethodDecl*, 8> Overridden; + bool Recursive; + +public: + OverrideSearch(Sema &S, ObjCMethodDecl *method) : S(S), Method(method) { + Selector selector = method->getSelector(); + + // Bypass this search if we've never seen an instance/class method + // with this selector before. + Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector); + if (it == S.MethodPool.end()) { + if (!S.ExternalSource) return; + it = S.ReadMethodPool(selector); + } + ObjCMethodList &list = + method->isInstanceMethod() ? it->second.first : it->second.second; + if (!list.Method) return; + + ObjCContainerDecl *container + = cast<ObjCContainerDecl>(method->getDeclContext()); + + // Prevent the search from reaching this container again. This is + // important with categories, which override methods from the + // interface and each other. + Searched.insert(container); + searchFromContainer(container); } - - ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second; - for (ObjCMethodList *M = &List; M; M = M->Next) { - if (M->Method && M->Method->hasRelatedResultType()) - return true; - } - - return false; + + typedef llvm::SmallPtrSet<ObjCMethodDecl*,8>::iterator iterator; + iterator begin() const { return Overridden.begin(); } + iterator end() const { return Overridden.end(); } + +private: + void searchFromContainer(ObjCContainerDecl *container) { + if (container->isInvalidDecl()) return; + + switch (container->getDeclKind()) { +#define OBJCCONTAINER(type, base) \ + case Decl::type: \ + searchFrom(cast<type##Decl>(container)); \ + break; +#define ABSTRACT_DECL(expansion) +#define DECL(type, base) \ + case Decl::type: +#include "clang/AST/DeclNodes.inc" + llvm_unreachable("not an ObjC container!"); + } + } + + void searchFrom(ObjCProtocolDecl *protocol) { + // A method in a protocol declaration overrides declarations from + // referenced ("parent") protocols. + search(protocol->getReferencedProtocols()); + } + + void searchFrom(ObjCCategoryDecl *category) { + // A method in a category declaration overrides declarations from + // the main class and from protocols the category references. + search(category->getClassInterface()); + search(category->getReferencedProtocols()); + } + + void searchFrom(ObjCCategoryImplDecl *impl) { + // A method in a category definition that has a category + // declaration overrides declarations from the category + // declaration. + if (ObjCCategoryDecl *category = impl->getCategoryDecl()) { + search(category); + + // Otherwise it overrides declarations from the class. + } else { + search(impl->getClassInterface()); + } + } + + void searchFrom(ObjCInterfaceDecl *iface) { + // A method in a class declaration overrides declarations from + + // - categories, + for (ObjCCategoryDecl *category = iface->getCategoryList(); + category; category = category->getNextClassCategory()) + search(category); + + // - the super class, and + if (ObjCInterfaceDecl *super = iface->getSuperClass()) + search(super); + + // - any referenced protocols. + search(iface->getReferencedProtocols()); + } + + void searchFrom(ObjCImplementationDecl *impl) { + // A method in a class implementation overrides declarations from + // the class interface. + search(impl->getClassInterface()); + } + + + void search(const ObjCProtocolList &protocols) { + for (ObjCProtocolList::iterator i = protocols.begin(), e = protocols.end(); + i != e; ++i) + search(*i); + } + + void search(ObjCContainerDecl *container) { + // Abort if we've already searched this container. + if (!Searched.insert(container)) return; + + // Check for a method in this container which matches this selector. + ObjCMethodDecl *meth = container->getMethod(Method->getSelector(), + Method->isInstanceMethod()); + + // If we find one, record it and bail out. + if (meth) { + Overridden.insert(meth); + return; + } + + // Otherwise, search for methods that a hypothetical method here + // would have overridden. + + // Note that we're now in a recursive case. + Recursive = true; + + searchFromContainer(container); + } +}; } Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, Decl *ClassDecl, + tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, - SourceLocation SelectorStartLoc, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -2281,12 +2519,15 @@ Decl *Sema::ActOnMethodDeclaration( AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic, bool MethodDefinition) { // Make sure we can establish a context for the method. - if (!ClassDecl) { + if (!CurContext->isObjCContainer()) { Diag(MethodLoc, diag::error_missing_method_context); return 0; } + ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); + Decl *ClassDecl = cast<Decl>(OCD); QualType resultDeclType; + bool HasRelatedResultType = false; TypeSourceInfo *ResultTInfo = 0; if (ReturnType) { resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo); @@ -2298,21 +2539,28 @@ Decl *Sema::ActOnMethodDeclaration( << 0 << resultDeclType; return 0; } - } else // get the type for "id". + + HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); + } else { // get the type for "id". resultDeclType = Context.getObjCIdType(); + Diag(MethodLoc, diag::warn_missing_method_return_type) + << FixItHint::CreateInsertion(SelectorLocs.front(), "(id)"); + } ObjCMethodDecl* ObjCMethod = - ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType, + ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, + resultDeclType, ResultTInfo, - cast<DeclContext>(ClassDecl), + CurContext, MethodType == tok::minus, isVariadic, - false, false, + /*isSynthesized=*/false, + /*isImplicitlyDeclared=*/false, /*isDefined=*/false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required, - false); + HasRelatedResultType); - llvm::SmallVector<ParmVarDecl*, 16> Params; + SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { QualType ArgType; @@ -2383,20 +2631,16 @@ Decl *Sema::ActOnMethodDeclaration( Params.push_back(Param); } - ObjCMethod->setMethodParams(Context, Params.data(), Params.size(), - Sel.getNumArgs()); + ObjCMethod->setMethodParams(Context, Params, SelectorLocs); ObjCMethod->setObjCDeclQualifier( CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); - const ObjCMethodDecl *PrevMethod = 0; if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); - const ObjCMethodDecl *InterfaceMD = 0; - // Add the method now. - if (ObjCImplementationDecl *ImpDecl = - dyn_cast<ObjCImplementationDecl>(ClassDecl)) { + const ObjCMethodDecl *PrevMethod = 0; + if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(ClassDecl)) { if (MethodType == tok::minus) { PrevMethod = ImpDecl->getInstanceMethod(Sel); ImpDecl->addInstanceMethod(ObjCMethod); @@ -2404,24 +2648,6 @@ Decl *Sema::ActOnMethodDeclaration( PrevMethod = ImpDecl->getClassMethod(Sel); ImpDecl->addClassMethod(ObjCMethod); } - InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, - MethodType == tok::minus); - - if (ObjCMethod->hasAttrs() && - containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) - Diag(EndLoc, diag::warn_attribute_method_def); - } else if (ObjCCategoryImplDecl *CatImpDecl = - dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { - if (MethodType == tok::minus) { - PrevMethod = CatImpDecl->getInstanceMethod(Sel); - CatImpDecl->addInstanceMethod(ObjCMethod); - } else { - PrevMethod = CatImpDecl->getClassMethod(Sel); - CatImpDecl->addClassMethod(ObjCMethod); - } - - if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl()) - InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus); if (ObjCMethod->hasAttrs() && containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) @@ -2429,6 +2655,7 @@ Decl *Sema::ActOnMethodDeclaration( } else { cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); } + if (PrevMethod) { // You can never have two method definitions with the same name. Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) @@ -2449,28 +2676,44 @@ Decl *Sema::ActOnMethodDeclaration( = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) CurrentClass = CatImpl->getClassInterface(); } - - // Merge information down from the interface declaration if we have one. - if (InterfaceMD) { - // Inherit the related result type, if we can. - if (InterfaceMD->hasRelatedResultType() && - !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + + ResultTypeCompatibilityKind RTC + = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass); + + // Search for overridden methods and merge information down from them. + OverrideSearch overrides(*this, ObjCMethod); + for (OverrideSearch::iterator + i = overrides.begin(), e = overrides.end(); i != e; ++i) { + ObjCMethodDecl *overridden = *i; + + // Propagate down the 'related result type' bit from overridden methods. + if (RTC != RTC_Incompatible && overridden->hasRelatedResultType()) ObjCMethod->SetRelatedResultType(); - - mergeObjCMethodDecls(ObjCMethod, InterfaceMD); + + // Then merge the declarations. + mergeObjCMethodDecls(ObjCMethod, overridden); + + // Check for overriding methods + if (isa<ObjCInterfaceDecl>(ObjCMethod->getDeclContext()) || + isa<ObjCImplementationDecl>(ObjCMethod->getDeclContext())) + CheckConflictingOverridingMethod(ObjCMethod, overridden, + isa<ObjCProtocolDecl>(overridden->getDeclContext())); } bool ARCError = false; if (getLangOptions().ObjCAutoRefCount) ARCError = CheckARCMethodDecl(*this, ObjCMethod); - if (!ObjCMethod->hasRelatedResultType() && !ARCError && - getLangOptions().ObjCInferRelatedResultType) { + // Infer the related result type when possible. + if (!ARCError && RTC == RTC_Compatible && + !ObjCMethod->hasRelatedResultType() && + LangOpts.ObjCInferRelatedResultType) { bool InferRelatedResultType = false; switch (ObjCMethod->getMethodFamily()) { case OMF_None: case OMF_copy: case OMF_dealloc: + case OMF_finalize: case OMF_mutableCopy: case OMF_release: case OMF_retainCount: @@ -2490,14 +2733,8 @@ Decl *Sema::ActOnMethodDeclaration( break; } - if (InferRelatedResultType && - !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)) + if (InferRelatedResultType) ObjCMethod->SetRelatedResultType(); - - if (!InterfaceMD && - anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod())) - CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl)); } return ObjCMethod; @@ -2506,7 +2743,12 @@ Decl *Sema::ActOnMethodDeclaration( bool Sema::CheckObjCDeclScope(Decl *D) { if (isa<TranslationUnitDecl>(CurContext->getRedeclContext())) return false; - + // Following is also an error. But it is caused by a missing @end + // and diagnostic is issued elsewhere. + if (isa<ObjCContainerDecl>(CurContext->getRedeclContext())) { + return false; + } + Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope); D->setInvalidDecl(); @@ -2517,7 +2759,7 @@ bool Sema::CheckObjCDeclScope(Decl *D) { /// instance variables of ClassName into Decls. void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, - llvm::SmallVectorImpl<Decl*> &Decls) { + SmallVectorImpl<Decl*> &Decls) { // Check that ClassName is a valid class ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { @@ -2530,11 +2772,11 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, } // Collect the instance variables - llvm::SmallVector<ObjCIvarDecl*, 32> Ivars; + SmallVector<const ObjCIvarDecl*, 32> Ivars; Context.DeepCollectObjCIvars(Class, true, Ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. for (unsigned i = 0; i < Ivars.size(); i++) { - FieldDecl* ID = cast<FieldDecl>(Ivars[i]); + const FieldDecl* ID = cast<FieldDecl>(Ivars[i]); RecordDecl *Record = dyn_cast<RecordDecl>(TagD); Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, /*FIXME: StartL=*/ID->getLocation(), @@ -2545,7 +2787,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, } // Introduce all of these fields into the appropriate scope. - for (llvm::SmallVectorImpl<Decl*>::iterator D = Decls.begin(); + for (SmallVectorImpl<Decl*>::iterator D = Decls.begin(); D != Decls.end(); ++D) { FieldDecl *FD = cast<FieldDecl>(*D); if (getLangOptions().CPlusPlus) @@ -2647,7 +2889,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + SmallVectorImpl<ObjCIvarDecl*> &Ivars) { for (ObjCIvarDecl *Iv = OI->all_declared_ivar_begin(); Iv; Iv= Iv->getNextIvar()) { QualType QT = Context.getBaseElementType(Iv->getType()); @@ -2656,20 +2898,15 @@ void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, } } -void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, - CXXCtorInitializer ** initializers, - unsigned numInitializers) { - if (numInitializers > 0) { - NumIvarInitializers = numInitializers; - CXXCtorInitializer **ivarInitializers = - new (C) CXXCtorInitializer*[NumIvarInitializers]; - memcpy(ivarInitializers, initializers, - numInitializers * sizeof(CXXCtorInitializer*)); - IvarInitializers = ivarInitializers; - } -} - void Sema::DiagnoseUseOfUnimplementedSelectors() { + // Load referenced selectors from the external source. + if (ExternalSource) { + SmallVector<std::pair<Selector, SourceLocation>, 4> Sels; + ExternalSource->ReadReferencedSelectors(Sels); + for (unsigned I = 0, N = Sels.size(); I != N; ++I) + ReferencedSelectors[Sels[I].first] = Sels[I].second; + } + // Warning will be issued only when selector table is // generated (which means there is at lease one implementation // in the TU). This is to match gcc's behavior. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index 7bcec31..92af2d9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -101,7 +101,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; unsigned DiagID = diag::err_mismatched_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; if (!CheckEquivalentExceptionSpec(PDiag(DiagID), @@ -205,7 +205,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { else OS << ", "; - OS << E->getAsString(Context.PrintingPolicy); + OS << E->getAsString(getPrintingPolicy()); } OS << ")"; break; @@ -217,13 +217,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { case EST_ComputedNoexcept: OS << "noexcept("; - OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, - Context.PrintingPolicy); + OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, + getPrintingPolicy()); OS << ")"; break; default: - assert(false && "This spec type is compatible with none."); + llvm_unreachable("This spec type is compatible with none."); } OS.flush(); @@ -264,7 +264,7 @@ bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { unsigned DiagID = diag::err_mismatched_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; return CheckEquivalentExceptionSpec( PDiag(DiagID), @@ -717,7 +717,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, } } unsigned DiagID = diag::err_override_exception_spec; - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) DiagID = diag::warn_override_exception_spec; return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(diag::note_overridden_virtual_function), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 5efc365..170097c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -36,10 +36,60 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/Template.h" using namespace clang; using namespace sema; +/// \brief Determine whether the use of this declaration is valid, without +/// emitting diagnostics. +bool Sema::CanUseDecl(NamedDecl *D) { + // See if this is an auto-typed variable whose initializer we are parsing. + if (ParsingInitForAutoVars.count(D)) + return false; + + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDeleted()) + return false; + } + return true; +} + +static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, + NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass) { + // See if this declaration is unavailable or deprecated. + std::string Message; + AvailabilityResult Result = D->getAvailability(&Message); + switch (Result) { + case AR_Available: + case AR_NotYetIntroduced: + break; + + case AR_Deprecated: + S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + break; + + case AR_Unavailable: + if (S.getCurContextAvailability() != AR_Unavailable) { + if (Message.empty()) { + if (!UnknownObjCClass) + S.Diag(Loc, diag::err_unavailable) << D->getDeclName(); + else + S.Diag(Loc, diag::warn_unavailable_fwdclass_message) + << D->getDeclName(); + } + else + S.Diag(Loc, diag::err_unavailable_message) + << D->getDeclName() << Message; + S.Diag(D->getLocation(), diag::note_unavailable_here) + << isa<FunctionDecl>(D) << false; + } + break; + } + return Result; +} /// \brief Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. @@ -50,9 +100,6 @@ using namespace sema; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// -/// If IgnoreDeprecated is set to true, this should not warn about deprecated -/// decls. -/// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// @@ -61,10 +108,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. - llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); if (Pos != SuppressedDiagnostics.end()) { - llvm::SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second; + SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second; for (unsigned I = 0, N = Suppressed.size(); I != N; ++I) Diag(Suppressed[I].first, Suppressed[I].second); @@ -91,40 +138,22 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } } - - // See if this declaration is unavailable or deprecated. - std::string Message; - switch (D->getAvailability(&Message)) { - case AR_Available: - case AR_NotYetIntroduced: - break; - - case AR_Deprecated: - EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); - break; - - case AR_Unavailable: - if (cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) { - if (Message.empty()) { - if (!UnknownObjCClass) - Diag(Loc, diag::err_unavailable) << D->getDeclName(); - else - Diag(Loc, diag::warn_unavailable_fwdclass_message) - << D->getDeclName(); - } - else - Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << Message; - Diag(D->getLocation(), diag::note_unavailable_here) - << isa<FunctionDecl>(D) << false; - } - break; - } + AvailabilityResult Result = + DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass); // Warn if this is used but marked unused. if (D->hasAttr<UnusedAttr>()) Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); - + // For available enumerator, it will become unavailable/deprecated + // if its enum declaration is as such. + if (Result == AR_Available) + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { + const DeclContext *DC = ECD->getDeclContext(); + if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) + DiagnoseAvailabilityOfDecl(*this, + const_cast< EnumDecl *>(TheEnumDecl), + Loc, UnknownObjCClass); + } return false; } @@ -145,94 +174,74 @@ std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { return std::string(); } -/// DiagnoseSentinelCalls - This routine checks on method dispatch calls -/// (and other functions in future), which have been declared with sentinel -/// attribute. It warns if call does not have the sentinel argument. -/// +/// DiagnoseSentinelCalls - This routine checks whether a call or +/// message-send is to a declaration with the sentinel attribute, and +/// if so, it checks that the requirements of the sentinel are +/// satisfied. void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, - Expr **Args, unsigned NumArgs) { + Expr **args, unsigned numArgs) { const SentinelAttr *attr = D->getAttr<SentinelAttr>(); if (!attr) return; - // FIXME: In C++0x, if any of the arguments are parameter pack - // expansions, we can't check for the sentinel now. - int sentinelPos = attr->getSentinel(); - int nullPos = attr->getNullPos(); + // The number of formal parameters of the declaration. + unsigned numFormalParams; + + // The kind of declaration. This is also an index into a %select in + // the diagnostic. + enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType; - // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common - // base class. Then we won't be needing two versions of the same code. - unsigned int i = 0; - bool warnNotEnoughArgs = false; - int isMethod = 0; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - // skip over named parameters. - ObjCMethodDecl::param_iterator P, E = MD->param_end(); - for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (P != E || i >= NumArgs); - isMethod = 1; + numFormalParams = MD->param_size(); + calleeType = CT_Method; } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // skip over named parameters. - ObjCMethodDecl::param_iterator P, E = FD->param_end(); - for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (P != E || i >= NumArgs); - } else if (VarDecl *V = dyn_cast<VarDecl>(D)) { - // block or function pointer call. - QualType Ty = V->getType(); - if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { - const FunctionType *FT = Ty->isFunctionPointerType() - ? Ty->getAs<PointerType>()->getPointeeType()->getAs<FunctionType>() - : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); - if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) { - unsigned NumArgsInProto = Proto->getNumArgs(); - unsigned k; - for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) { - if (nullPos) - --nullPos; - else - ++i; - } - warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs); - } - if (Ty->isBlockPointerType()) - isMethod = 2; - } else + numFormalParams = FD->param_size(); + calleeType = CT_Function; + } else if (isa<VarDecl>(D)) { + QualType type = cast<ValueDecl>(D)->getType(); + const FunctionType *fn = 0; + if (const PointerType *ptr = type->getAs<PointerType>()) { + fn = ptr->getPointeeType()->getAs<FunctionType>(); + if (!fn) return; + calleeType = CT_Function; + } else if (const BlockPointerType *ptr = type->getAs<BlockPointerType>()) { + fn = ptr->getPointeeType()->castAs<FunctionType>(); + calleeType = CT_Block; + } else { return; - } else - return; + } - if (warnNotEnoughArgs) { - Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) { + numFormalParams = proto->getNumArgs(); + } else { + numFormalParams = 0; + } + } else { return; } - int sentinel = i; - while (sentinelPos > 0 && i < NumArgs-1) { - --sentinelPos; - ++i; - } - if (sentinelPos > 0) { + + // "nullPos" is the number of formal parameters at the end which + // effectively count as part of the variadic arguments. This is + // useful if you would prefer to not have *any* formal parameters, + // but the language forces you to have at least one. + unsigned nullPos = attr->getNullPos(); + assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel"); + numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos); + + // The number of arguments which should follow the sentinel. + unsigned numArgsAfterSentinel = attr->getSentinel(); + + // If there aren't enough arguments for all the formal parameters, + // the sentinel, and the args after the sentinel, complain. + if (numArgs < numFormalParams + numArgsAfterSentinel + 1) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << calleeType; return; } - while (i < NumArgs-1) { - ++i; - ++sentinel; - } - Expr *sentinelExpr = Args[sentinel]; + + // Otherwise, find the sentinel expression. + Expr *sentinelExpr = args[numArgs - numArgsAfterSentinel - 1]; if (!sentinelExpr) return; - if (sentinelExpr->isTypeDependent()) return; if (sentinelExpr->isValueDependent()) return; // nullptr_t is always treated as null. @@ -246,13 +255,32 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, // Unfortunately, __null has type 'int'. if (isa<GNUNullExpr>(sentinelExpr)) return; - Diag(Loc, diag::warn_missing_sentinel) << isMethod; - Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + // Pick a reasonable string to insert. Optimistically use 'nil' or + // 'NULL' if those are actually defined in the context. Only use + // 'nil' for ObjC methods, where it's much more likely that the + // variadic arguments form a list of object pointers. + SourceLocation MissingNilLoc + = PP.getLocForEndOfToken(sentinelExpr->getLocEnd()); + std::string NullValue; + if (calleeType == CT_Method && + PP.getIdentifierInfo("nil")->hasMacroDefinition()) + NullValue = "nil"; + else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition()) + NullValue = "NULL"; + else + NullValue = "(void*) 0"; + + if (MissingNilLoc.isInvalid()) + Diag(Loc, diag::warn_missing_sentinel) << calleeType; + else + Diag(MissingNilLoc, diag::warn_missing_sentinel) + << calleeType + << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); + Diag(D->getLocation(), diag::note_sentinel_here) << calleeType; } -SourceRange Sema::getExprRange(ExprTy *E) const { - Expr *Ex = (Expr *)E; - return Ex? Ex->getSourceRange() : SourceRange(); +SourceRange Sema::getExprRange(Expr *E) const { + return E ? E->getSourceRange() : SourceRange(); } //===----------------------------------------------------------------------===// @@ -261,6 +289,13 @@ SourceRange Sema::getExprRange(ExprTy *E) const { /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { + // Handle any placeholder expressions which made it here. + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); @@ -306,6 +341,13 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) { } ExprResult Sema::DefaultLvalueConversion(Expr *E) { + // Handle any placeholder expressions which made it here. + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + // C++ [conv.lval]p1: // A glvalue of a non-function, non-array type T can be // converted to a prvalue. @@ -314,6 +356,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); + // We can't do lvalue-to-rvalue on atomics yet. + if (T->getAs<AtomicType>()) + return Owned(E); + // Create a load out of an ObjCProperty l-value, if necessary. if (E->getObjectKind() == OK_ObjCProperty) { ExprResult Res = ConvertPropertyForRValue(E); @@ -350,14 +396,14 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // C99 6.3.2.1p2: // If the lvalue has qualified type, the value has the unqualified // version of the type of the lvalue; otherwise, the value has the - // type of the lvalue. + // type of the lvalue. if (T.hasQualifiers()) T = T.getUnqualifiedType(); - CheckArrayAccess(E); - - return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, - E, 0, VK_RValue)); + ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, + E, 0, VK_RValue)); + + return Res; } ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { @@ -382,10 +428,15 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { if (Res.isInvalid()) return Owned(E); E = Res.take(); - + QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - + + // Half FP is a bit different: it's a storage-only type, meaning that any + // "use" of it should be promoted to float. + if (Ty->isHalfType()) + return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast); + // Try to perform integral promotions if the object has a theoretically // promotable type. if (Ty->isIntegralOrUnscopedEnumerationType()) { @@ -402,7 +453,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { // value is converted to an int; otherwise, it is converted to an // unsigned int. These are called the integer promotions. All // other types are unchanged by the integer promotions. - + QualType PTy = Context.isPromotableBitField(E); if (!PTy.isNull()) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).take(); @@ -433,6 +484,28 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { if (Ty->isSpecificBuiltinType(BuiltinType::Float)) E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take(); + // C++ performs lvalue-to-rvalue conversion as a default argument + // promotion, even on class types, but note: + // C++11 [conv.lval]p2: + // When an lvalue-to-rvalue conversion occurs in an unevaluated + // operand or a subexpression thereof the value contained in the + // referenced object is not accessed. Otherwise, if the glvalue + // has a class type, the conversion copy-initializes a temporary + // of type T from the glvalue and the result of the conversion + // is a prvalue for the temporary. + // FIXME: add some way to gate this entire thing for correctness in + // potentially potentially evaluated contexts. + if (getLangOptions().CPlusPlus && E->isGLValue() && + ExprEvalContexts.back().Context != Unevaluated) { + ExprResult Temp = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(E->getType()), + E->getExprLoc(), + Owned(E)); + if (Temp.isInvalid()) + return ExprError(); + E = Temp.get(); + } + return Owned(E); } @@ -450,20 +523,17 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); E = ExprRes.take(); - // __builtin_va_start takes the second argument as a "varargs" argument, but - // it doesn't actually do anything with it. It doesn't need to be non-pod - // etc. - if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) - return Owned(E); - // Don't allow one to pass an Objective-C interface to a vararg. if (E->getType()->isObjCObjectType() && DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << E->getType() << CT)) return ExprError(); - - if (!E->getType().isPODType(Context)) { + + // Complain about passing non-POD types through varargs. However, don't + // perform this check for incomplete types, which we can get here when we're + // in an unevaluated context. + if (!E->getType()->isIncompleteType() && !E->getType().isPODType(Context)) { // C++0x [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) // having a non-trivial copy constructor, a non-trivial move constructor, @@ -507,8 +577,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma, Call.get(), E); if (Comma.isInvalid()) - return ExprError(); - + return ExprError(); E = Comma.get(); } } @@ -516,307 +585,363 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return Owned(E); } -/// UsualArithmeticConversions - Performs various conversions that are common to -/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this -/// routine returns the first non-arithmetic type found. The client is -/// responsible for emitting appropriate error diagnostics. -/// FIXME: verify the conversion rules for "complex int" are consistent with -/// GCC. -QualType Sema::UsualArithmeticConversions(ExprResult &lhsExpr, ExprResult &rhsExpr, - bool isCompAssign) { - if (!isCompAssign) { - lhsExpr = UsualUnaryConversions(lhsExpr.take()); - if (lhsExpr.isInvalid()) - return QualType(); +/// \brief Converts an integer to complex float type. Helper function of +/// UsualArithmeticConversions() +/// +/// \return false if the integer expression is an integer type and is +/// successfully converted to the complex type. +static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, + ExprResult &ComplexExpr, + QualType IntTy, + QualType ComplexTy, + bool SkipCast) { + if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; + if (SkipCast) return false; + if (IntTy->isIntegerType()) { + QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType(); + IntExpr = S.ImpCastExprToType(IntExpr.take(), fpTy, CK_IntegralToFloating); + IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy, + CK_FloatingRealToComplex); + } else { + assert(IntTy->isComplexIntegerType()); + IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy, + CK_IntegralComplexToFloatingComplex); } + return false; +} - rhsExpr = UsualUnaryConversions(rhsExpr.take()); - if (rhsExpr.isInvalid()) - return QualType(); - - // For conversion purposes, we ignore any qualifiers. - // For example, "const float" and "float" are equivalent. - QualType lhs = - Context.getCanonicalType(lhsExpr.get()->getType()).getUnqualifiedType(); - QualType rhs = - Context.getCanonicalType(rhsExpr.get()->getType()).getUnqualifiedType(); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; - - // Apply unary and bitfield promotions to the LHS's type. - QualType lhs_unpromoted = lhs; - if (lhs->isPromotableIntegerType()) - lhs = Context.getPromotedIntegerType(lhs); - QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr.get()); - if (!LHSBitfieldPromoteTy.isNull()) - lhs = LHSBitfieldPromoteTy; - if (lhs != lhs_unpromoted && !isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), lhs, CK_IntegralCast); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // At this point, we have two different arithmetic types. - - // Handle complex types first (C99 6.3.1.8p1). - bool LHSComplexFloat = lhs->isComplexType(); - bool RHSComplexFloat = rhs->isComplexType(); - if (LHSComplexFloat || RHSComplexFloat) { - // if we have an integer operand, the result is the complex type. - - if (!RHSComplexFloat && !rhs->isRealFloatingType()) { - if (rhs->isIntegerType()) { - QualType fp = cast<ComplexType>(lhs)->getElementType(); - rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_IntegralToFloating); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); - } else { - assert(rhs->isComplexIntegerType()); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexToFloatingComplex); - } - return lhs; - } - - if (!LHSComplexFloat && !lhs->isRealFloatingType()) { - if (!isCompAssign) { - // int -> float -> _Complex float - if (lhs->isIntegerType()) { - QualType fp = cast<ComplexType>(rhs)->getElementType(); - lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_IntegralToFloating); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); - } else { - assert(lhs->isComplexIntegerType()); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexToFloatingComplex); - } - } - return rhs; - } - - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int order = Context.getFloatingTypeOrder(lhs, rhs); - - // If both are complex, just cast to the more precise type. - if (LHSComplexFloat && RHSComplexFloat) { - if (order > 0) { - // _Complex float -> _Complex double - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingComplexCast); - return lhs; - - } else if (order < 0) { - // _Complex float -> _Complex double - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingComplexCast); - return rhs; - } - return lhs; - } - - // If just the LHS is complex, the RHS needs to be converted, - // and the LHS might need to be promoted. - if (LHSComplexFloat) { - if (order > 0) { // LHS is wider - // float -> _Complex double - QualType fp = cast<ComplexType>(lhs)->getElementType(); - rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_FloatingCast); - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); - return lhs; - } - - // RHS is at least as wide. Find its corresponding complex type. - QualType result = (order == 0 ? lhs : Context.getComplexType(rhs)); - - // double -> _Complex double - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); - - // _Complex float -> _Complex double - if (!isCompAssign && order < 0) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingComplexCast); - - return result; - } - - // Just the RHS is complex, so the LHS needs to be converted - // and the RHS might need to be promoted. - assert(RHSComplexFloat); - - if (order < 0) { // RHS is wider - // float -> _Complex double - if (!isCompAssign) { - QualType fp = cast<ComplexType>(rhs)->getElementType(); - lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_FloatingCast); - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); - } - return rhs; - } - - // LHS is at least as wide. Find its corresponding complex type. - QualType result = (order == 0 ? rhs : Context.getComplexType(lhs)); - - // double -> _Complex double - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); +/// \brief Takes two complex float types and converts them to the same type. +/// Helper function of UsualArithmeticConversions() +static QualType +handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); + if (order < 0) { // _Complex float -> _Complex double - if (order > 0) - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingComplexCast); - - return result; + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingComplexCast); + return RHSType; } + if (order > 0) + // _Complex float -> _Complex double + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingComplexCast); + return LHSType; +} + +/// \brief Converts otherExpr to complex float and promotes complexExpr if +/// necessary. Helper function of UsualArithmeticConversions() +static QualType handleOtherComplexFloatConversion(Sema &S, + ExprResult &ComplexExpr, + ExprResult &OtherExpr, + QualType ComplexTy, + QualType OtherTy, + bool ConvertComplexExpr, + bool ConvertOtherExpr) { + int order = S.Context.getFloatingTypeOrder(ComplexTy, OtherTy); + + // If just the complexExpr is complex, the otherExpr needs to be converted, + // and the complexExpr might need to be promoted. + if (order > 0) { // complexExpr is wider + // float -> _Complex double + if (ConvertOtherExpr) { + QualType fp = cast<ComplexType>(ComplexTy)->getElementType(); + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), fp, CK_FloatingCast); + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), ComplexTy, + CK_FloatingRealToComplex); + } + return ComplexTy; + } + + // otherTy is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? ComplexTy : + S.Context.getComplexType(OtherTy)); + + // double -> _Complex double + if (ConvertOtherExpr) + OtherExpr = S.ImpCastExprToType(OtherExpr.take(), result, + CK_FloatingRealToComplex); + + // _Complex float -> _Complex double + if (ConvertComplexExpr && order < 0) + ComplexExpr = S.ImpCastExprToType(ComplexExpr.take(), result, + CK_FloatingComplexCast); - // Now handle "real" floating types (i.e. float, double, long double). - bool LHSFloat = lhs->isRealFloatingType(); - bool RHSFloat = rhs->isRealFloatingType(); - if (LHSFloat || RHSFloat) { - // If we have two real floating types, convert the smaller operand - // to the bigger result. - if (LHSFloat && RHSFloat) { - int order = Context.getFloatingTypeOrder(lhs, rhs); - if (order > 0) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingCast); - return lhs; - } - - assert(order < 0 && "illegal float comparison"); - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingCast); - return rhs; - } - - // If we have an integer operand, the result is the real floating type. - if (LHSFloat) { - if (rhs->isIntegerType()) { - // Convert rhs to the lhs floating point type. - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralToFloating); - return lhs; - } - - // Convert both sides to the appropriate complex float. - assert(rhs->isComplexIntegerType()); - QualType result = Context.getComplexType(lhs); - - // _Complex int -> _Complex float - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); - - // float -> _Complex float - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); - - return result; - } - - assert(RHSFloat); - if (lhs->isIntegerType()) { - // Convert lhs to the rhs floating point type. - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralToFloating); - return rhs; - } - - // Convert both sides to the appropriate complex float. - assert(lhs->isComplexIntegerType()); - QualType result = Context.getComplexType(rhs); + return result; +} - // _Complex int -> _Complex float - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); +/// \brief Handle arithmetic conversion with complex types. Helper function of +/// UsualArithmeticConversions() +static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + // if we have an integer operand, the result is the complex type. + if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, + /*skipCast*/false)) + return LHSType; + if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, + /*skipCast*/IsCompAssign)) + return RHSType; + + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + + bool LHSComplexFloat = LHSType->isComplexType(); + bool RHSComplexFloat = RHSType->isComplexType(); + + // If both are complex, just cast to the more precise type. + if (LHSComplexFloat && RHSComplexFloat) + return handleComplexFloatToComplexFloatConverstion(S, LHS, RHS, + LHSType, RHSType, + IsCompAssign); + + // If only one operand is complex, promote it if necessary and convert the + // other operand to complex. + if (LHSComplexFloat) + return handleOtherComplexFloatConversion( + S, LHS, RHS, LHSType, RHSType, /*convertComplexExpr*/!IsCompAssign, + /*convertOtherExpr*/ true); + + assert(RHSComplexFloat); + return handleOtherComplexFloatConversion( + S, RHS, LHS, RHSType, LHSType, /*convertComplexExpr*/true, + /*convertOtherExpr*/ !IsCompAssign); +} + +/// \brief Hande arithmetic conversion from integer to float. Helper function +/// of UsualArithmeticConversions() +static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, + ExprResult &IntExpr, + QualType FloatTy, QualType IntTy, + bool ConvertFloat, bool ConvertInt) { + if (IntTy->isIntegerType()) { + if (ConvertInt) + // Convert intExpr to the lhs floating point type. + IntExpr = S.ImpCastExprToType(IntExpr.take(), FloatTy, + CK_IntegralToFloating); + return FloatTy; + } + + // Convert both sides to the appropriate complex float. + assert(IntTy->isComplexIntegerType()); + QualType result = S.Context.getComplexType(FloatTy); + + // _Complex int -> _Complex float + if (ConvertInt) + IntExpr = S.ImpCastExprToType(IntExpr.take(), result, + CK_IntegralComplexToFloatingComplex); + + // float -> _Complex float + if (ConvertFloat) + FloatExpr = S.ImpCastExprToType(FloatExpr.take(), result, + CK_FloatingRealToComplex); - // float -> _Complex float - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); + return result; +} - return result; - } +/// \brief Handle arithmethic conversion with floating point types. Helper +/// function of UsualArithmeticConversions() +static QualType handleFloatConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { + bool LHSFloat = LHSType->isRealFloatingType(); + bool RHSFloat = RHSType->isRealFloatingType(); - // Handle GCC complex int extension. - // FIXME: if the operands are (int, _Complex long), we currently - // don't promote the complex. Also, signedness? - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - if (lhsComplexInt && rhsComplexInt) { - int order = Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()); + // If we have two real floating types, convert the smaller operand + // to the bigger result. + if (LHSFloat && RHSFloat) { + int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); + if (order > 0) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingCast); + return LHSType; + } + + assert(order < 0 && "illegal float comparison"); + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingCast); + return RHSType; + } + + if (LHSFloat) + return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, + /*convertFloat=*/!IsCompAssign, + /*convertInt=*/ true); + assert(RHSFloat); + return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, + /*convertInt=*/ true, + /*convertFloat=*/!IsCompAssign); +} + +/// \brief Handle conversions with GCC complex int extension. Helper function +/// of UsualArithmeticConversions() +// FIXME: if the operands are (int, _Complex long), we currently +// don't promote the complex. Also, signedness? +static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType(); + const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType(); + + if (LHSComplexInt && RHSComplexInt) { + int order = S.Context.getIntegerTypeOrder(LHSComplexInt->getElementType(), + RHSComplexInt->getElementType()); assert(order && "inequal types with equal element ordering"); if (order > 0) { // _Complex int -> _Complex long - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexCast); - return lhs; + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralComplexCast); + return LHSType; } - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexCast); - return rhs; - } else if (lhsComplexInt) { - // int -> _Complex int - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralRealToComplex); - return lhs; - } else if (rhsComplexInt) { + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralComplexCast); + return RHSType; + } + + if (LHSComplexInt) { // int -> _Complex int - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralRealToComplex); - return rhs; + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex); + return LHSType; } - // Finally, we have two differing integer types. + assert(RHSComplexInt); + // int -> _Complex int + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex); + return RHSType; +} + +/// \brief Handle integer arithmetic conversions. Helper function of +/// UsualArithmeticConversions() +static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { // The rules for this case are in C99 6.3.1.8 - int compare = Context.getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->hasSignedIntegerRepresentation(), - rhsSigned = rhs->hasSignedIntegerRepresentation(); - if (lhsSigned == rhsSigned) { + int order = S.Context.getIntegerTypeOrder(LHSType, RHSType); + bool LHSSigned = LHSType->hasSignedIntegerRepresentation(); + bool RHSSigned = RHSType->hasSignedIntegerRepresentation(); + if (LHSSigned == RHSSigned) { // Same signedness; use the higher-ranked type - if (compare >= 0) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; - } else if (compare != (lhsSigned ? 1 : -1)) { + if (order >= 0) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; + } else if (order != (LHSSigned ? 1 : -1)) { // The unsigned type has greater than or equal rank to the // signed type, so use the unsigned type - if (rhsSigned) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; - } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { + if (RHSSigned) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; + } else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) { // The two types are different widths; if we are here, that // means the signed type is larger than the unsigned type, so // use the signed type. - if (lhsSigned) { - rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); - return lhs; - } else if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); - return rhs; + if (LHSSigned) { + RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast); + return LHSType; + } else if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast); + return RHSType; } else { // The signed type is higher-ranked than the unsigned type, // but isn't actually any bigger (like unsigned int and long // on most 32-bit systems). Use the unsigned type corresponding // to the signed type. QualType result = - Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralCast); - if (!isCompAssign) - lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralCast); + S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType); + RHS = S.ImpCastExprToType(RHS.take(), result, CK_IntegralCast); + if (!IsCompAssign) + LHS = S.ImpCastExprToType(LHS.take(), result, CK_IntegralCast); return result; } } +/// UsualArithmeticConversions - Performs various conversions that are common to +/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this +/// routine returns the first non-arithmetic type found. The client is +/// responsible for emitting appropriate error diagnostics. +/// FIXME: verify the conversion rules for "complex int" are consistent with +/// GCC. +QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, + bool IsCompAssign) { + if (!IsCompAssign) { + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) + return QualType(); + } + + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) + return QualType(); + + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType LHSType = + Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); + QualType RHSType = + Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (LHSType == RHSType) + return LHSType; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType()) + return LHSType; + + // Apply unary and bitfield promotions to the LHS's type. + QualType LHSUnpromotedType = LHSType; + if (LHSType->isPromotableIntegerType()) + LHSType = Context.getPromotedIntegerType(LHSType); + QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); + if (!LHSBitfieldPromoteTy.isNull()) + LHSType = LHSBitfieldPromoteTy; + if (LHSType != LHSUnpromotedType && !IsCompAssign) + LHS = ImpCastExprToType(LHS.take(), LHSType, CK_IntegralCast); + + // If both types are identical, no conversion is needed. + if (LHSType == RHSType) + return LHSType; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + if (LHSType->isComplexType() || RHSType->isComplexType()) + return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Now handle "real" floating types (i.e. float, double, long double). + if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) + return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Handle GCC complex int extension. + if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) + return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + + // Finally, we have two differing integer types. + return handleIntegerConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); +} + //===----------------------------------------------------------------------===// // Semantic Analysis for various Expression Types //===----------------------------------------------------------------------===// @@ -827,13 +952,13 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, - MultiTypeArg types, - MultiExprArg exprs) { - unsigned NumAssocs = types.size(); - assert(NumAssocs == exprs.size()); + MultiTypeArg ArgTypes, + MultiExprArg ArgExprs) { + unsigned NumAssocs = ArgTypes.size(); + assert(NumAssocs == ArgExprs.size()); - ParsedType *ParsedTypes = types.release(); - Expr **Exprs = exprs.release(); + ParsedType *ParsedTypes = ArgTypes.release(); + Expr **Exprs = ArgExprs.release(); TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; for (unsigned i = 0; i < NumAssocs; ++i) { @@ -922,7 +1047,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, Types, Exprs, NumAssocs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack)); - llvm::SmallVector<unsigned, 1> CompatIndices; + SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; for (unsigned i = 0; i < NumAssocs; ++i) { if (!Types[i]) @@ -942,7 +1067,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match) << ControllingExpr->getSourceRange() << ControllingExpr->getType() << (unsigned) CompatIndices.size(); - for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(), + for (SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(), E = CompatIndices.end(); I != E; ++I) { Diag(Types[*I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) @@ -993,16 +1118,30 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { if (Literal.hadError) return ExprError(); - llvm::SmallVector<SourceLocation, 4> StringTokLocs; + SmallVector<SourceLocation, 4> StringTokLocs; for (unsigned i = 0; i != NumStringToks; ++i) StringTokLocs.push_back(StringToks[i].getLocation()); QualType StrTy = Context.CharTy; - if (Literal.AnyWide) + if (Literal.isWide()) StrTy = Context.getWCharType(); + else if (Literal.isUTF16()) + StrTy = Context.Char16Ty; + else if (Literal.isUTF32()) + StrTy = Context.Char32Ty; else if (Literal.Pascal) StrTy = Context.UnsignedCharTy; + StringLiteral::StringKind Kind = StringLiteral::Ascii; + if (Literal.isWide()) + Kind = StringLiteral::Wide; + else if (Literal.isUTF8()) + Kind = StringLiteral::UTF8; + else if (Literal.isUTF16()) + Kind = StringLiteral::UTF16; + else if (Literal.isUTF32()) + Kind = StringLiteral::UTF32; + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) StrTy.addConst(); @@ -1016,7 +1155,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { // Pass &StringTokLocs[0], StringTokLocs.size() to factory! return Owned(StringLiteral::Create(Context, Literal.GetString(), - Literal.AnyWide, Literal.Pascal, StrTy, + Kind, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size())); } @@ -1091,21 +1230,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, /// There is a well-formed capture at a particular scope level; /// propagate it through all the nested blocks. -static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex, - const BlockDecl::Capture &capture) { - VarDecl *var = capture.getVariable(); +static CaptureResult propagateCapture(Sema &S, unsigned ValidScopeIndex, + const BlockDecl::Capture &Capture) { + VarDecl *var = Capture.getVariable(); // Update all the inner blocks with the capture information. - for (unsigned i = validScopeIndex + 1, e = S.FunctionScopes.size(); + for (unsigned i = ValidScopeIndex + 1, e = S.FunctionScopes.size(); i != e; ++i) { BlockScopeInfo *innerBlock = cast<BlockScopeInfo>(S.FunctionScopes[i]); innerBlock->Captures.push_back( - BlockDecl::Capture(capture.getVariable(), capture.isByRef(), - /*nested*/ true, capture.getCopyExpr())); + BlockDecl::Capture(Capture.getVariable(), Capture.isByRef(), + /*nested*/ true, Capture.getCopyExpr())); innerBlock->CaptureMap[var] = innerBlock->Captures.size(); // +1 } - return capture.isByRef() ? CR_CaptureByRef : CR_Capture; + return Capture.isByRef() ? CR_CaptureByRef : CR_Capture; } /// shouldCaptureValueReference - Determine if a reference to the @@ -1114,9 +1253,9 @@ static CaptureResult propagateCapture(Sema &S, unsigned validScopeIndex, /// This also keeps the captures set in the BlockScopeInfo records /// up-to-date. static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, - ValueDecl *value) { + ValueDecl *Value) { // Only variables ever require capture. - VarDecl *var = dyn_cast<VarDecl>(value); + VarDecl *var = dyn_cast<VarDecl>(Value); if (!var) return CR_NoCapture; // Fast path: variables from the current context never require capture. @@ -1225,19 +1364,19 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, blockScope->Captures.back()); } -static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *vd, +static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD, const DeclarationNameInfo &NameInfo, - bool byRef) { - assert(isa<VarDecl>(vd) && "capturing non-variable"); + bool ByRef) { + assert(isa<VarDecl>(VD) && "capturing non-variable"); - VarDecl *var = cast<VarDecl>(vd); + VarDecl *var = cast<VarDecl>(VD); assert(var->hasLocalStorage() && "capturing non-local"); - assert(byRef == var->hasAttr<BlocksAttr>() && "byref set wrong"); + assert(ByRef == var->hasAttr<BlocksAttr>() && "byref set wrong"); QualType exprType = var->getType().getNonReferenceType(); BlockDeclRefExpr *BDRE; - if (!byRef) { + if (!ByRef) { // The variable will be bound by copy; make it const within the // closure, but record that this was done in the expression. bool constAdded = !exprType.isConstQualified(); @@ -1268,6 +1407,20 @@ ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS) { + if (getLangOptions().CUDA) + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) + if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { + CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller), + CalleeTarget = IdentifyCUDATarget(Callee); + if (CheckCUDATarget(CallerTarget, CalleeTarget)) { + Diag(NameInfo.getLoc(), diag::err_ref_bad_target) + << CalleeTarget << D->getIdentifier() << CallerTarget; + Diag(D->getLocation(), diag::note_previous_decl) + << D->getIdentifier(); + return ExprError(); + } + } + MarkDeclarationReferenced(NameInfo.getLoc(), D); Expr *E = DeclRefExpr::Create(Context, @@ -1276,7 +1429,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, D, NameInfo, Ty, VK); // Just in case we're building an illegal pointer-to-member. - if (isa<FieldDecl>(D) && cast<FieldDecl>(D)->getBitWidth()) + FieldDecl *FD = dyn_cast<FieldDecl>(D); + if (FD && FD->isBitField()) E->setObjectKind(OK_BitField); return Owned(E); @@ -1291,10 +1445,11 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, /// This actually loses a lot of source location information for /// non-standard name kinds; we should consider preserving that in /// some way. -void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, - TemplateArgumentListInfo &Buffer, - DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *&TemplateArgs) { +void +Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedId::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); @@ -1319,7 +1474,9 @@ void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, /// /// \return false if new lookup candidates were found bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, - CorrectTypoContext CTC) { + CorrectTypoContext CTC, + TemplateArgumentListInfo *ExplicitTemplateArgs, + Expr **Args, unsigned NumArgs) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -1358,6 +1515,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CXXMethodDecl *DepMethod = cast_or_null<CXXMethodDecl>( CurMethod->getInstantiatedFromMemberFunction()); if (DepMethod) { + if (getLangOptions().MicrosoftExt) + diagnostic = diag::warn_found_via_dependent_bases_lookup; Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); QualType DepThisType = DepMethod->getThisType(Context); @@ -1373,7 +1532,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CXXDependentScopeMemberExpr::Create( Context, DepThis, DepThisType, true, SourceLocation(), SS.getWithLocInContext(Context), NULL, - R.getLookupNameInfo(), &TList); + R.getLookupNameInfo(), + ULE->hasExplicitTemplateArgs() ? &TList : 0); CallsUndergoingInstantiation.back()->setCallee(DepExpr); } else { // FIXME: we should be able to handle this case too. It is correct @@ -1405,6 +1565,30 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, R.setLookupName(Corrected.getCorrection()); if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + if (Corrected.isOverloaded()) { + OverloadCandidateSet OCS(R.getNameLoc()); + OverloadCandidateSet::iterator Best; + for (TypoCorrection::decl_iterator CD = Corrected.begin(), + CDEnd = Corrected.end(); + CD != CDEnd; ++CD) { + if (FunctionTemplateDecl *FTD = + dyn_cast<FunctionTemplateDecl>(*CD)) + AddTemplateOverloadCandidate( + FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs, + Args, NumArgs, OCS); + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD)) + if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0) + AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), + Args, NumArgs, OCS); + } + switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) { + case OR_Success: + ND = Best->Function; + break; + default: + break; + } + } R.addDecl(ND); if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) { if (SS.isEmpty()) @@ -1430,7 +1614,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // correction, but don't make it a fix-it since we're not going // to recover well anyway. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr; + Diag(R.getNameLoc(), diagnostic_suggest) + << Name << CorrectedQuotedStr; else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr @@ -1467,96 +1652,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } -ObjCPropertyDecl *Sema::canSynthesizeProvisionalIvar(IdentifierInfo *II) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return 0; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return 0; - ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); - if (!property) - return 0; - if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || - PIDecl->getPropertyIvarDecl()) - return 0; - return property; -} - -bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return false; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return false; - if (ObjCPropertyImplDecl *PIDecl - = ClassImpDecl->FindPropertyImplDecl(Property->getIdentifier())) - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic || - PIDecl->getPropertyIvarDecl()) - return false; - - return true; -} - -ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup, - IdentifierInfo *II, - SourceLocation NameLoc) { - ObjCMethodDecl *CurMeth = getCurMethodDecl(); - bool LookForIvars; - if (Lookup.empty()) - LookForIvars = true; - else if (CurMeth->isClassMethod()) - LookForIvars = false; - else - LookForIvars = (Lookup.isSingleResult() && - Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod() && - (Lookup.getAsSingle<VarDecl>() != 0)); - if (!LookForIvars) - return 0; - - ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); - if (!IDecl) - return 0; - ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); - if (!ClassImpDecl) - return 0; - bool DynamicImplSeen = false; - ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); - if (!property) - return 0; - if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) { - DynamicImplSeen = - (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); - // property implementation has a designated ivar. No need to assume a new - // one. - if (!DynamicImplSeen && PIDecl->getPropertyIvarDecl()) - return 0; - } - if (!DynamicImplSeen) { - QualType PropType = Context.getCanonicalType(property->getType()); - ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, - NameLoc, NameLoc, - II, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Private, - (Expr *)0, true); - ClassImpDecl->addDecl(Ivar); - IDecl->makeDeclVisibleInContext(Ivar, false); - property->setPropertyIvarDecl(Ivar); - return Ivar; - } - return 0; -} - ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id, bool HasTrailingLParen, - bool isAddressOfOperand) { - assert(!(isAddressOfOperand && HasTrailingLParen) && + bool IsAddressOfOperand) { + assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) @@ -1598,7 +1699,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, } if (DependentID) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); bool IvarLookupFollowUp = false; @@ -1618,7 +1719,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); } else { IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); @@ -1627,7 +1728,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If the result might be in a dependent base class, this is a dependent // id-expression. if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) - return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, TemplateArgs); // If this reference is in an Objective-C method, then we need to do @@ -1640,19 +1741,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (Expr *Ex = E.takeAs<Expr>()) return Owned(Ex); - // Synthesize ivars lazily. - if (getLangOptions().ObjCDefaultSynthProperties && - getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(R, II, NameLoc)) { - if (const ObjCPropertyDecl *Property = - canSynthesizeProvisionalIvar(II)) { - Diag(NameLoc, diag::warn_synthesized_ivar_access) << II; - Diag(Property->getLocation(), diag::note_property_declare); - } - return ActOnIdExpression(S, SS, Id, HasTrailingLParen, - isAddressOfOperand); - } - } // for further use, this must be set to false if in class method. IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod(); } @@ -1676,6 +1764,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { + + // In Microsoft mode, if we are inside a template class member function + // and we can't resolve an identifier then assume the identifier is type + // dependent. The goal is to postpone name lookup to instantiation time + // to be able to search into type dependent base classes. + if (getLangOptions().MicrosoftMode && CurContext->isDependentContext() && + isa<CXXMethodDecl>(CurContext)) + return ActOnDependentIdExpression(SS, NameInfo, IsAddressOfOperand, + TemplateArgs); + if (DiagnoseEmptyLookup(S, SS, R, CTC_Unknown)) return ExprError(); @@ -1688,7 +1786,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S, if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { R.clear(); ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); - assert(E.isInvalid() || E.get()); + // In a hopelessly buggy code, Objective-C instance variable + // lookup fails and no expression will be built to reference it. + if (!E.isInvalid() && !E.get()) + return ExprError(); return move(E); } } @@ -1723,7 +1824,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // instance method. if (!R.empty() && (*R.begin())->isCXXClassMember()) { bool MightBeImplicitMember; - if (!isAddressOfOperand) + if (!IsAddressOfOperand) MightBeImplicitMember = true; else if (!SS.isEmpty()) MightBeImplicitMember = false; @@ -1950,7 +2051,7 @@ Sema::PerformObjectMemberConversion(Expr *From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); - ExprValueKind VK = CastCategory(From); + ExprValueKind VK = From->getValueKind(); // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its @@ -2341,7 +2442,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. // This should only be possible with a type written directly. - if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType())) + if (const FunctionProtoType *proto + = dyn_cast<FunctionProtoType>(VD->getType())) if (proto->getResultType() == Context.UnknownAnyTy) { type = Context.UnknownAnyTy; valueKind = VK_RValue; @@ -2375,7 +2477,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentType IT; switch (Kind) { - default: assert(0 && "Unknown simple primary expr!"); + default: llvm_unreachable("Unknown simple primary expr!"); case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2] case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break; case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break; @@ -2408,12 +2510,12 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; bool Invalid = false; - llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); + StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); if (Invalid) return ExprError(); CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), - PP); + PP, Tok.getKind()); if (Literal.hadError()) return ExprError(); @@ -2422,14 +2524,25 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { Ty = Context.IntTy; // 'x' and L'x' -> int in C. else if (Literal.isWide()) Ty = Context.WCharTy; // L'x' -> wchar_t in C++. + else if (Literal.isUTF16()) + Ty = Context.Char16Ty; // u'x' -> char16_t in C++0x. + else if (Literal.isUTF32()) + Ty = Context.Char32Ty; // U'x' -> char32_t in C++0x. else if (Literal.isMultiChar()) Ty = Context.IntTy; // 'wxyz' -> int in C++. else Ty = Context.CharTy; // 'x' -> char in C++ - return Owned(new (Context) CharacterLiteral(Literal.getValue(), - Literal.isWide(), - Ty, Tok.getLocation())); + CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii; + if (Literal.isWide()) + Kind = CharacterLiteral::Wide; + else if (Literal.isUTF16()) + Kind = CharacterLiteral::UTF16; + else if (Literal.isUTF32()) + Kind = CharacterLiteral::UTF32; + + return Owned(new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty, + Tok.getLocation())); } ExprResult Sema::ActOnNumericConstant(const Token &Tok) { @@ -2437,7 +2550,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // cannot have a trigraph, escaped newline, radix prefix, or type suffix. if (Tok.getLength() == 1) { const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok); - unsigned IntSize = Context.Target.getIntWidth(); + unsigned IntSize = Context.getTargetInfo().getIntWidth(); return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'), Context.IntTy, Tok.getLocation())); } @@ -2492,7 +2605,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { Diag(Tok.getLocation(), diagnostic) << Ty - << llvm::StringRef(buffer.data(), buffer.size()); + << StringRef(buffer.data(), buffer.size()); } bool isExact = (result == APFloat::opOK); @@ -2517,7 +2630,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { Diag(Tok.getLocation(), diag::ext_longlong); // Get the value in the widest-possible width. - llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0); + llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0); if (Literal.GetIntegerValue(ResultVal)) { // If this value didn't fit into uintmax_t, warn and force to ull. @@ -2537,7 +2650,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { unsigned Width = 0; if (!Literal.isLong && !Literal.isLongLong) { // Are int/unsigned possibilities? - unsigned IntSize = Context.Target.getIntWidth(); + unsigned IntSize = Context.getTargetInfo().getIntWidth(); // Does it fit in a unsigned int? if (ResultVal.isIntN(IntSize)) { @@ -2552,7 +2665,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Are long/unsigned long possibilities? if (Ty.isNull() && !Literal.isLongLong) { - unsigned LongSize = Context.Target.getLongWidth(); + unsigned LongSize = Context.getTargetInfo().getLongWidth(); // Does it fit in a unsigned long? if (ResultVal.isIntN(LongSize)) { @@ -2567,7 +2680,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Finally, check long long if needed. if (Ty.isNull()) { - unsigned LongLongSize = Context.Target.getLongLongWidth(); + unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth(); // Does it fit in a unsigned long long? if (ResultVal.isIntN(LongLongSize)) { @@ -2575,7 +2688,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // To be compatible with MSVC, hex integer literals ending with the // LL or i64 suffix are always signed in Microsoft mode. if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 || - (getLangOptions().Microsoft && Literal.isLongLong))) + (getLangOptions().MicrosoftExt && Literal.isLongLong))) Ty = Context.LongLongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; @@ -2588,7 +2701,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { if (Ty.isNull()) { Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed); Ty = Context.UnsignedLongLongTy; - Width = Context.Target.getLongLongWidth(); + Width = Context.getTargetInfo().getLongLongWidth(); } if (ResultVal.getBitWidth() != Width) @@ -2605,8 +2718,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { return Owned(Res); } -ExprResult Sema::ActOnParenExpr(SourceLocation L, - SourceLocation R, Expr *E) { +ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) { assert((E != 0) && "ActOnParenExpr() missing expr"); return Owned(new (Context) ParenExpr(L, R, E)); } @@ -2672,9 +2784,9 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, /// expression. The logic mostly mirrors the type-based overload, but may modify /// the expression as it completes the type for that expression through template /// instantiation, etc. -bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, +bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind) { - QualType ExprTy = Op->getType(); + QualType ExprTy = E->getType(); // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." @@ -2684,36 +2796,36 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, ExprTy = Ref->getPointeeType(); if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange()); + return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), + E->getSourceRange()); // Whitelist some types as extensions - if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange(), ExprKind)) + if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(), + E->getSourceRange(), ExprKind)) return false; - if (RequireCompleteExprType(Op, + if (RequireCompleteExprType(E, PDiag(diag::err_sizeof_alignof_incomplete_type) - << ExprKind << Op->getSourceRange(), + << ExprKind << E->getSourceRange(), std::make_pair(SourceLocation(), PDiag(0)))) return true; // Completeing the expression's type may have changed it. - ExprTy = Op->getType(); + ExprTy = E->getType(); if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) ExprTy = Ref->getPointeeType(); - if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(), - Op->getSourceRange(), ExprKind)) + if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), + E->getSourceRange(), ExprKind)) return true; if (ExprKind == UETT_SizeOf) { - if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(Op->IgnoreParens())) { + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { QualType OType = PVD->getOriginalType(); QualType Type = PVD->getType(); if (Type->isPointerType() && OType->isArrayType()) { - Diag(Op->getExprLoc(), diag::warn_sizeof_array_param) + Diag(E->getExprLoc(), diag::warn_sizeof_array_param) << Type << OType; Diag(PVD->getLocation(), diag::note_declared_at); } @@ -2739,34 +2851,34 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, /// standard conversions are not applied to the operand of sizeof. /// /// This policy is followed for all of the unary trait expressions. -bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind) { - if (exprType->isDependentType()) + if (ExprType->isDependentType()) return false; // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = exprType->getAs<ReferenceType>()) - exprType = Ref->getPointeeType(); + if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) + ExprType = Ref->getPointeeType(); if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange); + return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); // Whitelist some types as extensions - if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange, + if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, ExprKind)) return false; - if (RequireCompleteType(OpLoc, exprType, + if (RequireCompleteType(OpLoc, ExprType, PDiag(diag::err_sizeof_alignof_incomplete_type) << ExprKind << ExprRange)) return true; - if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange, + if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, ExprKind)) return true; @@ -2870,12 +2982,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, /// Note that the ArgRange is invalid if isType is false. ExprResult Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, bool isType, + UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, const SourceRange &ArgRange) { // If error parsing type, ignore. if (TyOrEx == 0) return ExprError(); - if (isType) { + if (IsType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); @@ -2887,7 +2999,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, } static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, - bool isReal) { + bool IsReal) { if (V.get()->isTypeDependent()) return S.Context.DependentTy; @@ -2911,12 +3023,12 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, if (PR.isInvalid()) return QualType(); if (PR.get() != V.get()) { V = move(PR); - return CheckRealImagOperand(S, V, Loc, isReal); + return CheckRealImagOperand(S, V, Loc, IsReal); } // Reject anything else. S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType() - << (isReal ? "__real" : "__imag"); + << (IsReal ? "__real" : "__imag"); return QualType(); } @@ -2927,7 +3039,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input) { UnaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown unary op!"); + default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PostInc; break; case tok::minusminus: Opc = UO_PostDec; break; } @@ -2967,7 +3079,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, - Expr *Idx, SourceLocation RLoc) { + Expr *Idx, SourceLocation RLoc) { Expr *LHSExp = Base; Expr *RHSExp = Idx; @@ -3190,7 +3302,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool IsExecConfig) { // Bail out early if calling a builtin with custom typechecking. // We don't need to do this in the if (FDecl) @@ -3202,14 +3315,29 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); bool Invalid = false; + unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumArgsInProto; + unsigned FnKind = Fn->getType()->isBlockPointerType() + ? 1 /* block */ + : (IsExecConfig ? 3 /* kernel function (exec config) */ + : 0 /* function */); // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { - if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) - << Fn->getType()->isBlockPointerType() - << NumArgsInProto << NumArgs << Fn->getSourceRange(); + if (NumArgs < MinArgs) { + Diag(RParenLoc, MinArgs == NumArgsInProto + ? diag::err_typecheck_call_too_few_args + : diag::err_typecheck_call_too_few_args_at_least) + << FnKind + << MinArgs << NumArgs << Fn->getSourceRange(); + + // Emit the location of the prototype. + if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig) + Diag(FDecl->getLocStart(), diag::note_callee_decl) + << FDecl; + + return true; + } Call->setNumArgs(Context, NumArgsInProto); } @@ -3218,24 +3346,25 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (NumArgs > NumArgsInProto) { if (!Proto->isVariadic()) { Diag(Args[NumArgsInProto]->getLocStart(), - diag::err_typecheck_call_too_many_args) - << Fn->getType()->isBlockPointerType() + MinArgs == NumArgsInProto + ? diag::err_typecheck_call_too_many_args + : diag::err_typecheck_call_too_many_args_at_most) + << FnKind << NumArgsInProto << NumArgs << Fn->getSourceRange() << SourceRange(Args[NumArgsInProto]->getLocStart(), Args[NumArgs-1]->getLocEnd()); // Emit the location of the prototype. - if (FDecl && !FDecl->getBuiltinID()) - Diag(FDecl->getLocStart(), - diag::note_typecheck_call_too_many_args) - << FDecl; + if (FDecl && !FDecl->getBuiltinID() && !IsExecConfig) + Diag(FDecl->getLocStart(), diag::note_callee_decl) + << FDecl; // This deletes the extra arguments. Call->setNumArgs(Context, NumArgsInProto); return true; } } - llvm::SmallVector<Expr *, 8> AllArgs; + SmallVector<Expr *, 8> AllArgs; VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; if (Fn->getType()->isBlockPointerType()) @@ -3258,7 +3387,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, const FunctionProtoType *Proto, unsigned FirstProtoArg, Expr **Args, unsigned NumArgs, - llvm::SmallVector<Expr *, 8> &AllArgs, + SmallVector<Expr *, 8> &AllArgs, VariadicCallType CallType) { unsigned NumArgsInProto = Proto->getNumArgs(); unsigned NumArgsToCheck = NumArgs; @@ -3307,6 +3436,12 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, Arg = ArgExpr.takeAs<Expr>(); } + + // Check for array bounds violations for each argument to the call. This + // check only triggers warnings when the argument isn't a more complex Expr + // with its own checking, such as a BinaryOperator. + CheckArrayAccess(Arg); + AllArgs.push_back(Arg); } @@ -3330,11 +3465,16 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // Otherwise do argument promotion, (C99 6.5.2.2p7). } else { for (unsigned i = ArgIx; i != NumArgs; ++i) { - ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl); + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, + FDecl); Invalid |= Arg.isInvalid(); AllArgs.push_back(Arg.take()); } } + + // Check for array bounds violations. + for (unsigned i = ArgIx; i != NumArgs; ++i) + CheckArrayAccess(Args[i]); } return Invalid; } @@ -3348,16 +3488,16 @@ static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); /// locations. ExprResult Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, - MultiExprArg args, SourceLocation RParenLoc, - Expr *ExecConfig) { - unsigned NumArgs = args.size(); + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig, bool IsExecConfig) { + unsigned NumArgs = ArgExprs.size(); // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn); if (Result.isInvalid()) return ExprError(); Fn = Result.take(); - Expr **Args = args.release(); + Expr **Args = ArgExprs.release(); if (getLangOptions().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. @@ -3419,8 +3559,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic if there's an '&' involved. - if (!find.IsAddressOfOperand) { + // We aren't supposed to apply this logic for if there's an '&' involved. + if (!find.HasFormOfMemberPointer) { OverloadExpr *ovl = find.Expression; if (isa<UnresolvedLookupExpr>(ovl)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl); @@ -3448,12 +3588,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc, - ExecConfig); + ExecConfig, IsExecConfig); } ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, - MultiExprArg execConfig, SourceLocation GGGLoc) { + MultiExprArg ExecConfig, SourceLocation GGGLoc) { FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); if (!ConfigDecl) return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) @@ -3463,27 +3603,29 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, DeclRefExpr *ConfigDR = new (Context) DeclRefExpr( ConfigDecl, ConfigQTy, VK_LValue, LLLLoc); - return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); + return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0, + /*IsExecConfig=*/true); } /// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. /// /// __builtin_astype( value, dst type ) /// -ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty, +ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc) { ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; - QualType DstTy = GetTypeFromParser(destty); - QualType SrcTy = expr->getType(); + QualType DstTy = GetTypeFromParser(ParsedDestTy); + QualType SrcTy = E->getType(); if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) return ExprError(Diag(BuiltinLoc, diag::err_invalid_astype_of_different_size) << DstTy << SrcTy - << expr->getSourceRange()); - return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc)); + << E->getSourceRange()); + return Owned(new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc, + RParenLoc)); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -3497,7 +3639,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, - Expr *Config) { + Expr *Config, bool IsExecConfig) { FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); // Promote the function operand. @@ -3567,6 +3709,11 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (!FuncT->getResultType()->isVoidType()) return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return) << Fn->getType() << Fn->getSourceRange()); + } else { + // CUDA: Calls to global functions must be configured + if (FDecl && FDecl->hasAttr<CUDAGlobalAttr>()) + return ExprError(Diag(LParenLoc, diag::err_global_call_not_config) + << FDecl->getName() << Fn->getSourceRange()); } } @@ -3582,7 +3729,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs, - RParenLoc)) + RParenLoc, IsExecConfig)) return ExprError(); } else { assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!"); @@ -3682,23 +3829,23 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, ExprResult Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, - SourceLocation RParenLoc, Expr *literalExpr) { + SourceLocation RParenLoc, Expr *LiteralExpr) { QualType literalType = TInfo->getType(); if (literalType->isArrayType()) { if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType), PDiag(diag::err_illegal_decl_array_incomplete_type) << SourceRange(LParenLoc, - literalExpr->getSourceRange().getEnd()))) + LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) - << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())); + << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())); } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, PDiag(diag::err_typecheck_decl_incomplete_type) << SourceRange(LParenLoc, - literalExpr->getSourceRange().getEnd()))) + LiteralExpr->getSourceRange().getEnd()))) return ExprError(); InitializedEntity Entity @@ -3706,17 +3853,17 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializationKind Kind = InitializationKind::CreateCStyleCast(LParenLoc, SourceRange(LParenLoc, RParenLoc)); - InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &literalExpr, 1), + MultiExprArg(*this, &LiteralExpr, 1), &literalType); if (Result.isInvalid()) return ExprError(); - literalExpr = Result.get(); + LiteralExpr = Result.get(); bool isFileScope = getCurFunctionOrMethodDecl() == 0; if (isFileScope) { // 6.5.2.5p3 - if (CheckForConstantInitializer(literalExpr, literalType)) + if (CheckForConstantInitializer(LiteralExpr, literalType)) return ExprError(); } @@ -3725,14 +3872,14 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return MaybeBindToTemporary( new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - VK, literalExpr, isFileScope)); + VK, LiteralExpr, isFileScope)); } ExprResult -Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, +Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { - unsigned NumInit = initlist.size(); - Expr **InitList = initlist.release(); + unsigned NumInit = InitArgList.size(); + Expr **InitList = InitArgList.release(); // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. @@ -3743,27 +3890,68 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } +/// Do an explicit extend of the given block pointer if we're in ARC. +static void maybeExtendBlockObject(Sema &S, ExprResult &E) { + assert(E.get()->getType()->isBlockPointerType()); + assert(E.get()->isRValue()); + + // Only do this in an r-value context. + if (!S.getLangOptions().ObjCAutoRefCount) return; + + E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), + CK_ARCExtendBlockObject, E.get(), + /*base path*/ 0, VK_RValue); + S.ExprNeedsCleanups = true; +} + +/// Prepare a conversion of the given expression to an ObjC object +/// pointer type. +CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { + QualType type = E.get()->getType(); + if (type->isObjCObjectPointerType()) { + return CK_BitCast; + } else if (type->isBlockPointerType()) { + maybeExtendBlockObject(*this, E); + return CK_BlockPointerToObjCPointerCast; + } else { + assert(type->isPointerType()); + return CK_CPointerToObjCPointerCast; + } +} + /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. -static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { +CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { // Both Src and Dest are scalar types, i.e. arithmetic or pointer. // Also, callers should have filtered out the invalid cases with // pointers. Everything else should be possible. QualType SrcTy = Src.get()->getType(); - if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy)) + if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; - switch (SrcTy->getScalarTypeKind()) { + switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) { case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_BlockPointer: + case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: - return DestTy->isObjCObjectPointerType() ? - CK_AnyPointerToObjCPointerCast : - CK_BitCast; + case Type::STK_CPointer: + return CK_BitCast; + case Type::STK_BlockPointer: + return (SrcKind == Type::STK_BlockPointer + ? CK_BitCast : CK_AnyPointerToBlockPointerCast); + case Type::STK_ObjCObjectPointer: + if (SrcKind == Type::STK_ObjCObjectPointer) + return CK_BitCast; + else if (SrcKind == Type::STK_CPointer) + return CK_CPointerToObjCPointerCast; + else { + maybeExtendBlockObject(*this, Src); + return CK_BlockPointerToObjCPointerCast; + } case Type::STK_Bool: return CK_PointerToBoolean; case Type::STK_Integral: @@ -3779,8 +3967,11 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { - case Type::STK_Pointer: - if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: + if (Src.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) return CK_NullToPointer; return CK_IntegralToPointer; case Type::STK_Bool: @@ -3790,12 +3981,14 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Floating: return CK_IntegralToFloating; case Type::STK_IntegralComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralCast); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_IntegralCast); return CK_IntegralRealToComplex; case Type::STK_FloatingComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralToFloating); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_IntegralToFloating); return CK_FloatingRealToComplex; case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3811,14 +4004,18 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_Integral: return CK_FloatingToIntegral; case Type::STK_FloatingComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingCast); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_FloatingCast); return CK_FloatingRealToComplex; case Type::STK_IntegralComplex: - Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingToIntegral); + Src = ImpCastExprToType(Src.take(), + DestTy->castAs<ComplexType>()->getElementType(), + CK_FloatingToIntegral); return CK_IntegralRealToComplex; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3832,19 +4029,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_IntegralComplex: return CK_FloatingComplexToIntegralComplex; case Type::STK_Floating: { - QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); - if (S.Context.hasSameType(ET, DestTy)) + QualType ET = SrcTy->castAs<ComplexType>()->getElementType(); + if (Context.hasSameType(ET, DestTy)) return CK_FloatingComplexToReal; - Src = S.ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal); + Src = ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal); return CK_FloatingCast; } case Type::STK_Bool: return CK_FloatingComplexToBoolean; case Type::STK_Integral: - Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), - CK_FloatingComplexToReal); + Src = ImpCastExprToType(Src.take(), + SrcTy->castAs<ComplexType>()->getElementType(), + CK_FloatingComplexToReal); return CK_FloatingToIntegral; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3858,19 +4058,22 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { case Type::STK_IntegralComplex: return CK_IntegralComplexCast; case Type::STK_Integral: { - QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); - if (S.Context.hasSameType(ET, DestTy)) + QualType ET = SrcTy->castAs<ComplexType>()->getElementType(); + if (Context.hasSameType(ET, DestTy)) return CK_IntegralComplexToReal; - Src = S.ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal); + Src = ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal); return CK_IntegralCast; } case Type::STK_Bool: return CK_IntegralComplexToBoolean; case Type::STK_Floating: - Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), - CK_IntegralComplexToReal); + Src = ImpCastExprToType(Src.take(), + SrcTy->castAs<ComplexType>()->getElementType(), + CK_IntegralComplexToReal); return CK_IntegralToFloating; - case Type::STK_Pointer: + case Type::STK_CPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_BlockPointer: llvm_unreachable("valid complex int->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -3879,193 +4082,6 @@ static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { } llvm_unreachable("Unhandled scalar cast"); - return CK_BitCast; -} - -/// CheckCastTypes - Check type constraints for casting between types. -ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR, - QualType castType, Expr *castExpr, - CastKind& Kind, ExprValueKind &VK, - CXXCastPath &BasePath, bool FunctionalStyle) { - if (castExpr->getType() == Context.UnknownAnyTy) - return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); - - if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(SourceRange(CastStartLoc, - castExpr->getLocEnd()), - castType, VK, castExpr, Kind, BasePath, - FunctionalStyle); - - assert(!castExpr->getType()->isPlaceholderType()); - - // We only support r-value casts in C. - VK = VK_RValue; - - // C99 6.5.4p2: the cast type needs to be void or scalar and the expression - // type needs to be scalar. - if (castType->isVoidType()) { - // We don't necessarily do lvalue-to-rvalue conversions on this. - ExprResult castExprRes = IgnoredValueConversions(castExpr); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - // Cast to void allows any expr type. - Kind = CK_ToVoid; - return Owned(castExpr); - } - - ExprResult castExprRes = DefaultFunctionArrayLvalueConversion(castExpr); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - if (RequireCompleteType(TyR.getBegin(), castType, - diag::err_typecheck_cast_to_incomplete)) - return ExprError(); - - if (!castType->isScalarType() && !castType->isVectorType()) { - if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && - (castType->isStructureType() || castType->isUnionType())) { - // GCC struct/union extension: allow cast to self. - // FIXME: Check that the cast destination type is complete. - Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) - << castType << castExpr->getSourceRange(); - Kind = CK_NoOp; - return Owned(castExpr); - } - - if (castType->isUnionType()) { - // GCC cast to union extension - RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); - RecordDecl::field_iterator Field, FieldEnd; - for (Field = RD->field_begin(), FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Context.hasSameUnqualifiedType(Field->getType(), - castExpr->getType()) && - !Field->isUnnamedBitfield()) { - Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) - << castExpr->getSourceRange(); - break; - } - } - if (Field == FieldEnd) { - Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) - << castExpr->getType() << castExpr->getSourceRange(); - return ExprError(); - } - Kind = CK_ToUnion; - return Owned(castExpr); - } - - // Reject any other conversions to non-scalar types. - Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) - << castType << castExpr->getSourceRange(); - return ExprError(); - } - - // The type we're casting to is known to be a scalar or vector. - - // Require the operand to be a scalar or vector. - if (!castExpr->getType()->isScalarType() && - !castExpr->getType()->isVectorType()) { - Diag(castExpr->getLocStart(), - diag::err_typecheck_expect_scalar_operand) - << castExpr->getType() << castExpr->getSourceRange(); - return ExprError(); - } - - if (castType->isExtVectorType()) - return CheckExtVectorCast(TyR, castType, castExpr, Kind); - - if (castType->isVectorType()) { - if (castType->getAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector && - (castExpr->getType()->isIntegerType() || - castExpr->getType()->isFloatingType())) { - Kind = CK_VectorSplat; - return Owned(castExpr); - } else if (CheckVectorCast(TyR, castType, castExpr->getType(), Kind)) { - return ExprError(); - } else - return Owned(castExpr); - } - if (castExpr->getType()->isVectorType()) { - if (CheckVectorCast(TyR, castExpr->getType(), castType, Kind)) - return ExprError(); - else - return Owned(castExpr); - } - - // The source and target types are both scalars, i.e. - // - arithmetic types (fundamental, enum, and complex) - // - all kinds of pointers - // Note that member pointers were filtered out with C++, above. - - if (isa<ObjCSelectorExpr>(castExpr)) { - Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); - return ExprError(); - } - - // If either type is a pointer, the other type has to be either an - // integer or a pointer. - QualType castExprType = castExpr->getType(); - if (!castType->isArithmeticType()) { - if (!castExprType->isIntegralType(Context) && - castExprType->isArithmeticType()) { - Diag(castExpr->getLocStart(), - diag::err_cast_pointer_from_non_pointer_int) - << castExprType << castExpr->getSourceRange(); - return ExprError(); - } - } else if (!castExpr->getType()->isArithmeticType()) { - if (!castType->isIntegralType(Context) && castType->isArithmeticType()) { - Diag(castExpr->getLocStart(), diag::err_cast_pointer_to_non_pointer_int) - << castType << castExpr->getSourceRange(); - return ExprError(); - } - } - - if (getLangOptions().ObjCAutoRefCount) { - // Diagnose problems with Objective-C casts involving lifetime qualifiers. - CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()), - castType, castExpr, CCK_CStyleCast); - - if (const PointerType *CastPtr = castType->getAs<PointerType>()) { - if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) { - Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers(); - Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers(); - if (CastPtr->getPointeeType()->isObjCLifetimeType() && - ExprPtr->getPointeeType()->isObjCLifetimeType() && - !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) { - Diag(castExpr->getLocStart(), - diag::err_typecheck_incompatible_ownership) - << castExprType << castType << AA_Casting - << castExpr->getSourceRange(); - - return ExprError(); - } - } - } - else if (!CheckObjCARCUnavailableWeakConversion(castType, castExprType)) { - Diag(castExpr->getLocStart(), - diag::err_arc_convesion_of_weak_unavailable) << 1 - << castExprType << castType - << castExpr->getSourceRange(); - return ExprError(); - } - } - - castExprRes = Owned(castExpr); - Kind = PrepareScalarCast(*this, castExprRes, castType); - if (castExprRes.isInvalid()) - return ExprError(); - castExpr = castExprRes.take(); - - if (Kind == CK_BitCast) - CheckCastAlign(castExpr, castType, TyR); - - return Owned(castExpr); } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, @@ -4096,8 +4112,12 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. + // In OpenCL, casts between vectors of different types are not allowed. + // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) { + if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy) + || (getLangOptions().OpenCL && + (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; return ExprError(); @@ -4116,7 +4136,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); ExprResult CastExprRes = Owned(CastExpr); - CastKind CK = PrepareScalarCast(*this, CastExprRes, DestElemTy); + CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy); if (CastExprRes.isInvalid()) return ExprError(); CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take(); @@ -4128,11 +4148,11 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, ExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, - SourceLocation RParenLoc, Expr *castExpr) { - assert(!D.isInvalidType() && (castExpr != 0) && + SourceLocation RParenLoc, Expr *CastExpr) { + assert(!D.isInvalidType() && (CastExpr != 0) && "ActOnCastExpr(): missing type or expr"); - TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType()); + TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, CastExpr->getType()); if (D.isInvalidType()) return ExprError(); @@ -4141,6 +4161,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, CheckExtraCXXDefaultArguments(D); } + checkUnusedDeclAttributes(D); + QualType castType = castTInfo->getType(); Ty = CreateParsedType(castType, castTInfo); @@ -4148,9 +4170,10 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, // Check for an altivec or OpenCL literal, // i.e. all the elements are integer constants. - ParenExpr *PE = dyn_cast<ParenExpr>(castExpr); - ParenListExpr *PLE = dyn_cast<ParenListExpr>(castExpr); - if (getLangOptions().AltiVec && castType->isVectorType() && (PE || PLE)) { + ParenExpr *PE = dyn_cast<ParenExpr>(CastExpr); + ParenListExpr *PLE = dyn_cast<ParenListExpr>(CastExpr); + if ((getLangOptions().AltiVec || getLangOptions().OpenCL) + && castType->isVectorType() && (PE || PLE)) { if (PLE && PLE->getNumExprs() == 0) { Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer); return ExprError(); @@ -4167,37 +4190,18 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. if (isVectorLiteral) - return BuildVectorLiteral(LParenLoc, RParenLoc, castExpr, castTInfo); + return BuildVectorLiteral(LParenLoc, RParenLoc, CastExpr, castTInfo); // If the Expr being casted is a ParenListExpr, handle it specially. // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. - if (isa<ParenListExpr>(castExpr)) { - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, castExpr); + if (isa<ParenListExpr>(CastExpr)) { + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, CastExpr); if (Result.isInvalid()) return ExprError(); - castExpr = Result.take(); + CastExpr = Result.take(); } - return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr); -} - -ExprResult -Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, - SourceLocation RParenLoc, Expr *castExpr) { - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - ExprResult CastResult = - CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(), - castExpr, Kind, VK, BasePath); - if (CastResult.isInvalid()) - return ExprError(); - castExpr = CastResult.take(); - - return Owned(CStyleCastExpr::Create(Context, - Ty->getType().getNonLValueExprType(Context), - VK, Kind, castExpr, &BasePath, Ty, - LParenLoc, RParenLoc)); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, @@ -4221,7 +4225,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType Ty = TInfo->getType(); assert(Ty->isVectorType() && "Expected vector type"); - llvm::SmallVector<Expr *, 8> initExprs; + SmallVector<Expr *, 8> initExprs; const VectorType *VTy = Ty->getAs<VectorType>(); unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); @@ -4237,7 +4241,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); ExprResult Literal = Owned(exprs[0]); Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); + PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); } else if (numExprs < numElems) { @@ -4258,7 +4262,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); ExprResult Literal = Owned(exprs[0]); Literal = ImpCastExprToType(Literal.take(), ElemTy, - PrepareScalarCast(*this, Literal, ElemTy)); + PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); } @@ -4277,10 +4281,10 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, /// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence /// of comma binary operators. ExprResult -Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { - ParenListExpr *E = dyn_cast<ParenListExpr>(expr); +Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { + ParenListExpr *E = dyn_cast<ParenListExpr>(OrigExpr); if (!E) - return Owned(expr); + return Owned(OrigExpr); ExprResult Result(E->getExpr(0)); @@ -4294,8 +4298,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { } ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, - SourceLocation R, - MultiExprArg Val) { + SourceLocation R, + MultiExprArg Val) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast<Expr**>(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); @@ -4309,18 +4313,19 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, } /// \brief Emit a specialized diagnostic when one expression is a null pointer -/// constant and the other is not a pointer. -bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, +/// constant and the other is not a pointer. Returns true if a diagnostic is +/// emitted. +bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc) { - Expr *NullExpr = LHS; - Expr *NonPointerExpr = RHS; + Expr *NullExpr = LHSExpr; + Expr *NonPointerExpr = RHSExpr; Expr::NullPointerConstantKind NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); if (NullKind == Expr::NPCK_NotNull) { - NullExpr = RHS; - NonPointerExpr = LHS; + NullExpr = RHSExpr; + NonPointerExpr = LHSExpr; NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); @@ -4345,20 +4350,228 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, return true; } -/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension. -/// In that case, lhs = cond. +/// \brief Return false if the condition expression is valid, true otherwise. +static bool checkCondition(Sema &S, Expr *Cond) { + QualType CondTy = Cond->getType(); + + // C99 6.5.15p2 + if (CondTy->isScalarType()) return false; + + // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. + if (S.getLangOptions().OpenCL && CondTy->isVectorType()) + return false; + + // Emit the proper error message. + S.Diag(Cond->getLocStart(), S.getLangOptions().OpenCL ? + diag::err_typecheck_cond_expect_scalar : + diag::err_typecheck_cond_expect_scalar_or_vector) + << CondTy; + return true; +} + +/// \brief Return false if the two expressions can be converted to a vector, +/// true otherwise +static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS, + ExprResult &RHS, + QualType CondTy) { + // Both operands should be of scalar type. + if (!LHS.get()->getType()->isScalarType()) { + S.Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return true; + } + if (!RHS.get()->getType()->isScalarType()) { + S.Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return true; + } + + // Implicity convert these scalars to the type of the condition. + LHS = S.ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast); + RHS = S.ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast); + return false; +} + +/// \brief Handle when one or both operands are void type. +static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, + ExprResult &RHS) { + Expr *LHSExpr = LHS.get(); + Expr *RHSExpr = RHS.get(); + + if (!LHSExpr->getType()->isVoidType()) + S.Diag(RHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void) + << RHSExpr->getSourceRange(); + if (!RHSExpr->getType()->isVoidType()) + S.Diag(LHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void) + << LHSExpr->getSourceRange(); + LHS = S.ImpCastExprToType(LHS.take(), S.Context.VoidTy, CK_ToVoid); + RHS = S.ImpCastExprToType(RHS.take(), S.Context.VoidTy, CK_ToVoid); + return S.Context.VoidTy; +} + +/// \brief Return false if the NullExpr can be promoted to PointerTy, +/// true otherwise. +static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, + QualType PointerTy) { + if ((!PointerTy->isAnyPointerType() && !PointerTy->isBlockPointerType()) || + !NullExpr.get()->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNull)) + return true; + + NullExpr = S.ImpCastExprToType(NullExpr.take(), PointerTy, CK_NullToPointer); + return false; +} + +/// \brief Checks compatibility between two pointers and return the resulting +/// type. +static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + if (S.Context.hasSameType(LHSTy, RHSTy)) { + // Two identical pointers types are always compatible. + return LHSTy; + } + + QualType lhptee, rhptee; + + // Get the pointee types. + if (const BlockPointerType *LHSBTy = LHSTy->getAs<BlockPointerType>()) { + lhptee = LHSBTy->getPointeeType(); + rhptee = RHSTy->castAs<BlockPointerType>()->getPointeeType(); + } else { + lhptee = LHSTy->castAs<PointerType>()->getPointeeType(); + rhptee = RHSTy->castAs<PointerType>()->getPointeeType(); + } + + if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) { + S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + // In this situation, we assume void* type. No especially good + // reason, but this is what gcc does, and we do have to pick + // to get a consistent AST. + QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy); + LHS = S.ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); + return incompatTy; + } + + // The pointer types are compatible. + // C99 6.5.15p6: If both operands are pointers to compatible types *or* to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the *composite* + // type. + // FIXME: Need to calculate the composite type. + // FIXME: Need to add qualifiers + + LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + return LHSTy; +} + +/// \brief Return the resulting type when the operands are both block pointers. +static QualType checkConditionalBlockPointerCompatibility(Sema &S, + ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { + if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { + QualType destType = S.Context.getPointerType(S.Context.VoidTy); + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast); + return destType; + } + S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + // We have 2 block pointer types. + return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); +} + +/// \brief Return the resulting type when the operands are both pointers. +static QualType +checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + // get the pointer types + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + + // get the "pointed to" types + QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + + // ignore qualifiers on void (C99 6.5.15p3, clause 6) + if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { + // Figure out necessary qualifiers (C99 6.5.15p6) + QualType destPointee + = S.Context.getQualifiedType(lhptee, rhptee.getQualifiers()); + QualType destType = S.Context.getPointerType(destPointee); + // Add qualifiers if necessary. + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_NoOp); + // Promote to void*. + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast); + return destType; + } + if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { + QualType destPointee + = S.Context.getQualifiedType(rhptee, lhptee.getQualifiers()); + QualType destType = S.Context.getPointerType(destPointee); + // Add qualifiers if necessary. + RHS = S.ImpCastExprToType(RHS.take(), destType, CK_NoOp); + // Promote to void*. + LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast); + return destType; + } + + return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); +} + +/// \brief Return false if the first expression is not an integer and the second +/// expression is not a pointer, true otherwise. +static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, + Expr* PointerExpr, SourceLocation Loc, + bool IsIntFirstExpr) { + if (!PointerExpr->getType()->isPointerType() || + !Int.get()->getType()->isIntegerType()) + return false; + + Expr *Expr1 = IsIntFirstExpr ? Int.get() : PointerExpr; + Expr *Expr2 = IsIntFirstExpr ? PointerExpr : Int.get(); + + S.Diag(Loc, diag::warn_typecheck_cond_pointer_integer_mismatch) + << Expr1->getType() << Expr2->getType() + << Expr1->getSourceRange() << Expr2->getSourceRange(); + Int = S.ImpCastExprToType(Int.take(), PointerExpr->getType(), + CK_IntegralToPointer); + return true; +} + +/// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. +/// In that case, LHS = cond. /// C99 6.5.15 -QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, - ExprValueKind &VK, ExprObjectKind &OK, +QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation QuestionLoc) { - ExprResult lhsResult = CheckPlaceholderExpr(LHS.get()); - if (!lhsResult.isUsable()) return QualType(); - LHS = move(lhsResult); + ExprResult LHSResult = CheckPlaceholderExpr(LHS.get()); + if (!LHSResult.isUsable()) return QualType(); + LHS = move(LHSResult); - ExprResult rhsResult = CheckPlaceholderExpr(RHS.get()); - if (!rhsResult.isUsable()) return QualType(); - RHS = move(rhsResult); + ExprResult RHSResult = CheckPlaceholderExpr(RHS.get()); + if (!RHSResult.isUsable()) return QualType(); + RHS = move(RHSResult); // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) @@ -4382,23 +4595,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR QualType RHSTy = RHS.get()->getType(); // first, check the condition. - if (!CondTy->isScalarType()) { // C99 6.5.15p2 - // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar. - // Throw an error if its not either. - if (getLangOptions().OpenCL) { - if (!CondTy->isVectorType()) { - Diag(Cond.get()->getLocStart(), - diag::err_typecheck_cond_expect_scalar_or_vector) - << CondTy; - return QualType(); - } - } - else { - Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return QualType(); - } - } + if (checkCondition(*this, Cond.get())) + return QualType(); // Now check the two expressions. if (LHSTy->isVectorType() || RHSTy->isVectorType()) @@ -4407,22 +4605,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // OpenCL: If the condition is a vector, and both operands are scalar, // attempt to implicity convert them to the vector type to act like the // built in select. - if (getLangOptions().OpenCL && CondTy->isVectorType()) { - // Both operands should be of scalar type. - if (!LHSTy->isScalarType()) { - Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; - return QualType(); - } - if (!RHSTy->isScalarType()) { - Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) - << CondTy; + if (getLangOptions().OpenCL && CondTy->isVectorType()) + if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy)) return QualType(); - } - // Implicity convert these scalars to the type of the condition. - LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast); - RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast); - } // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. @@ -4447,29 +4632,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { - if (!LHSTy->isVoidType()) - Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) - << RHS.get()->getSourceRange(); - if (!RHSTy->isVoidType()) - Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) - << LHS.get()->getSourceRange(); - LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid); - RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid); - return Context.VoidTy; + return checkConditionalVoidType(*this, LHS, RHS); } + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." - if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && - RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - // promote the null to a pointer. - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer); - return LHSTy; - } - if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && - LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer); - return RHSTy; - } + if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy; + if (!checkConditionalNullPointer(*this, LHS, RHSTy)) return RHSTy; // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, @@ -4481,116 +4650,23 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Handle block pointer types. - if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { - if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { - if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { - QualType destType = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); - return destType; - } - Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - return QualType(); - } - // We have 2 block pointer types. - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical block pointer types are always compatible. - return LHSTy; - } - // The block pointer types aren't identical, continue checking. - QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); - - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { - Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - // In this situation, we assume void* type. No especially good - // reason, but this is what gcc does, and we do have to pick - // to get a consistent AST. - QualType incompatTy = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); - return incompatTy; - } - // The block pointer types are compatible. - LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); - return LHSTy; - } + if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) + return checkConditionalBlockPointerCompatibility(*this, LHS, RHS, + QuestionLoc); // Check constraints for C object pointers types (C99 6.5.15p3,6). - if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - // get the "pointed to" types - QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); - - // ignore qualifiers on void (C99 6.5.15p3, clause 6) - if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { - // Figure out necessary qualifiers (C99 6.5.15p6) - QualType destPointee - = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp); - // Promote to void*. - RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); - return destType; - } - if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { - QualType destPointee - = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp); - // Promote to void*. - LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); - return destType; - } - - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical pointer types are always compatible. - return LHSTy; - } - if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), - rhptee.getUnqualifiedType())) { - Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - // In this situation, we assume void* type. No especially good - // reason, but this is what gcc does, and we do have to pick - // to get a consistent AST. - QualType incompatTy = Context.getPointerType(Context.VoidTy); - LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); - return incompatTy; - } - // The pointer types are compatible. - // C99 6.5.15p6: If both operands are pointers to compatible types *or* to - // differently qualified versions of compatible types, the result type is - // a pointer to an appropriately qualified version of the *composite* - // type. - // FIXME: Need to calculate the composite type. - // FIXME: Need to add qualifiers - LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); - return LHSTy; - } + if (LHSTy->isPointerType() && RHSTy->isPointerType()) + return checkConditionalObjectPointersCompatibility(*this, LHS, RHS, + QuestionLoc); // GCC compatibility: soften pointer/integer mismatch. Note that // null pointers have been filtered out by this point. - if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { - Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer); + if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc, + /*isIntFirstExpr=*/true)) return RHSTy; - } - if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { - Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer); + if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc, + /*isIntFirstExpr=*/false)) return LHSTy; - } // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most @@ -4600,14 +4676,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprR // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); return QualType(); } /// FindCompositeObjCPointerType - Helper method to find composite type of /// two objective-c pointer types of the two input expressions. QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, - SourceLocation QuestionLoc) { + SourceLocation QuestionLoc) { QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); @@ -4615,34 +4692,34 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && - (Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + (Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) { + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCClassType() && - (Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + (Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) { + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && - (Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) { - RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); + (Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) { + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCIdType() && - (Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) { - LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); + (Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) { + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && - (Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) { + (Context.hasSameType(RHSTy, Context.getObjCSelRedefinitionType()))) { RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && - (Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) { + (Context.hasSameType(LHSTy, Context.getObjCSelRedefinitionType()))) { LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); return RHSTy; } @@ -4653,8 +4730,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, // Two identical object pointer types are always compatible. return LHSTy; } - const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *LHSOPT = LHSTy->castAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHSTy->castAs<ObjCObjectPointerType>(); QualType compositeType = LHSTy; // If both operands are interfaces and either operand can be @@ -4752,18 +4829,20 @@ static bool IsArithmeticOp(BinaryOperatorKind Opc) { /// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary /// expression, either using a built-in or overloaded operator, -/// and sets *OpCode to the opcode and *RHS to the right-hand side expression. +/// and sets *OpCode to the opcode and *RHSExprs to the right-hand side +/// expression. static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, - Expr **RHS) { - E = E->IgnoreParenImpCasts(); + Expr **RHSExprs) { + // Don't strip parenthesis: we should not warn if E is in parenthesis. + E = E->IgnoreImpCasts(); E = E->IgnoreConversionOperator(); - E = E->IgnoreParenImpCasts(); + E = E->IgnoreImpCasts(); // Built-in binary operator. if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { if (IsArithmeticOp(OP->getOpcode())) { *Opcode = OP->getOpcode(); - *RHS = OP->getRHS(); + *RHSExprs = OP->getRHS(); return true; } } @@ -4782,7 +4861,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); if (IsArithmeticOp(OpKind)) { *Opcode = OpKind; - *RHS = Call->getArg(1); + *RHSExprs = Call->getArg(1); return true; } } @@ -4817,8 +4896,8 @@ static bool ExprLooksBoolean(Expr *E) { static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, Expr *Condition, - Expr *LHS, - Expr *RHS) { + Expr *LHSExpr, + Expr *RHSExpr) { BinaryOperatorKind CondOpcode; Expr *CondRHS; @@ -4841,7 +4920,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self, SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_conditional_first), - SourceRange(CondRHS->getLocStart(), RHS->getLocEnd())); + SourceRange(CondRHS->getLocStart(), RHSExpr->getLocEnd())); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null @@ -4898,7 +4977,8 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, return Owned(new (Context) BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(), - RHS.take(), QuestionLoc, ColonLoc, result, VK, OK)); + RHS.take(), QuestionLoc, ColonLoc, result, VK, + OK)); } // checkPointerTypesForAssignment - This is a very tricky routine (despite @@ -4907,15 +4987,15 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. static Sema::AssignConvertType -checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { - assert(lhsType.isCanonical() && "LHS not canonicalized!"); - assert(rhsType.isCanonical() && "RHS not canonicalized!"); +checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { + assert(LHSType.isCanonical() && "LHS not canonicalized!"); + assert(RHSType.isCanonical() && "RHS not canonicalized!"); // get the "pointed to" type (ignoring qualifiers at the top level) const Type *lhptee, *rhptee; Qualifiers lhq, rhq; - llvm::tie(lhptee, lhq) = cast<PointerType>(lhsType)->getPointeeType().split(); - llvm::tie(rhptee, rhq) = cast<PointerType>(rhsType)->getPointeeType().split(); + llvm::tie(lhptee, lhq) = cast<PointerType>(LHSType)->getPointeeType().split(); + llvm::tie(rhptee, rhq) = cast<PointerType>(RHSType)->getPointeeType().split(); Sema::AssignConvertType ConvTy = Sema::Compatible; @@ -5019,6 +5099,9 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { // General pointer incompatibility takes priority over qualifiers. return Sema::IncompatiblePointer; } + if (!S.getLangOptions().CPlusPlus && + S.IsNoReturnConversion(ltrans, rtrans, ltrans)) + return Sema::IncompatiblePointer; return ConvTy; } @@ -5027,16 +5110,16 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { /// are compatible. It is more restrict than comparing two function pointer // types. static Sema::AssignConvertType -checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, - QualType rhsType) { - assert(lhsType.isCanonical() && "LHS not canonicalized!"); - assert(rhsType.isCanonical() && "RHS not canonicalized!"); +checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, + QualType RHSType) { + assert(LHSType.isCanonical() && "LHS not canonicalized!"); + assert(RHSType.isCanonical() && "RHS not canonicalized!"); QualType lhptee, rhptee; // get the "pointed to" type (ignoring qualifiers at the top level) - lhptee = cast<BlockPointerType>(lhsType)->getPointeeType(); - rhptee = cast<BlockPointerType>(rhsType)->getPointeeType(); + lhptee = cast<BlockPointerType>(LHSType)->getPointeeType(); + rhptee = cast<BlockPointerType>(RHSType)->getPointeeType(); // In C++, the types have to match exactly. if (S.getLangOptions().CPlusPlus) @@ -5048,7 +5131,7 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, if (lhptee.getLocalQualifiers() != rhptee.getLocalQualifiers()) ConvTy = Sema::CompatiblePointerDiscardsQualifiers; - if (!S.Context.typesAreBlockPointerCompatible(lhsType, rhsType)) + if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) return Sema::IncompatibleBlockPointer; return ConvTy; @@ -5057,51 +5140,49 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType lhsType, /// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types /// for assignment compatibility. static Sema::AssignConvertType -checkObjCPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { - assert(lhsType.isCanonical() && "LHS was not canonicalized!"); - assert(rhsType.isCanonical() && "RHS was not canonicalized!"); +checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType, + QualType RHSType) { + assert(LHSType.isCanonical() && "LHS was not canonicalized!"); + assert(RHSType.isCanonical() && "RHS was not canonicalized!"); - if (lhsType->isObjCBuiltinType()) { + if (LHSType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() && - !rhsType->isObjCQualifiedClassType()) + if (LHSType->isObjCClassType() && !RHSType->isObjCBuiltinType() && + !RHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } - if (rhsType->isObjCBuiltinType()) { - // Class is not compatible with ObjC object pointers. - if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() && - !lhsType->isObjCQualifiedClassType()) + if (RHSType->isObjCBuiltinType()) { + if (RHSType->isObjCClassType() && !LHSType->isObjCBuiltinType() && + !LHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } - QualType lhptee = - lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = - rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType(); if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) return Sema::CompatiblePointerDiscardsQualifiers; - if (S.Context.typesAreCompatible(lhsType, rhsType)) + if (S.Context.typesAreCompatible(LHSType, RHSType)) return Sema::Compatible; - if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) + if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType()) return Sema::IncompatibleObjCQualifiedId; return Sema::IncompatiblePointer; } Sema::AssignConvertType Sema::CheckAssignmentConstraints(SourceLocation Loc, - QualType lhsType, QualType rhsType) { + QualType LHSType, QualType RHSType) { // Fake up an opaque expression. We don't actually care about what // cast operations are required, so if CheckAssignmentConstraints // adds casts to this they'll be wasted, but fortunately that doesn't // usually happen on valid code. - OpaqueValueExpr rhs(Loc, rhsType, VK_RValue); - ExprResult rhsPtr = &rhs; + OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue); + ExprResult RHSPtr = &RHSExpr; CastKind K = CK_Invalid; - return CheckAssignmentConstraints(lhsType, rhsPtr, K); + return CheckAssignmentConstraints(LHSType, RHSPtr, K); } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -5122,18 +5203,22 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// /// Sets 'Kind' for any result kind except Incompatible. Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, +Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind) { - QualType rhsType = rhs.get()->getType(); - QualType origLhsType = lhsType; + QualType RHSType = RHS.get()->getType(); + QualType OrigLHSType = LHSType; // Get canonical types. We're not formatting these types, just comparing // them. - lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType(); - rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType(); + LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType(); + RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType(); + + // We can't do assignment from/to atomics yet. + if (LHSType->isAtomicType()) + return Incompatible; // Common case: no conversion required. - if (lhsType == rhsType) { + if (LHSType == RHSType) { Kind = CK_NoOp; return Compatible; } @@ -5143,10 +5228,10 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // e.g., as a parameter type in a built-in function. In this case, // just make sure that the type referenced is compatible with the // right-hand side type. The caller is responsible for adjusting - // lhsType so that the resulting expression does not have reference + // LHSType so that the resulting expression does not have reference // type. - if (const ReferenceType *lhsTypeRef = lhsType->getAs<ReferenceType>()) { - if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) { + if (const ReferenceType *LHSTypeRef = LHSType->getAs<ReferenceType>()) { + if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) { Kind = CK_LValueBitCast; return Compatible; } @@ -5155,16 +5240,16 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. - if (lhsType->isExtVectorType()) { - if (rhsType->isExtVectorType()) + if (LHSType->isExtVectorType()) { + if (RHSType->isExtVectorType()) return Incompatible; - if (rhsType->isArithmeticType()) { + if (RHSType->isArithmeticType()) { // CK_VectorSplat does T -> vector T, so first cast to the // element type. - QualType elType = cast<ExtVectorType>(lhsType)->getElementType(); - if (elType != rhsType) { - Kind = PrepareScalarCast(*this, rhs, elType); - rhs = ImpCastExprToType(rhs.take(), elType, Kind); + QualType elType = cast<ExtVectorType>(LHSType)->getElementType(); + if (elType != RHSType) { + Kind = PrepareScalarCast(RHS, elType); + RHS = ImpCastExprToType(RHS.take(), elType, Kind); } Kind = CK_VectorSplat; return Compatible; @@ -5172,11 +5257,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to or from vector type. - if (lhsType->isVectorType() || rhsType->isVectorType()) { - if (lhsType->isVectorType() && rhsType->isVectorType()) { + if (LHSType->isVectorType() || RHSType->isVectorType()) { + if (LHSType->isVectorType() && RHSType->isVectorType()) { // Allow assignments of an AltiVec vector type to an equivalent GCC // vector type and vice versa - if (Context.areCompatibleVectorTypes(lhsType, rhsType)) { + if (Context.areCompatibleVectorTypes(LHSType, RHSType)) { Kind = CK_BitCast; return Compatible; } @@ -5185,7 +5270,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, // vectors, the total size only needs to be the same. This is a bitcast; // no bits are changed but the result type is different. if (getLangOptions().LaxVectorConversions && - (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) { + (Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) { Kind = CK_BitCast; return IncompatibleVectors; } @@ -5194,38 +5279,39 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Arithmetic conversions. - if (lhsType->isArithmeticType() && rhsType->isArithmeticType() && - !(getLangOptions().CPlusPlus && lhsType->isEnumeralType())) { - Kind = PrepareScalarCast(*this, rhs, lhsType); + if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && + !(getLangOptions().CPlusPlus && LHSType->isEnumeralType())) { + Kind = PrepareScalarCast(RHS, LHSType); return Compatible; } // Conversions to normal pointers. - if (const PointerType *lhsPointer = dyn_cast<PointerType>(lhsType)) { + if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { Kind = CK_BitCast; - return checkPointerTypesForAssignment(*this, lhsType, rhsType); + return checkPointerTypesForAssignment(*this, LHSType, RHSType); } // int -> T* - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null? return IntToPointer; } // C pointers are not compatible with ObjC object pointers, // with two exceptions: - if (isa<ObjCObjectPointerType>(rhsType)) { + if (isa<ObjCObjectPointerType>(RHSType)) { // - conversions to void* - if (lhsPointer->getPointeeType()->isVoidType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (LHSPointer->getPointeeType()->isVoidType()) { + Kind = CK_BitCast; return Compatible; } // - conversions from 'Class' to the redefinition type - if (rhsType->isObjCClassType() && - Context.hasSameType(lhsType, Context.ObjCClassRedefinitionType)) { + if (RHSType->isObjCClassType() && + Context.hasSameType(LHSType, + Context.getObjCClassRedefinitionType())) { Kind = CK_BitCast; return Compatible; } @@ -5235,8 +5321,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // U^ -> void* - if (rhsType->getAs<BlockPointerType>()) { - if (lhsPointer->getPointeeType()->isVoidType()) { + if (RHSType->getAs<BlockPointerType>()) { + if (LHSPointer->getPointeeType()->isVoidType()) { Kind = CK_BitCast; return Compatible; } @@ -5246,27 +5332,27 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to block pointers. - if (isa<BlockPointerType>(lhsType)) { + if (isa<BlockPointerType>(LHSType)) { // U^ -> T^ - if (rhsType->isBlockPointerType()) { - Kind = CK_AnyPointerToBlockPointerCast; - return checkBlockPointerTypesForAssignment(*this, lhsType, rhsType); + if (RHSType->isBlockPointerType()) { + Kind = CK_BitCast; + return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } // int or null -> T^ - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToBlockPointer; } // id -> T^ - if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) { + if (getLangOptions().ObjC1 && RHSType->isObjCIdType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } // void* -> T^ - if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) + if (const PointerType *RHSPT = RHSType->getAs<PointerType>()) if (RHSPT->getPointeeType()->isVoidType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; @@ -5276,48 +5362,49 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions to Objective-C pointers. - if (isa<ObjCObjectPointerType>(lhsType)) { + if (isa<ObjCObjectPointerType>(LHSType)) { // A* -> B* - if (rhsType->isObjCObjectPointerType()) { + if (RHSType->isObjCObjectPointerType()) { Kind = CK_BitCast; Sema::AssignConvertType result = - checkObjCPointerTypesForAssignment(*this, lhsType, rhsType); + checkObjCPointerTypesForAssignment(*this, LHSType, RHSType); if (getLangOptions().ObjCAutoRefCount && result == Compatible && - !CheckObjCARCUnavailableWeakConversion(origLhsType, rhsType)) + !CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType)) result = IncompatibleObjCWeakRef; return result; } // int or null -> A* - if (rhsType->isIntegerType()) { + if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToPointer; } // In general, C pointers are not compatible with ObjC object pointers, // with two exceptions: - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { + Kind = CK_CPointerToObjCPointerCast; + // - conversions from 'void*' - if (rhsType->isVoidPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (RHSType->isVoidPointerType()) { return Compatible; } // - conversions to 'Class' from its redefinition type - if (lhsType->isObjCClassType() && - Context.hasSameType(rhsType, Context.ObjCClassRedefinitionType)) { - Kind = CK_BitCast; + if (LHSType->isObjCClassType() && + Context.hasSameType(RHSType, + Context.getObjCClassRedefinitionType())) { return Compatible; } - Kind = CK_AnyPointerToObjCPointerCast; return IncompatiblePointer; } // T^ -> A* - if (rhsType->isBlockPointerType()) { - Kind = CK_AnyPointerToObjCPointerCast; + if (RHSType->isBlockPointerType()) { + maybeExtendBlockObject(*this, RHS); + Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } @@ -5325,15 +5412,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions from pointers that are not covered by the above. - if (isa<PointerType>(rhsType)) { + if (isa<PointerType>(RHSType)) { // T* -> _Bool - if (lhsType == Context.BoolTy) { + if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int - if (lhsType->isIntegerType()) { + if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } @@ -5342,15 +5429,15 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // Conversions from Objective-C pointers that are not covered by the above. - if (isa<ObjCObjectPointerType>(rhsType)) { + if (isa<ObjCObjectPointerType>(RHSType)) { // T* -> _Bool - if (lhsType == Context.BoolTy) { + if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int - if (lhsType->isIntegerType()) { + if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } @@ -5359,8 +5446,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, } // struct A -> struct B - if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) { - if (Context.typesAreCompatible(lhsType, rhsType)) { + if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) { + if (Context.typesAreCompatible(LHSType, RHSType)) { Kind = CK_NoOp; return Compatible; } @@ -5371,8 +5458,9 @@ Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, /// \brief Constructs a transparent union from an expression that is /// used to initialize the transparent union. -static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult, - QualType UnionType, FieldDecl *Field) { +static void ConstructTransparentUnion(Sema &S, ASTContext &C, + ExprResult &EResult, QualType UnionType, + FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. Expr *E = EResult.take(); @@ -5391,8 +5479,9 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResul } Sema::AssignConvertType -Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rExpr) { - QualType FromType = rExpr.get()->getType(); +Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, + ExprResult &RHS) { + QualType RHSType = RHS.get()->getType(); // If the ArgType is a Union type, we want to handle a potential // transparent_union GCC extension. @@ -5411,25 +5500,26 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx // If the transparent union contains a pointer type, we allow: // 1) void pointer // 2) null pointer constant - if (FromType->isPointerType()) - if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_BitCast); + if (RHSType->isPointerType()) + if (RHSType->castAs<PointerType>()->getPointeeType()->isVoidType()) { + RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast); InitField = *it; break; } - if (rExpr.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_NullToPointer); + if (RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + RHS = ImpCastExprToType(RHS.take(), it->getType(), + CK_NullToPointer); InitField = *it; break; } } CastKind Kind = CK_Invalid; - if (CheckAssignmentConstraints(it->getType(), rExpr, Kind) + if (CheckAssignmentConstraints(it->getType(), RHS, Kind) == Compatible) { - rExpr = ImpCastExprToType(rExpr.take(), it->getType(), Kind); + RHS = ImpCastExprToType(RHS.take(), it->getType(), Kind); InitField = *it; break; } @@ -5438,42 +5528,46 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rEx if (!InitField) return Incompatible; - ConstructTransparentUnion(*this, Context, rExpr, ArgType, InitField); + ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField); return Compatible; } Sema::AssignConvertType -Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { +Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, + bool Diagnose) { if (getLangOptions().CPlusPlus) { - if (!lhsType->isRecordType()) { + if (!LHSType->isRecordType() && !LHSType->isAtomicType()) { // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. - ExprResult Res = PerformImplicitConversion(rExpr.get(), - lhsType.getUnqualifiedType(), - AA_Assigning); + ExprResult Res = PerformImplicitConversion(RHS.get(), + LHSType.getUnqualifiedType(), + AA_Assigning, Diagnose); if (Res.isInvalid()) return Incompatible; Sema::AssignConvertType result = Compatible; if (getLangOptions().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(lhsType, rExpr.get()->getType())) + !CheckObjCARCUnavailableWeakConversion(LHSType, + RHS.get()->getType())) result = IncompatibleObjCWeakRef; - rExpr = move(Res); + RHS = move(Res); return result; } // FIXME: Currently, we fall through and treat C++ classes like C // structures. - } + // FIXME: We also fall through for atomics; not sure what should + // happen there, though. + } // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. - if ((lhsType->isPointerType() || - lhsType->isObjCObjectPointerType() || - lhsType->isBlockPointerType()) - && rExpr.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - rExpr = ImpCastExprToType(rExpr.take(), lhsType, CK_NullToPointer); + if ((LHSType->isPointerType() || + LHSType->isObjCObjectPointerType() || + LHSType->isBlockPointerType()) + && RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer); return Compatible; } @@ -5483,15 +5577,15 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { // expressions that suppress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. - if (!lhsType->isReferenceType()) { - rExpr = DefaultFunctionArrayLvalueConversion(rExpr.take()); - if (rExpr.isInvalid()) + if (!LHSType->isReferenceType()) { + RHS = DefaultFunctionArrayLvalueConversion(RHS.take()); + if (RHS.isInvalid()) return Incompatible; } CastKind Kind = CK_Invalid; Sema::AssignConvertType result = - CheckAssignmentConstraints(lhsType, rExpr, Kind); + CheckAssignmentConstraints(LHSType, RHS, Kind); // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. @@ -5499,150 +5593,202 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { // so that we can use references in built-in functions even in C. // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. - if (result != Incompatible && rExpr.get()->getType() != lhsType) - rExpr = ImpCastExprToType(rExpr.take(), lhsType.getNonLValueExprType(Context), Kind); + if (result != Incompatible && RHS.get()->getType() != LHSType) + RHS = ImpCastExprToType(RHS.take(), + LHSType.getNonLValueExprType(Context), Kind); return result; } -QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { +QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { Diag(Loc, diag::err_typecheck_invalid_operands) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } -QualType Sema::CheckVectorOperands(ExprResult &lex, ExprResult &rex, - SourceLocation Loc, bool isCompAssign) { +QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. - QualType lhsType = - Context.getCanonicalType(lex.get()->getType()).getUnqualifiedType(); - QualType rhsType = - Context.getCanonicalType(rex.get()->getType()).getUnqualifiedType(); + QualType LHSType = + Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); + QualType RHSType = + Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); // If the vector types are identical, return. - if (lhsType == rhsType) - return lhsType; + if (LHSType == RHSType) + return LHSType; // Handle the case of equivalent AltiVec and GCC vector types - if (lhsType->isVectorType() && rhsType->isVectorType() && - Context.areCompatibleVectorTypes(lhsType, rhsType)) { - if (lhsType->isExtVectorType()) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; + if (LHSType->isVectorType() && RHSType->isVectorType() && + Context.areCompatibleVectorTypes(LHSType, RHSType)) { + if (LHSType->isExtVectorType()) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + return LHSType; } - if (!isCompAssign) - lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); - return rhsType; + if (!IsCompAssign) + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); + return RHSType; } if (getLangOptions().LaxVectorConversions && - Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) { + Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType)) { // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a // bitcast; no bits are changed but the result type is different. // FIXME: Should we really be allowing this? - rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); + return LHSType; } // Canonicalize the ExtVector to the LHS, remember if we swapped so we can // swap back (so that we don't reverse the inputs to a subtract, for instance. bool swapped = false; - if (rhsType->isExtVectorType() && !isCompAssign) { + if (RHSType->isExtVectorType() && !IsCompAssign) { swapped = true; - std::swap(rex, lex); - std::swap(rhsType, lhsType); + std::swap(RHS, LHS); + std::swap(RHSType, LHSType); } // Handle the case of an ext vector and scalar. - if (const ExtVectorType *LV = lhsType->getAs<ExtVectorType>()) { + if (const ExtVectorType *LV = LHSType->getAs<ExtVectorType>()) { QualType EltTy = LV->getElementType(); - if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) { - int order = Context.getIntegerTypeOrder(EltTy, rhsType); + if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) { + int order = Context.getIntegerTypeOrder(EltTy, RHSType); if (order > 0) - rex = ImpCastExprToType(rex.take(), EltTy, CK_IntegralCast); + RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast); if (order >= 0) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); - if (swapped) std::swap(rex, lex); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat); + if (swapped) std::swap(RHS, LHS); + return LHSType; } } - if (EltTy->isRealFloatingType() && rhsType->isScalarType() && - rhsType->isRealFloatingType()) { - int order = Context.getFloatingTypeOrder(EltTy, rhsType); + if (EltTy->isRealFloatingType() && RHSType->isScalarType() && + RHSType->isRealFloatingType()) { + int order = Context.getFloatingTypeOrder(EltTy, RHSType); if (order > 0) - rex = ImpCastExprToType(rex.take(), EltTy, CK_FloatingCast); + RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast); if (order >= 0) { - rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); - if (swapped) std::swap(rex, lex); - return lhsType; + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat); + if (swapped) std::swap(RHS, LHS); + return LHSType; } } } // Vectors of different size or scalar and non-ext-vector are errors. - if (swapped) std::swap(rex, lex); + if (swapped) std::swap(RHS, LHS); Diag(Loc, diag::err_typecheck_vector_not_convertable) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } -QualType Sema::CheckMultiplyDivideOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); +// checkArithmeticNull - Detect when a NULL constant is used improperly in an +// expression. These are mainly cases where the null pointer is used as an +// integer instead of a pointer. +static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompare) { + // The canonical way to check for a GNU null is with isNullPointerConstant, + // but we use a bit of a hack here for speed; this is a relatively + // hot path, and isNullPointerConstant is slow. + bool LHSNull = isa<GNUNullExpr>(LHS.get()->IgnoreParenImpCasts()); + bool RHSNull = isa<GNUNullExpr>(RHS.get()->IgnoreParenImpCasts()); + + QualType NonNullType = LHSNull ? RHS.get()->getType() : LHS.get()->getType(); + + // Avoid analyzing cases where the result will either be invalid (and + // diagnosed as such) or entirely valid and not something to warn about. + if ((!LHSNull && !RHSNull) || NonNullType->isBlockPointerType() || + NonNullType->isMemberPointerType() || NonNullType->isFunctionType()) + return; + + // Comparison operations would not make sense with a null pointer no matter + // what the other expression is. + if (!IsCompare) { + S.Diag(Loc, diag::warn_null_in_arithmetic_operation) + << (LHSNull ? LHS.get()->getSourceRange() : SourceRange()) + << (RHSNull ? RHS.get()->getSourceRange() : SourceRange()); + return; + } + + // The rest of the operations only make sense with a null pointer + // if the other expression is a pointer. + if (LHSNull == RHSNull || NonNullType->isAnyPointerType() || + NonNullType->canDecayToPointerType()) + return; + + S.Diag(Loc, diag::warn_null_in_comparison_operation) + << LHSNull /* LHS is NULL */ << NonNullType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign, bool IsDiv) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isArithmeticType() || - !rex.get()->getType()->isArithmeticType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isArithmeticType() || + !RHS.get()->getType()->isArithmeticType()) + return InvalidOperands(Loc, LHS, RHS); // Check for division by zero. - if (isDiv && - rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_division_by_zero) - << rex.get()->getSourceRange()); + if (IsDiv && + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_division_by_zero) + << RHS.get()->getSourceRange()); return compType; } QualType Sema::CheckRemainderOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - if (lex.get()->getType()->hasIntegerRepresentation() && - rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); - return InvalidOperands(Loc, lex, rex); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); + return InvalidOperands(Loc, LHS, RHS); } - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isIntegerType() || !rex.get()->getType()->isIntegerType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isIntegerType() || + !RHS.get()->getType()->isIntegerType()) + return InvalidOperands(Loc, LHS, RHS); // Check for remainder by zero. - if (rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_remainder_by_zero) - << rex.get()->getSourceRange()); + if (RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_remainder_by_zero) + << RHS.get()->getSourceRange()); return compType; } /// \brief Diagnose invalid arithmetic on two void pointers. static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, - Expr *LHS, Expr *RHS) { + Expr *LHSExpr, Expr *RHSExpr) { S.Diag(Loc, S.getLangOptions().CPlusPlus ? diag::err_typecheck_pointer_arith_void_type : diag::ext_gnu_void_ptr) - << 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange(); + << 1 /* two pointers */ << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); } /// \brief Diagnose invalid arithmetic on a void pointer. @@ -5682,6 +5828,24 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, << Pointer->getSourceRange(); } +/// \brief Emit error if Operand is incomplete pointer type +/// +/// \returns True if pointer has incomplete type +static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, + Expr *Operand) { + if ((Operand->getType()->isPointerType() && + !Operand->getType()->isDependentType()) || + Operand->getType()->isObjCObjectPointerType()) { + QualType PointeeTy = Operand->getType()->getPointeeType(); + if (S.RequireCompleteType( + Loc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) + << PointeeTy << Operand->getSourceRange())) + return true; + } + return false; +} + /// \brief Check the validity of an arithmetic pointer operand. /// /// If the operand has pointer type, this code will check for pointer types @@ -5704,16 +5868,7 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, return !S.getLangOptions().CPlusPlus; } - if ((Operand->getType()->isPointerType() && - !Operand->getType()->isDependentType()) || - Operand->getType()->isObjCObjectPointerType()) { - QualType PointeeTy = Operand->getType()->getPointeeType(); - if (S.RequireCompleteType( - Loc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PointeeTy << Operand->getSourceRange())) - return false; - } + if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false; return true; } @@ -5728,22 +5883,22 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, /// /// \returns True when the operand is valid to use (even if as an extension). static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, - Expr *LHS, Expr *RHS) { - bool isLHSPointer = LHS->getType()->isAnyPointerType(); - bool isRHSPointer = RHS->getType()->isAnyPointerType(); + Expr *LHSExpr, Expr *RHSExpr) { + bool isLHSPointer = LHSExpr->getType()->isAnyPointerType(); + bool isRHSPointer = RHSExpr->getType()->isAnyPointerType(); if (!isLHSPointer && !isRHSPointer) return true; QualType LHSPointeeTy, RHSPointeeTy; - if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType(); - if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType(); + if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType(); + if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // Check for arithmetic on pointers to incomplete types. bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); if (isLHSVoidPtr || isRHSVoidPtr) { - if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS); - else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS); - else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS); + if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHSExpr); + else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr); + else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOptions().CPlusPlus; } @@ -5751,160 +5906,179 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType(); bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType(); if (isLHSFuncPtr || isRHSFuncPtr) { - if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS); - else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS); - else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS); + if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHSExpr); + else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, + RHSExpr); + else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOptions().CPlusPlus; } - Expr *Operands[] = { LHS, RHS }; - for (unsigned i = 0; i < 2; ++i) { - Expr *Operand = Operands[i]; - if ((Operand->getType()->isPointerType() && - !Operand->getType()->isDependentType()) || - Operand->getType()->isObjCObjectPointerType()) { - QualType PointeeTy = Operand->getType()->getPointeeType(); - if (S.RequireCompleteType( - Loc, PointeeTy, - S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) - << PointeeTy << Operand->getSourceRange())) - return false; - } - } + if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false; + if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false; + return true; } +/// \brief Check bad cases where we step over interface counts. +static bool checkArithmethicPointerOnNonFragileABI(Sema &S, + SourceLocation OpLoc, + Expr *Op) { + assert(Op->getType()->isAnyPointerType()); + QualType PointeeTy = Op->getType()->getPointeeType(); + if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI) + return true; + + S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) + << PointeeTy << Op->getSourceRange(); + return false; +} + +/// \brief Emit error when two pointers are incompatible. +static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc, + Expr *LHSExpr, Expr *RHSExpr) { + assert(LHSExpr->getType()->isAnyPointerType()); + assert(RHSExpr->getType()->isAnyPointerType()); + S.Diag(Loc, diag::err_typecheck_sub_ptr_compatible) + << LHSExpr->getType() << RHSExpr->getType() << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); +} + QualType Sema::CheckAdditionOperands( // C99 6.5.6 - ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } - QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // handle the common case first (both operands are arithmetic). - if (lex.get()->getType()->isArithmeticType() && - rex.get()->getType()->isArithmeticType()) { + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Put any potential pointer into PExp - Expr* PExp = lex.get(), *IExp = rex.get(); + Expr* PExp = LHS.get(), *IExp = RHS.get(); if (IExp->getType()->isAnyPointerType()) std::swap(PExp, IExp); - if (PExp->getType()->isAnyPointerType()) { - if (IExp->getType()->isIntegerType()) { - if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) - return QualType(); + if (!PExp->getType()->isAnyPointerType()) + return InvalidOperands(Loc, LHS, RHS); - QualType PointeeTy = PExp->getType()->getPointeeType(); + if (!IExp->getType()->isIntegerType()) + return InvalidOperands(Loc, LHS, RHS); - // Diagnose bad cases where we step over interface counts. - if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(Loc, diag::err_arithmetic_nonfragile_interface) - << PointeeTy << PExp->getSourceRange(); - return QualType(); - } + if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) + return QualType(); - if (CompLHSTy) { - QualType LHSTy = Context.isPromotableBitField(lex.get()); - if (LHSTy.isNull()) { - LHSTy = lex.get()->getType(); - if (LHSTy->isPromotableIntegerType()) - LHSTy = Context.getPromotedIntegerType(LHSTy); - } - *CompLHSTy = LHSTy; - } - return PExp->getType(); + // Diagnose bad cases where we step over interface counts. + if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp)) + return QualType(); + + // Check array bounds for pointer arithemtic + CheckArrayAccess(PExp, IExp); + + if (CompLHSTy) { + QualType LHSTy = Context.isPromotableBitField(LHS.get()); + if (LHSTy.isNull()) { + LHSTy = LHS.get()->getType(); + if (LHSTy->isPromotableIntegerType()) + LHSTy = Context.getPromotedIntegerType(LHSTy); } + *CompLHSTy = LHSTy; } - return InvalidOperands(Loc, lex, rex); + return PExp->getType(); } // C99 6.5.6 -QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, - SourceLocation Loc, QualType* CompLHSTy) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands(lex, rex, Loc, CompLHSTy); +QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + QualType* CompLHSTy) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy); if (CompLHSTy) *CompLHSTy = compType; return compType; } - QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); - if (lex.isInvalid() || rex.isInvalid()) + QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // Enforce type constraints: C99 6.5.6p3. // Handle the common case first (both operands are arithmetic). - if (lex.get()->getType()->isArithmeticType() && - rex.get()->getType()->isArithmeticType()) { + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Either ptr - int or ptr - ptr. - if (lex.get()->getType()->isAnyPointerType()) { - QualType lpointee = lex.get()->getType()->getPointeeType(); + if (LHS.get()->getType()->isAnyPointerType()) { + QualType lpointee = LHS.get()->getType()->getPointeeType(); // Diagnose bad cases where we step over interface counts. - if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(Loc, diag::err_arithmetic_nonfragile_interface) - << lpointee << lex.get()->getSourceRange(); + if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get())) return QualType(); - } // The result type of a pointer-int computation is the pointer type. - if (rex.get()->getType()->isIntegerType()) { - if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get())) + if (RHS.get()->getType()->isIntegerType()) { + if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get())) return QualType(); - if (CompLHSTy) *CompLHSTy = lex.get()->getType(); - return lex.get()->getType(); + Expr *IExpr = RHS.get()->IgnoreParenCasts(); + UnaryOperator negRex(IExpr, UO_Minus, IExpr->getType(), VK_RValue, + OK_Ordinary, IExpr->getExprLoc()); + // Check array bounds for pointer arithemtic + CheckArrayAccess(LHS.get()->IgnoreParenCasts(), &negRex); + + if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); + return LHS.get()->getType(); } // Handle pointer-pointer subtractions. - if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) { + if (const PointerType *RHSPTy + = RHS.get()->getType()->getAs<PointerType>()) { QualType rpointee = RHSPTy->getPointeeType(); if (getLangOptions().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { - Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - return QualType(); + diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); } } else { // Pointee types must be compatible C99 6.5.6p3 if (!Context.typesAreCompatible( Context.getCanonicalType(lpointee).getUnqualifiedType(), Context.getCanonicalType(rpointee).getUnqualifiedType())) { - Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex.get()->getType() << rex.get()->getType() - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); return QualType(); } } if (!checkArithmeticBinOpPointerOperands(*this, Loc, - lex.get(), rex.get())) + LHS.get(), RHS.get())) return QualType(); - if (CompLHSTy) *CompLHSTy = lex.get()->getType(); + if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); return Context.getPointerDiffType(); } } - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } static bool isScopedEnumerationType(QualType T) { @@ -5913,26 +6087,27 @@ static bool isScopedEnumerationType(QualType T) { return false; } -static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, +static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, - QualType LHSTy) { + QualType LHSType) { llvm::APSInt Right; // Check right/shifter operand - if (rex.get()->isValueDependent() || !rex.get()->isIntegerConstantExpr(Right, S.Context)) + if (RHS.get()->isValueDependent() || + !RHS.get()->isIntegerConstantExpr(Right, S.Context)) return; if (Right.isNegative()) { - S.DiagRuntimeBehavior(Loc, rex.get(), + S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_negative) - << rex.get()->getSourceRange()); + << RHS.get()->getSourceRange()); return; } llvm::APInt LeftBits(Right.getBitWidth(), - S.Context.getTypeSize(lex.get()->getType())); + S.Context.getTypeSize(LHS.get()->getType())); if (Right.uge(LeftBits)) { - S.DiagRuntimeBehavior(Loc, rex.get(), + S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_gt_typewidth) - << rex.get()->getSourceRange()); + << RHS.get()->getSourceRange()); return; } if (Opc != BO_Shl) @@ -5943,8 +6118,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, // integers have defined behavior modulo one more than the maximum value // representable in the result type, so never warn for those. llvm::APSInt Left; - if (lex.get()->isValueDependent() || !lex.get()->isIntegerConstantExpr(Left, S.Context) || - LHSTy->hasUnsignedIntegerRepresentation()) + if (LHS.get()->isValueDependent() || + !LHS.get()->isIntegerConstantExpr(Left, S.Context) || + LHSType->hasUnsignedIntegerRepresentation()) return; llvm::APInt ResultBits = static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); @@ -5964,57 +6140,62 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, // turned off separately if needed. if (LeftBits == ResultBits - 1) { S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) - << HexResult.str() << LHSTy - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << HexResult.str() << LHSType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << HexResult.str() << Result.getMinSignedBits() << LHSTy - << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << HexResult.str() << Result.getMinSignedBits() << LHSType + << Left.getBitWidth() << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } // C99 6.5.7 -QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, - unsigned Opc, bool isCompAssign) { +QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, unsigned Opc, + bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex.get()->getType()->hasIntegerRepresentation() || - !rex.get()->getType()->hasIntegerRepresentation()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->hasIntegerRepresentation() || + !RHS.get()->getType()->hasIntegerRepresentation()) + return InvalidOperands(Loc, LHS, RHS); // C++0x: Don't allow scoped enums. FIXME: Use something better than // hasIntegerRepresentation() above instead of this. - if (isScopedEnumerationType(lex.get()->getType()) || - isScopedEnumerationType(rex.get()->getType())) { - return InvalidOperands(Loc, lex, rex); + if (isScopedEnumerationType(LHS.get()->getType()) || + isScopedEnumerationType(RHS.get()->getType())) { + return InvalidOperands(Loc, LHS, RHS); } // Vector shifts promote their scalar inputs to vector type. - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 // For the LHS, do usual unary conversions, but then reset them away // if this is a compound assignment. - ExprResult old_lex = lex; - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + ExprResult OldLHS = LHS; + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - QualType LHSTy = lex.get()->getType(); - if (isCompAssign) lex = old_lex; + QualType LHSType = LHS.get()->getType(); + if (IsCompAssign) LHS = OldLHS; // The RHS is simpler. - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); // Sanity-check shift operands - DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy); + DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); // "The type of the result is that of the promoted left operand." - return LHSTy; + return LHSType; } static bool IsWithinTemplateSpecialization(Decl *D) { @@ -6027,42 +6208,125 @@ static bool IsWithinTemplateSpecialization(Decl *D) { return false; } +/// If two different enums are compared, raise a warning. +static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS) { + QualType LHSStrippedType = LHS.get()->IgnoreParenImpCasts()->getType(); + QualType RHSStrippedType = RHS.get()->IgnoreParenImpCasts()->getType(); + + const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>(); + if (!LHSEnumType) + return; + const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>(); + if (!RHSEnumType) + return; + + // Ignore anonymous enums. + if (!LHSEnumType->getDecl()->getIdentifier()) + return; + if (!RHSEnumType->getDecl()->getIdentifier()) + return; + + if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) + return; + + S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) + << LHSStrippedType << RHSStrippedType + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +/// \brief Diagnose bad pointer comparisons. +static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, + ExprResult &LHS, ExprResult &RHS, + bool IsError) { + S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_distinct_pointers + : diag::ext_typecheck_comparison_of_distinct_pointers) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + +/// \brief Returns false if the pointers are converted to a composite type, +/// true otherwise. +static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, + ExprResult &LHS, ExprResult &RHS) { + // C++ [expr.rel]p2: + // [...] Pointer conversions (4.10) and qualification + // conversions (4.4) are performed on pointer operands (or on + // a pointer operand and a null pointer constant) to bring + // them to their composite pointer type. [...] + // + // C++ [expr.eq]p1 uses the same notion for (in)equality + // comparisons of pointers. + + // C++ [expr.eq]p2: + // In addition, pointers to members can be compared, or a pointer to + // member and a null pointer constant. Pointer to member conversions + // (4.11) and qualification conversions (4.4) are performed to bring + // them to a common type. If one operand is a null pointer constant, + // the common type is the type of the other operand. Otherwise, the + // common type is a pointer to member type similar (4.4) to the type + // of one of the operands, with a cv-qualification signature (4.4) + // that is the union of the cv-qualification signatures of the operand + // types. + + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); + assert((LHSType->isPointerType() && RHSType->isPointerType()) || + (LHSType->isMemberPointerType() && RHSType->isMemberPointerType())); + + bool NonStandardCompositeType = false; + bool *BoolPtr = S.isSFINAEContext() ? 0 : &NonStandardCompositeType; + QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr); + if (T.isNull()) { + diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); + return true; + } + + if (NonStandardCompositeType) + S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << LHSType << RHSType << T << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + + LHS = S.ImpCastExprToType(LHS.take(), T, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.take(), T, CK_BitCast); + return false; +} + +static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc, + ExprResult &LHS, + ExprResult &RHS, + bool IsError) { + S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_fptr_to_void + : diag::ext_typecheck_comparison_of_fptr_to_void) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); +} + // C99 6.5.8, C++ [expr.rel] -QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, - unsigned OpaqueOpc, bool isRelational) { +QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, unsigned OpaqueOpc, + bool IsRelational) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true); + BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc; // Handle vector comparisons separately. - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) - return CheckVectorCompareOperands(lex, rex, Loc, isRelational); + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational); - QualType lType = lex.get()->getType(); - QualType rType = rex.get()->getType(); - - Expr *LHSStripped = lex.get()->IgnoreParenImpCasts(); - Expr *RHSStripped = rex.get()->IgnoreParenImpCasts(); - QualType LHSStrippedType = LHSStripped->getType(); - QualType RHSStrippedType = RHSStripped->getType(); + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); - + Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts(); + Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts(); - // Two different enums will raise a warning when compared. - if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) { - if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) { - if (LHSEnumType->getDecl()->getIdentifier() && - RHSEnumType->getDecl()->getIdentifier() && - !Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { - Diag(Loc, diag::warn_comparison_of_mixed_enum_types) - << LHSStrippedType << RHSStrippedType - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - } - } + checkEnumComparison(*this, Loc, LHS, RHS); - if (!lType->hasFloatingRepresentation() && - !(lType->isBlockPointerType() && isRelational) && - !lex.get()->getLocStart().isMacroID() && - !rex.get()->getLocStart().isMacroID()) { + if (!LHSType->hasFloatingRepresentation() && + !(LHSType->isBlockPointerType() && IsRelational) && + !LHS.get()->getLocStart().isMacroID() && + !RHS.get()->getLocStart().isMacroID()) { // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. @@ -6082,7 +6346,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca << (Opc == BO_EQ || Opc == BO_LE || Opc == BO_GE)); - } else if (lType->isArrayType() && rType->isArrayType() && + } else if (LHSType->isArrayType() && RHSType->isArrayType() && !DRL->getDecl()->getType()->isReferenceType() && !DRR->getDecl()->getType()->isReferenceType()) { // what is it always going to eval to? @@ -6118,13 +6382,13 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && !RHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = lex.get(); + literalString = LHS.get(); literalStringStripped = LHSStripped; } else if ((isa<StringLiteral>(RHSStripped) || isa<ObjCEncodeExpr>(RHSStripped)) && !LHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = rex.get(); + literalString = RHS.get(); literalStringStripped = RHSStripped; } @@ -6137,7 +6401,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca case BO_GE: resultComparison = ") >= 0"; break; case BO_EQ: resultComparison = ") == 0"; break; case BO_NE: resultComparison = ") != 0"; break; - default: assert(false && "Invalid comparison operator"); + default: llvm_unreachable("Invalid comparison operator"); } DiagRuntimeBehavior(Loc, 0, @@ -6148,56 +6412,57 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca } // C99 6.5.8p3 / C99 6.5.9p4 - if (lex.get()->getType()->isArithmeticType() && rex.get()->getType()->isArithmeticType()) { - UsualArithmeticConversions(lex, rex); - if (lex.isInvalid() || rex.isInvalid()) + if (LHS.get()->getType()->isArithmeticType() && + RHS.get()->getType()->isArithmeticType()) { + UsualArithmeticConversions(LHS, RHS); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); } else { - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); } - lType = lex.get()->getType(); - rType = rex.get()->getType(); + LHSType = LHS.get()->getType(); + RHSType = RHS.get()->getType(); // The result of comparisons is 'bool' in C++, 'int' in C. QualType ResultTy = Context.getLogicalOperationType(); - if (isRelational) { - if (lType->isRealType() && rType->isRealType()) + if (IsRelational) { + if (LHSType->isRealType() && RHSType->isRealType()) return ResultTy; } else { // Check for comparisons of floating point operands using != and ==. - if (lType->hasFloatingRepresentation()) - CheckFloatComparison(Loc, lex.get(), rex.get()); + if (LHSType->hasFloatingRepresentation()) + CheckFloatComparison(Loc, LHS.get(), RHS.get()); - if (lType->isArithmeticType() && rType->isArithmeticType()) + if (LHSType->isArithmeticType() && RHSType->isArithmeticType()) return ResultTy; } - bool LHSIsNull = lex.get()->isNullPointerConstant(Context, + bool LHSIsNull = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - bool RHSIsNull = rex.get()->isNullPointerConstant(Context, + bool RHSIsNull = RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); // All of the following pointer-related warnings are GCC extensions, except // when handling null pointer constants. - if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 + if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 QualType LCanPointeeTy = - Context.getCanonicalType(lType->getAs<PointerType>()->getPointeeType()); + LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); QualType RCanPointeeTy = - Context.getCanonicalType(rType->getAs<PointerType>()->getPointeeType()); + RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); if (getLangOptions().CPlusPlus) { if (LCanPointeeTy == RCanPointeeTy) return ResultTy; - if (!isRelational && + if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { // Valid unless comparison between non-null pointer and function pointer // This is a gcc extension compatibility comparison. @@ -6205,214 +6470,178 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca // conformance with the C++ standard. if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) && !LHSIsNull && !RHSIsNull) { - Diag(Loc, - isSFINAEContext()? - diag::err_typecheck_comparison_of_fptr_to_void - : diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnoseFunctionPointerToVoidComparison( + *this, Loc, LHS, RHS, /*isError*/ isSFINAEContext()); if (isSFINAEContext()) return QualType(); - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } } - // C++ [expr.rel]p2: - // [...] Pointer conversions (4.10) and qualification - // conversions (4.4) are performed on pointer operands (or on - // a pointer operand and a null pointer constant) to bring - // them to their composite pointer type. [...] - // - // C++ [expr.eq]p1 uses the same notion for (in)equality - // comparisons of pointers. - bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(Loc, lex, rex, - isSFINAEContext()? 0 : &NonStandardCompositeType); - if (T.isNull()) { - Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); - } else if (NonStandardCompositeType) { - Diag(Loc, - diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - - lex = ImpCastExprToType(lex.take(), T, CK_BitCast); - rex = ImpCastExprToType(rex.take(), T, CK_BitCast); - return ResultTy; + else + return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), RCanPointeeTy.getUnqualifiedType())) { // Valid unless a relational comparison of function pointers - if (isRelational && LCanPointeeTy->isFunctionType()) { + if (IsRelational && LCanPointeeTy->isFunctionType()) { Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } - } else if (!isRelational && + } else if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { // Valid unless comparison between non-null pointer and function pointer if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) - && !LHSIsNull && !RHSIsNull) { - Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } + && !LHSIsNull && !RHSIsNull) + diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS, + /*isError*/false); } else { // Invalid - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } if (LCanPointeeTy != RCanPointeeTy) { if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); } return ResultTy; } if (getLangOptions().CPlusPlus) { // Comparison of nullptr_t with itself. - if (lType->isNullPtrType() && rType->isNullPtrType()) + if (LHSType->isNullPtrType() && RHSType->isNullPtrType()) return ResultTy; // Comparison of pointers with null pointer constants and equality // comparisons of member pointers to null pointer constants. if (RHSIsNull && - ((lType->isAnyPointerType() || lType->isNullPtrType()) || - (!isRelational && - (lType->isMemberPointerType() || lType->isBlockPointerType())))) { - rex = ImpCastExprToType(rex.take(), lType, - lType->isMemberPointerType() + ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) || + (!IsRelational && + (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) { + RHS = ImpCastExprToType(RHS.take(), LHSType, + LHSType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); return ResultTy; } if (LHSIsNull && - ((rType->isAnyPointerType() || rType->isNullPtrType()) || - (!isRelational && - (rType->isMemberPointerType() || rType->isBlockPointerType())))) { - lex = ImpCastExprToType(lex.take(), rType, - rType->isMemberPointerType() + ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) || + (!IsRelational && + (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) { + LHS = ImpCastExprToType(LHS.take(), RHSType, + RHSType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); return ResultTy; } // Comparison of member pointers. - if (!isRelational && - lType->isMemberPointerType() && rType->isMemberPointerType()) { - // C++ [expr.eq]p2: - // In addition, pointers to members can be compared, or a pointer to - // member and a null pointer constant. Pointer to member conversions - // (4.11) and qualification conversions (4.4) are performed to bring - // them to a common type. If one operand is a null pointer constant, - // the common type is the type of the other operand. Otherwise, the - // common type is a pointer to member type similar (4.4) to the type - // of one of the operands, with a cv-qualification signature (4.4) - // that is the union of the cv-qualification signatures of the operand - // types. - bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(Loc, lex, rex, - isSFINAEContext()? 0 : &NonStandardCompositeType); - if (T.isNull()) { - Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (!IsRelational && + LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) { + if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); - } else if (NonStandardCompositeType) { - Diag(Loc, - diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T - << lex.get()->getSourceRange() << rex.get()->getSourceRange(); - } - - lex = ImpCastExprToType(lex.take(), T, CK_BitCast); - rex = ImpCastExprToType(rex.take(), T, CK_BitCast); - return ResultTy; + else + return ResultTy; } // Handle scoped enumeration types specifically, since they don't promote // to integers. - if (lex.get()->getType()->isEnumeralType() && - Context.hasSameUnqualifiedType(lex.get()->getType(), rex.get()->getType())) + if (LHS.get()->getType()->isEnumeralType() && + Context.hasSameUnqualifiedType(LHS.get()->getType(), + RHS.get()->getType())) return ResultTy; } // Handle block pointer types. - if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) { - QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType(); - QualType rpointee = rType->getAs<BlockPointerType>()->getPointeeType(); + if (!IsRelational && LHSType->isBlockPointerType() && + RHSType->isBlockPointerType()) { + QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType(); + QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType(); if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } // Allow block pointers to be compared with null pointer constants. - if (!isRelational - && ((lType->isBlockPointerType() && rType->isPointerType()) - || (lType->isPointerType() && rType->isBlockPointerType()))) { + if (!IsRelational + && ((LHSType->isBlockPointerType() && RHSType->isPointerType()) + || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { - if (!((rType->isPointerType() && rType->castAs<PointerType>() + if (!((RHSType->isPointerType() && RHSType->castAs<PointerType>() ->getPointeeType()->isVoidType()) - || (lType->isPointerType() && lType->castAs<PointerType>() + || (LHSType->isPointerType() && LHSType->castAs<PointerType>() ->getPointeeType()->isVoidType()))) Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LHSType->isPointerType() ? CK_BitCast + : CK_AnyPointerToBlockPointerCast); return ResultTy; } - if (lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType()) { - const PointerType *LPT = lType->getAs<PointerType>(); - const PointerType *RPT = rType->getAs<PointerType>(); + if (LHSType->isObjCObjectPointerType() || + RHSType->isObjCObjectPointerType()) { + const PointerType *LPT = LHSType->getAs<PointerType>(); + const PointerType *RPT = RHSType->getAs<PointerType>(); if (LPT || RPT) { bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false; bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false; if (!LPtrToVoid && !RPtrToVoid && - !Context.typesAreCompatible(lType, rType)) { - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + !Context.typesAreCompatible(LHSType, RHSType)) { + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, + /*isError*/false); } if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, + RPT ? CK_BitCast :CK_CPointerToObjCPointerCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, + LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); return ResultTy; } - if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { - if (!Context.areComparableObjCPointerTypes(lType, rType)) - Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (LHSType->isObjCObjectPointerType() && + RHSType->isObjCObjectPointerType()) { + if (!Context.areComparableObjCPointerTypes(LHSType, RHSType)) + diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, + /*isError*/false); if (LHSIsNull && !RHSIsNull) - lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast); else - rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast); return ResultTy; } } - if ((lType->isAnyPointerType() && rType->isIntegerType()) || - (lType->isIntegerType() && rType->isAnyPointerType())) { + if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || + (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { unsigned DiagID = 0; bool isError = false; - if ((LHSIsNull && lType->isIntegerType()) || - (RHSIsNull && rType->isIntegerType())) { - if (isRelational && !getLangOptions().CPlusPlus) + if ((LHSIsNull && LHSType->isIntegerType()) || + (RHSIsNull && RHSType->isIntegerType())) { + if (IsRelational && !getLangOptions().CPlusPlus) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; - } else if (isRelational && !getLangOptions().CPlusPlus) + } else if (IsRelational && !getLangOptions().CPlusPlus) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; else if (getLangOptions().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; @@ -6422,50 +6651,51 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca if (DiagID) { Diag(Loc, DiagID) - << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); if (isError) return QualType(); } - if (lType->isIntegerType()) - lex = ImpCastExprToType(lex.take(), rType, + if (LHSType->isIntegerType()) + LHS = ImpCastExprToType(LHS.take(), RHSType, LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); else - rex = ImpCastExprToType(rex.take(), lType, + RHS = ImpCastExprToType(RHS.take(), LHSType, RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); return ResultTy; } // Handle block pointers. - if (!isRelational && RHSIsNull - && lType->isBlockPointerType() && rType->isIntegerType()) { - rex = ImpCastExprToType(rex.take(), lType, CK_NullToPointer); + if (!IsRelational && RHSIsNull + && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { + RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer); return ResultTy; } - if (!isRelational && LHSIsNull - && lType->isIntegerType() && rType->isBlockPointerType()) { - lex = ImpCastExprToType(lex.take(), rType, CK_NullToPointer); + if (!IsRelational && LHSIsNull + && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { + LHS = ImpCastExprToType(LHS.take(), RHSType, CK_NullToPointer); return ResultTy; } - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } /// CheckVectorCompareOperands - vector comparisons are a clang extension that /// operates on extended vector types. Instead of producing an IntTy result, /// like a scalar comparison, a vector comparison produces a vector of integer /// types. -QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, +QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, - bool isRelational) { + bool IsRelational) { // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(lex, rex, Loc, /*isCompAssign*/false); + QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false); if (vType.isNull()) return vType; - QualType lType = lex.get()->getType(); - QualType rType = rex.get()->getType(); + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C @@ -6475,9 +6705,9 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. - if (!lType->hasFloatingRepresentation()) { - if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex.get()->IgnoreParens())) - if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex.get()->IgnoreParens())) + if (!LHSType->hasFloatingRepresentation()) { + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens())) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) @@ -6487,18 +6717,18 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, } // Check for comparisons of floating point operands using != and ==. - if (!isRelational && lType->hasFloatingRepresentation()) { - assert (rType->hasFloatingRepresentation()); - CheckFloatComparison(Loc, lex.get(), rex.get()); + if (!IsRelational && LHSType->hasFloatingRepresentation()) { + assert (RHSType->hasFloatingRepresentation()); + CheckFloatComparison(Loc, LHS.get(), RHS.get()); } // Return the type for the comparison, which is the same as vector type for // integer vectors, or an integer type of identical size and number of // elements for floating point vectors. - if (lType->hasIntegerRepresentation()) - return lType; + if (LHSType->hasIntegerRepresentation()) + return LHSType; - const VectorType *VTy = lType->getAs<VectorType>(); + const VectorType *VTy = LHSType->getAs<VectorType>(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); @@ -6511,36 +6741,41 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, } inline QualType Sema::CheckBitwiseOperands( - ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { - if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { - if (lex.get()->getType()->hasIntegerRepresentation() && - rex.get()->getType()->hasIntegerRepresentation()) - return CheckVectorOperands(lex, rex, Loc, isCompAssign); + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) { + if (LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign); - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } - ExprResult lexResult = Owned(lex), rexResult = Owned(rex); - QualType compType = UsualArithmeticConversions(lexResult, rexResult, isCompAssign); - if (lexResult.isInvalid() || rexResult.isInvalid()) + ExprResult LHSResult = Owned(LHS), RHSResult = Owned(RHS); + QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, + IsCompAssign); + if (LHSResult.isInvalid() || RHSResult.isInvalid()) return QualType(); - lex = lexResult.take(); - rex = rexResult.take(); + LHS = LHSResult.take(); + RHS = RHSResult.take(); - if (lex.get()->getType()->isIntegralOrUnscopedEnumerationType() && - rex.get()->getType()->isIntegralOrUnscopedEnumerationType()) + if (LHS.get()->getType()->isIntegralOrUnscopedEnumerationType() && + RHS.get()->getType()->isIntegralOrUnscopedEnumerationType()) return compType; - return InvalidOperands(Loc, lex, rex); + return InvalidOperands(Loc, LHS, RHS); } inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] - ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc) { + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) { // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. - if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() && - rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() && + if (LHS.get()->getType()->isIntegerType() && + !LHS.get()->getType()->isBooleanType() && + RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. !Loc.isMacroID() && ActiveTemplateInstantiations.empty()) { // If the RHS can be constant folded, and if it constant folds to something @@ -6548,27 +6783,43 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // happened to fold to true/false) then warn. // Parens on the RHS are ignored. Expr::EvalResult Result; - if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects) - if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) || + if (RHS.get()->Evaluate(Result, Context) && !Result.HasSideEffects) + if ((getLangOptions().Bool && !RHS.get()->getType()->isBooleanType()) || (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex.get()->getSourceRange() - << (Opc == BO_LAnd ? "&&" : "||") - << (Opc == BO_LAnd ? "&" : "|"); - } + << RHS.get()->getSourceRange() + << (Opc == BO_LAnd ? "&&" : "||"); + // Suggest replacing the logical operator with the bitwise version + Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator) + << (Opc == BO_LAnd ? "&" : "|") + << FixItHint::CreateReplacement(SourceRange( + Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(), + getLangOptions())), + Opc == BO_LAnd ? "&" : "|"); + if (Opc == BO_LAnd) + // Suggest replacing "Foo() && kNonZero" with "Foo()" + Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant) + << FixItHint::CreateRemoval( + SourceRange( + Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(), + 0, getSourceManager(), + getLangOptions()), + RHS.get()->getLocEnd())); + } } if (!Context.getLangOptions().CPlusPlus) { - lex = UsualUnaryConversions(lex.take()); - if (lex.isInvalid()) + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) return QualType(); - rex = UsualUnaryConversions(rex.take()); - if (rex.isInvalid()) + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) return QualType(); - if (!lex.get()->getType()->isScalarType() || !rex.get()->getType()->isScalarType()) - return InvalidOperands(Loc, lex, rex); + if (!LHS.get()->getType()->isScalarType() || + !RHS.get()->getType()->isScalarType()) + return InvalidOperands(Loc, LHS, RHS); return Context.IntTy; } @@ -6579,15 +6830,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both contextually converted to type bool. - ExprResult lexRes = PerformContextuallyConvertToBool(lex.get()); - if (lexRes.isInvalid()) - return InvalidOperands(Loc, lex, rex); - lex = move(lexRes); + ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get()); + if (LHSRes.isInvalid()) + return InvalidOperands(Loc, LHS, RHS); + LHS = move(LHSRes); - ExprResult rexRes = PerformContextuallyConvertToBool(rex.get()); - if (rexRes.isInvalid()) - return InvalidOperands(Loc, lex, rex); - rex = move(rexRes); + ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get()); + if (RHSRes.isInvalid()) + return InvalidOperands(Loc, LHS, RHS); + RHS = move(RHSRes); // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 @@ -6758,25 +7009,26 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { // C99 6.5.16.1 -QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, +QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType) { // Verify that LHS is a modifiable lvalue, and emit error if not. - if (CheckForModifiableLvalue(LHS, Loc, *this)) + if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) return QualType(); - QualType LHSType = LHS->getType(); - QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; + QualType LHSType = LHSExpr->getType(); + QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : + CompoundType; AssignConvertType ConvTy; if (CompoundType.isNull()) { QualType LHSTy(LHSType); // Simple assignment "x = y". - if (LHS->getObjectKind() == OK_ObjCProperty) { - ExprResult LHSResult = Owned(LHS); + if (LHSExpr->getObjectKind() == OK_ObjCProperty) { + ExprResult LHSResult = Owned(LHSExpr); ConvertPropertyForLValue(LHSResult, RHS, LHSTy); if (LHSResult.isInvalid()) return QualType(); - LHS = LHSResult.take(); + LHSExpr = LHSResult.take(); } ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); if (RHS.isInvalid()) @@ -6806,10 +7058,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, UO->getOpcode() == UO_Minus) && Loc.isFileID() && UO->getOperatorLoc().isFileID() && // Only if the two operators are exactly adjacent. - Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() && + Loc.getLocWithOffset(1) == UO->getOperatorLoc() && // And there is a space or other character before the subexpr of the // unary +/-. We don't want to warn on "x=-1". - Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() && + Loc.getLocWithOffset(2) != UO->getSubExpr()->getLocStart() && UO->getSubExpr()->getLocStart().isFileID()) { Diag(Loc, diag::warn_not_compound_assign) << (UO->getOpcode() == UO_Plus ? "+" : "-") @@ -6819,9 +7071,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, if (ConvTy == Compatible) { if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) - checkRetainCycles(LHS, RHS.get()); + checkRetainCycles(LHSExpr, RHS.get()); else if (getLangOptions().ObjCAutoRefCount) - checkUnsafeExprAssigns(Loc, LHS, RHS.get()); + checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); } } else { // Compound assignment "x += y" @@ -6832,10 +7084,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, RHS.get(), AA_Assigning)) return QualType(); - CheckForNullPointerDereference(*this, LHS); - // Check for trivial buffer overflows. - CheckArrayAccess(LHS->IgnoreParenCasts()); - + CheckForNullPointerDereference(*this, LHSExpr); + // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. @@ -6872,7 +7122,8 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, if (RHS.isInvalid()) return QualType(); if (!RHS.get()->getType()->isVoidType()) - S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type); + S.RequireCompleteType(Loc, RHS.get()->getType(), + diag::err_incomplete_type); } return RHS.get()->getType(); @@ -6883,7 +7134,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprValueKind &VK, SourceLocation OpLoc, - bool isInc, bool isPrefix) { + bool IsInc, bool IsPrefix) { if (Op->isTypeDependent()) return S.Context.DependentTy; @@ -6892,7 +7143,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) { // Decrement of bool is not allowed. - if (!isInc) { + if (!IsInc) { S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); return QualType(); } @@ -6901,18 +7152,13 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } else if (ResType->isRealType()) { // OK! } else if (ResType->isAnyPointerType()) { - QualType PointeeTy = ResType->getPointeeType(); - // C99 6.5.2.4p2, 6.5.6p2 if (!checkArithmeticOpPointerOperand(S, OpLoc, Op)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { - S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) - << PointeeTy << Op->getSourceRange(); + else if (!checkArithmethicPointerOnNonFragileABI(S, OpLoc, Op)) return QualType(); - } } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. S.Diag(OpLoc, diag::ext_integer_increment_complex) @@ -6921,12 +7167,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, - isInc, isPrefix); + IsInc, IsPrefix); } else if (S.getLangOptions().AltiVec && ResType->isVectorType()) { // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) - << ResType << int(isInc) << Op->getSourceRange(); + << ResType << int(IsInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. @@ -6936,7 +7182,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. - if (isPrefix && S.getLangOptions().CPlusPlus) { + if (IsPrefix && S.getLangOptions().CPlusPlus) { VK = VK_LValue; return ResType; } else { @@ -6973,7 +7219,13 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { << PRE->getBase()->getType(); } } - + else { + // lvalue-ness of an explicit property is determined by + // getter type. + QualType ResT = PRE->getGetterResultType(); + VK = Expr::getValueKindForType(ResT); + } + E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK); @@ -6984,7 +7236,8 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) { return Owned(E); } -void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &LHSTy) { +void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, + QualType &LHSTy) { assert(LHS.get()->getValueKind() == VK_LValue && LHS.get()->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); @@ -6996,7 +7249,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & // setter, RHS expression is being passed to the setter argument. So, // type conversion (and comparison) is RHS to setter's argument type. if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { - ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); + ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin(); LHSTy = (*P)->getType(); Consumed = (getLangOptions().ObjCAutoRefCount && (*P)->hasAttr<NSConsumedAttr>()); @@ -7015,7 +7268,7 @@ void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType & const ObjCMethodDecl *setter = PropRef->getExplicitProperty()->getSetterMethodDecl(); if (setter) { - ObjCMethodDecl::param_iterator P = setter->param_begin(); + ObjCMethodDecl::param_const_iterator P = setter->param_begin(); LHSTy = (*P)->getType(); Consumed = (*P)->hasAttr<NSConsumedAttr>(); } @@ -7092,6 +7345,23 @@ static ValueDecl *getPrimaryDecl(Expr *E) { } } +namespace { + enum { + AO_Bit_Field = 0, + AO_Vector_Element = 1, + AO_Property_Expansion = 2, + AO_Register_Variable = 3, + AO_No_Error = 4 + }; +} +/// \brief Diagnose invalid operand for address of operations. +/// +/// \param Type The type of operand which cannot have its address taken. +static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, + Expr *E, unsigned Type) { + S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange(); +} + /// CheckAddressOfOperand - The operand of & must be either a function /// designator or an lvalue designating an object. If it is an lvalue, the /// object cannot be declared with storage class register or be a bit field. @@ -7103,8 +7373,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, SourceLocation OpLoc) { if (OrigOp->isTypeDependent()) return S.Context.DependentTy; - if (OrigOp->getType() == S.Context.OverloadTy) + if (OrigOp->getType() == S.Context.OverloadTy) { + if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) { + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + << OrigOp->getSourceRange(); + return QualType(); + } + return S.Context.OverloadTy; + } if (OrigOp->getType() == S.Context.UnknownAnyTy) return S.Context.UnknownAnyTy; if (OrigOp->getType() == S.Context.BoundMemberTy) { @@ -7131,6 +7408,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, } ValueDecl *dcl = getPrimaryDecl(op); Expr::LValueClassification lval = op->ClassifyLValue(S.Context); + unsigned AddressOfError = AO_No_Error; if (lval == Expr::LV_ClassTemporary) { bool sfinae = S.isSFINAEContext(); @@ -7178,19 +7456,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, } } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1 // The operand cannot be a bit-field - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "bit-field" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Bit_Field; } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "vector element" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Vector_Element; } else if (op->getObjectKind() == OK_ObjCProperty) { // cannot take address of a property expression. - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "property expression" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Property_Expansion; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -7199,9 +7471,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, // variable (c++03 7.1.1P3) if (vd->getStorageClass() == SC_Register && !S.getLangOptions().CPlusPlus) { - S.Diag(OpLoc, diag::err_typecheck_address_of) - << "register variable" << op->getSourceRange(); - return QualType(); + AddressOfError = AO_Register_Variable; } } else if (isa<FunctionTemplateDecl>(dcl)) { return S.Context.OverloadTy; @@ -7225,8 +7495,13 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, S.Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); } } - } else if (!isa<FunctionDecl>(dcl)) - assert(0 && "Unknown/unexpected decl type"); + } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl)) + llvm_unreachable("Unknown/unexpected decl type"); + } + + if (AddressOfError != AO_No_Error) { + diagnoseAddressOfInvalidType(S, OpLoc, op, AddressOfError); + return QualType(); } if (lval == Expr::LV_IncompleteVoidType) { @@ -7297,7 +7572,7 @@ static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode( tok::TokenKind Kind) { BinaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown binop!"); + default: llvm_unreachable("Unknown binop!"); case tok::periodstar: Opc = BO_PtrMemD; break; case tok::arrowstar: Opc = BO_PtrMemI; break; case tok::star: Opc = BO_Mul; break; @@ -7338,7 +7613,7 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( tok::TokenKind Kind) { UnaryOperatorKind Opc; switch (Kind) { - default: assert(0 && "Unknown unary op!"); + default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PreInc; break; case tok::minusminus: Opc = UO_PreDec; break; case tok::amp: Opc = UO_AddrOf; break; @@ -7357,35 +7632,35 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. /// This warning is only emitted for builtin assignment operations. It is also /// suppressed in the event of macro expansions. -static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, +static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, SourceLocation OpLoc) { if (!S.ActiveTemplateInstantiations.empty()) return; if (OpLoc.isInvalid() || OpLoc.isMacroID()) return; - lhs = lhs->IgnoreParenImpCasts(); - rhs = rhs->IgnoreParenImpCasts(); - const DeclRefExpr *LeftDeclRef = dyn_cast<DeclRefExpr>(lhs); - const DeclRefExpr *RightDeclRef = dyn_cast<DeclRefExpr>(rhs); - if (!LeftDeclRef || !RightDeclRef || - LeftDeclRef->getLocation().isMacroID() || - RightDeclRef->getLocation().isMacroID()) + LHSExpr = LHSExpr->IgnoreParenImpCasts(); + RHSExpr = RHSExpr->IgnoreParenImpCasts(); + const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); + const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); + if (!LHSDeclRef || !RHSDeclRef || + LHSDeclRef->getLocation().isMacroID() || + RHSDeclRef->getLocation().isMacroID()) return; - const ValueDecl *LeftDecl = - cast<ValueDecl>(LeftDeclRef->getDecl()->getCanonicalDecl()); - const ValueDecl *RightDecl = - cast<ValueDecl>(RightDeclRef->getDecl()->getCanonicalDecl()); - if (LeftDecl != RightDecl) + const ValueDecl *LHSDecl = + cast<ValueDecl>(LHSDeclRef->getDecl()->getCanonicalDecl()); + const ValueDecl *RHSDecl = + cast<ValueDecl>(RHSDeclRef->getDecl()->getCanonicalDecl()); + if (LHSDecl != RHSDecl) return; - if (LeftDecl->getType().isVolatileQualified()) + if (LHSDecl->getType().isVolatileQualified()) return; - if (const ReferenceType *RefTy = LeftDecl->getType()->getAs<ReferenceType>()) + if (const ReferenceType *RefTy = LHSDecl->getType()->getAs<ReferenceType>()) if (RefTy->getPointeeType().isVolatileQualified()) return; S.Diag(OpLoc, diag::warn_self_assignment) - << LeftDeclRef->getType() - << lhs->getSourceRange() << rhs->getSourceRange(); + << LHSDeclRef->getType() + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with @@ -7393,8 +7668,8 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, /// built-in operations; ActOnBinOp handles overloaded operators. ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, - Expr *lhsExpr, Expr *rhsExpr) { - ExprResult lhs = Owned(lhsExpr), rhs = Owned(rhsExpr); + Expr *LHSExpr, Expr *RHSExpr) { + ExprResult LHS = Owned(LHSExpr), RHS = Owned(RHSExpr); QualType ResultTy; // Result type of the binary operator. // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation @@ -7410,172 +7685,131 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // f<int> == 0; // resolve f<int> blindly // void (*p)(int); p = f<int>; // resolve f<int> using target if (Opc != BO_Assign) { - ExprResult resolvedLHS = CheckPlaceholderExpr(lhs.get()); + ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get()); if (!resolvedLHS.isUsable()) return ExprError(); - lhs = move(resolvedLHS); + LHS = move(resolvedLHS); - ExprResult resolvedRHS = CheckPlaceholderExpr(rhs.get()); + ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get()); if (!resolvedRHS.isUsable()) return ExprError(); - rhs = move(resolvedRHS); - } - - // The canonical way to check for a GNU null is with isNullPointerConstant, - // but we use a bit of a hack here for speed; this is a relatively - // hot path, and isNullPointerConstant is slow. - bool LeftNull = isa<GNUNullExpr>(lhs.get()->IgnoreParenImpCasts()); - bool RightNull = isa<GNUNullExpr>(rhs.get()->IgnoreParenImpCasts()); - - // Detect when a NULL constant is used improperly in an expression. These - // are mainly cases where the null pointer is used as an integer instead - // of a pointer. - if (LeftNull || RightNull) { - // Avoid analyzing cases where the result will either be invalid (and - // diagnosed as such) or entirely valid and not something to warn about. - QualType LeftType = lhs.get()->getType(); - QualType RightType = rhs.get()->getType(); - if (!LeftType->isBlockPointerType() && !LeftType->isMemberPointerType() && - !LeftType->isFunctionType() && - !RightType->isBlockPointerType() && - !RightType->isMemberPointerType() && - !RightType->isFunctionType()) { - if (Opc == BO_Mul || Opc == BO_Div || Opc == BO_Rem || Opc == BO_Add || - Opc == BO_Sub || Opc == BO_Shl || Opc == BO_Shr || Opc == BO_And || - Opc == BO_Xor || Opc == BO_Or || Opc == BO_MulAssign || - Opc == BO_DivAssign || Opc == BO_AddAssign || Opc == BO_SubAssign || - Opc == BO_RemAssign || Opc == BO_ShlAssign || Opc == BO_ShrAssign || - Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign) { - // These are the operations that would not make sense with a null pointer - // no matter what the other expression is. - Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() : SourceRange()) - << (RightNull ? rhs.get()->getSourceRange() : SourceRange()); - } else if (Opc == BO_LE || Opc == BO_LT || Opc == BO_GE || Opc == BO_GT || - Opc == BO_EQ || Opc == BO_NE) { - // These are the operations that would not make sense with a null pointer - // if the other expression the other expression is not a pointer. - if (LeftNull != RightNull && - !LeftType->isAnyPointerType() && - !LeftType->canDecayToPointerType() && - !RightType->isAnyPointerType() && - !RightType->canDecayToPointerType()) { - Diag(OpLoc, diag::warn_null_in_arithmetic_operation) - << (LeftNull ? lhs.get()->getSourceRange() - : rhs.get()->getSourceRange()); - } - } - } + RHS = move(resolvedRHS); } switch (Opc) { case BO_Assign: - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); if (getLangOptions().CPlusPlus && - lhs.get()->getObjectKind() != OK_ObjCProperty) { - VK = lhs.get()->getValueKind(); - OK = lhs.get()->getObjectKind(); + LHS.get()->getObjectKind() != OK_ObjCProperty) { + VK = LHS.get()->getValueKind(); + OK = LHS.get()->getObjectKind(); } if (!ResultTy.isNull()) - DiagnoseSelfAssignment(*this, lhs.get(), rhs.get(), OpLoc); + DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); break; case BO_PtrMemD: case BO_PtrMemI: - ResultTy = CheckPointerToMemberOperands(lhs, rhs, VK, OpLoc, + ResultTy = CheckPointerToMemberOperands(LHS, RHS, VK, OpLoc, Opc == BO_PtrMemI); break; case BO_Mul: case BO_Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, + ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; case BO_Rem: - ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); + ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: - ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc); + ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc); break; case BO_Sub: - ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc); + ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: case BO_Shr: - ResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc); + ResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc); break; case BO_LE: case BO_LT: case BO_GE: case BO_GT: - ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); break; case BO_EQ: case BO_NE: - ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; case BO_And: case BO_Xor: case BO_Or: - ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc); + ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc); break; case BO_LAnd: case BO_LOr: - ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc); + ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: - CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, + CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_RemAssign: - CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: - CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: - CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_ShlAssign: case BO_ShrAssign: - CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true); + CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: - CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) - ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) + ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_Comma: - ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc); - if (getLangOptions().CPlusPlus && !rhs.isInvalid()) { - VK = rhs.get()->getValueKind(); - OK = rhs.get()->getObjectKind(); + ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc); + if (getLangOptions().CPlusPlus && !RHS.isInvalid()) { + VK = RHS.get()->getValueKind(); + OK = RHS.get()->getObjectKind(); } break; } - if (ResultTy.isNull() || lhs.isInvalid() || rhs.isInvalid()) + if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + + // Check for array bounds violations for both sides of the BinaryOperator + CheckArrayAccess(LHS.get()); + CheckArrayAccess(RHS.get()); + if (CompResultTy.isNull()) - return Owned(new (Context) BinaryOperator(lhs.take(), rhs.take(), Opc, + return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, OpLoc)); - if (getLangOptions().CPlusPlus && lhs.get()->getObjectKind() != OK_ObjCProperty) { + if (getLangOptions().CPlusPlus && LHS.get()->getObjectKind() != + OK_ObjCProperty) { VK = VK_LValue; - OK = lhs.get()->getObjectKind(); + OK = LHS.get()->getObjectKind(); } - return Owned(new (Context) CompoundAssignOperator(lhs.take(), rhs.take(), Opc, + return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc)); } @@ -7585,51 +7819,49 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// comparison operators have higher precedence. The most typical example of /// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, - SourceLocation OpLoc,Expr *lhs,Expr *rhs){ + SourceLocation OpLoc, Expr *LHSExpr, + Expr *RHSExpr) { typedef BinaryOperator BinOp; - BinOp::Opcode lhsopc = static_cast<BinOp::Opcode>(-1), - rhsopc = static_cast<BinOp::Opcode>(-1); - if (BinOp *BO = dyn_cast<BinOp>(lhs)) - lhsopc = BO->getOpcode(); - if (BinOp *BO = dyn_cast<BinOp>(rhs)) - rhsopc = BO->getOpcode(); + BinOp::Opcode LHSopc = static_cast<BinOp::Opcode>(-1), + RHSopc = static_cast<BinOp::Opcode>(-1); + if (BinOp *BO = dyn_cast<BinOp>(LHSExpr)) + LHSopc = BO->getOpcode(); + if (BinOp *BO = dyn_cast<BinOp>(RHSExpr)) + RHSopc = BO->getOpcode(); // Subs are not binary operators. - if (lhsopc == -1 && rhsopc == -1) + if (LHSopc == -1 && RHSopc == -1) return; // Bitwise operations are sometimes used as eager logical ops. // Don't diagnose this. - if ((BinOp::isComparisonOp(lhsopc) || BinOp::isBitwiseOp(lhsopc)) && - (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) + if ((BinOp::isComparisonOp(LHSopc) || BinOp::isBitwiseOp(LHSopc)) && + (BinOp::isComparisonOp(RHSopc) || BinOp::isBitwiseOp(RHSopc))) return; - if (BinOp::isComparisonOp(lhsopc)) { - Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) - << SourceRange(lhs->getLocStart(), OpLoc) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_silence) - << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange()); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_first) - << BinOp::getOpcodeStr(Opc), - SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); - } else if (BinOp::isComparisonOp(rhsopc)) { - Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) - << SourceRange(OpLoc, rhs->getLocEnd()) - << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_silence) - << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange()); - SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_first) - << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocStart(), - cast<BinOp>(rhs)->getLHS()->getLocStart())); - } + bool isLeftComp = BinOp::isComparisonOp(LHSopc); + bool isRightComp = BinOp::isComparisonOp(RHSopc); + if (!isLeftComp && !isRightComp) return; + + SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(), + OpLoc) + : SourceRange(OpLoc, RHSExpr->getLocEnd()); + std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc) + : BinOp::getOpcodeStr(RHSopc); + SourceRange ParensRange = isLeftComp ? + SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(), + RHSExpr->getLocEnd()) + : SourceRange(LHSExpr->getLocStart(), + cast<BinOp>(RHSExpr)->getLHS()->getLocStart()); + + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr; + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr, + RHSExpr->getSourceRange()); + SuggestParentheses(Self, OpLoc, + Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), + ParensRange); } /// \brief It accepts a '&' expr that is inside a '|' one. @@ -7676,11 +7908,11 @@ static bool EvaluatesAsFalse(Sema &S, Expr *E) { /// \brief Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, - Expr *OrLHS, Expr *OrRHS) { - if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrLHS)) { + Expr *LHSExpr, Expr *RHSExpr) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "a && b || 0" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, OrRHS)) + if (EvaluatesAsFalse(S, RHSExpr)) return; // If it's "1 && a || b" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getLHS())) @@ -7698,11 +7930,11 @@ static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, /// \brief Look for '&&' in the right hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, - Expr *OrLHS, Expr *OrRHS) { - if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(OrRHS)) { + Expr *LHSExpr, Expr *RHSExpr) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "0 || a && b" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, OrLHS)) + if (EvaluatesAsFalse(S, LHSExpr)) return; // If it's "a || b && 1" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getRHS())) @@ -7723,52 +7955,54 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, - SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + SourceLocation OpLoc, Expr *LHSExpr, + Expr *RHSExpr){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) - DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, LHSExpr, RHSExpr); // Diagnose "arg1 & arg2 | arg3" if (Opc == BO_Or && !OpLoc.isMacroID()/* Don't warn in macros. */) { - DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, lhs); - DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, rhs); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, LHSExpr); + DiagnoseBitwiseAndInBitwiseOr(Self, OpLoc, RHSExpr); } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) { - DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, lhs, rhs); - DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, lhs, rhs); + DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr); + DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr); } } // Binary Operators. 'Tok' is the token for the operator. ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, - Expr *lhs, Expr *rhs) { + Expr *LHSExpr, Expr *RHSExpr) { BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind); - assert((lhs != 0) && "ActOnBinOp(): missing left expression"); - assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + assert((LHSExpr != 0) && "ActOnBinOp(): missing left expression"); + assert((RHSExpr != 0) && "ActOnBinOp(): missing right expression"); // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" - DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr); - return BuildBinOp(S, TokLoc, Opc, lhs, rhs); + return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr); } ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, - Expr *lhs, Expr *rhs) { + Expr *LHSExpr, Expr *RHSExpr) { if (getLangOptions().CPlusPlus) { bool UseBuiltinOperator; - if (lhs->isTypeDependent() || rhs->isTypeDependent()) { + if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) { UseBuiltinOperator = false; - } else if (Opc == BO_Assign && lhs->getObjectKind() == OK_ObjCProperty) { + } else if (Opc == BO_Assign && + LHSExpr->getObjectKind() == OK_ObjCProperty) { UseBuiltinOperator = true; } else { - UseBuiltinOperator = !lhs->getType()->isOverloadableType() && - !rhs->getType()->isOverloadableType(); + UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() && + !RHSExpr->getType()->isOverloadableType(); } if (!UseBuiltinOperator) { @@ -7780,17 +8014,17 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); if (S && OverOp != OO_None) - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); + LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(), + RHSExpr->getType(), Functions); // Build the (potentially-overloaded, potentially-dependent) // binary operation. - return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); + return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr); } } // Build a built-in binary operation. - return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); + return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, @@ -7876,6 +8110,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Input = DefaultFunctionArrayLvalueConversion(Input.take()); if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); + + // Though we still have to promote half FP to float... + if (resultType->isHalfType()) { + Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take(); + resultType = Context.FloatTy; + } + if (resultType->isDependentType()) break; if (resultType->isScalarType()) { @@ -7917,13 +8158,19 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (resultType.isNull() || Input.isInvalid()) return ExprError(); + // Check for array bounds violations in the operand of the UnaryOperator, + // except for the '*' and '&' operators that have to be handled specially + // by CheckArrayAccess (as there are special cases like &array[arraysize] + // that are explicitly defined as valid by the standard). + if (Opc != UO_AddrOf && Opc != UO_Deref) + CheckArrayAccess(Input.get()); + return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType, VK, OK, OpLoc)); } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperatorKind Opc, - Expr *Input) { + UnaryOperatorKind Opc, Expr *Input) { if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() && UnaryOperator::getOverloadedOperator(Opc) != OO_None) { // Find all of the overloaded operators visible from this @@ -7962,13 +8209,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, /// ns_returns_retained function) and, if so, rebuild it to hoist the /// release out of the full-expression. Otherwise, return null. /// Cannot fail. -static Expr *maybeRebuildARCConsumingStmt(Stmt *s) { +static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) { // Should always be wrapped with one of these. - ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s); + ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement); if (!cleanups) return 0; ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr()); - if (!cast || cast->getCastKind() != CK_ObjCConsumeObject) + if (!cast || cast->getCastKind() != CK_ARCConsumeObject) return 0; // Splice out the cast. This shouldn't modify any interesting @@ -8091,8 +8338,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, bool DidWarnAboutNonPOD = false; QualType CurrentType = ArgTy; typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; - llvm::SmallVector<OffsetOfNode, 4> Comps; - llvm::SmallVector<Expr*, 4> Exprs; + SmallVector<OffsetOfNode, 4> Comps; + SmallVector<Expr*, 4> Exprs; for (unsigned i = 0; i != NumComponents; ++i) { const OffsetOfComponent &OC = CompPtr[i]; if (OC.isBrackets) { @@ -8174,7 +8421,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, // (If the specified member is a bit-field, the behavior is undefined.) // // We diagnose this as an error. - if (MemberDecl->getBitWidth()) { + if (MemberDecl->isBitField()) { Diag(OC.LocEnd, diag::err_offsetof_bitfield) << MemberDecl->getDeclName() << SourceRange(BuiltinLoc, RParenLoc); @@ -8219,13 +8466,13 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, - ParsedType argty, + ParsedType ParsedArgTy, OffsetOfComponent *CompPtr, unsigned NumComponents, - SourceLocation RPLoc) { + SourceLocation RParenLoc) { TypeSourceInfo *ArgTInfo; - QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo); + QualType ArgTy = GetTypeFromParser(ParsedArgTy, &ArgTInfo); if (ArgTy.isNull()) return ExprError(); @@ -8233,7 +8480,7 @@ ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, - RPLoc); + RParenLoc); } @@ -8279,12 +8526,12 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, //===----------------------------------------------------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is started. -void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { +void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); - PushBlockScope(BlockScope, Block); + PushBlockScope(CurScope, Block); CurContext->addDecl(Block); - if (BlockScope) - PushDeclContext(BlockScope, Block); + if (CurScope) + PushDeclContext(CurScope, Block); else CurContext = Block; } @@ -8351,7 +8598,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->ReturnType = RetTy; // Push block parameters from the declarator if we had them. - llvm::SmallVector<ParmVarDecl*, 8> Params; + SmallVector<ParmVarDecl*, 8> Params; if (ExplicitSignature) { for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) { ParmVarDecl *Param = ExplicitSignature.getArg(I); @@ -8378,7 +8625,7 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // Set the parameters on the block decl. if (!Params.empty()) { - CurBlock->TheDecl->setParams(Params.data(), Params.size()); + CurBlock->TheDecl->setParams(Params); CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(), CurBlock->TheDecl->param_end(), /*CheckParameterNames=*/false); @@ -8500,6 +8747,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, getCurFunction()->setHasBranchProtectedScope(); } + computeNRVO(Body, getCurBlock()); + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result); @@ -8508,11 +8757,11 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, - Expr *expr, ParsedType type, + Expr *E, ParsedType Ty, SourceLocation RPLoc) { TypeSourceInfo *TInfo; - GetTypeFromParser(type, &TInfo); - return BuildVAArgExpr(BuiltinLoc, expr, TInfo, RPLoc); + GetTypeFromParser(Ty, &TInfo); + return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc); } ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, @@ -8559,11 +8808,14 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, << TInfo->getTypeLoc().getSourceRange())) return ExprError(); - if (!TInfo->getType().isPODType(Context)) + if (!TInfo->getType().isPODType(Context)) { Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::warn_second_parameter_to_va_arg_not_pod) + TInfo->getType()->isObjCLifetimeType() + ? diag::warn_second_parameter_to_va_arg_ownership_qualified + : diag::warn_second_parameter_to_va_arg_not_pod) << TInfo->getType() << TInfo->getTypeLoc().getSourceRange(); + } // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). @@ -8591,16 +8843,15 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; - unsigned pw = Context.Target.getPointerWidth(0); - if (pw == Context.Target.getIntWidth()) + unsigned pw = Context.getTargetInfo().getPointerWidth(0); + if (pw == Context.getTargetInfo().getIntWidth()) Ty = Context.IntTy; - else if (pw == Context.Target.getLongWidth()) + else if (pw == Context.getTargetInfo().getLongWidth()) Ty = Context.LongTy; - else if (pw == Context.Target.getLongLongWidth()) + else if (pw == Context.getTargetInfo().getLongLongWidth()) Ty = Context.LongLongTy; else { - assert(!"I don't know size of pointer!"); - Ty = Context.IntTy; + llvm_unreachable("I don't know size of pointer!"); } return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); @@ -8625,7 +8876,7 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, // Strip off any parens and casts. StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts()); - if (!SL || SL->isWide()) + if (!SL || !SL->isAscii()) return; Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@"); @@ -8644,21 +8895,31 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, bool isInvalid = false; unsigned DiagKind; FixItHint Hint; + ConversionFixItGenerator ConvHints; + bool MayHaveConvFixit = false; switch (ConvTy) { - default: assert(0 && "Unknown conversion type"); + default: llvm_unreachable("Unknown conversion type"); case Compatible: return false; case PointerToInt: DiagKind = diag::ext_typecheck_convert_pointer_int; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; break; case IntToPointer: DiagKind = diag::ext_typecheck_convert_int_pointer; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; break; case IncompatiblePointer: MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); + if (Hint.isNull() && !CheckInferredResultType) { + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + } + MayHaveConvFixit = true; break; case IncompatiblePointerSign: DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; @@ -8722,6 +8983,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; case Incompatible: DiagKind = diag::err_typecheck_convert_incompatible; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; isInvalid = true; break; } @@ -8746,8 +9009,23 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; } - Diag(Loc, DiagKind) << FirstType << SecondType << Action - << SrcExpr->getSourceRange() << Hint; + PartialDiagnostic FDiag = PDiag(DiagKind); + FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange(); + + // If we can fix the conversion, suggest the FixIts. + assert(ConvHints.isNull() || Hint.isNull()); + if (!ConvHints.isNull()) { + for (llvm::SmallVector<FixItHint, 1>::iterator + HI = ConvHints.Hints.begin(), HE = ConvHints.Hints.end(); + HI != HE; ++HI) + FDiag << *HI; + } else { + FDiag << Hint; + } + if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); } + + Diag(Loc, FDiag); + if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); @@ -8786,7 +9064,7 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ if (EvalResult.Diag && Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc) - != Diagnostic::Ignored) + != DiagnosticsEngine::Ignored) Diag(EvalResult.DiagLoc, EvalResult.Diag); if (Result) @@ -8803,8 +9081,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { ExprNeedsCleanups = false; } -void -Sema::PopExpressionEvaluationContext() { +void Sema::PopExpressionEvaluationContext() { // Pop the current expression evaluation context off the stack. ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); ExprEvalContexts.pop_back(); @@ -8874,10 +9151,10 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (D->isUsed(false)) return; - // Mark a parameter or variable declaration "used", regardless of whether we're in a - // template or not. The reason for this is that unevaluated expressions - // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and - // -Wunused-parameters) + // Mark a parameter or variable declaration "used", regardless of whether + // we're in a template or not. The reason for this is that unevaluated + // expressions (e.g. (void)sizeof()) constitute a use for warning purposes + // (-Wunused-variables and -Wunused-parameters) if (isa<ParmVarDecl>(D) || (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) { D->setUsed(); @@ -8917,15 +9194,19 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) { - if (Constructor->isTrivial()) - return; - if (!Constructor->isUsed(false)) - DefineImplicitDefaultConstructor(Loc, Constructor); - } else if (Constructor->isDefaulted() && - Constructor->isCopyConstructor()) { - if (!Constructor->isUsed(false)) - DefineImplicitCopyConstructor(Loc, Constructor); + if (Constructor->isDefaulted()) { + if (Constructor->isDefaultConstructor()) { + if (Constructor->isTrivial()) + return; + if (!Constructor->isUsed(false)) + DefineImplicitDefaultConstructor(Loc, Constructor); + } else if (Constructor->isCopyConstructor()) { + if (!Constructor->isUsed(false)) + DefineImplicitCopyConstructor(Loc, Constructor); + } else if (Constructor->isMoveConstructor()) { + if (!Constructor->isUsed(false)) + DefineImplicitMoveConstructor(Loc, Constructor); + } } MarkVTableUsed(Loc, Constructor->getParent()); @@ -8937,8 +9218,12 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) { if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { - if (!MethodDecl->isUsed(false)) - DefineImplicitCopyAssignment(Loc, MethodDecl); + if (!MethodDecl->isUsed(false)) { + if (MethodDecl->isCopyAssignmentOperator()) + DefineImplicitCopyAssignment(Loc, MethodDecl); + else + DefineImplicitMoveAssignment(Loc, MethodDecl); + } } else if (MethodDecl->isVirtual()) MarkVTableUsed(Loc, MethodDecl->getParent()); } @@ -9147,7 +9432,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. -bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case Unevaluated: @@ -9156,9 +9441,9 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt, case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: - if (stmt && getCurFunctionOrMethodDecl()) { + if (Statement && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. - push_back(sema::PossiblyUnreachableDiag(PD, Loc, stmt)); + push_back(sema::PossiblyUnreachableDiag(PD, Loc, Statement)); } else Diag(Loc, PD); @@ -9203,8 +9488,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { unsigned diagnostic = diag::warn_condition_is_assignment; bool IsOrAssign = false; - if (isa<BinaryOperator>(E)) { - BinaryOperator *Op = cast<BinaryOperator>(E); + if (BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { if (Op->getOpcode() != BO_Assign && Op->getOpcode() != BO_OrAssign) return; @@ -9225,8 +9509,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { } Loc = Op->getOperatorLoc(); - } else if (isa<CXXOperatorCallExpr>(E)) { - CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E); + } else if (CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { if (Op->getOperator() != OO_Equal && Op->getOperator() != OO_PipeEqual) return; @@ -9255,16 +9538,16 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { /// \brief Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. -void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { +void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { // Don't warn if the parens came from a macro. - SourceLocation parenLoc = parenE->getLocStart(); + SourceLocation parenLoc = ParenE->getLocStart(); if (parenLoc.isInvalid() || parenLoc.isMacroID()) return; // Don't warn for dependent expressions. - if (parenE->isTypeDependent()) + if (ParenE->isTypeDependent()) return; - Expr *E = parenE->IgnoreParens(); + Expr *E = ParenE->IgnoreParens(); if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E)) if (opE->getOpcode() == BO_EQ && @@ -9274,8 +9557,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange(); Diag(Loc, diag::note_equality_comparison_silence) - << FixItHint::CreateRemoval(parenE->getSourceRange().getBegin()) - << FixItHint::CreateRemoval(parenE->getSourceRange().getEnd()); + << FixItHint::CreateRemoval(ParenE->getSourceRange().getBegin()) + << FixItHint::CreateRemoval(ParenE->getSourceRange().getEnd()); Diag(Loc, diag::note_equality_comparison_to_assign) << FixItHint::CreateReplacement(Loc, "="); } @@ -9311,11 +9594,11 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { } ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, - Expr *Sub) { - if (!Sub) + Expr *SubExpr) { + if (!SubExpr) return ExprError(); - return CheckBooleanCondition(Sub, Loc); + return CheckBooleanCondition(SubExpr, Loc); } namespace { @@ -9333,76 +9616,76 @@ namespace { return ExprError(); } - ExprResult VisitExpr(Expr *expr) { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call) - << expr->getSourceRange(); + ExprResult VisitExpr(Expr *E) { + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_call) + << E->getSourceRange(); return ExprError(); } /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. - template <class T> ExprResult rebuildSugarExpr(T *expr) { - ExprResult subResult = Visit(expr->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); + template <class T> ExprResult rebuildSugarExpr(T *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - expr->setSubExpr(subExpr); - expr->setType(subExpr->getType()); - expr->setValueKind(subExpr->getValueKind()); - assert(expr->getObjectKind() == OK_Ordinary); - return expr; + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(SubExpr->getType()); + E->setValueKind(SubExpr->getValueKind()); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult VisitParenExpr(ParenExpr *paren) { - return rebuildSugarExpr(paren); + ExprResult VisitParenExpr(ParenExpr *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryExtension(UnaryOperator *op) { - return rebuildSugarExpr(op); + ExprResult VisitUnaryExtension(UnaryOperator *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryAddrOf(UnaryOperator *op) { - ExprResult subResult = Visit(op->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); + ExprResult VisitUnaryAddrOf(UnaryOperator *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - op->setSubExpr(subExpr); - op->setType(S.Context.getPointerType(subExpr->getType())); - assert(op->getValueKind() == VK_RValue); - assert(op->getObjectKind() == OK_Ordinary); - return op; + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(S.Context.getPointerType(SubExpr->getType())); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult resolveDecl(Expr *expr, ValueDecl *decl) { - if (!isa<FunctionDecl>(decl)) return VisitExpr(expr); + ExprResult resolveDecl(Expr *E, ValueDecl *VD) { + if (!isa<FunctionDecl>(VD)) return VisitExpr(E); - expr->setType(decl->getType()); + E->setType(VD->getType()); - assert(expr->getValueKind() == VK_RValue); + assert(E->getValueKind() == VK_RValue); if (S.getLangOptions().CPlusPlus && - !(isa<CXXMethodDecl>(decl) && - cast<CXXMethodDecl>(decl)->isInstance())) - expr->setValueKind(VK_LValue); + !(isa<CXXMethodDecl>(VD) && + cast<CXXMethodDecl>(VD)->isInstance())) + E->setValueKind(VK_LValue); - return expr; + return E; } - ExprResult VisitMemberExpr(MemberExpr *mem) { - return resolveDecl(mem, mem->getMemberDecl()); + ExprResult VisitMemberExpr(MemberExpr *E) { + return resolveDecl(E, E->getMemberDecl()); } - ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { - return resolveDecl(ref, ref->getDecl()); + ExprResult VisitDeclRefExpr(DeclRefExpr *E) { + return resolveDecl(E, E->getDecl()); } }; } /// Given a function expression of unknown-any type, try to rebuild it /// to have a function type. -static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) { - ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn); - if (result.isInvalid()) return ExprError(); - return S.DefaultFunctionArrayConversion(result.take()); +static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *FunctionExpr) { + ExprResult Result = RebuildUnknownAnyFunction(S).Visit(FunctionExpr); + if (Result.isInvalid()) return ExprError(); + return S.DefaultFunctionArrayConversion(Result.take()); } namespace { @@ -9418,80 +9701,80 @@ namespace { /// The current destination type. QualType DestType; - RebuildUnknownAnyExpr(Sema &S, QualType castType) - : S(S), DestType(castType) {} + RebuildUnknownAnyExpr(Sema &S, QualType CastType) + : S(S), DestType(CastType) {} ExprResult VisitStmt(Stmt *S) { llvm_unreachable("unexpected statement!"); return ExprError(); } - ExprResult VisitExpr(Expr *expr) { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr) - << expr->getSourceRange(); + ExprResult VisitExpr(Expr *E) { + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << E->getSourceRange(); return ExprError(); } - ExprResult VisitCallExpr(CallExpr *call); - ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message); + ExprResult VisitCallExpr(CallExpr *E); + ExprResult VisitObjCMessageExpr(ObjCMessageExpr *E); /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. - template <class T> ExprResult rebuildSugarExpr(T *expr) { - ExprResult subResult = Visit(expr->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); - Expr *subExpr = subResult.take(); - expr->setSubExpr(subExpr); - expr->setType(subExpr->getType()); - expr->setValueKind(subExpr->getValueKind()); - assert(expr->getObjectKind() == OK_Ordinary); - return expr; + template <class T> ExprResult rebuildSugarExpr(T *E) { + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); + Expr *SubExpr = SubResult.take(); + E->setSubExpr(SubExpr); + E->setType(SubExpr->getType()); + E->setValueKind(SubExpr->getValueKind()); + assert(E->getObjectKind() == OK_Ordinary); + return E; } - ExprResult VisitParenExpr(ParenExpr *paren) { - return rebuildSugarExpr(paren); + ExprResult VisitParenExpr(ParenExpr *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryExtension(UnaryOperator *op) { - return rebuildSugarExpr(op); + ExprResult VisitUnaryExtension(UnaryOperator *E) { + return rebuildSugarExpr(E); } - ExprResult VisitUnaryAddrOf(UnaryOperator *op) { - const PointerType *ptr = DestType->getAs<PointerType>(); - if (!ptr) { - S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof) - << op->getSourceRange(); + ExprResult VisitUnaryAddrOf(UnaryOperator *E) { + const PointerType *Ptr = DestType->getAs<PointerType>(); + if (!Ptr) { + S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof) + << E->getSourceRange(); return ExprError(); } - assert(op->getValueKind() == VK_RValue); - assert(op->getObjectKind() == OK_Ordinary); - op->setType(DestType); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); + E->setType(DestType); // Build the sub-expression as if it were an object of the pointee type. - DestType = ptr->getPointeeType(); - ExprResult subResult = Visit(op->getSubExpr()); - if (subResult.isInvalid()) return ExprError(); - op->setSubExpr(subResult.take()); - return op; + DestType = Ptr->getPointeeType(); + ExprResult SubResult = Visit(E->getSubExpr()); + if (SubResult.isInvalid()) return ExprError(); + E->setSubExpr(SubResult.take()); + return E; } - ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice); + ExprResult VisitImplicitCastExpr(ImplicitCastExpr *E); - ExprResult resolveDecl(Expr *expr, ValueDecl *decl); + ExprResult resolveDecl(Expr *E, ValueDecl *VD); - ExprResult VisitMemberExpr(MemberExpr *mem) { - return resolveDecl(mem, mem->getMemberDecl()); + ExprResult VisitMemberExpr(MemberExpr *E) { + return resolveDecl(E, E->getMemberDecl()); } - ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { - return resolveDecl(ref, ref->getDecl()); + ExprResult VisitDeclRefExpr(DeclRefExpr *E) { + return resolveDecl(E, E->getDecl()); } }; } /// Rebuilds a call expression which yielded __unknown_anytype. -ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { - Expr *callee = call->getCallee(); +ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) { + Expr *CalleeExpr = E->getCallee(); enum FnKind { FK_MemberFunction, @@ -9499,49 +9782,49 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { FK_BlockPointer }; - FnKind kind; - QualType type = callee->getType(); - if (type == S.Context.BoundMemberTy) { - assert(isa<CXXMemberCallExpr>(call) || isa<CXXOperatorCallExpr>(call)); - kind = FK_MemberFunction; - type = Expr::findBoundMemberType(callee); - } else if (const PointerType *ptr = type->getAs<PointerType>()) { - type = ptr->getPointeeType(); - kind = FK_FunctionPointer; + FnKind Kind; + QualType CalleeType = CalleeExpr->getType(); + if (CalleeType == S.Context.BoundMemberTy) { + assert(isa<CXXMemberCallExpr>(E) || isa<CXXOperatorCallExpr>(E)); + Kind = FK_MemberFunction; + CalleeType = Expr::findBoundMemberType(CalleeExpr); + } else if (const PointerType *Ptr = CalleeType->getAs<PointerType>()) { + CalleeType = Ptr->getPointeeType(); + Kind = FK_FunctionPointer; } else { - type = type->castAs<BlockPointerType>()->getPointeeType(); - kind = FK_BlockPointer; + CalleeType = CalleeType->castAs<BlockPointerType>()->getPointeeType(); + Kind = FK_BlockPointer; } - const FunctionType *fnType = type->castAs<FunctionType>(); + const FunctionType *FnType = CalleeType->castAs<FunctionType>(); // Verify that this is a legal result type of a function. if (DestType->isArrayType() || DestType->isFunctionType()) { unsigned diagID = diag::err_func_returning_array_function; - if (kind == FK_BlockPointer) + if (Kind == FK_BlockPointer) diagID = diag::err_block_returning_array_function; - S.Diag(call->getExprLoc(), diagID) + S.Diag(E->getExprLoc(), diagID) << DestType->isFunctionType() << DestType; return ExprError(); } // Otherwise, go ahead and set DestType as the call's result. - call->setType(DestType.getNonLValueExprType(S.Context)); - call->setValueKind(Expr::getValueKindForType(DestType)); - assert(call->getObjectKind() == OK_Ordinary); + E->setType(DestType.getNonLValueExprType(S.Context)); + E->setValueKind(Expr::getValueKindForType(DestType)); + assert(E->getObjectKind() == OK_Ordinary); // Rebuild the function type, replacing the result type with DestType. - if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType)) DestType = S.Context.getFunctionType(DestType, - proto->arg_type_begin(), - proto->getNumArgs(), - proto->getExtProtoInfo()); + Proto->arg_type_begin(), + Proto->getNumArgs(), + Proto->getExtProtoInfo()); else DestType = S.Context.getFunctionNoProtoType(DestType, - fnType->getExtInfo()); + FnType->getExtInfo()); // Rebuild the appropriate pointer-to-function type. - switch (kind) { + switch (Kind) { case FK_MemberFunction: // Nothing to do. break; @@ -9556,121 +9839,131 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { } // Finally, we can recurse. - ExprResult calleeResult = Visit(callee); - if (!calleeResult.isUsable()) return ExprError(); - call->setCallee(calleeResult.take()); + ExprResult CalleeResult = Visit(CalleeExpr); + if (!CalleeResult.isUsable()) return ExprError(); + E->setCallee(CalleeResult.take()); // Bind a temporary if necessary. - return S.MaybeBindToTemporary(call); + return S.MaybeBindToTemporary(E); } -ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { +ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) { // Verify that this is a legal result type of a call. if (DestType->isArrayType() || DestType->isFunctionType()) { - S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function) + S.Diag(E->getExprLoc(), diag::err_func_returning_array_function) << DestType->isFunctionType() << DestType; return ExprError(); } // Rewrite the method result type if available. - if (ObjCMethodDecl *method = msg->getMethodDecl()) { - assert(method->getResultType() == S.Context.UnknownAnyTy); - method->setResultType(DestType); + if (ObjCMethodDecl *Method = E->getMethodDecl()) { + assert(Method->getResultType() == S.Context.UnknownAnyTy); + Method->setResultType(DestType); } // Change the type of the message. - msg->setType(DestType.getNonReferenceType()); - msg->setValueKind(Expr::getValueKindForType(DestType)); + E->setType(DestType.getNonReferenceType()); + E->setValueKind(Expr::getValueKindForType(DestType)); - return S.MaybeBindToTemporary(msg); + return S.MaybeBindToTemporary(E); } -ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) { +ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) { // The only case we should ever see here is a function-to-pointer decay. - assert(ice->getCastKind() == CK_FunctionToPointerDecay); - assert(ice->getValueKind() == VK_RValue); - assert(ice->getObjectKind() == OK_Ordinary); + assert(E->getCastKind() == CK_FunctionToPointerDecay); + assert(E->getValueKind() == VK_RValue); + assert(E->getObjectKind() == OK_Ordinary); - ice->setType(DestType); + E->setType(DestType); // Rebuild the sub-expression as the pointee (function) type. DestType = DestType->castAs<PointerType>()->getPointeeType(); - ExprResult result = Visit(ice->getSubExpr()); - if (!result.isUsable()) return ExprError(); + ExprResult Result = Visit(E->getSubExpr()); + if (!Result.isUsable()) return ExprError(); - ice->setSubExpr(result.take()); - return S.Owned(ice); + E->setSubExpr(Result.take()); + return S.Owned(E); } -ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) { - ExprValueKind valueKind = VK_LValue; - QualType type = DestType; +ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { + ExprValueKind ValueKind = VK_LValue; + QualType Type = DestType; // We know how to make this work for certain kinds of decls: // - functions - if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { - // This is true because FunctionDecls must always have function - // type, so we can't be resolving the entire thing at once. - assert(type->isFunctionType()); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(VD)) { + if (const PointerType *Ptr = Type->getAs<PointerType>()) { + DestType = Ptr->getPointeeType(); + ExprResult Result = resolveDecl(E, VD); + if (Result.isInvalid()) return ExprError(); + return S.ImpCastExprToType(Result.take(), Type, + CK_FunctionToPointerDecay, VK_RValue); + } + + if (!Type->isFunctionType()) { + S.Diag(E->getExprLoc(), diag::err_unknown_any_function) + << VD << E->getSourceRange(); + return ExprError(); + } - if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn)) - if (method->isInstance()) { - valueKind = VK_RValue; - type = S.Context.BoundMemberTy; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + if (MD->isInstance()) { + ValueKind = VK_RValue; + Type = S.Context.BoundMemberTy; } // Function references aren't l-values in C. if (!S.getLangOptions().CPlusPlus) - valueKind = VK_RValue; + ValueKind = VK_RValue; // - variables - } else if (isa<VarDecl>(decl)) { - if (const ReferenceType *refTy = type->getAs<ReferenceType>()) { - type = refTy->getPointeeType(); - } else if (type->isFunctionType()) { - S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type) - << decl << expr->getSourceRange(); + } else if (isa<VarDecl>(VD)) { + if (const ReferenceType *RefTy = Type->getAs<ReferenceType>()) { + Type = RefTy->getPointeeType(); + } else if (Type->isFunctionType()) { + S.Diag(E->getExprLoc(), diag::err_unknown_any_var_function_type) + << VD << E->getSourceRange(); return ExprError(); } // - nothing else } else { - S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl) - << decl << expr->getSourceRange(); + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_decl) + << VD << E->getSourceRange(); return ExprError(); } - decl->setType(DestType); - expr->setType(type); - expr->setValueKind(valueKind); - return S.Owned(expr); + VD->setType(DestType); + E->setType(Type); + E->setValueKind(ValueKind); + return S.Owned(E); } /// Check a cast of an unknown-any type. We intentionally only /// trigger this for C-style casts. -ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType, - Expr *castExpr, CastKind &castKind, - ExprValueKind &VK, CXXCastPath &path) { +ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, + Expr *CastExpr, CastKind &CastKind, + ExprValueKind &VK, CXXCastPath &Path) { // Rewrite the casted expression from scratch. - ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr); + ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr); if (!result.isUsable()) return ExprError(); - castExpr = result.take(); - VK = castExpr->getValueKind(); - castKind = CK_NoOp; + CastExpr = result.take(); + VK = CastExpr->getValueKind(); + CastKind = CK_NoOp; - return castExpr; + return CastExpr; } -static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { - Expr *orig = e; +static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { + Expr *orig = E; unsigned diagID = diag::err_uncasted_use_of_unknown_any; while (true) { - e = e->IgnoreParenImpCasts(); - if (CallExpr *call = dyn_cast<CallExpr>(e)) { - e = call->getCallee(); + E = E->IgnoreParenImpCasts(); + if (CallExpr *call = dyn_cast<CallExpr>(E)) { + E = call->getCallee(); diagID = diag::err_uncasted_call_of_unknown_any; } else { break; @@ -9679,20 +9972,25 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { SourceLocation loc; NamedDecl *d; - if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) { + if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(E)) { loc = ref->getLocation(); d = ref->getDecl(); - } else if (MemberExpr *mem = dyn_cast<MemberExpr>(e)) { + } else if (MemberExpr *mem = dyn_cast<MemberExpr>(E)) { loc = mem->getMemberLoc(); d = mem->getMemberDecl(); - } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(e)) { + } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(E)) { diagID = diag::err_uncasted_call_of_unknown_any; - loc = msg->getSelectorLoc(); + loc = msg->getSelectorStartLoc(); d = msg->getMethodDecl(); - assert(d && "unknown method returning __unknown_any?"); + if (!d) { + S.Diag(loc, diag::err_uncasted_send_to_unknown_any_method) + << static_cast<unsigned>(msg->isClassMessage()) << msg->getSelector() + << orig->getSourceRange(); + return ExprError(); + } } else { - S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr) - << e->getSourceRange(); + S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << E->getSourceRange(); return ExprError(); } @@ -9709,17 +10007,27 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { QualType type = E->getType(); // Overloaded expressions. - if (type == Context.OverloadTy) - return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true, - E->getSourceRange(), - QualType(), - diag::err_ovl_unresolvable); + if (type == Context.OverloadTy) { + // Try to resolve a single function template specialization. + // This is obligatory. + ExprResult result = Owned(E); + if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) { + return result; + + // If that failed, try to recover with a call. + } else { + tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable), + /*complain*/ true); + return result; + } + } // Bound member functions. if (type == Context.BoundMemberTy) { - Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) - << E->getSourceRange(); - return ExprError(); + ExprResult result = Owned(E); + tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function), + /*complain*/ true); + return result; } // Expressions of unknown type. @@ -9730,10 +10038,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { return Owned(E); } -bool Sema::CheckCaseExpression(Expr *expr) { - if (expr->isTypeDependent()) +bool Sema::CheckCaseExpression(Expr *E) { + if (E->isTypeDependent()) return true; - if (expr->isValueDependent() || expr->isIntegerConstantExpr(Context)) - return expr->getType()->isIntegralOrEnumerationType(); + if (E->isValueDependent() || E->isIntegerConstantExpr(Context)) + return E->getType()->isIntegralOrEnumerationType(); return false; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index e804fcd..3300444 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -295,6 +295,12 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation RParenLoc) { bool isUnevaluatedOperand = true; if (E && !E->isTypeDependent()) { + if (E->getType()->isPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + } + QualType T = E->getType(); if (const RecordType *RecordT = T->getAs<RecordType>()) { CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); @@ -325,7 +331,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; - E = ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)).take(); + E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).take(); } } @@ -545,7 +551,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, - CastCategory(E)).take(); + E->getValueKind()).take(); ExprResult Res = DefaultFunctionArrayConversion(E); if (Res.isInvalid()) @@ -739,27 +745,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. - // if (NumExprs == 1) { - CastKind Kind = CK_Invalid; - ExprValueKind VK = VK_RValue; - CXXCastPath BasePath; - ExprResult CastExpr = - CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(), - TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], - Kind, VK, BasePath, - /*FunctionalStyle=*/true); - if (CastExpr.isInvalid()) - return ExprError(); - Exprs[0] = CastExpr.take(); - + Expr *Arg = Exprs[0]; exprs.release(); - - return Owned(CXXFunctionalCastExpr::Create(Context, - Ty.getNonLValueExprType(Context), - VK, TInfo, TyBeginLoc, Kind, - Exprs[0], &BasePath, - RParenLoc)); + return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); @@ -1058,7 +1047,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); - llvm::SmallVector<Expr *, 8> AllPlaceArgs; + SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { // Add default arguments, if any. const FunctionProtoType *Proto = @@ -1079,6 +1068,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- CXXConstructorDecl *Constructor = 0; + bool HadMultipleCandidates = false; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); ASTOwningVector<Expr*> ConvertedConstructorArgs(*this); @@ -1125,6 +1115,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(FullInitExpr)) { Constructor = Construct->getConstructor(); + HadMultipleCandidates = Construct->hadMultipleCandidates(); for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(), AEnd = Construct->arg_end(); A != AEnd; ++A) @@ -1166,7 +1157,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, TypeIdParens, ArraySize, Constructor, Init, - ConsArgs, NumConsArgs, OperatorDelete, + ConsArgs, NumConsArgs, + HadMultipleCandidates, + OperatorDelete, UsualArrayDeleteWantsSize, ResultType, AllocTypeInfo, StartLoc, @@ -1246,12 +1239,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 3) The first argument is always size_t. Append the arguments from the // placement form. - llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs); + SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs); // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? IntegerLiteral Size(Context, llvm::APInt::getNullValue( - Context.Target.getPointerWidth(0)), + Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); AllocArgs[0] = &Size; @@ -1325,7 +1318,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, FoundDelete.suppressDiagnostics(); - llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; + SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; // Whether we're looking for a placement operator delete is dictated // by whether we selected a placement operator new, not by whether @@ -1352,7 +1345,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, const FunctionProtoType *Proto = OperatorNew->getType()->getAs<FunctionProtoType>(); - llvm::SmallVector<QualType, 4> ArgTypes; + SmallVector<QualType, 4> ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) ArgTypes.push_back(Proto->getArgType(I)); @@ -1525,8 +1518,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, return true; } } - assert(false && "Unreachable, bad result from BestViableFunction"); - return true; + llvm_unreachable("Unreachable, bad result from BestViableFunction"); } @@ -1671,7 +1663,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, SourceLocation(), 0, Argument, /*TInfo=*/0, SC_None, SC_None, 0); - Alloc->setParams(&Param, 1); + Alloc->setParams(Param); // FIXME: Also add this declaration to the IdentifierResolver, but // make sure it is at the end of the chain to coincide with the @@ -1691,7 +1683,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); - llvm::SmallVector<DeclAccessPair,4> Matches; + SmallVector<DeclAccessPair,4> Matches; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { NamedDecl *ND = (*F)->getUnderlyingDecl(); @@ -1727,7 +1719,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; - for (llvm::SmallVectorImpl<DeclAccessPair>::iterator + for (SmallVectorImpl<DeclAccessPair>::iterator F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; @@ -1792,7 +1784,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::err_delete_incomplete_class_type))) return ExprError(); - llvm::SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; + SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); @@ -1840,24 +1832,32 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex.get()->getSourceRange()); QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); + QualType PointeeElem = Context.getBaseElementType(Pointee); + + if (unsigned AddressSpace = Pointee.getAddressSpace()) + return Diag(Ex.get()->getLocStart(), + diag::err_address_space_qualified_delete) + << Pointee.getUnqualifiedType() << AddressSpace; + + CXXRecordDecl *PointeeRD = 0; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); - } else if (Pointee->isFunctionType() || Pointee->isVoidType()) + } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); - else if (!Pointee->isDependentType() && - RequireCompleteType(StartLoc, Pointee, - PDiag(diag::warn_delete_incomplete) - << Ex.get()->getSourceRange())) - return ExprError(); - else if (unsigned AddressSpace = Pointee.getAddressSpace()) - return Diag(Ex.get()->getLocStart(), - diag::err_address_space_qualified_delete) - << Pointee.getUnqualifiedType() << AddressSpace; + } else if (!Pointee->isDependentType()) { + if (!RequireCompleteType(StartLoc, Pointee, + PDiag(diag::warn_delete_incomplete) + << Ex.get()->getSourceRange())) { + if (const RecordType *RT = PointeeElem->getAs<RecordType>()) + PointeeRD = cast<CXXRecordDecl>(RT->getDecl()); + } + } + // C++ [expr.delete]p2: // [Note: a pointer to a const type can be the operand of a // delete-expression; it is not necessary to cast away the constness @@ -1877,12 +1877,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); - QualType PointeeElem = Context.getBaseElementType(Pointee); - if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - + if (PointeeRD) { if (!UseGlobal && - FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) + FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, + OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the @@ -1900,8 +1898,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); } - if (!RD->hasTrivialDestructor()) - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (!PointeeRD->hasTrivialDestructor()) + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkDeclarationReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); @@ -1915,10 +1913,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // behavior is undefined. // // Note: a final class cannot be derived from, no issue there - if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) { - CXXDestructorDecl *dtor = RD->getDestructor(); - if (!dtor || !dtor->isVirtual()) - Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) { + CXXDestructorDecl *dtor = PointeeRD->getDestructor(); + if (dtor && !dtor->isVirtual()) { + if (PointeeRD->isAbstract()) { + // If the class is abstract, we warn by default, because we're + // sure the code has undefined behavior. + Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor) + << PointeeElem; + } else if (!ArrayForm) { + // Otherwise, if this is not an array delete, it's a bit suspect, + // but not necessarily wrong. + Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + } + } } } else if (getLangOptions().ObjCAutoRefCount && @@ -1944,9 +1952,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, MarkDeclarationReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. - if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { + if (PointeeRD) { + if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } @@ -2026,12 +2033,20 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { = ToPtrType->getPointeeType()->getAs<BuiltinType>()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). - if (!ToPtrType->getPointeeType().hasQualifiers() && - ((StrLit->isWide() && ToPointeeType->isWideCharType()) || - (!StrLit->isWide() && - (ToPointeeType->getKind() == BuiltinType::Char_U || - ToPointeeType->getKind() == BuiltinType::Char_S)))) - return true; + if (!ToPtrType->getPointeeType().hasQualifiers()) { + switch (StrLit->getKind()) { + case StringLiteral::UTF8: + case StringLiteral::UTF16: + case StringLiteral::UTF32: + // We don't allow UTF literals to be implicitly converted + break; + case StringLiteral::Ascii: + return (ToPointeeType->getKind() == BuiltinType::Char_U || + ToPointeeType->getKind() == BuiltinType::Char_S); + case StringLiteral::Wide: + return ToPointeeType->isWideCharType(); + } + } } return false; @@ -2042,23 +2057,28 @@ static ExprResult BuildCXXCastArgument(Sema &S, QualType Ty, CastKind Kind, CXXMethodDecl *Method, - NamedDecl *FoundDecl, + DeclAccessPair FoundDecl, + bool HadMultipleCandidates, Expr *From) { switch (Kind) { - default: assert(0 && "Unhandled cast kind!"); + default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method); ASTOwningVector<Expr*> ConstructorArgs(S); - if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + if (S.CompleteConstructorCall(Constructor, MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) return ExprError(); - ExprResult Result = - S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs), - /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, - SourceRange()); + S.CheckConstructorAccess(CastLoc, Constructor, Constructor->getAccess(), + S.PDiag(diag::err_access_ctor)); + + ExprResult Result + = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); @@ -2069,10 +2089,13 @@ static ExprResult BuildCXXCastArgument(Sema &S, assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. - ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method); + ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Method, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); + S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl); + return S.MaybeBindToTemporary(Result.get()); } } @@ -2138,6 +2161,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ToType.getNonReferenceType(), CastKind, cast<CXXMethodDecl>(FD), ICS.UserDefined.FoundConversionFunction, + ICS.UserDefined.HadMultipleCandidates, From); if (CastArg.isInvalid()) @@ -2156,8 +2180,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); case ImplicitConversionSequence::EllipsisConversion: - assert(false && "Cannot perform an ellipsis conversion"); - return Owned(From); + llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: return ExprError(); @@ -2198,6 +2221,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, move_arg(ConstructorArgs), + /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -2205,6 +2229,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, MultiExprArg(*this, &From, 1), + /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -2241,9 +2266,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (!From->isGLValue()) break; } - // Check for trivial buffer overflows. - CheckArrayAccess(From); - FromType = FromType.getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, From, 0, VK_RValue); @@ -2262,8 +2284,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, break; default: - assert(false && "Improper first standard conversion"); - break; + llvm_unreachable("Improper first standard conversion"); } // Perform the second implicit conversion @@ -2340,12 +2361,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action - << From->getSourceRange(); + << From->getSourceRange() << 0; else Diag(From->getSourceRange().getBegin(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action - << From->getSourceRange(); + << From->getSourceRange() << 0; if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) @@ -2354,20 +2375,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, else if (getLangOptions().ObjCAutoRefCount && !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { - if (Action == AA_Initializing) - Diag(From->getSourceRange().getBegin(), - diag::err_arc_weak_unavailable_assign); - else - Diag(From->getSourceRange().getBegin(), - diag::err_arc_convesion_of_weak_unavailable) - << (Action == AA_Casting) << From->getType() << ToType - << From->getSourceRange(); - } + if (Action == AA_Initializing) + Diag(From->getSourceRange().getBegin(), + diag::err_arc_weak_unavailable_assign); + else + Diag(From->getSourceRange().getBegin(), + diag::err_arc_convesion_of_weak_unavailable) + << (Action == AA_Casting) << From->getType() << ToType + << From->getSourceRange(); + } CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); + + // Make sure we extend blocks if necessary. + // FIXME: doing this here is really ugly. + if (Kind == CK_BlockPointerToObjCPointerCast) { + ExprResult E = From; + (void) PrepareCastToObjCObjectPointer(E); + From = E.take(); + } + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .take(); break; @@ -2386,6 +2416,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Boolean_Conversion: + // Perform half-to-boolean conversion via float. + if (From->getType()->isHalfType()) { + From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take(); + FromType = Context.FloatTy; + } + From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/0, CCK).take(); @@ -2402,7 +2438,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); From = ImpCastExprToType(From, ToType.getNonReferenceType(), - CK_DerivedToBase, CastCategory(From), + CK_DerivedToBase, From->getValueKind(), &BasePath, CCK).take(); break; } @@ -2493,8 +2529,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Function_To_Pointer: case ICK_Qualification: case ICK_Num_Conversion_Kinds: - assert(false && "Improper second standard conversion"); - break; + llvm_unreachable("Improper second standard conversion"); } switch (SCS.Third) { @@ -2506,7 +2541,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? - CastCategory(From) : VK_RValue; + From->getValueKind() : VK_RValue; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK_NoOp, VK, /*BasePath=*/0, CCK).take(); @@ -2519,8 +2554,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } default: - assert(false && "Improper third standard conversion"); - break; + llvm_unreachable("Improper third standard conversion"); } return Owned(From); @@ -2835,8 +2869,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc), Sema::LookupOrdinaryName); if (Self.LookupQualifiedName(Res, RD)) { + Res.suppressDiagnostics(); for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); Op != OpEnd; ++Op) { + if (isa<FunctionTemplateDecl>(*Op)) + continue; + CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); if (Operator->isCopyAssignmentOperator()) { FoundAssign = true; @@ -2849,7 +2887,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, } } } - + return FoundAssign; } return false; @@ -3240,34 +3278,34 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, RParen, Context.BoolTy)); } -QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, +QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { - assert(!lex.get()->getType()->isPlaceholderType() && - !rex.get()->getType()->isPlaceholderType() && + assert(!LHS.get()->getType()->isPlaceholderType() && + !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); // The LHS undergoes lvalue conversions if this is ->*. if (isIndirect) { - lex = DefaultLvalueConversion(lex.take()); - if (lex.isInvalid()) return QualType(); + LHS = DefaultLvalueConversion(LHS.take()); + if (LHS.isInvalid()) return QualType(); } // The RHS always undergoes lvalue conversions. - rex = DefaultLvalueConversion(rex.take()); - if (rex.isInvalid()) return QualType(); + RHS = DefaultLvalueConversion(RHS.take()); + if (RHS.isInvalid()) return QualType(); const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] - QualType RType = rex.get()->getType(); - const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>(); + QualType RHSType = RHS.get()->getType(); + const MemberPointerType *MemPtr = RHSType->getAs<MemberPointerType>(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) - << OpSpelling << RType << rex.get()->getSourceRange(); + << OpSpelling << RHSType << RHS.get()->getSourceRange(); return QualType(); } @@ -3283,21 +3321,21 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] - QualType LType = lex.get()->getType(); + QualType LHSType = LHS.get()->getType(); if (isIndirect) { - if (const PointerType *Ptr = LType->getAs<PointerType>()) - LType = Ptr->getPointeeType(); + if (const PointerType *Ptr = LHSType->getAs<PointerType>()) + LHSType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) - << OpSpelling << 1 << LType + << OpSpelling << 1 << LHSType << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } - if (!Context.hasSameUnqualifiedType(Class, LType)) { + if (!Context.hasSameUnqualifiedType(Class, LHSType)) { // If we want to check the hierarchy, we need a complete type. - if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs) + if (RequireCompleteType(Loc, LHSType, PDiag(diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect)) { return QualType(); } @@ -3305,23 +3343,23 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? - if (!IsDerivedFrom(LType, Class, Paths) || + if (!IsDerivedFrom(LHSType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex.get()->getType(); + << (int)isIndirect << LHS.get()->getType(); return QualType(); } // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; - ExprValueKind VK = - isIndirect ? VK_RValue : CastCategory(lex.get()); + ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind(); CXXCastPath BasePath; BuildBasePathArray(Paths, BasePath); - lex = ImpCastExprToType(lex.take(), UseType, CK_DerivedToBase, VK, &BasePath); + LHS = ImpCastExprToType(LHS.take(), UseType, CK_DerivedToBase, VK, + &BasePath); } - if (isa<CXXScalarValueInitExpr>(rex.get()->IgnoreParens())) { + if (isa<CXXScalarValueInitExpr>(RHS.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; @@ -3334,7 +3372,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. QualType Result = MemPtr->getPointeeType(); - Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is @@ -3349,15 +3387,15 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, break; case RQ_LValue: - if (!isIndirect && !lex.get()->Classify(Context).isLValue()) + if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 1 << lex.get()->getSourceRange(); + << RHSType << 1 << LHS.get()->getSourceRange(); break; case RQ_RValue: - if (isIndirect || !lex.get()->Classify(Context).isRValue()) + if (isIndirect || !LHS.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 0 << lex.get()->getSourceRange(); + << RHSType << 0 << LHS.get()->getSourceRange(); break; } } @@ -3375,7 +3413,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, } else if (isIndirect) { VK = VK_LValue; } else { - VK = lex.get()->getValueKind(); + VK = LHS.get()->getValueKind(); } return Result; @@ -3528,8 +3566,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS break; case OR_Deleted: - assert(false && "Conditional operator has only built-in overloads"); - break; + llvm_unreachable("Conditional operator has only built-in overloads"); } return true; } @@ -3838,9 +3875,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. // FIXME: extended qualifiers? - typedef llvm::SmallVector<unsigned, 4> QualifierVector; + typedef SmallVector<unsigned, 4> QualifierVector; QualifierVector QualifierUnion; - typedef llvm::SmallVector<std::pair<const Type *, const Type *>, 4> + typedef SmallVector<std::pair<const Type *, const Type *>, 4> ContainingClassVector; ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), @@ -4044,27 +4081,30 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { // actual method. FIXME: we should infer retention by selector in // cases where we don't have an actual method. } else { - Decl *D = 0; + ObjCMethodDecl *D = 0; if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) { D = Send->getMethodDecl(); } else { CastExpr *CE = cast<CastExpr>(E); - // FIXME. What other cast kinds to check for? - if (CE->getCastKind() == CK_ObjCProduceObject || - CE->getCastKind() == CK_LValueToRValue) - return MaybeBindToTemporary(CE->getSubExpr()); assert(CE->getCastKind() == CK_GetObjCProperty); const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty(); D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0); } ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>()); + + // Don't do reclaims on performSelector calls; despite their + // return type, the invoked method doesn't necessarily actually + // return an object. + if (!ReturnsRetained && + D && D->getMethodFamily() == OMF_performSelector) + return Owned(E); } ExprNeedsCleanups = true; - CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject - : CK_ObjCReclaimReturnedObject); + CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject + : CK_ARCReclaimReturnedObject); return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0, VK_RValue)); } @@ -4172,7 +4212,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, if (OpKind == tok::arrow) { // The set of types we've considered so far. llvm::SmallPtrSet<CanQualType,8> CTypes; - llvm::SmallVector<SourceLocation, 8> Locations; + SmallVector<SourceLocation, 8> Locations; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { @@ -4509,7 +4549,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, - CXXMethodDecl *Method) { + CXXMethodDecl *Method, + bool HadMultipleCandidates) { ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0, FoundDecl, Method); if (Exp.isInvalid()) @@ -4519,6 +4560,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method, SourceLocation(), Method->getType(), VK_RValue, OK_Ordinary); + if (HadMultipleCandidates) + ME->setHadMultipleCandidates(true); + QualType ResultType = Method->getResultType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); @@ -4608,7 +4652,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE) { if (FullExpr.isInvalid()) return ExprError(); - CheckImplicitConversions(FullExpr.get()); + CheckImplicitConversions(FullExpr.get(), FullExpr.get()->getExprLoc()); return MaybeCreateExprWithCleanups(FullExpr); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index 2488dc8..26867c2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp @@ -298,7 +298,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); + << StringRef(compStr, 1) << SourceRange(CompLoc); return QualType(); } @@ -337,10 +337,14 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); // Now look up the TypeDefDecl from the vector type. Without this, // diagostics look bad. We want extended vector types to appear built-in. - for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { - if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) - return S.Context.getTypedefType(S.ExtVectorDecls[i]); + for (Sema::ExtVectorDeclsType::iterator + I = S.ExtVectorDecls.begin(S.ExternalSource), + E = S.ExtVectorDecls.end(); + I != E; ++I) { + if ((*I)->getUnderlyingType() == VT) + return S.Context.getTypedefType(*I); } + return VT; // should never get here (a typedef type should always be found). } @@ -949,9 +953,9 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { QualType redef; if (ty->isObjCId()) { - redef = S.Context.ObjCIdRedefinitionType; + redef = S.Context.getObjCIdRedefinitionType(); } else if (ty->isObjCClass()) { - redef = S.Context.ObjCClassRedefinitionType; + redef = S.Context.getObjCClassRedefinitionType(); } else { return false; } @@ -966,6 +970,15 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { return true; } +static bool isRecordType(QualType T) { + return T->isRecordType(); +} +static bool isPointerToRecordType(QualType T) { + if (const PointerType *PT = T->getAs<PointerType>()) + return PT->getPointeeType()->isRecordType(); + return false; +} + /// Look up the given member of the given non-type-dependent /// expression. This can return in one of two ways: /// * If it returns a sentinel null-but-valid result, the caller will @@ -985,6 +998,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Perform default conversions. BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); if (IsArrow) { BaseExpr = DefaultLvalueConversion(BaseExpr.take()); @@ -1041,6 +1056,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Handle ivar access to Objective-C objects. if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { + if (!SS.isEmpty() && !SS.isInvalid()) { + Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access) + << 1 << SS.getScopeRep() + << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); // There are three cases for the base type: @@ -1159,6 +1181,13 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // Objective-C property access. const ObjCObjectPointerType *OPT; if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { + if (!SS.isEmpty() && !SS.isInvalid()) { + Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access) + << 0 << SS.getScopeRep() + << FixItHint::CreateRemoval(SS.getRange()); + SS.clear(); + } + // This actually uses the base as an r-value. BaseExpr = DefaultLvalueConversion(BaseExpr.take()); if (BaseExpr.isInvalid()) @@ -1318,8 +1347,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // not just a pointer to builtin-sel again. if (IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && - !Context.ObjCSelRedefinitionType->isObjCSelType()) { - BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, + !Context.getObjCSelRedefinitionType()->isObjCSelType()) { + BaseExpr = ImpCastExprToType(BaseExpr.take(), + Context.getObjCSelRedefinitionType(), CK_BitCast); return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); @@ -1351,50 +1381,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, // If the user is trying to apply -> or . to a function name, it's probably // because they forgot parentheses to call that function. - QualType ZeroArgCallTy; - UnresolvedSet<4> Overloads; - if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { - if (ZeroArgCallTy.isNull()) { - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); - UnresolvedSet<2> PlausibleOverloads; - for (OverloadExpr::decls_iterator It = Overloads.begin(), - DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { - const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); - QualType OverloadResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && OverloadResultTy->isRecordType()) || - (IsArrow && OverloadResultTy->isPointerType() && - OverloadResultTy->getPointeeType()->isRecordType())) - PlausibleOverloads.addDecl(It.getDecl()); - } - NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); + if (tryToRecoverWithCall(BaseExpr, + PDiag(diag::err_member_reference_needs_call), + /*complain*/ false, + IsArrow ? &isRecordType : &isPointerToRecordType)) { + if (BaseExpr.isInvalid()) return ExprError(); - } - if ((!IsArrow && ZeroArgCallTy->isRecordType()) || - (IsArrow && ZeroArgCallTy->isPointerType() && - ZeroArgCallTy->getPointeeType()->isRecordType())) { - // At this point, we know BaseExpr looks like it's potentially callable - // with 0 arguments, and that it returns something of a reasonable type, - // so we can emit a fixit and carry on pretending that BaseExpr was - // actually a CallExpr. - SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); - Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) - << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() - << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - // FIXME: Try this before emitting the fixit, and suppress diagnostics - // while doing so. - ExprResult NewBase = - ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc.getFileLocWithOffset(1)); - if (NewBase.isInvalid()) - return ExprError(); - BaseExpr = NewBase; - BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); - } + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); + return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl, HasTemplateArgs); } Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) @@ -1427,7 +1422,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, return ExprError(); // Warn about the explicit constructor calls Microsoft extension. - if (getLangOptions().Microsoft && + if (getLangOptions().MicrosoftExt && Id.getKind() == UnqualifiedId::IK_ConstructorName) Diag(Id.getSourceRange().getBegin(), diag::ext_ms_explicit_constructor_call); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 02a4682..20098b2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" @@ -26,6 +27,7 @@ using namespace clang; using namespace sema; +using llvm::makeArrayRef; ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, Expr **strings, @@ -42,13 +44,13 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, if (NumStrings != 1) { // Concatenate objc strings. llvm::SmallString<128> StrBuf; - llvm::SmallVector<SourceLocation, 8> StrLocs; + SmallVector<SourceLocation, 8> StrLocs; for (unsigned i = 0; i != NumStrings; ++i) { S = Strings[i]; - // ObjC strings can't be wide. - if (S->isWide()) { + // ObjC strings can't be wide or UTF. + if (!S->isAscii()) { Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant) << S->getSourceRange(); return true; @@ -64,7 +66,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // Create the aggregate string with the appropriate content and location // information. S = StringLiteral::Create(Context, StrBuf, - /*Wide=*/false, /*Pascal=*/false, + StringLiteral::Ascii, /*Pascal=*/false, Context.getPointerType(Context.CharTy), &StrLocs[0], StrLocs.size()); } @@ -203,6 +205,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, case OMF_None: case OMF_alloc: case OMF_copy: + case OMF_finalize: case OMF_init: case OMF_mutableCopy: case OMF_new: @@ -270,6 +273,13 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() { return method; } +static QualType stripObjCInstanceType(ASTContext &Context, QualType T) { + if (T == Context.getObjCInstanceType()) + return Context.getObjCIdType(); + + return T; +} + QualType Sema::getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage) { @@ -282,7 +292,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) - return Method->getSendResultType(); + return stripObjCInstanceType(Context, Method->getSendResultType()); // - if the receiver is super, T is a pointer to the class of the // enclosing method definition @@ -301,7 +311,7 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) - return Method->getSendResultType(); + return stripObjCInstanceType(Context, Method->getSendResultType()); // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise @@ -327,6 +337,10 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) { MsgSend->getType())) return; + if (!Context.hasSameUnqualifiedType(Method->getResultType(), + Context.getObjCInstanceType())) + return; + Diag(Method->getLocation(), diag::note_related_result_type_inferred) << Method->isInstanceMethod() << Method->getSelector() << MsgSend->getType(); @@ -356,8 +370,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, else DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; - Diag(lbrac, DiagID) - << Sel << isClassMessage << SourceRange(lbrac, rbrac); + if (!getLangOptions().DebuggerSupport) + Diag(lbrac, DiagID) + << Sel << isClassMessage << SourceRange(lbrac, rbrac); // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. @@ -947,7 +962,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { // Determine whether we are inside a method or not. @@ -975,13 +990,18 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // We are in a method whose class has a superclass, so 'super' // is acting as a keyword. if (Method->isInstanceMethod()) { + if (Sel.getMethodFamily() == OMF_dealloc) + ObjCShouldCallSuperDealloc = false; + if (Sel.getMethodFamily() == OMF_finalize) + ObjCShouldCallSuperFinalize = false; + // Since we are in an instance method, this is an instance // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(0, SuperTy, SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } // Since we are in a class method, this is a class message to @@ -989,7 +1009,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return BuildClassMessage(/*ReceiverTypeInfo=*/0, Context.getObjCInterfaceType(Super), SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build an Objective-C class message expression. @@ -1026,7 +1046,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg ArgsIn) { SourceLocation Loc = SuperLoc.isValid()? SuperLoc @@ -1045,8 +1065,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, - Sel, SelectorLoc, /*Method=*/0, - Args, NumArgs, RBracLoc)); + Sel, SelectorLocs, /*Method=*/0, + makeArrayRef(Args, NumArgs),RBracLoc)); } // Find the class to which we are sending this message. @@ -1107,12 +1127,14 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, SelectorLoc, - Method, Args, NumArgs, RBracLoc); + ReceiverType, Sel, SelectorLocs, + Method, makeArrayRef(Args, NumArgs), + RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - ReceiverTypeInfo, Sel, SelectorLoc, - Method, Args, NumArgs, RBracLoc); + ReceiverTypeInfo, Sel, SelectorLocs, + Method, makeArrayRef(Args, NumArgs), + RBracLoc); return MaybeBindToTemporary(Result); } @@ -1123,7 +1145,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { TypeSourceInfo *ReceiverTypeInfo; @@ -1137,7 +1159,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, return BuildClassMessage(ReceiverTypeInfo, ReceiverType, /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build an Objective-C instance message expression. @@ -1174,7 +1196,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg ArgsIn) { // The location of the receiver. @@ -1197,8 +1219,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel, - SelectorLoc, /*Method=*/0, - Args, NumArgs, RBracLoc)); + SelectorLocs, /*Method=*/0, + makeArrayRef(Args, NumArgs), + RBracLoc)); } // If necessary, apply function/array conversion to the receiver. @@ -1346,7 +1369,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_BitCast).take(); + CK_CPointerToObjCPointerCast).take(); else { // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, @@ -1355,24 +1378,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, IsNull ? CK_NullToPointer : CK_IntegralToPointer).take(); } ReceiverType = Receiver->getType(); - } - else { + } else { ExprResult ReceiverRes; if (getLangOptions().CPlusPlus) - ReceiverRes = PerformContextuallyConvertToObjCId(Receiver); + ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver); if (ReceiverRes.isUsable()) { Receiver = ReceiverRes.take(); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { - Receiver = ICE->getSubExpr(); - ReceiverType = Receiver->getType(); - } return BuildInstanceMessage(Receiver, ReceiverType, SuperLoc, Sel, Method, LBracLoc, - SelectorLoc, + SelectorLocs, RBracLoc, move(ArgsIn)); } else { @@ -1402,6 +1420,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); + SourceLocation SelLoc = SelectorLocs.front(); + // In ARC, forbid the user from sending messages to // retain/release/autorelease/dealloc/retainCount explicitly. if (getLangOptions().ObjCAutoRefCount) { @@ -1415,6 +1435,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_None: case OMF_alloc: case OMF_copy: + case OMF_finalize: case OMF_mutableCopy: case OMF_new: case OMF_self: @@ -1426,7 +1447,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_autorelease: case OMF_retainCount: Diag(Loc, diag::err_arc_illegal_explicit_message) - << Sel << SelectorLoc; + << Sel << SelLoc; break; case OMF_performSelector: @@ -1452,7 +1473,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // Issue error, unless ns_returns_not_retained. if (!SelMethod->hasAttr<NSReturnsNotRetainedAttr>()) { // selector names a +1 method - Diag(SelectorLoc, + Diag(SelLoc, diag::err_arc_perform_selector_retains); Diag(SelMethod->getLocation(), diag::note_method_declared_at); } @@ -1461,7 +1482,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // +0 call. OK. unless ns_returns_retained. if (SelMethod->hasAttr<NSReturnsRetainedAttr>()) { // selector names a +1 method - Diag(SelectorLoc, + Diag(SelLoc, diag::err_arc_perform_selector_retains); Diag(SelMethod->getLocation(), diag::note_method_declared_at); } @@ -1470,7 +1491,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } else { // error (may leak). - Diag(SelectorLoc, diag::warn_arc_perform_selector_leaks); + Diag(SelLoc, diag::warn_arc_perform_selector_leaks); Diag(Args[0]->getExprLoc(), diag::note_used_here); } } @@ -1483,12 +1504,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (SuperLoc.isValid()) Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, SelectorLoc, Method, - Args, NumArgs, RBracLoc); + ReceiverType, Sel, SelectorLocs, Method, + makeArrayRef(Args, NumArgs), RBracLoc); else Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - Receiver, Sel, SelectorLoc, Method, - Args, NumArgs, RBracLoc); + Receiver, Sel, SelectorLocs, Method, + makeArrayRef(Args, NumArgs), RBracLoc); if (getLangOptions().ObjCAutoRefCount) { // In ARC, annotate delegate init calls. @@ -1520,7 +1541,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args) { if (!Receiver) @@ -1528,206 +1549,360 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, return BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLoc, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, move(Args)); } enum ARCConversionTypeClass { + /// int, void, struct A ACTC_none, + + /// id, void (^)() ACTC_retainable, - ACTC_indirectRetainable + + /// id*, id***, void (^*)(), + ACTC_indirectRetainable, + + /// void* might be a normal C type, or it might a CF type. + ACTC_voidPtr, + + /// struct A* + ACTC_coreFoundation }; +static bool isAnyRetainable(ARCConversionTypeClass ACTC) { + return (ACTC == ACTC_retainable || + ACTC == ACTC_coreFoundation || + ACTC == ACTC_voidPtr); +} +static bool isAnyCLike(ARCConversionTypeClass ACTC) { + return ACTC == ACTC_none || + ACTC == ACTC_voidPtr || + ACTC == ACTC_coreFoundation; +} + static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) { - ARCConversionTypeClass ACTC = ACTC_retainable; + bool isIndirect = false; // Ignore an outermost reference type. - if (const ReferenceType *ref = type->getAs<ReferenceType>()) + if (const ReferenceType *ref = type->getAs<ReferenceType>()) { type = ref->getPointeeType(); + isIndirect = true; + } // Drill through pointers and arrays recursively. while (true) { if (const PointerType *ptr = type->getAs<PointerType>()) { type = ptr->getPointeeType(); + + // The first level of pointer may be the innermost pointer on a CF type. + if (!isIndirect) { + if (type->isVoidType()) return ACTC_voidPtr; + if (type->isRecordType()) return ACTC_coreFoundation; + } } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) { type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0); } else { break; } - ACTC = ACTC_indirectRetainable; + isIndirect = true; } - if (!type->isObjCRetainableType()) return ACTC_none; - return ACTC; + if (isIndirect) { + if (type->isObjCARCBridgableType()) + return ACTC_indirectRetainable; + return ACTC_none; + } + + if (type->isObjCARCBridgableType()) + return ACTC_retainable; + + return ACTC_none; } namespace { - /// Return true if the given expression can be reasonably converted - /// between a retainable pointer type and a C pointer type. - struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> { + /// A result from the cast checker. + enum ACCResult { + /// Cannot be casted. + ACC_invalid, + + /// Can be safely retained or not retained. + ACC_bottom, + + /// Can be casted at +0. + ACC_plusZero, + + /// Can be casted at +1. + ACC_plusOne + }; + ACCResult merge(ACCResult left, ACCResult right) { + if (left == right) return left; + if (left == ACC_bottom) return right; + if (right == ACC_bottom) return left; + return ACC_invalid; + } + + /// A checker which white-lists certain expressions whose conversion + /// to or from retainable type would otherwise be forbidden in ARC. + class ARCCastChecker : public StmtVisitor<ARCCastChecker, ACCResult> { + typedef StmtVisitor<ARCCastChecker, ACCResult> super; + ASTContext &Context; - ARCCastChecker(ASTContext &Context) : Context(Context) {} - bool VisitStmt(Stmt *s) { - return false; + ARCConversionTypeClass SourceClass; + ARCConversionTypeClass TargetClass; + + static bool isCFType(QualType type) { + // Someday this can use ns_bridged. For now, it has to do this. + return type->isCARCBridgableType(); } - bool VisitExpr(Expr *e) { - return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); + + public: + ARCCastChecker(ASTContext &Context, ARCConversionTypeClass source, + ARCConversionTypeClass target) + : Context(Context), SourceClass(source), TargetClass(target) {} + + using super::Visit; + ACCResult Visit(Expr *e) { + return super::Visit(e->IgnoreParens()); } - - bool VisitParenExpr(ParenExpr *e) { - return Visit(e->getSubExpr()); + + ACCResult VisitStmt(Stmt *s) { + return ACC_invalid; + } + + /// Null pointer constants can be casted however you please. + ACCResult VisitExpr(Expr *e) { + if (e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + return ACC_bottom; + return ACC_invalid; } - bool VisitCastExpr(CastExpr *e) { + + /// Objective-C string literals can be safely casted. + ACCResult VisitObjCStringLiteral(ObjCStringLiteral *e) { + // If we're casting to any retainable type, go ahead. Global + // strings are immune to retains, so this is bottom. + if (isAnyRetainable(TargetClass)) return ACC_bottom; + + return ACC_invalid; + } + + /// Look through certain implicit and explicit casts. + ACCResult VisitCastExpr(CastExpr *e) { switch (e->getCastKind()) { case CK_NullToPointer: - return true; + return ACC_bottom; + case CK_NoOp: case CK_LValueToRValue: case CK_BitCast: - case CK_AnyPointerToObjCPointerCast: + case CK_GetObjCProperty: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(e->getSubExpr()); + default: - return false; + return ACC_invalid; } } - bool VisitUnaryExtension(UnaryOperator *e) { + + /// Look through unary extension. + ACCResult VisitUnaryExtension(UnaryOperator *e) { return Visit(e->getSubExpr()); } - bool VisitBinComma(BinaryOperator *e) { + + /// Ignore the LHS of a comma operator. + ACCResult VisitBinComma(BinaryOperator *e) { return Visit(e->getRHS()); } - bool VisitConditionalOperator(ConditionalOperator *e) { - // Conditional operators are okay if both sides are okay. - return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr()); - } - bool VisitObjCStringLiteral(ObjCStringLiteral *e) { - // Always white-list Objective-C string literals. - return true; + + /// Conditional operators are okay if both sides are okay. + ACCResult VisitConditionalOperator(ConditionalOperator *e) { + ACCResult left = Visit(e->getTrueExpr()); + if (left == ACC_invalid) return ACC_invalid; + return merge(left, Visit(e->getFalseExpr())); } - bool VisitStmtExpr(StmtExpr *e) { + + /// Statement expressions are okay if their result expression is okay. + ACCResult VisitStmtExpr(StmtExpr *e) { return Visit(e->getSubStmt()->body_back()); } - bool VisitDeclRefExpr(DeclRefExpr *e) { - // White-list references to global extern strings from system - // headers. - if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl())) - if (var->getStorageClass() == SC_Extern && - var->getType().isConstQualified() && - Context.getSourceManager().isInSystemHeader(var->getLocation())) - return true; - return false; + + /// Some declaration references are okay. + ACCResult VisitDeclRefExpr(DeclRefExpr *e) { + // References to global constants from system headers are okay. + // These are things like 'kCFStringTransformToLatin'. They are + // can also be assumed to be immune to retains. + VarDecl *var = dyn_cast<VarDecl>(e->getDecl()); + if (isAnyRetainable(TargetClass) && + isAnyRetainable(SourceClass) && + var && + var->getStorageClass() == SC_Extern && + var->getType().isConstQualified() && + Context.getSourceManager().isInSystemHeader(var->getLocation())) { + return ACC_bottom; + } + + // Nothing else. + return ACC_invalid; } - }; -} -bool -Sema::ValidObjCARCNoBridgeCastExpr(Expr *&Exp, QualType castType) { - Expr *NewExp = Exp->IgnoreParenCasts(); - - if (!isa<ObjCMessageExpr>(NewExp) && !isa<ObjCPropertyRefExpr>(NewExp) - && !isa<CallExpr>(NewExp)) - return false; - ObjCMethodDecl *method = 0; - bool MethodReturnsPlusOne = false; - - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(NewExp)) { - method = PRE->getExplicitProperty()->getGetterMethodDecl(); - } - else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(NewExp)) - method = ME->getMethodDecl(); - else { - CallExpr *CE = cast<CallExpr>(NewExp); - Decl *CallDecl = CE->getCalleeDecl(); - if (!CallDecl) - return false; - if (CallDecl->hasAttr<CFReturnsNotRetainedAttr>()) - return true; - MethodReturnsPlusOne = CallDecl->hasAttr<CFReturnsRetainedAttr>(); - if (!MethodReturnsPlusOne) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(CallDecl)) - if (const IdentifierInfo *Id = ND->getIdentifier()) - if (Id->isStr("__builtin___CFStringMakeConstantString")) - return true; + /// Some calls are okay. + ACCResult VisitCallExpr(CallExpr *e) { + if (FunctionDecl *fn = e->getDirectCallee()) + if (ACCResult result = checkCallToFunction(fn)) + return result; + + return super::VisitCallExpr(e); } - } - - if (!MethodReturnsPlusOne) { - if (!method) - return false; - if (method->hasAttr<CFReturnsNotRetainedAttr>()) - return true; - MethodReturnsPlusOne = method->hasAttr<CFReturnsRetainedAttr>(); - if (!MethodReturnsPlusOne) { - ObjCMethodFamily family = method->getSelector().getMethodFamily(); - switch (family) { - case OMF_alloc: - case OMF_copy: - case OMF_mutableCopy: - case OMF_new: - MethodReturnsPlusOne = true; - break; - default: - break; + + ACCResult checkCallToFunction(FunctionDecl *fn) { + // Require a CF*Ref return type. + if (!isCFType(fn->getResultType())) + return ACC_invalid; + + if (!isAnyRetainable(TargetClass)) + return ACC_invalid; + + // Honor an explicit 'not retained' attribute. + if (fn->hasAttr<CFReturnsNotRetainedAttr>()) + return ACC_plusZero; + + // Honor an explicit 'retained' attribute, except that for + // now we're not going to permit implicit handling of +1 results, + // because it's a bit frightening. + if (fn->hasAttr<CFReturnsRetainedAttr>()) + return ACC_invalid; // ACC_plusOne if we start accepting this + + // Recognize this specific builtin function, which is used by CFSTR. + unsigned builtinID = fn->getBuiltinID(); + if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) + return ACC_bottom; + + // Otherwise, don't do anything implicit with an unaudited function. + if (!fn->hasAttr<CFAuditedTransferAttr>()) + return ACC_invalid; + + // Otherwise, it's +0 unless it follows the create convention. + if (ento::coreFoundation::followsCreateRule(fn)) + return ACC_invalid; // ACC_plusOne if we start accepting this + + return ACC_plusZero; + } + + ACCResult VisitObjCMessageExpr(ObjCMessageExpr *e) { + return checkCallToMethod(e->getMethodDecl()); + } + + ACCResult VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *e) { + ObjCMethodDecl *method; + if (e->isExplicitProperty()) + method = e->getExplicitProperty()->getGetterMethodDecl(); + else + method = e->getImplicitPropertyGetter(); + return checkCallToMethod(method); + } + + ACCResult checkCallToMethod(ObjCMethodDecl *method) { + if (!method) return ACC_invalid; + + // Check for message sends to functions returning CF types. We + // just obey the Cocoa conventions with these, even though the + // return type is CF. + if (!isAnyRetainable(TargetClass) || !isCFType(method->getResultType())) + return ACC_invalid; + + // If the method is explicitly marked not-retained, it's +0. + if (method->hasAttr<CFReturnsNotRetainedAttr>()) + return ACC_plusZero; + + // If the method is explicitly marked as returning retained, or its + // selector follows a +1 Cocoa convention, treat it as +1. + if (method->hasAttr<CFReturnsRetainedAttr>()) + return ACC_plusOne; + + switch (method->getSelector().getMethodFamily()) { + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + return ACC_plusOne; + + default: + // Otherwise, treat it as +0. + return ACC_plusZero; } } - } - - if (MethodReturnsPlusOne) { - TypeSourceInfo *TSInfo = - Context.getTrivialTypeSourceInfo(castType, SourceLocation()); - ExprResult ExpRes = BuildObjCBridgedCast(SourceLocation(), OBC_BridgeTransfer, - SourceLocation(), TSInfo, Exp); - Exp = ExpRes.take(); - } - return true; + }; } void Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&castExpr, CheckedConversionKind CCK) { QualType castExprType = castExpr->getType(); + + // For the purposes of the classification, we assume reference types + // will bind to temporaries. + QualType effCastType = castType; + if (const ReferenceType *ref = castType->getAs<ReferenceType>()) + effCastType = ref->getPointeeType(); ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); - ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); + ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); if (exprACTC == castACTC) return; - if (exprACTC && castType->isIntegralType(Context)) return; + if (isAnyCLike(exprACTC) && isAnyCLike(castACTC)) return; + + // Allow all of these types to be cast to integer types (but not + // vice-versa). + if (castACTC == ACTC_none && castType->isIntegralType(Context)) + return; // Allow casts between pointers to lifetime types (e.g., __strong id*) // and pointers to void (e.g., cv void *). Casting from void* to lifetime* // must be explicit. - if (const PointerType *CastPtr = castType->getAs<PointerType>()) { - if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) { - QualType CastPointee = CastPtr->getPointeeType(); - QualType CastExprPointee = CastExprPtr->getPointeeType(); - if ((CCK != CCK_ImplicitConversion && - CastPointee->isObjCIndirectLifetimeType() && - CastExprPointee->isVoidType()) || - (CastPointee->isVoidType() && - CastExprPointee->isObjCIndirectLifetimeType())) - return; - } - } - - if (ARCCastChecker(Context).Visit(castExpr)) + if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) + return; + if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && + CCK != CCK_ImplicitConversion) return; + + switch (ARCCastChecker(Context, exprACTC, castACTC).Visit(castExpr)) { + // For invalid casts, fall through. + case ACC_invalid: + break; + + // Do nothing for both bottom and +0. + case ACC_bottom: + case ACC_plusZero: + return; + + // If the result is +1, consume it here. + case ACC_plusOne: + castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(), + CK_ARCConsumeObject, castExpr, + 0, VK_RValue); + ExprNeedsCleanups = true; + return; + } SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); + (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc()); if (makeUnavailableInSystemHeader(loc, - "converts between Objective-C and C pointers in -fobjc-arc")) + "converts between Objective-C and C pointers in -fobjc-arc")) return; unsigned srcKind = 0; switch (exprACTC) { - case ACTC_none: - srcKind = (castExprType->isPointerType() ? 1 : 0); - break; - case ACTC_retainable: - srcKind = (castExprType->isBlockPointerType() ? 2 : 3); - break; - case ACTC_indirectRetainable: - srcKind = 4; - break; + case ACTC_none: + case ACTC_coreFoundation: + case ACTC_voidPtr: + srcKind = (castExprType->isPointerType() ? 1 : 0); + break; + case ACTC_retainable: + srcKind = (castExprType->isBlockPointerType() ? 2 : 3); + break; + case ACTC_indirectRetainable: + srcKind = 4; + break; } if (CCK == CCK_CStyleCast) { @@ -1735,12 +1910,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin()); SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc; - if (castType->isObjCARCBridgableType() && - castExprType->isCARCBridgableType()) { - // explicit unbridged casts are allowed if the source of the cast is a - // message sent to an objc method (or property access) - if (ValidObjCARCNoBridgeCastExpr(castExpr, castType)) - return; + if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { Diag(loc, diag::err_arc_cast_requires_bridge) << 2 << castExprType @@ -1757,8 +1927,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, return; } - if (castType->isCARCBridgableType() && - castExprType->isObjCARCBridgableType()){ + if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { Diag(loc, diag::err_arc_cast_requires_bridge) << (castExprType->isBlockPointerType()? 1 : 0) << castExprType @@ -1806,7 +1975,7 @@ static Expr *maybeUndoReclaimObject(Expr *e) { // value-propagating subexpressions --- we can't reliably rebuild // in-place because of expression sharing. if (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) - if (ice->getCastKind() == CK_ObjCReclaimReturnedObject) + if (ice->getCastKind() == CK_ARCReclaimReturnedObject) return ice->getSubExpr(); return e; @@ -1817,14 +1986,23 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr) { + ExprResult SubResult = UsualUnaryConversions(SubExpr); + if (SubResult.isInvalid()) return ExprError(); + SubExpr = SubResult.take(); + QualType T = TSInfo->getType(); QualType FromType = SubExpr->getType(); + CastKind CK; + bool MustConsume = false; if (T->isDependentType() || SubExpr->isTypeDependent()) { // Okay: we'll build a dependent expression type. + CK = CK_Dependent; } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) { // Casting CF -> id + CK = (T->isBlockPointerType() ? CK_AnyPointerToBlockPointerCast + : CK_CPointerToObjCPointerCast); switch (Kind) { case OBC_Bridge: break; @@ -1854,6 +2032,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, } } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) { // Okay: id -> CF + CK = CK_BitCast; switch (Kind) { case OBC_Bridge: // Reclaiming a value that's going to be __bridge-casted to CF @@ -1864,7 +2043,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, case OBC_BridgeRetained: // Produce the object before casting it. SubExpr = ImplicitCastExpr::Create(Context, FromType, - CK_ObjCProduceObject, + CK_ARCProduceObject, SubExpr, 0, VK_RValue); break; @@ -1894,13 +2073,13 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, return ExprError(); } - Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, + Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, CK, BridgeKeywordLoc, TSInfo, SubExpr); if (MustConsume) { ExprNeedsCleanups = true; - Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result, + Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result, 0, VK_RValue); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp new file mode 100644 index 0000000..8e8a46d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp @@ -0,0 +1,160 @@ +//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaFixItUtils.h" + +using namespace clang; + +bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + if (!To.isAtLeastAsQualifiedAs(From)) + return false; + + From = From.getNonReferenceType(); + To = To.getNonReferenceType(); + + // If both are pointer types, work with the pointee types. + if (isa<PointerType>(From) && isa<PointerType>(To)) { + From = S.Context.getCanonicalType( + (cast<PointerType>(From))->getPointeeType()); + To = S.Context.getCanonicalType( + (cast<PointerType>(To))->getPointeeType()); + } + + const CanQualType FromUnq = From.getUnqualifiedType(); + const CanQualType ToUnq = To.getUnqualifiedType(); + + if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) && + To.isAtLeastAsQualifiedAs(From)) + return true; + return false; +} + +bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, + const QualType FromTy, + const QualType ToTy, + Sema &S) { + if (!FullExpr) + return false; + + const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); + const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); + const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); + const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange() + .getEnd()); + + // Strip the implicit casts - those are implied by the compiler, not the + // original source code. + const Expr* Expr = FullExpr->IgnoreImpCasts(); + + bool NeedParen = true; + if (isa<ArraySubscriptExpr>(Expr) || + isa<CallExpr>(Expr) || + isa<DeclRefExpr>(Expr) || + isa<CastExpr>(Expr) || + isa<CXXNewExpr>(Expr) || + isa<CXXConstructExpr>(Expr) || + isa<CXXDeleteExpr>(Expr) || + isa<CXXNoexceptExpr>(Expr) || + isa<CXXPseudoDestructorExpr>(Expr) || + isa<CXXScalarValueInitExpr>(Expr) || + isa<CXXThisExpr>(Expr) || + isa<CXXTypeidExpr>(Expr) || + isa<CXXUnresolvedConstructExpr>(Expr) || + isa<ObjCMessageExpr>(Expr) || + isa<ObjCPropertyRefExpr>(Expr) || + isa<ObjCProtocolExpr>(Expr) || + isa<MemberExpr>(Expr) || + isa<ParenExpr>(FullExpr) || + isa<ParenListExpr>(Expr) || + isa<SizeOfPackExpr>(Expr) || + isa<UnaryOperator>(Expr)) + NeedParen = false; + + // Check if the argument needs to be dereferenced: + // (type * -> type) or (type * -> type &). + if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { + OverloadFixItKind FixKind = OFIK_Dereference; + + bool CanConvert = CompareTypes( + S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, + S, Begin, VK_LValue); + if (CanConvert) { + // Do not suggest dereferencing a Null pointer. + if (Expr->IgnoreParenCasts()-> + isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) + return false; + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_AddrOf) { + FixKind = OFIK_RemoveTakeAddress; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + // Check if the pointer to the argument needs to be passed: + // (type -> type *) or (type & -> type *). + if (isa<PointerType>(ToQTy)) { + bool CanConvert = false; + OverloadFixItKind FixKind = OFIK_TakeAddress; + + // Only suggest taking address of L-values. + if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) + return false; + + CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, + S, Begin, VK_RValue); + if (CanConvert) { + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_Deref) { + FixKind = OFIK_RemoveDereference; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index 9fbcbab..7ed3fa8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -7,9 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis for initializers. The main entry -// point is Sema::CheckInitList(), but all of the work is performed -// within the InitListChecker class. +// This file implements semantic analysis for initializers. // //===----------------------------------------------------------------------===// @@ -24,6 +22,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include <map> using namespace clang; @@ -48,20 +47,30 @@ static Expr *IsStringInit(Expr *Init, const ArrayType *AT, if (SL == 0) return 0; QualType ElemTy = Context.getCanonicalType(AT->getElementType()); - // char array can be initialized with a narrow string. - // Only allow char x[] = "foo"; not char x[] = L"foo"; - if (!SL->isWide()) + + switch (SL->getKind()) { + case StringLiteral::Ascii: + case StringLiteral::UTF8: + // char array can be initialized with a narrow string. + // Only allow char x[] = "foo"; not char x[] = L"foo"; return ElemTy->isCharType() ? Init : 0; + case StringLiteral::UTF16: + return ElemTy->isChar16Type() ? Init : 0; + case StringLiteral::UTF32: + return ElemTy->isChar32Type() ? Init : 0; + case StringLiteral::Wide: + // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with + // correction from DR343): "An array with element type compatible with a + // qualified or unqualified version of wchar_t may be initialized by a wide + // string literal, optionally enclosed in braces." + if (Context.typesAreCompatible(Context.getWCharType(), + ElemTy.getUnqualifiedType())) + return Init; - // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with - // correction from DR343): "An array with element type compatible with a - // qualified or unqualified version of wchar_t may be initialized by a wide - // string literal, optionally enclosed in braces." - if (Context.typesAreCompatible(Context.getWCharType(), - ElemTy.getUnqualifiedType())) - return Init; + return 0; + } - return 0; + llvm_unreachable("missed a StringLiteral kind?"); } static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { @@ -160,14 +169,14 @@ namespace { class InitListChecker { Sema &SemaRef; bool hadError; + bool VerifyOnly; // no diagnostics, no structure building std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; void CheckImplicitInitList(const InitializedEntity &Entity, InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, - bool TopLevelObject = false); + unsigned &StructuredIndex); void CheckExplicitInitList(const InitializedEntity &Entity, InitListExpr *IList, QualType &T, unsigned &Index, InitListExpr *StructuredList, @@ -185,6 +194,11 @@ class InitListChecker { unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex); + void CheckComplexType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); void CheckScalarType(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, unsigned &Index, @@ -239,9 +253,12 @@ class InitListChecker { InitListExpr *ILE, bool &RequiresSecondPass); void FillInValueInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass); + bool CheckFlexibleArrayInit(const InitializedEntity &Entity, + Expr *InitExpr, FieldDecl *Field, + bool TopLevelObject); public: InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T); + InitListExpr *IL, QualType &T, bool VerifyOnly); bool HadError() { return hadError; } // @brief Retrieves the fully-structured initializer list used for @@ -434,8 +451,9 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T) - : SemaRef(S) { + InitListExpr *IL, QualType &T, + bool VerifyOnly) + : SemaRef(S), VerifyOnly(VerifyOnly) { hadError = false; unsigned newIndex = 0; @@ -446,7 +464,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, FullyStructuredList, newStructuredIndex, /*TopLevelObject=*/true); - if (!hadError) { + if (!hadError && !VerifyOnly) { bool RequiresSecondPass = false; FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass); if (RequiresSecondPass && !hadError) @@ -472,7 +490,7 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { Field = structDecl->field_begin(), FieldEnd = structDecl->field_end(); Field != FieldEnd; ++Field) { - if ((*Field)->getIdentifier() || !(*Field)->isBitField()) + if (!Field->isUnnamedBitfield()) ++InitializableMembers; } if (structDecl->isUnion()) @@ -484,8 +502,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, InitListExpr *ParentIList, QualType T, unsigned &Index, InitListExpr *StructuredList, - unsigned &StructuredIndex, - bool TopLevelObject) { + unsigned &StructuredIndex) { int maxElements = 0; if (T->isArrayType()) @@ -495,11 +512,12 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, else if (T->isVectorType()) maxElements = T->getAs<VectorType>()->getNumElements(); else - assert(0 && "CheckImplicitInitList(): Illegal type"); + llvm_unreachable("CheckImplicitInitList(): Illegal type"); if (maxElements == 0) { - SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), - diag::err_implicit_empty_initializer); + if (!VerifyOnly) + SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), + diag::err_implicit_empty_initializer); ++Index; hadError = true; return; @@ -518,29 +536,31 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, CheckListElementTypes(Entity, ParentIList, T, /*SubobjectIsDesignatorContext=*/false, Index, StructuredSubobjectInitList, - StructuredSubobjectInitIndex, - TopLevelObject); + StructuredSubobjectInitIndex); unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); - StructuredSubobjectInitList->setType(T); - - // Update the structured sub-object initializer so that it's ending - // range corresponds with the end of the last initializer it used. - if (EndIndex < ParentIList->getNumInits()) { - SourceLocation EndLoc - = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); - StructuredSubobjectInitList->setRBraceLoc(EndLoc); - } - - // Warn about missing braces. - if (T->isArrayType() || T->isRecordType()) { - SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), - diag::warn_missing_braces) - << StructuredSubobjectInitList->getSourceRange() - << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), - "{") - << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( + if (!VerifyOnly) { + StructuredSubobjectInitList->setType(T); + + // Update the structured sub-object initializer so that it's ending + // range corresponds with the end of the last initializer it used. + if (EndIndex < ParentIList->getNumInits()) { + SourceLocation EndLoc + = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); + StructuredSubobjectInitList->setRBraceLoc(EndLoc); + } + + // Warn about missing braces. + if (T->isArrayType() || T->isRecordType()) { + SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), + diag::warn_missing_braces) + << StructuredSubobjectInitList->getSourceRange() + << FixItHint::CreateInsertion( + StructuredSubobjectInitList->getLocStart(), "{") + << FixItHint::CreateInsertion( + SemaRef.PP.getLocForEndOfToken( StructuredSubobjectInitList->getLocEnd()), - "}"); + "}"); + } } } @@ -551,18 +571,31 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, unsigned &StructuredIndex, bool TopLevelObject) { assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); - SyntacticToSemantic[IList] = StructuredList; - StructuredList->setSyntacticForm(IList); + if (!VerifyOnly) { + SyntacticToSemantic[IList] = StructuredList; + StructuredList->setSyntacticForm(IList); + } CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true, Index, StructuredList, StructuredIndex, TopLevelObject); - QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); - IList->setType(ExprTy); - StructuredList->setType(ExprTy); + if (!VerifyOnly) { + QualType ExprTy = T.getNonLValueExprType(SemaRef.Context); + IList->setType(ExprTy); + StructuredList->setType(ExprTy); + } if (hadError) return; if (Index < IList->getNumInits()) { // We have leftover initializers + if (VerifyOnly) { + if (SemaRef.getLangOptions().CPlusPlus || + (SemaRef.getLangOptions().OpenCL && + IList->getType()->isVectorType())) { + hadError = true; + } + return; + } + if (StructuredIndex == 1 && IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) { unsigned DK = diag::warn_excess_initializers_in_char_array_initializer; @@ -599,7 +632,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, } } - if (T->isScalarType() && !TopLevelObject) + if (!VerifyOnly && T->isScalarType() && IList->getNumInits() == 1 && + !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() << FixItHint::CreateRemoval(IList->getLocStart()) @@ -614,7 +648,12 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { - if (DeclType->isScalarType()) { + if (DeclType->isAnyComplexType() && SubobjectIsDesignatorContext) { + // Explicitly braced initializer for complex type can be real+imaginary + // parts. + CheckComplexType(Entity, IList, DeclType, Index, + StructuredList, StructuredIndex); + } else if (DeclType->isScalarType()) { CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isVectorType()) { @@ -635,12 +674,13 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex); } else - assert(0 && "Aggregate that isn't a structure or array?!"); + llvm_unreachable("Aggregate that isn't a structure or array?!"); } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { // This type is invalid, issue a diagnostic. ++Index; - SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; hadError = true; } else if (DeclType->isRecordType()) { // C++ [dcl.init]p14: @@ -651,19 +691,22 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, // we have an initializer list and a destination type that is not // an aggregate. // FIXME: In C++0x, this is yet another form of initialization. - SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) - << DeclType << IList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); hadError = true; } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); } else if (DeclType->isObjCObjectType()) { - SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) + << DeclType; hadError = true; } else { - SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) - << DeclType; + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; hadError = true; } } @@ -701,8 +744,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // type here, though. if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) { - CheckStringInit(Str, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + if (!VerifyOnly) { + CheckStringInit(Str, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + } ++Index; return; } @@ -712,7 +757,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, } else if (SemaRef.getLangOptions().CPlusPlus) { // C++ [dcl.init.aggr]p12: // All implicit type conversions (clause 4) are considered when - // initializing the aggregate member with an ini- tializer from + // initializing the aggregate member with an initializer from // an initializer-list. If the initializer can initialize a // member, the member is initialized. [...] @@ -722,13 +767,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); if (Seq) { - ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); - if (Result.isInvalid()) - hadError = true; - - UpdateStructuredListElement(StructuredList, StructuredIndex, - Result.takeAs<Expr>()); + if (!VerifyOnly) { + ExprResult Result = + Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); + if (Result.isInvalid()) + hadError = true; + + UpdateStructuredListElement(StructuredList, StructuredIndex, + Result.takeAs<Expr>()); + } ++Index; return; } @@ -745,7 +792,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // that of the expression. ExprResult ExprRes = SemaRef.Owned(expr); if ((ElemType->isRecordType() || ElemType->isVectorType()) && - SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes) + SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes, + !VerifyOnly) == Sema::Compatible) { if (ExprRes.isInvalid()) hadError = true; @@ -775,25 +823,68 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, StructuredIndex); ++StructuredIndex; } else { - // We cannot initialize this element, so let - // PerformCopyInitialization produce the appropriate diagnostic. - SemaRef.PerformCopyInitialization(Entity, SourceLocation(), - SemaRef.Owned(expr)); + if (!VerifyOnly) { + // We cannot initialize this element, so let + // PerformCopyInitialization produce the appropriate diagnostic. + SemaRef.PerformCopyInitialization(Entity, SourceLocation(), + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); + } hadError = true; ++Index; ++StructuredIndex; } } +void InitListChecker::CheckComplexType(const InitializedEntity &Entity, + InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + assert(Index == 0 && "Index in explicit init list must be zero"); + + // As an extension, clang supports complex initializers, which initialize + // a complex number component-wise. When an explicit initializer list for + // a complex number contains two two initializers, this extension kicks in: + // it exepcts the initializer list to contain two elements convertible to + // the element type of the complex type. The first element initializes + // the real part, and the second element intitializes the imaginary part. + + if (IList->getNumInits() != 2) + return CheckScalarType(Entity, IList, DeclType, Index, StructuredList, + StructuredIndex); + + // This is an extension in C. (The builtin _Complex type does not exist + // in the C++ standard.) + if (!SemaRef.getLangOptions().CPlusPlus && !VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::ext_complex_component_init) + << IList->getSourceRange(); + + // Initialize the complex number. + QualType elementType = DeclType->getAs<ComplexType>()->getElementType(); + InitializedEntity ElementEntity = + InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); + + for (unsigned i = 0; i < 2; ++i) { + ElementEntity.setElementIndex(Index); + CheckSubElementType(ElementEntity, IList, elementType, Index, + StructuredList, StructuredIndex); + } +} + + void InitListChecker::CheckScalarType(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { - SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) - << IList->getSourceRange(); - hadError = true; + if (!SemaRef.getLangOptions().CPlusPlus0x) { + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + hadError = true; + } ++Index; ++StructuredIndex; return; @@ -801,26 +892,36 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, Expr *expr = IList->getInit(Index); if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) { - SemaRef.Diag(SubIList->getLocStart(), - diag::warn_many_braces_around_scalar_init) - << SubIList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(SubIList->getLocStart(), + diag::warn_many_braces_around_scalar_init) + << SubIList->getSourceRange(); CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, StructuredIndex); return; } else if (isa<DesignatedInitExpr>(expr)) { - SemaRef.Diag(expr->getSourceRange().getBegin(), - diag::err_designator_for_scalar_init) - << DeclType << expr->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(expr->getSourceRange().getBegin(), + diag::err_designator_for_scalar_init) + << DeclType << expr->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; return; } + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr))) + hadError = true; + ++Index; + return; + } + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), - SemaRef.Owned(expr)); + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); Expr *ResultExpr = 0; @@ -846,46 +947,57 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex) { - if (Index < IList->getNumInits()) { - Expr *expr = IList->getInit(Index); - if (isa<InitListExpr>(expr)) { - SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) - << DeclType << IList->getSourceRange(); - hadError = true; - ++Index; - ++StructuredIndex; - return; - } - - ExprResult Result = - SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), - SemaRef.Owned(expr)); - - if (Result.isInvalid()) - hadError = true; - - expr = Result.takeAs<Expr>(); - IList->setInit(Index, expr); - - if (hadError) - ++StructuredIndex; - else - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); - ++Index; - } else { + if (Index >= IList->getNumInits()) { // FIXME: It would be wonderful if we could point at the actual member. In // general, it would be useful to pass location information down the stack, // so that we know the location (or decl) of the "current object" being // initialized. - SemaRef.Diag(IList->getLocStart(), - diag::err_init_reference_member_uninitialized) - << DeclType - << IList->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), + diag::err_init_reference_member_uninitialized) + << DeclType + << IList->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; return; } + + Expr *expr = IList->getInit(Index); + if (isa<InitListExpr>(expr)) { + // FIXME: Allowed in C++11. + if (!VerifyOnly) + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr))) + hadError = true; + ++Index; + return; + } + + ExprResult Result = + SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), + SemaRef.Owned(expr), + /*TopLevelOfInitList=*/true); + + if (Result.isInvalid()) + hadError = true; + + expr = Result.takeAs<Expr>(); + IList->setInit(Index, expr); + + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; } void InitListChecker::CheckVectorType(const InitializedEntity &Entity, @@ -906,9 +1018,17 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, // instead of breaking it apart (which is doomed to failure anyway). Expr *Init = IList->getInit(Index); if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) { + if (VerifyOnly) { + if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(Init))) + hadError = true; + ++Index; + return; + } + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(), - SemaRef.Owned(Init)); + SemaRef.Owned(Init), + /*TopLevelOfInitList=*/true); Expr *ResultExpr = 0; if (Result.isInvalid()) @@ -924,7 +1044,8 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, if (hadError) ++StructuredIndex; else - UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); + UpdateStructuredListElement(StructuredList, StructuredIndex, + ResultExpr); ++Index; return; } @@ -977,11 +1098,11 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, } // OpenCL requires all elements to be initialized. - if (numEltsInit != maxElements) - if (SemaRef.getLangOptions().OpenCL) - SemaRef.Diag(IList->getSourceRange().getBegin(), - diag::err_vector_incorrect_num_initializers) - << (numEltsInit < maxElements) << maxElements << numEltsInit; + // FIXME: Shouldn't this set hadError to true then? + if (numEltsInit != maxElements && !VerifyOnly) + SemaRef.Diag(IList->getSourceRange().getBegin(), + diag::err_vector_incorrect_num_initializers) + << (numEltsInit < maxElements) << maxElements << numEltsInit; } void InitListChecker::CheckArrayType(const InitializedEntity &Entity, @@ -997,14 +1118,16 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, if (Index < IList->getNumInits()) { if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context)) { - CheckStringInit(Str, DeclType, arrayType, SemaRef); // We place the string literal directly into the resulting // initializer list. This is the only place where the structure // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); - StructuredList->resizeInits(SemaRef.Context, StructuredIndex); + if (!VerifyOnly) { + CheckStringInit(Str, DeclType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + StructuredList->resizeInits(SemaRef.Context, StructuredIndex); + } ++Index; return; } @@ -1013,9 +1136,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for VLAs; in standard C it would be possible to check this // earlier, but I don't know where clang accepts VLAs (gcc accepts // them in all sorts of strange places). - SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), - diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; @@ -1085,7 +1209,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, if (!maxElementsKnown && elementIndex > maxElements) maxElements = elementIndex; } - if (!hadError && DeclType->isIncompleteArrayType()) { + if (!hadError && DeclType->isIncompleteArrayType() && !VerifyOnly) { // If this is an incomplete array type, the actual type needs to // be calculated here. llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned()); @@ -1101,6 +1225,45 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, } } +bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity, + Expr *InitExpr, + FieldDecl *Field, + bool TopLevelObject) { + // Handle GNU flexible array initializers. + unsigned FlexArrayDiag; + if (isa<InitListExpr>(InitExpr) && + cast<InitListExpr>(InitExpr)->getNumInits() == 0) { + // Empty flexible array init always allowed as an extension + FlexArrayDiag = diag::ext_flexible_array_init; + } else if (SemaRef.getLangOptions().CPlusPlus) { + // Disallow flexible array init in C++; it is not required for gcc + // compatibility, and it needs work to IRGen correctly in general. + FlexArrayDiag = diag::err_flexible_array_init; + } else if (!TopLevelObject) { + // Disallow flexible array init on non-top-level object + FlexArrayDiag = diag::err_flexible_array_init; + } else if (Entity.getKind() != InitializedEntity::EK_Variable) { + // Disallow flexible array init on anything which is not a variable. + FlexArrayDiag = diag::err_flexible_array_init; + } else if (cast<VarDecl>(Entity.getDecl())->hasLocalStorage()) { + // Disallow flexible array init on local variables. + FlexArrayDiag = diag::err_flexible_array_init; + } else { + // Allow other cases. + FlexArrayDiag = diag::ext_flexible_array_init; + } + + if (!VerifyOnly) { + SemaRef.Diag(InitExpr->getSourceRange().getBegin(), + FlexArrayDiag) + << InitExpr->getSourceRange().getBegin(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << Field; + } + + return FlexArrayDiag != diag::ext_flexible_array_init; +} + void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, @@ -1120,13 +1283,15 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - // Value-initialize the first named member of the union. - RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); - for (RecordDecl::field_iterator FieldEnd = RD->field_end(); - Field != FieldEnd; ++Field) { - if (Field->getDeclName()) { - StructuredList->setInitializedFieldInUnion(*Field); - break; + if (!VerifyOnly) { + // Value-initialize the first named member of the union. + RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Field->getDeclName()) { + StructuredList->setInitializedFieldInUnion(*Field); + break; + } } } return; @@ -1186,13 +1351,18 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } // Make sure we can use this declaration. - if (SemaRef.DiagnoseUseOfDecl(*Field, - IList->getInit(Index)->getLocStart())) { + bool InvalidUse; + if (VerifyOnly) + InvalidUse = !SemaRef.CanUseDecl(*Field); + else + InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, + IList->getInit(Index)->getLocStart()); + if (InvalidUse) { ++Index; ++Field; hadError = true; continue; - } + } InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); @@ -1200,7 +1370,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, StructuredList, StructuredIndex); InitializedSomething = true; - if (DeclType->isUnionType()) { + if (DeclType->isUnionType() && !VerifyOnly) { // Initialize the first field within the union. StructuredList->setInitializedFieldInUnion(*Field); } @@ -1209,8 +1379,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } // Emit warnings for missing struct field initializers. - if (InitializedSomething && CheckForMissingFields && Field != FieldEnd && - !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { + if (!VerifyOnly && InitializedSomething && CheckForMissingFields && + Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && + !DeclType->isUnionType()) { // It is possible we have one or more unnamed bitfields remaining. // Find first (if any) named field and emit warning. for (RecordDecl::field_iterator it = Field, end = RD->field_end(); @@ -1227,24 +1398,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, Index >= IList->getNumInits()) return; - // Handle GNU flexible array initializers. - if (!TopLevelObject && - (!isa<InitListExpr>(IList->getInit(Index)) || - cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), - diag::err_flexible_array_init_nonempty) - << IList->getInit(Index)->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (CheckFlexibleArrayInit(Entity, IList->getInit(Index), *Field, + TopLevelObject)) { hadError = true; ++Index; return; - } else { - SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), - diag::ext_flexible_array_init) - << IList->getInit(Index)->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; } InitializedEntity MemberEntity = @@ -1269,7 +1427,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, typedef DesignatedInitExpr::Designator Designator; // Build the replacement designators. - llvm::SmallVector<Designator, 4> Replacements; + SmallVector<Designator, 4> Replacements; for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(), PE = IndirectField->chain_end(); PI != PE; ++PI) { if (PI + 1 == PE) @@ -1304,6 +1462,18 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, return 0; } +static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, + DesignatedInitExpr *DIE) { + unsigned NumIndexExprs = DIE->getNumSubExprs() - 1; + SmallVector<Expr*, 4> IndexExprs(NumIndexExprs); + for (unsigned I = 0; I < NumIndexExprs; ++I) + IndexExprs[I] = DIE->getSubExpr(I + 1); + return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(), + DIE->size(), IndexExprs.data(), + NumIndexExprs, DIE->getEqualOrColonLoc(), + DIE->usesGNUSyntax(), DIE->getInit()); +} + /// @brief Check the well-formedness of a C99 designated initializer. /// /// Determines whether the designated initializer @p DIE, which @@ -1342,14 +1512,14 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, bool InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, InitListExpr *IList, - DesignatedInitExpr *DIE, - unsigned DesigIdx, - QualType &CurrentObjectType, - RecordDecl::field_iterator *NextField, - llvm::APSInt *NextElementIndex, - unsigned &Index, - InitListExpr *StructuredList, - unsigned &StructuredIndex, + DesignatedInitExpr *DIE, + unsigned DesigIdx, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, bool FinishSubobjectInit, bool TopLevelObject) { if (DesigIdx == DIE->size()) { @@ -1374,19 +1544,21 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return hadError && !prevHadError; } - bool IsFirstDesignator = (DesigIdx == 0); - assert((IsFirstDesignator || StructuredList) && - "Need a non-designated initializer list to start from"); - DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); - // Determine the structural initializer list that corresponds to the - // current subobject. - StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] - : getStructuredSubobjectInit(IList, Index, CurrentObjectType, - StructuredList, StructuredIndex, - SourceRange(D->getStartLocation(), - DIE->getSourceRange().getEnd())); - assert(StructuredList && "Expected a structured initializer list"); + bool IsFirstDesignator = (DesigIdx == 0); + if (!VerifyOnly) { + assert((IsFirstDesignator || StructuredList) && + "Need a non-designated initializer list to start from"); + + // Determine the structural initializer list that corresponds to the + // current subobject. + StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] + : getStructuredSubobjectInit(IList, Index, CurrentObjectType, + StructuredList, StructuredIndex, + SourceRange(D->getStartLocation(), + DIE->getSourceRange().getEnd())); + assert(StructuredList && "Expected a structured initializer list"); + } if (D->isFieldDesignator()) { // C99 6.7.8p7: @@ -1403,8 +1575,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, SourceLocation Loc = D->getDotLoc(); if (Loc.isInvalid()) Loc = D->getFieldLoc(); - SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) - << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType; + if (!VerifyOnly) + SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) + << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType; ++Index; return true; } @@ -1427,6 +1600,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (!KnownField && Field->isAnonymousStructOrUnion()) { if (IndirectFieldDecl *IF = FindIndirectFieldDesignator(*Field, FieldName)) { + // In verify mode, don't modify the original. + if (VerifyOnly) + DIE = CloneDesignatedInitExpr(SemaRef, DIE); ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF); D = DIE->getDesignator(DesigIdx); break; @@ -1441,6 +1617,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } if (Field == FieldEnd) { + if (VerifyOnly) { + ++Index; + return true; // No typo correction when just trying this out. + } + // There was no normal field in the struct with the designated // name. Perform another lookup for this name, which may find // something that we can't designate (e.g., a member function), @@ -1470,6 +1651,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr); SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; + hadError = true; } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; @@ -1510,22 +1692,30 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // the initializer list. if (RT->getDecl()->isUnion()) { FieldIndex = 0; - StructuredList->setInitializedFieldInUnion(*Field); + if (!VerifyOnly) + StructuredList->setInitializedFieldInUnion(*Field); } // Make sure we can use this declaration. - if (SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc())) { + bool InvalidUse; + if (VerifyOnly) + InvalidUse = !SemaRef.CanUseDecl(*Field); + else + InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc()); + if (InvalidUse) { ++Index; return true; - } + } - // Update the designator with the field declaration. - D->setField(*Field); + if (!VerifyOnly) { + // Update the designator with the field declaration. + D->setField(*Field); - // Make sure that our non-designated initializer list has space - // for a subobject corresponding to this field. - if (FieldIndex >= StructuredList->getNumInits()) - StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this field. + if (FieldIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + } // This designator names a flexible array member. if (Field->getType()->isIncompleteArrayType()) { @@ -1533,38 +1723,36 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if ((DesigIdx + 1) != DIE->size()) { // We can't designate an object within the flexible array // member (because GCC doesn't allow it). - DesignatedInitExpr::Designator *NextD - = DIE->getDesignator(DesigIdx + 1); - SemaRef.Diag(NextD->getStartLocation(), - diag::err_designator_into_flexible_array_member) - << SourceRange(NextD->getStartLocation(), - DIE->getSourceRange().getEnd()); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (!VerifyOnly) { + DesignatedInitExpr::Designator *NextD + = DIE->getDesignator(DesigIdx + 1); + SemaRef.Diag(NextD->getStartLocation(), + diag::err_designator_into_flexible_array_member) + << SourceRange(NextD->getStartLocation(), + DIE->getSourceRange().getEnd()); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + } Invalid = true; } if (!hadError && !isa<InitListExpr>(DIE->getInit()) && !isa<StringLiteral>(DIE->getInit())) { // The initializer is not an initializer list. - SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), - diag::err_flexible_array_init_needs_braces) - << DIE->getInit()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + if (!VerifyOnly) { + SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), + diag::err_flexible_array_init_needs_braces) + << DIE->getInit()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + } Invalid = true; } - // Handle GNU flexible array initializers. - if (!Invalid && !TopLevelObject && - cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) { - SemaRef.Diag(DIE->getSourceRange().getBegin(), - diag::err_flexible_array_init_nonempty) - << DIE->getSourceRange().getBegin(); - SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) - << *Field; + // Check GNU flexible array initializer. + if (!Invalid && CheckFlexibleArrayInit(Entity, DIE->getInit(), *Field, + TopLevelObject)) Invalid = true; - } if (Invalid) { ++Index; @@ -1651,8 +1839,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // [ constant-expression ... constant-expression ] const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType); if (!AT) { - SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) - << CurrentObjectType; + if (!VerifyOnly) + SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) + << CurrentObjectType; ++Index; return true; } @@ -1661,15 +1850,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, llvm::APSInt DesignatedStartIndex, DesignatedEndIndex; if (D->isArrayDesignator()) { IndexExpr = DIE->getArrayIndex(*D); - DesignatedStartIndex = IndexExpr->EvaluateAsInt(SemaRef.Context); + DesignatedStartIndex = IndexExpr->EvaluateKnownConstInt(SemaRef.Context); DesignatedEndIndex = DesignatedStartIndex; } else { assert(D->isArrayRangeDesignator() && "Need array-range designator"); DesignatedStartIndex = - DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context); + DIE->getArrayRangeStart(*D)->EvaluateKnownConstInt(SemaRef.Context); DesignatedEndIndex = - DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context); + DIE->getArrayRangeEnd(*D)->EvaluateKnownConstInt(SemaRef.Context); IndexExpr = DIE->getArrayRangeEnd(*D); // Codegen can't handle evaluating array range designators that have side @@ -1678,7 +1867,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // elements with something that has a side effect, so codegen can emit an // "error unsupported" error instead of miscompiling the app. if (DesignatedStartIndex.getZExtValue()!=DesignatedEndIndex.getZExtValue()&& - DIE->getInit()->HasSideEffects(SemaRef.Context)) + DIE->getInit()->HasSideEffects(SemaRef.Context) && !VerifyOnly) FullyStructuredList->sawArrayRangeDesignator(); } @@ -1691,10 +1880,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, = DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned()); if (DesignatedEndIndex >= MaxElements) { - SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), - diag::err_array_designator_too_large) - << DesignatedEndIndex.toString(10) << MaxElements.toString(10) - << IndexExpr->getSourceRange(); + if (!VerifyOnly) + SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), + diag::err_array_designator_too_large) + << DesignatedEndIndex.toString(10) << MaxElements.toString(10) + << IndexExpr->getSourceRange(); ++Index; return true; } @@ -1713,7 +1903,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Make sure that our non-designated initializer list has space // for a subobject corresponding to this array element. - if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) + if (!VerifyOnly && + DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) StructuredList->resizeInits(SemaRef.Context, DesignatedEndIndex.getZExtValue() + 1); @@ -1773,6 +1964,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, InitListExpr *StructuredList, unsigned StructuredIndex, SourceRange InitRange) { + if (VerifyOnly) + return 0; // No structured list in verification-only mode. Expr *ExistingInit = 0; if (!StructuredList) ExistingInit = SyntacticToSemantic[IList]; @@ -1844,9 +2037,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, RDecl->field_end()); } - if (NumElements < NumInits) - NumElements = IList->getNumInits(); - Result->reserveInits(SemaRef.Context, NumElements); // Link this new initializer list into the structured initializer @@ -1915,8 +2105,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, typedef DesignatedInitExpr::Designator ASTDesignator; bool Invalid = false; - llvm::SmallVector<ASTDesignator, 32> Designators; - llvm::SmallVector<Expr *, 32> InitExpressions; + SmallVector<ASTDesignator, 32> Designators; + SmallVector<Expr *, 32> InitExpressions; // Build designators and check array designator expressions. for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) { @@ -2007,15 +2197,6 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, return Owned(DIE); } -bool Sema::CheckInitList(const InitializedEntity &Entity, - InitListExpr *&InitList, QualType &DeclType) { - InitListChecker CheckInitList(*this, Entity, InitList, DeclType); - if (!CheckInitList.HadError()) - InitList = CheckInitList.getFullyStructuredList(); - - return CheckInitList.HadError(); -} - //===----------------------------------------------------------------------===// // Initialization entity //===----------------------------------------------------------------------===// @@ -2027,9 +2208,14 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { Kind = EK_ArrayElement; Type = AT->getElementType(); - } else { + } else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) { Kind = EK_VectorElement; - Type = Parent.getType()->getAs<VectorType>()->getElementType(); + Type = VT->getElementType(); + } else { + const ComplexType *CT = Parent.getType()->getAs<ComplexType>(); + assert(CT && "Unexpected type"); + Kind = EK_ComplexElement; + Type = CT->getElementType(); } } @@ -2066,6 +2252,7 @@ DeclarationName InitializedEntity::getName() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return DeclarationName(); } @@ -2091,6 +2278,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: return 0; } @@ -2114,6 +2302,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: + case EK_ComplexElement: case EK_BlockElement: break; } @@ -2139,6 +2328,7 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionXValue: case SK_QualificationConversionLValue: case SK_ListInitialization: + case SK_ListConstructorCall: case SK_ConstructorInitialization: case SK_ZeroInitialization: case SK_CAssignment: @@ -2182,6 +2372,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_Incomplete: case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: + case FK_ListInitializationFailed: return false; case FK_ReferenceInitOverloadFailed: @@ -2197,12 +2388,171 @@ bool InitializationSequence::isConstructorInitialization() const { return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization; } +bool InitializationSequence::endsWithNarrowing(ASTContext &Ctx, + const Expr *Initializer, + bool *isInitializerConstant, + APValue *ConstantValue) const { + if (Steps.empty() || Initializer->isValueDependent()) + return false; + + const Step &LastStep = Steps.back(); + if (LastStep.Kind != SK_ConversionSequence) + return false; + + const ImplicitConversionSequence &ICS = *LastStep.ICS; + const StandardConversionSequence *SCS = NULL; + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + SCS = &ICS.Standard; + break; + case ImplicitConversionSequence::UserDefinedConversion: + SCS = &ICS.UserDefined.After; + break; + case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + return false; + } + + // Check if SCS represents a narrowing conversion, according to C++0x + // [dcl.init.list]p7: + // + // A narrowing conversion is an implicit conversion ... + ImplicitConversionKind PossibleNarrowing = SCS->Second; + QualType FromType = SCS->getToType(0); + QualType ToType = SCS->getToType(1); + switch (PossibleNarrowing) { + // * from a floating-point type to an integer type, or + // + // * from an integer type or unscoped enumeration type to a floating-point + // type, except where the source is a constant expression and the actual + // value after conversion will fit into the target type and will produce + // the original value when converted back to the original type, or + case ICK_Floating_Integral: + if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) { + *isInitializerConstant = false; + return true; + } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) { + llvm::APSInt IntConstantValue; + if (Initializer && + Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) { + // Convert the integer to the floating type. + llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType)); + Result.convertFromAPInt(IntConstantValue, IntConstantValue.isSigned(), + llvm::APFloat::rmNearestTiesToEven); + // And back. + llvm::APSInt ConvertedValue = IntConstantValue; + bool ignored; + Result.convertToInteger(ConvertedValue, + llvm::APFloat::rmTowardZero, &ignored); + // If the resulting value is different, this was a narrowing conversion. + if (IntConstantValue != ConvertedValue) { + *isInitializerConstant = true; + *ConstantValue = APValue(IntConstantValue); + return true; + } + } else { + // Variables are always narrowings. + *isInitializerConstant = false; + return true; + } + } + return false; + + // * from long double to double or float, or from double to float, except + // where the source is a constant expression and the actual value after + // conversion is within the range of values that can be represented (even + // if it cannot be represented exactly), or + case ICK_Floating_Conversion: + if (1 == Ctx.getFloatingTypeOrder(FromType, ToType)) { + // FromType is larger than ToType. + Expr::EvalResult InitializerValue; + // FIXME: Check whether Initializer is a constant expression according + // to C++0x [expr.const], rather than just whether it can be folded. + if (Initializer->Evaluate(InitializerValue, Ctx) && + !InitializerValue.HasSideEffects && InitializerValue.Val.isFloat()) { + // Constant! (Except for FIXME above.) + llvm::APFloat FloatVal = InitializerValue.Val.getFloat(); + // Convert the source value into the target type. + bool ignored; + llvm::APFloat::opStatus ConvertStatus = FloatVal.convert( + Ctx.getFloatTypeSemantics(ToType), + llvm::APFloat::rmNearestTiesToEven, &ignored); + // If there was no overflow, the source value is within the range of + // values that can be represented. + if (ConvertStatus & llvm::APFloat::opOverflow) { + *isInitializerConstant = true; + *ConstantValue = InitializerValue.Val; + return true; + } + } else { + *isInitializerConstant = false; + return true; + } + } + return false; + + // * from an integer type or unscoped enumeration type to an integer type + // that cannot represent all the values of the original type, except where + // the source is a constant expression and the actual value after + // conversion will fit into the target type and will produce the original + // value when converted back to the original type. + case ICK_Boolean_Conversion: // Bools are integers too. + if (!FromType->isIntegralOrUnscopedEnumerationType()) { + // Boolean conversions can be from pointers and pointers to members + // [conv.bool], and those aren't considered narrowing conversions. + return false; + } // Otherwise, fall through to the integral case. + case ICK_Integral_Conversion: { + assert(FromType->isIntegralOrUnscopedEnumerationType()); + assert(ToType->isIntegralOrUnscopedEnumerationType()); + const bool FromSigned = FromType->isSignedIntegerOrEnumerationType(); + const unsigned FromWidth = Ctx.getIntWidth(FromType); + const bool ToSigned = ToType->isSignedIntegerOrEnumerationType(); + const unsigned ToWidth = Ctx.getIntWidth(ToType); + + if (FromWidth > ToWidth || + (FromWidth == ToWidth && FromSigned != ToSigned)) { + // Not all values of FromType can be represented in ToType. + llvm::APSInt InitializerValue; + if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) { + *isInitializerConstant = true; + *ConstantValue = APValue(InitializerValue); + + // Add a bit to the InitializerValue so we don't have to worry about + // signed vs. unsigned comparisons. + InitializerValue = InitializerValue.extend( + InitializerValue.getBitWidth() + 1); + // Convert the initializer to and from the target width and signed-ness. + llvm::APSInt ConvertedValue = InitializerValue; + ConvertedValue = ConvertedValue.trunc(ToWidth); + ConvertedValue.setIsSigned(ToSigned); + ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth()); + ConvertedValue.setIsSigned(InitializerValue.isSigned()); + // If the result is different, this was a narrowing conversion. + return ConvertedValue != InitializerValue; + } else { + // Variables are always narrowings. + *isInitializerConstant = false; + return true; + } + } + return false; + } + + default: + // Other kinds of conversions are not narrowings. + return false; + } +} + void InitializationSequence::AddAddressOverloadResolutionStep( FunctionDecl *Function, DeclAccessPair Found) { Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); + S.Function.HadMultipleCandidates = false; S.Function.Function = Function; S.Function.FoundDecl = Found; Steps.push_back(S); @@ -2242,6 +2592,7 @@ void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, Step S; S.Kind = SK_UserConversion; S.Type = T; + S.Function.HadMultipleCandidates = false; S.Function.Function = Function; S.Function.FoundDecl = FoundDecl; Steps.push_back(S); @@ -2291,6 +2642,7 @@ InitializationSequence::AddConstructorInitializationStep( Step S; S.Kind = SK_ConstructorInitialization; S.Type = T; + S.Function.HadMultipleCandidates = false; S.Function.Function = Constructor; S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access); Steps.push_back(S); @@ -2391,44 +2743,33 @@ static void TryListInitialization(Sema &S, const InitializationKind &Kind, InitListExpr *InitList, InitializationSequence &Sequence) { - // FIXME: We only perform rudimentary checking of list - // initializations at this point, then assume that any list - // initialization of an array, aggregate, or scalar will be - // well-formed. When we actually "perform" list initialization, we'll - // do all of the necessary checking. C++0x initializer lists will - // force us to perform more checking here. - QualType DestType = Entity.getType(); - // C++ [dcl.init]p13: - // If T is a scalar type, then a declaration of the form - // - // T x = { a }; - // - // is equivalent to - // - // T x = a; - if (DestType->isScalarType()) { - if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) { - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); - return; - } - - // Assume scalar initialization from a single value works. - } else if (DestType->isAggregateType()) { - // Assume aggregate initialization works. - } else if (DestType->isVectorType()) { - // Assume vector initialization works. - } else if (DestType->isReferenceType()) { - // FIXME: C++0x defines behavior for this. + // C++ doesn't allow scalar initialization with more than one argument. + // But C99 complex numbers are scalars and it makes sense there. + if (S.getLangOptions().CPlusPlus && DestType->isScalarType() && + !DestType->isAnyComplexType() && InitList->getNumInits() > 1) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + return; + } + // FIXME: C++0x defines behavior for these two cases. + if (DestType->isReferenceType()) { Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); return; - } else if (DestType->isRecordType()) { - // FIXME: C++0x defines behavior for this + } + if (DestType->isRecordType() && !DestType->isAggregateType()) { Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + return; } - // Add a general "list initialization" step. + InitListChecker CheckInitList(S, Entity, InitList, + DestType, /*VerifyOnly=*/true); + if (CheckInitList.HadError()) { + Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed); + return; + } + + // Add the list initialization step with the built init list. Sequence.AddListInitializationStep(DestType); } @@ -2767,7 +3108,7 @@ static void TryReferenceInitialization(Sema &S, // // The constructor that would be used to make the copy shall // be callable whether or not the copy is actually done. - if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().Microsoft) + if (!S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt) Sequence.AddExtraneousCopyToTemporary(cv2T2); } @@ -2887,6 +3228,14 @@ static void TryConstructorInitialization(Sema &S, Expr **Args, unsigned NumArgs, QualType DestType, InitializationSequence &Sequence) { + // Check constructor arguments for self reference. + if (DeclaratorDecl *DD = Entity.getDecl()) + // Parameters arguments are occassionially constructed with itself, + // for instance, in recursive functions. Skip them. + if (!isa<ParmVarDecl>(DD)) + for (unsigned i = 0; i < NumArgs; ++i) + S.CheckSelfReference(DD, Args[i]); + // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -3577,7 +3926,7 @@ InitializationSequence::InitializationSequence(Sema &S, } InitializationSequence::~InitializationSequence() { - for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(), + for (SmallVectorImpl<Step>::iterator Step = Steps.begin(), StepEnd = Steps.end(); Step != StepEnd; ++Step) Step->Destroy(); @@ -3613,6 +3962,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_Member: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: return Sema::AA_Initializing; } @@ -3632,6 +3982,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: return false; @@ -3654,6 +4005,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: return false; @@ -3739,6 +4091,7 @@ static ExprResult CopyObject(Sema &S, case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart(); break; @@ -3790,6 +4143,8 @@ static ExprResult CopyObject(Sema &S, &CurInitExpr, 1, CandidateSet, true); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, Loc, Best)) { case OR_Success: @@ -3867,6 +4222,7 @@ static ExprResult CopyObject(Sema &S, // Actually perform the constructor call. CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -3982,6 +4338,7 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionXValue: case SK_QualificationConversionRValue: case SK_ConversionSequence: + case SK_ListConstructorCall: case SK_ListInitialization: case SK_CAssignment: case SK_StringInit: @@ -4127,8 +4484,8 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; bool CreatedObject = false; - bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); @@ -4146,6 +4503,7 @@ InitializationSequence::Perform(Sema &S, // Build the an expression that constructs a temporary. CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, move_arg(ConstructorArgs), + HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -4166,7 +4524,6 @@ InitializationSequence::Perform(Sema &S, } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); - IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0, FoundFn); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); @@ -4182,7 +4539,8 @@ InitializationSequence::Perform(Sema &S, CurInit = move(CurInitExprRes); // Build the actual call to the conversion function. - CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion); + CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion, + HadMultipleCandidates); if (CurInit.isInvalid() || !CurInit.get()) return ExprError(); @@ -4206,11 +4564,10 @@ InitializationSequence::Perform(Sema &S, } } - // FIXME: xvalues CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), CastKind, CurInit.get(), 0, - IsLvalue ? VK_LValue : VK_RValue)); + CurInit.get()->getValueKind())); if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, @@ -4251,18 +4608,24 @@ InitializationSequence::Perform(Sema &S, case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); QualType Ty = Step->Type; - if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty)) + InitListChecker PerformInitList(S, Entity, InitList, + ResultType ? *ResultType : Ty, /*VerifyOnly=*/false); + if (PerformInitList.HadError()) return ExprError(); CurInit.release(); - CurInit = S.Owned(InitList); + CurInit = S.Owned(PerformInitList.getFullyStructuredList()); break; } + case SK_ListConstructorCall: + assert(false && "List constructor calls not yet supported."); + case SK_ConstructorInitialization: { unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); + bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); @@ -4309,6 +4672,7 @@ InitializationSequence::Perform(Sema &S, Exprs, NumExprs, Kind.getParenRange(), + HadMultipleCandidates, ConstructorInitRequiresZeroInit)); } else { CXXConstructExpr::ConstructionKind ConstructKind = @@ -4333,6 +4697,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, /*Elidable=*/true, move_arg(ConstructorArgs), + HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, parenRange); @@ -4340,6 +4705,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, move_arg(ConstructorArgs), + HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, parenRange); @@ -4427,7 +4793,7 @@ InitializationSequence::Perform(Sema &S, case SK_ObjCObjectConversion: CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_ObjCObjectLValueCast, - S.CastCategory(CurInit.get())); + CurInit.get()->getValueKind()); break; case SK_ArrayInit: @@ -4463,7 +4829,7 @@ InitializationSequence::Perform(Sema &S, case SK_ProduceObjCObject: CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type, - CK_ObjCProduceObject, + CK_ARCProduceObject, CurInit.take(), 0, VK_RValue)); break; } @@ -4759,17 +5125,28 @@ bool InitializationSequence::Diagnose(Sema &S, } break; - case FK_Incomplete: - S.RequireCompleteType(Kind.getLocation(), DestType, - diag::err_init_incomplete_type); - break; + case FK_Incomplete: + S.RequireCompleteType(Kind.getLocation(), DestType, + diag::err_init_incomplete_type); + break; + + case FK_ListInitializationFailed: { + // Run the init list checker again to emit diagnostics. + InitListExpr* InitList = cast<InitListExpr>(Args[0]); + QualType DestType = Entity.getType(); + InitListChecker DiagnoseInitList(S, Entity, InitList, + DestType, /*VerifyOnly=*/false); + assert(DiagnoseInitList.HadError() && + "Inconsistent init list check result."); + break; + } } PrintInitLocationNote(S, Entity); return true; } -void InitializationSequence::dump(llvm::raw_ostream &OS) const { +void InitializationSequence::dump(raw_ostream &OS) const { switch (SequenceKind) { case FailedSequence: { OS << "Failed sequence: "; @@ -4857,6 +5234,9 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case FK_Incomplete: OS << "initialization of incomplete type"; break; + + case FK_ListInitializationFailed: + OS << "list initialization checker failure"; } OS << '\n'; return; @@ -4906,7 +5286,7 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_UserConversion: - OS << "user-defined conversion via " << S->Function.Function; + OS << "user-defined conversion via " << *S->Function.Function; break; case SK_QualificationConversionRValue: @@ -4926,7 +5306,11 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_ListInitialization: - OS << "list initialization"; + OS << "list aggregate initialization"; + break; + + case SK_ListConstructorCall: + OS << "list initialization via constructor"; break; case SK_ConstructorInitialization: @@ -4972,6 +5356,51 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } +static void DiagnoseNarrowingInInitList( + Sema& S, QualType EntityType, const Expr *InitE, + bool Constant, const APValue &ConstantValue) { + if (Constant) { + S.Diag(InitE->getLocStart(), + S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt + ? diag::err_init_list_constant_narrowing + : diag::warn_init_list_constant_narrowing) + << InitE->getSourceRange() + << ConstantValue + << EntityType.getLocalUnqualifiedType(); + } else + S.Diag(InitE->getLocStart(), + S.getLangOptions().CPlusPlus0x && !S.getLangOptions().MicrosoftExt + ? diag::err_init_list_variable_narrowing + : diag::warn_init_list_variable_narrowing) + << InitE->getSourceRange() + << InitE->getType().getLocalUnqualifiedType() + << EntityType.getLocalUnqualifiedType(); + + llvm::SmallString<128> StaticCast; + llvm::raw_svector_ostream OS(StaticCast); + OS << "static_cast<"; + if (const TypedefType *TT = EntityType->getAs<TypedefType>()) { + // It's important to use the typedef's name if there is one so that the + // fixit doesn't break code using types like int64_t. + // + // FIXME: This will break if the typedef requires qualification. But + // getQualifiedNameAsString() includes non-machine-parsable components. + OS << *TT->getDecl(); + } else if (const BuiltinType *BT = EntityType->getAs<BuiltinType>()) + OS << BT->getName(S.getLangOptions()); + else { + // Oops, we didn't find the actual type of the variable. Don't emit a fixit + // with a broken cast. + return; + } + OS << ">("; + S.Diag(InitE->getLocStart(), diag::note_init_list_narrowing_override) + << InitE->getSourceRange() + << FixItHint::CreateInsertion(InitE->getLocStart(), OS.str()) + << FixItHint::CreateInsertion( + S.getPreprocessor().getLocForEndOfToken(InitE->getLocEnd()), ")"); +} + //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// @@ -4993,7 +5422,8 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, - ExprResult Init) { + ExprResult Init, + bool TopLevelOfInitList) { if (Init.isInvalid()) return ExprError(); @@ -5007,5 +5437,13 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, EqualLoc); InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); Init.release(); + + bool Constant = false; + APValue Result; + if (TopLevelOfInitList && + Seq.endsWithNarrowing(Context, InitE, &Constant, &Result)) { + DiagnoseNarrowingInInitList(*this, Entity.getType(), InitE, + Constant, Result); + } return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 0e448e3..d5bee1d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -35,6 +35,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/ErrorHandling.h" #include <limits> #include <list> @@ -86,7 +87,7 @@ namespace { /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { - typedef llvm::SmallVector<UnqualUsingEntry, 8> ListTy; + typedef SmallVector<UnqualUsingEntry, 8> ListTy; ListTy list; llvm::SmallPtrSet<DeclContext*, 8> visited; @@ -147,7 +148,7 @@ namespace { // by its using directives, transitively) as if they appeared in // the given effective context. void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { - llvm::SmallVector<DeclContext*,4> queue; + SmallVector<DeclContext*,4> queue; while (true) { DeclContext::udir_iterator I, End; for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) { @@ -460,7 +461,7 @@ void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { setAmbiguous(AmbiguousBaseSubobjectTypes); } -void LookupResult::print(llvm::raw_ostream &Out) { +void LookupResult::print(raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; @@ -549,6 +550,16 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); + if (getLangOptions().CPlusPlus0x) { + // If the move constructor has not yet been declared, do so now. + if (Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); // might not actually do it + + // If the move assignment operator has not yet been declared, do so now. + if (Class->needsImplicitMoveAssignment()) + DeclareImplicitMoveAssignment(Class); // might not actually do it + } + // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) DeclareImplicitDestructor(Class); @@ -585,11 +596,14 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(S.Context, Record)) { + CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record); if (Record->needsImplicitDefaultConstructor()) - S.DeclareImplicitDefaultConstructor( - const_cast<CXXRecordDecl *>(Record)); + S.DeclareImplicitDefaultConstructor(Class); if (!Record->hasDeclaredCopyConstructor()) - S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record)); + S.DeclareImplicitCopyConstructor(Class); + if (S.getLangOptions().CPlusPlus0x && + Record->needsImplicitMoveConstructor()) + S.DeclareImplicitMoveConstructor(Class); } break; @@ -604,10 +618,17 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, if (Name.getCXXOverloadedOperator() != OO_Equal) break; - if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) - if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() && - CanDeclareSpecialMemberFunction(S.Context, Record)) - S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record)); + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) { + if (Record->getDefinition() && + CanDeclareSpecialMemberFunction(S.Context, Record)) { + CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record); + if (!Record->hasDeclaredCopyAssignment()) + S.DeclareImplicitCopyAssignment(Class); + if (S.getLangOptions().CPlusPlus0x && + Record->needsImplicitMoveAssignment()) + S.DeclareImplicitMoveAssignment(Class); + } + } break; default: @@ -648,7 +669,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); - if (!Record->isDefinition()) + if (!Record->isCompleteDefinition()) return Found; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); @@ -1187,7 +1208,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, // We have not yet looked into these namespaces, much less added // their "using-children" to the queue. - llvm::SmallVector<NamespaceDecl*, 8> Queue; + SmallVector<NamespaceDecl*, 8> Queue; // We have already looked into the initial namespace; seed the queue // with its using-children. @@ -1332,7 +1353,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Make sure that the declaration context is complete. assert((!isa<TagDecl>(LookupCtx) || LookupCtx->isDependentContext() || - cast<TagDecl>(LookupCtx)->isDefinition() || + cast<TagDecl>(LookupCtx)->isCompleteDefinition() || Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>() ->isBeingDefined()) && "Declaration context must already be complete!"); @@ -1802,7 +1823,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Add direct and indirect base classes along with their associated // namespaces. - llvm::SmallVector<CXXRecordDecl *, 32> Bases; + SmallVector<CXXRecordDecl *, 32> Bases; Bases.push_back(Class); while (!Bases.empty()) { // Pop this class off the stack. @@ -1852,7 +1873,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // the types do not contribute to this set. The sets of namespaces // and classes are determined in the following way: - llvm::SmallVector<const Type *, 16> Queue; + SmallVector<const Type *, 16> Queue; const Type *T = Ty->getCanonicalTypeInternal().getTypePtr(); while (true) { @@ -1979,6 +2000,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::ObjCObjectPointer: Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; + + // Atomic types are just wrappers; use the associations of the + // contained type. + case Type::Atomic: + T = cast<AtomicType>(T)->getValueType().getTypePtr(); + continue; } if (Queue.empty()) break; @@ -2210,12 +2237,14 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, Name = Context.DeclarationNames.getCXXConstructorName(CanTy); if (!RD->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(RD); - // TODO: Move constructors + if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(RD); } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); if (!RD->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(RD); - // TODO: Move assignment + if (getLangOptions().CPlusPlus0x && RD->needsImplicitMoveAssignment()) + DeclareImplicitMoveAssignment(RD); } QualType ArgType = CanTy; @@ -2358,6 +2387,15 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, return cast_or_null<CXXConstructorDecl>(Result->getMethod()); } +/// \brief Look up the moving constructor for the given class. +CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class) { + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXMoveConstructor, false, + false, false, false, false); + + return cast_or_null<CXXConstructorDecl>(Result->getMethod()); +} + /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. @@ -2366,6 +2404,8 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { DeclareImplicitDefaultConstructor(Class); if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); + if (getLangOptions().CPlusPlus0x && Class->needsImplicitMoveConstructor()) + DeclareImplicitMoveConstructor(Class); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); @@ -2394,6 +2434,20 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, return Result->getMethod(); } +/// \brief Look up the moving assignment operator for the given class. +CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, + bool RValueThis, + unsigned ThisQuals) { + assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && + "non-const, non-volatile qualifiers for copy assignment this"); + SpecialMemberOverloadResult *Result = + LookupSpecialMember(Class, CXXMoveAssignment, false, false, RValueThis, + ThisQuals & Qualifiers::Const, + ThisQuals & Qualifiers::Volatile); + + return Result->getMethod(); +} + /// \brief Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of @@ -2530,24 +2584,7 @@ public: /// \brief An entry in the shadow map, which is optimized to store a /// single declaration (the common case) but can also store a list /// of declarations. - class ShadowMapEntry { - typedef llvm::SmallVector<NamedDecl *, 4> DeclVector; - - /// \brief Contains either the solitary NamedDecl * or a vector - /// of declarations. - llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector; - - public: - ShadowMapEntry() : DeclOrVector() { } - - void Add(NamedDecl *ND); - void Destroy(); - - // Iteration. - typedef NamedDecl * const *iterator; - iterator begin(); - iterator end(); - }; + typedef llvm::TinyPtrVector<NamedDecl*> ShadowMapEntry; private: /// \brief A mapping from declaration names to the declarations that have @@ -2581,7 +2618,9 @@ public: NamedDecl *checkHidden(NamedDecl *ND); /// \brief Add a declaration to the current shadow map. - void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].Add(ND); } + void add(NamedDecl *ND) { + ShadowMaps.back()[ND->getDeclName()].push_back(ND); + } }; /// \brief RAII object that records when we've entered a shadow context. @@ -2596,66 +2635,12 @@ public: } ~ShadowContextRAII() { - for (ShadowMap::iterator E = Visible.ShadowMaps.back().begin(), - EEnd = Visible.ShadowMaps.back().end(); - E != EEnd; - ++E) - E->second.Destroy(); - Visible.ShadowMaps.pop_back(); } }; } // end anonymous namespace -void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) { - if (DeclOrVector.isNull()) { - // 0 - > 1 elements: just set the single element information. - DeclOrVector = ND; - return; - } - - if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { - // 1 -> 2 elements: create the vector of results and push in the - // existing declaration. - DeclVector *Vec = new DeclVector; - Vec->push_back(PrevND); - DeclOrVector = Vec; - } - - // Add the new element to the end of the vector. - DeclOrVector.get<DeclVector*>()->push_back(ND); -} - -void VisibleDeclsRecord::ShadowMapEntry::Destroy() { - if (DeclVector *Vec = DeclOrVector.dyn_cast<DeclVector *>()) { - delete Vec; - DeclOrVector = ((NamedDecl *)0); - } -} - -VisibleDeclsRecord::ShadowMapEntry::iterator -VisibleDeclsRecord::ShadowMapEntry::begin() { - if (DeclOrVector.isNull()) - return 0; - - if (DeclOrVector.is<NamedDecl *>()) - return DeclOrVector.getAddrOf<NamedDecl *>(); - - return DeclOrVector.get<DeclVector *>()->begin(); -} - -VisibleDeclsRecord::ShadowMapEntry::iterator -VisibleDeclsRecord::ShadowMapEntry::end() { - if (DeclOrVector.isNull()) - return 0; - - if (DeclOrVector.is<NamedDecl *>()) - return DeclOrVector.getAddrOf<NamedDecl *>() + 1; - - return DeclOrVector.get<DeclVector *>()->end(); -} - NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); @@ -2722,7 +2707,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } else if (ObjCForwardProtocolDecl *ForwardProto @@ -2733,19 +2718,17 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, P != PEnd; ++P) { if (Result.isAcceptableDecl(*P)) { - Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass); + Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass); Visited.add(*P); } } } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) { - for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); - I != IEnd; ++I) { - ObjCInterfaceDecl *IFace = I->getInterface(); + ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl(); if (Result.isAcceptableDecl(IFace)) { - Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass); + Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx, + InBaseClass); Visited.add(IFace); } - } } // Visit transparent contexts and inline namespaces inside this context. @@ -2885,7 +2868,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false); Visited.add(ND); } } @@ -2909,24 +2892,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); - - // Look for properties from which we can synthesize ivars, if - // permitted. - if (Result.getSema().getLangOptions().ObjCNonFragileABI2 && - IFace->getImplementation() && - Result.getLookupKind() == Sema::LookupOrdinaryName) { - for (ObjCInterfaceDecl::prop_iterator - P = IFace->prop_begin(), - PEnd = IFace->prop_end(); - P != PEnd; ++P) { - if (Result.getSema().canSynthesizeProvisionalIvar(*P) && - !IFace->lookupInstanceVariable((*P)->getIdentifier())) { - Consumer.FoundDecl(*P, Visited.checkHidden(*P), false); - Visited.add(*P); - } - } - } + /*InBaseClass=*/false, Consumer, Visited); } } @@ -3056,7 +3022,7 @@ static const unsigned MaxTypoDistanceResultSets = 5; class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The name written that is a typo in the source. - llvm::StringRef Typo; + StringRef Typo; /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. @@ -3084,11 +3050,12 @@ public: delete I->second; } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); - void FoundName(llvm::StringRef Name); - void addKeywordResult(llvm::StringRef Keyword); - void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance, - NestedNameSpecifier *NNS=NULL); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass); + void FoundName(StringRef Name); + void addKeywordResult(StringRef Keyword); + void addName(StringRef Name, NamedDecl *ND, unsigned Distance, + NestedNameSpecifier *NNS=NULL, bool isKeyword=false); void addCorrection(TypoCorrection Correction); typedef TypoResultsMap::iterator result_iterator; @@ -3099,7 +3066,7 @@ public: unsigned size() const { return BestResults.size(); } bool empty() const { return BestResults.empty(); } - TypoCorrection &operator[](llvm::StringRef Name) { + TypoCorrection &operator[](StringRef Name) { return (*BestResults.begin()->second)[Name]; } @@ -3115,7 +3082,7 @@ public: } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, - bool InBaseClass) { + DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; @@ -3130,7 +3097,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, FoundName(Name->getName()); } -void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { +void TypoCorrectionConsumer::FoundName(StringRef Name) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); @@ -3156,7 +3123,7 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { addName(Name, NULL, ED); } -void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) { +void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. @@ -3167,19 +3134,21 @@ void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) { return; } - addName(Keyword, TypoCorrection::KeywordDecl(), ED); + addName(Keyword, NULL, ED, NULL, true); } -void TypoCorrectionConsumer::addName(llvm::StringRef Name, +void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, unsigned Distance, - NestedNameSpecifier *NNS) { - addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name), - ND, NNS, Distance)); + NestedNameSpecifier *NNS, + bool isKeyword) { + TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance); + if (isKeyword) TC.makeKeyword(); + addCorrection(TC); } void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { - llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); + StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); TypoResultsMap *& Map = BestResults[Correction.getEditDistance()]; if (!Map) Map = new TypoResultsMap; @@ -3213,8 +3182,8 @@ class SpecifierInfo { : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {} }; -typedef llvm::SmallVector<DeclContext*, 4> DeclContextList; -typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList; +typedef SmallVector<DeclContext*, 4> DeclContextList; +typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; class NamespaceSpecifierSet { ASTContext &Context; @@ -3264,14 +3233,14 @@ DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { } void NamespaceSpecifierSet::SortNamespaces() { - llvm::SmallVector<unsigned, 4> sortedDistances; + SmallVector<unsigned, 4> sortedDistances; sortedDistances.append(Distances.begin(), Distances.end()); if (sortedDistances.size() > 1) std::sort(sortedDistances.begin(), sortedDistances.end()); Specifiers.clear(); - for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(), + for (SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(), DIEnd = sortedDistances.end(); DI != DIEnd; ++DI) { SpecifierInfoList &SpecList = DistanceMap[*DI]; @@ -3648,7 +3617,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, = Context.Idents.getExternalIdentifierLookup()) { llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers()); do { - llvm::StringRef Name = Iter->Next(); + StringRef Name = Iter->Next(); if (Name.empty()) break; @@ -3692,7 +3661,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (getLangOptions().CPlusPlus) { // Load any externally-known namespaces. if (ExternalSource && !LoadedExternalKnownNamespaces) { - llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; + SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; LoadedExternalKnownNamespaces = true; ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) @@ -3730,6 +3699,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, switch (TmpRes.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundUnresolvedValue: QualifiedResults.insert(Name); // We didn't find this name in our scope, or didn't like what we found; // ignore it. @@ -3745,12 +3715,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // We don't deal with ambiguities. return TypoCorrection(); + case LookupResult::FoundOverloaded: { + // Store all of the Decls for overloaded symbols + for (LookupResult::iterator TRD = TmpRes.begin(), + TRDEnd = TmpRes.end(); + TRD != TRDEnd; ++TRD) + I->second.addCorrectionDecl(*TRD); + ++I; + break; + } + case LookupResult::Found: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>()); - // FIXME: This sets the CorrectionDecl to NULL for overloaded functions. - // It would be nice to find the right one with overload resolution. ++I; break; } @@ -3786,14 +3762,23 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, switch (TmpRes.getResultKind()) { case LookupResult::Found: - case LookupResult::FoundOverloaded: - case LookupResult::FoundUnresolvedValue: Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(), QualifiedED, NI->NameSpecifier); break; + case LookupResult::FoundOverloaded: { + TypoCorrection corr(&Context.Idents.get((*QRI)->getName()), NULL, + NI->NameSpecifier, QualifiedED); + for (LookupResult::iterator TRD = TmpRes.begin(), + TRDEnd = TmpRes.end(); + TRD != TRDEnd; ++TRD) + corr.addCorrectionDecl(*TRD); + Consumer.addCorrection(corr); + break; + } case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: + case LookupResult::FoundUnresolvedValue: break; } } @@ -3870,6 +3855,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, return TypoCorrection(); } +void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { + if (!CDecl) return; + + if (isKeyword()) + CorrectionDecls.clear(); + + CorrectionDecls.push_back(CDecl); + + if (!CorrectionName) + CorrectionName = CDecl->getDeclName(); +} + std::string TypoCorrection::getAsString(const LangOptions &LO) const { if (CorrectionNameSpec) { std::string tmpBuffer; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index d826ea8..751f553 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Initialization.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/DenseSet.h" using namespace clang; @@ -24,6 +25,37 @@ using namespace clang; // Grammar actions. //===----------------------------------------------------------------------===// +/// getImpliedARCOwnership - Given a set of property attributes and a +/// type, infer an expected lifetime. The type's ownership qualification +/// is not considered. +/// +/// Returns OCL_None if the attributes as stated do not imply an ownership. +/// Never returns OCL_Autoreleasing. +static Qualifiers::ObjCLifetime getImpliedARCOwnership( + ObjCPropertyDecl::PropertyAttributeKind attrs, + QualType type) { + // retain, strong, copy, weak, and unsafe_unretained are only legal + // on properties of retainable pointer type. + if (attrs & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy)) { + return type->getObjCARCImplicitLifetime(); + } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) { + return Qualifiers::OCL_Weak; + } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) { + return Qualifiers::OCL_ExplicitNone; + } + + // assign can appear on other types, so we have to check the + // property type. + if (attrs & ObjCPropertyDecl::OBJC_PR_assign && + type->isObjCRetainableType()) { + return Qualifiers::OCL_ExplicitNone; + } + + return Qualifiers::OCL_None; +} + /// Check the internal consistency of a property declaration. static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { if (property->isInvalidDecl()) return; @@ -36,26 +68,23 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { // Nothing to do if we don't have a lifetime. if (propertyLifetime == Qualifiers::OCL_None) return; - Qualifiers::ObjCLifetime expectedLifetime; - unsigned selector; - - // Strong properties should have either strong or no lifetime. - if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy)) { - expectedLifetime = Qualifiers::OCL_Strong; - selector = 0; - } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) { - expectedLifetime = Qualifiers::OCL_Weak; - selector = 1; - } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained) && - property->getType()->isObjCRetainableType()) { - expectedLifetime = Qualifiers::OCL_ExplicitNone; - selector = 2; - } else { + Qualifiers::ObjCLifetime expectedLifetime + = getImpliedARCOwnership(propertyKind, property->getType()); + if (!expectedLifetime) { // We have a lifetime qualifier but no dominating property - // attribute. That's okay. + // attribute. That's okay, but restore reasonable invariants by + // setting the property attribute according to the lifetime + // qualifier. + ObjCPropertyDecl::PropertyAttributeKind attr; + if (propertyLifetime == Qualifiers::OCL_Strong) { + attr = ObjCPropertyDecl::OBJC_PR_strong; + } else if (propertyLifetime == Qualifiers::OCL_Weak) { + attr = ObjCPropertyDecl::OBJC_PR_weak; + } else { + assert(propertyLifetime == Qualifiers::OCL_ExplicitNone); + attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + } + property->setPropertyAttributes(attr); return; } @@ -65,7 +94,7 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { S.Diag(property->getLocation(), diag::err_arc_inconsistent_property_ownership) << property->getDeclName() - << selector + << expectedLifetime << propertyLifetime; } @@ -74,14 +103,13 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, - Decl *ClassCategory, bool *isOverridingProperty, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - if ((getLangOptions().getGCMode() != LangOptions::NonGC && + if ((getLangOptions().getGC() != LangOptions::NonGC && T.isObjCGCWeak()) || (getLangOptions().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_Weak)) @@ -101,12 +129,11 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_weak))); // Proceed with constructing the ObjCPropertDecls. - ObjCContainerDecl *ClassDecl = - cast<ObjCContainerDecl>(ClassCategory); + ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) if (CDecl->IsClassExtension()) { - Decl *Res = HandlePropertyInClassExtension(S, CDecl, AtLoc, + Decl *Res = HandlePropertyInClassExtension(S, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, @@ -137,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, } Decl * -Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, +Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isAssign, @@ -146,9 +173,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, bool *isOverridingProperty, TypeSourceInfo *T, tok::ObjCKeywordKind MethodImplKind) { - + ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext); // Diagnose if this property is already in continuation class. - DeclContext *DC = cast<DeclContext>(CDecl); + DeclContext *DC = CurContext; IdentifierInfo *PropertyId = FD.D.getIdentifier(); ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); @@ -209,7 +236,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, /* lexicalDC = */ CDecl); return PDecl; } - + if (PIDecl->getType().getCanonicalType() + != PDecl->getType().getCanonicalType()) { + Diag(AtLoc, + diag::warn_type_mismatch_continuation_class) << PDecl->getType(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + // The property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributesAsWritten(); @@ -235,12 +268,15 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ProtocolPropertyODS. setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) PIkind); - + // Must re-establish the context from class extension to primary + // class context. + ContextRAII SavedContext(*this, CCPrimary); + Decl *ProtocolPtrTy = ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, PIDecl->getGetterName(), PIDecl->getSetterName(), - CCPrimary, isOverridingProperty, + isOverridingProperty, MethodImplKind, /* lexicalDC = */ CDecl); PIDecl = cast<ObjCPropertyDecl>(ProtocolPtrTy); @@ -290,7 +326,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // Issue a warning if property is 'assign' as default and its object, which is // gc'able conforms to NSCopying protocol - if (getLangOptions().getGCMode() != LangOptions::NonGC && + if (getLangOptions().getGC() != LangOptions::NonGC && isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) if (const ObjCObjectPointerType *ObjPtrTy = T->getAs<ObjCObjectPointerType>()) { @@ -392,9 +428,10 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (isAssign) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + // In the semantic attributes, one of nonatomic or atomic is always set. if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - else if (Attributes & ObjCDeclSpec::DQ_PR_atomic) + else PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); // 'unsafe_unretained' is alias for 'assign'. @@ -416,82 +453,49 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, ObjCIvarDecl *ivar) { if (property->isInvalidDecl() || ivar->isInvalidDecl()) return; - QualType propertyType = property->getType(); - Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime(); - ObjCPropertyDecl::PropertyAttributeKind propertyKind - = property->getPropertyAttributes(); - QualType ivarType = ivar->getType(); Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime(); - - // Case 1: strong properties. - if (propertyLifetime == Qualifiers::OCL_Strong || - (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy))) { - switch (ivarLifetime) { - case Qualifiers::OCL_Strong: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Weak: - S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) - << property->getDeclName() - << ivar->getDeclName() - << ivarLifetime; - break; - } - // Case 2: weak properties. - } else if (propertyLifetime == Qualifiers::OCL_Weak || - (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) { - switch (ivarLifetime) { - case Qualifiers::OCL_Weak: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Strong: - S.Diag(propertyImplLoc, diag::error_weak_property) - << property->getDeclName() - << ivar->getDeclName(); - break; - } + // The lifetime implied by the property's attributes. + Qualifiers::ObjCLifetime propertyLifetime = + getImpliedARCOwnership(property->getPropertyAttributes(), + property->getType()); - // Case 3: assign properties. - } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) && - propertyType->isObjCRetainableType()) { - switch (ivarLifetime) { - case Qualifiers::OCL_ExplicitNone: - // Okay. - return; - - case Qualifiers::OCL_None: - case Qualifiers::OCL_Autoreleasing: - // These aren't valid lifetimes for object ivars; don't diagnose twice. - return; - - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Strong: - S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) - << property->getDeclName() - << ivar->getDeclName(); - break; - } + // We're fine if they match. + if (propertyLifetime == ivarLifetime) return; - // Any other property should be ignored. - } else { + // These aren't valid lifetimes for object ivars; don't diagnose twice. + if (ivarLifetime == Qualifiers::OCL_None || + ivarLifetime == Qualifiers::OCL_Autoreleasing) + return; + + switch (propertyLifetime) { + case Qualifiers::OCL_Strong: + S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) + << property->getDeclName() + << ivar->getDeclName() + << ivarLifetime; + break; + + case Qualifiers::OCL_Weak: + S.Diag(propertyImplLoc, diag::error_weak_property) + << property->getDeclName() + << ivar->getDeclName(); + break; + + case Qualifiers::OCL_ExplicitNone: + S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership) + << property->getDeclName() + << ivar->getDeclName() + << ((property->getPropertyAttributesAsWritten() + & ObjCPropertyDecl::OBJC_PR_assign) != 0); + break; + + case Qualifiers::OCL_Autoreleasing: + llvm_unreachable("properties cannot be autoreleasing"); + + case Qualifiers::OCL_None: + // Any other property should be ignored. return; } @@ -507,12 +511,11 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool Synthesize, - Decl *ClassCatImpDecl, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc) { ObjCContainerDecl *ClassImpDecl = - cast_or_null<ObjCContainerDecl>(ClassCatImpDecl); + dyn_cast<ObjCContainerDecl>(CurContext); // Make sure we have a context for the property implementation declaration. if (!ClassImpDecl) { Diag(AtLoc, diag::error_missing_property_context); @@ -586,61 +589,65 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ObjCIvarDecl *Ivar = 0; // Check that we have a valid, previously declared ivar for @synthesize if (Synthesize) { - if (getLangOptions().ObjCAutoRefCount && - !property->hasWrittenStorageAttribute() && - property->getType()->isObjCRetainableType()) { - Diag(PropertyLoc, diag::err_arc_objc_property_default_assign_on_object); - Diag(property->getLocation(), diag::note_property_declare); - } - // @synthesize if (!PropertyIvar) PropertyIvar = PropertyId; ObjCPropertyDecl::PropertyAttributeKind kind = property->getPropertyAttributes(); - QualType PropType = Context.getCanonicalType(property->getType()); - QualType PropertyIvarType = PropType; - if (PropType->isReferenceType()) - PropertyIvarType = cast<ReferenceType>(PropType)->getPointeeType(); + QualType PropType = property->getType(); + + QualType PropertyIvarType = PropType.getNonReferenceType(); + + // Add GC __weak to the ivar type if the property is weak. + if ((kind & ObjCPropertyDecl::OBJC_PR_weak) && + getLangOptions().getGC() != LangOptions::NonGC) { + assert(!getLangOptions().ObjCAutoRefCount); + if (PropertyIvarType.isObjCGCStrong()) { + Diag(PropertyLoc, diag::err_gc_weak_property_strong_type); + Diag(property->getLocation(), diag::note_property_declare); + } else { + PropertyIvarType = + Context.getObjCGCQualType(PropertyIvarType, Qualifiers::Weak); + } + } + // Check that this is a previously declared 'ivar' in 'IDecl' interface ObjCInterfaceDecl *ClassDeclared; Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { - // In ARC, give the ivar a lifetime qualifier based on its + // In ARC, give the ivar a lifetime qualifier based on the // property attributes. if (getLangOptions().ObjCAutoRefCount && - !PropertyIvarType.getObjCLifetime()) { - - // retain/copy have retaining lifetime. - if (kind & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy)) { - Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_Strong); - PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); - } - else if (kind & ObjCPropertyDecl::OBJC_PR_weak) { - if (!getLangOptions().ObjCRuntimeHasWeak) { + !PropertyIvarType.getObjCLifetime() && + PropertyIvarType->isObjCRetainableType()) { + + // It's an error if we have to do this and the user didn't + // explicitly write an ownership attribute on the property. + if (!property->hasWrittenStorageAttribute() && + !(kind & ObjCPropertyDecl::OBJC_PR_strong)) { + Diag(PropertyLoc, + diag::err_arc_objc_property_default_assign_on_object); + Diag(property->getLocation(), diag::note_property_declare); + } else { + Qualifiers::ObjCLifetime lifetime = + getImpliedARCOwnership(kind, PropertyIvarType); + assert(lifetime && "no lifetime for property?"); + + if (lifetime == Qualifiers::OCL_Weak && + !getLangOptions().ObjCRuntimeHasWeak) { Diag(PropertyLoc, diag::err_arc_weak_no_runtime); Diag(property->getLocation(), diag::note_property_declare); } + Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_Weak); + qs.addObjCLifetime(lifetime); PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); } - else if (kind & ObjCPropertyDecl::OBJC_PR_assign && - PropertyIvarType->isObjCRetainableType()) { - // assume that an 'assign' property synthesizes __unsafe_unretained - // ivar - Qualifiers qs; - qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); - PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs); - } } if (kind & ObjCPropertyDecl::OBJC_PR_weak && !getLangOptions().ObjCAutoRefCount && - getLangOptions().getGCMode() == LangOptions::NonGC) { + getLangOptions().getGC() == LangOptions::NonGC) { Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc); Diag(property->getLocation(), diag::note_property_declare); } @@ -670,7 +677,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, QualType IvarType = Context.getCanonicalType(Ivar->getType()); // Check that type of property and its ivar are type compatible. - if (PropertyIvarType != IvarType) { + if (Context.getCanonicalType(PropertyIvarType) != IvarType) { bool compat = false; if (isa<ObjCObjectPointerType>(PropertyIvarType) && isa<ObjCObjectPointerType>(IvarType)) @@ -709,15 +716,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } // __weak is explicit. So it works on Canonical type. if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC)) { + getLangOptions().getGC() != LangOptions::NonGC)) { Diag(PropertyLoc, diag::error_weak_property) << property->getDeclName() << Ivar->getDeclName(); + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Fall thru - see previous comment } // Fall thru - see previous comment if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { + getLangOptions().getGC() != LangOptions::NonGC) { Diag(PropertyLoc, diag::error_strong_property) << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment @@ -793,6 +801,17 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, VK_LValue, SourceLocation()); ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); + if (property->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Expr *callExpr = Res.takeAs<Expr>(); + if (const CXXOperatorCallExpr *CXXCE = + dyn_cast_or_null<CXXOperatorCallExpr>(callExpr)) + if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee()) + if (!FuncDecl->isTrivial()) + Diag(PropertyLoc, + diag::warn_atomic_property_nontrivial_assign_op) + << property->getType(); + } PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>()); } } @@ -880,7 +899,7 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "copy" << inheritedName; - else { + else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){ unsigned CAttrRetain = (CAttr & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); @@ -917,9 +936,11 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, QualType ConvertedType; if (!isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC) || - IncompatibleObjC) + IncompatibleObjC) { Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) << Property->getType() << SuperProperty->getType() << inheritedName; + Diag(SuperProperty->getLocation(), diag::note_property_declare); + } } } @@ -1146,7 +1167,8 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()]; // Exclude property for protocols which conform to class's super-class, // as super-class has to implement the property. - if (!PropertyFromSuper || PropertyFromSuper != Prop) { + if (!PropertyFromSuper || + PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) { ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; if (!PropEntry) PropEntry = Prop; @@ -1241,10 +1263,20 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return 0; } +static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop, + ASTContext &Ctx) { + llvm::SmallString<128> ivarName; + { + llvm::raw_svector_ostream os(ivarName); + os << '_' << Prop->getIdentifier()->getName(); + } + return &Ctx.Idents.get(ivarName.str()); +} + /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in class's @implementation. -void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl) { +void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl) { llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; CollectClassPropertyImplementations(IDecl, PropMap); @@ -1280,12 +1312,23 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, // Saying that they are located at the @implementation isn't really going // to help users. ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(), - true,IMPDecl, - Prop->getIdentifier(), Prop->getIdentifier(), + true, + /* property = */ Prop->getIdentifier(), + /* ivar = */ getDefaultSynthIvarName(Prop, Context), SourceLocation()); } } +void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { + if (!LangOpts.ObjCDefaultSynthProperties || !LangOpts.ObjCNonFragileABI2) + return; + ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D); + if (!IC) + return; + if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) + DefaultSynthesizeProperties(S, IC, IDecl); +} + void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap) { @@ -1313,23 +1356,23 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>()) continue; if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), + Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); + Diag(Prop->getLocation(), + diag::note_property_declare); } if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), + Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : diag::warn_setter_getter_impl_required) << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); + Diag(Prop->getLocation(), + diag::note_property_declare); } } } @@ -1338,7 +1381,7 @@ void Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl) { // Rules apply in non-GC mode only - if (getLangOptions().getGCMode() != LangOptions::NonGC) + if (getLangOptions().getGC() != LangOptions::NonGC) return; for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), E = IDecl->prop_end(); @@ -1349,10 +1392,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, bool LookedUpGetterSetter = false; unsigned Attributes = Property->getPropertyAttributes(); - unsigned AttributesAsWrittern = Property->getPropertyAttributesAsWritten(); + unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten(); - if (!(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_atomic) && - !(AttributesAsWrittern & ObjCPropertyDecl::OBJC_PR_nonatomic)) { + if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) && + !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) { GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); LookedUpGetterSetter = true; @@ -1388,7 +1431,9 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, (GetterMethod ? GetterMethod->getLocation() : SetterMethod->getLocation()); Diag(MethodLoc, diag::warn_atomic_property_rule) - << Property->getIdentifier(); + << Property->getIdentifier() << (GetterMethod != 0) + << (SetterMethod != 0); + Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); Diag(Property->getLocation(), diag::note_property_declare); } } @@ -1396,7 +1441,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) { - if (getLangOptions().getGCMode() == LangOptions::GCOnly) + if (getLangOptions().getGC() == LangOptions::GCOnly) return; for (ObjCImplementationDecl::propimpl_iterator @@ -1417,7 +1462,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D if (getLangOptions().ObjCAutoRefCount) Diag(PID->getLocation(), diag::err_ownin_getter_rule); else - Diag(PID->getLocation(), diag::warn_ownin_getter_rule); + Diag(PID->getLocation(), diag::warn_owning_getter_rule); Diag(PD->getLocation(), diag::note_property_declare); } } @@ -1464,7 +1509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, Context.VoidTy) Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || - ((*SetterMethod->param_begin())->getType() != property->getType())) { + !Context.hasSameUnqualifiedType( + (*SetterMethod->param_begin())->getType(), property->getType())) { Diag(property->getLocation(), diag::warn_accessor_property_type_mismatch) << property->getDeclName() @@ -1489,8 +1535,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getGetterName(), - property->getType(), 0, CD, true, false, true, - false, + property->getType(), 0, CD, /*isInstance=*/true, + /*isVariadic=*/false, /*isSynthesized=*/true, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1526,7 +1573,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getSetterName(), Context.VoidTy, 0, - CD, true, false, true, false, + CD, /*isInstance=*/true, /*isVariadic=*/false, + /*isSynthesized=*/true, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1542,7 +1592,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, SC_None, SC_None, 0); - SetterMethod->setMethodParams(Context, &Argument, 1, 1); + SetterMethod->setMethodParams(Context, Argument, + ArrayRef<SourceLocation>()); AddPropertyAttrs(*this, SetterMethod, property); @@ -1686,7 +1737,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, (Attributes & ObjCDeclSpec::DQ_PR_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; } else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) && (Attributes & ObjCDeclSpec::DQ_PR_weak)) { @@ -1695,6 +1746,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, Attributes &= ~ObjCDeclSpec::DQ_PR_weak; } + if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) && + (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "atomic" << "nonatomic"; + Attributes &= ~ObjCDeclSpec::DQ_PR_atomic; + } + // Warn if user supplied no assignment attribute, property is // readwrite, and this is an object type. if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | @@ -1703,13 +1761,19 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, ObjCDeclSpec::DQ_PR_weak)) && !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && PropertyTy->isObjCObjectPointerType()) { - // Skip this warning in gc-only mode. - if (getLangOptions().getGCMode() != LangOptions::GCOnly) - Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + if (getLangOptions().ObjCAutoRefCount) + // With arc, @property definitions should default to (strong) when + // not specified + PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + else { + // Skip this warning in gc-only mode. + if (getLangOptions().getGC() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); - // If non-gc code warn that this is likely inappropriate. - if (getLangOptions().getGCMode() == LangOptions::NonGC) - Diag(Loc, diag::warn_objc_property_default_assign_on_object); + // If non-gc code warn that this is likely inappropriate. + if (getLangOptions().getGC() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + } // FIXME: Implement warning dependent on NSCopying being // implemented. See also: @@ -1719,7 +1783,13 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly) - && getLangOptions().getGCMode() == LangOptions::GCOnly + && getLangOptions().getGC() == LangOptions::GCOnly && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); + else if (getLangOptions().ObjCAutoRefCount && + (Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && + !(Attributes & ObjCDeclSpec::DQ_PR_strong) && + PropertyTy->isBlockPointerType()) + Diag(Loc, diag::warn_objc_property_retain_of_block); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 437b2b5..b0dd5e2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -37,11 +37,14 @@ using namespace sema; /// A convenience routine for creating a decayed reference to a /// function. static ExprResult -CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, +CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ - ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), - VK_LValue, Loc, LocInfo)); + DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, Fn->getType(), + VK_LValue, Loc, LocInfo); + if (HadMultipleCandidates) + DRE->setHadMultipleCandidates(true); + ExprResult E = S.Owned(DRE); E = S.DefaultFunctionArrayConversion(E.take()); if (E.isInvalid()) return ExprError(); @@ -258,7 +261,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// DebugPrint - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. void StandardConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { OS << GetImplicitConversionName(First); @@ -297,12 +300,12 @@ void StandardConversionSequence::DebugPrint() const { /// DebugPrint - Print this user-defined conversion sequence to standard /// error. Useful for debugging overloading issues. void UserDefinedConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); if (Before.First || Before.Second || Before.Third) { Before.DebugPrint(); OS << " -> "; } - OS << '\'' << ConversionFunction << '\''; + OS << '\'' << *ConversionFunction << '\''; if (After.First || After.Second || After.Third) { OS << " -> "; After.DebugPrint(); @@ -312,7 +315,7 @@ void UserDefinedConversionSequence::DebugPrint() const { /// DebugPrint - Print this implicit conversion sequence to standard /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::DebugPrint() const { - llvm::raw_ostream &OS = llvm::errs(); + raw_ostream &OS = llvm::errs(); switch (ConversionKind) { case StandardConversion: OS << "Standard conversion: "; @@ -909,20 +912,22 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType, /// explicit user-defined conversions are permitted. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, - AssignmentAction Action, bool AllowExplicit) { + AssignmentAction Action, bool AllowExplicit, + bool Diagnose) { ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS, + Diagnose); } ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - ImplicitConversionSequence& ICS) { + ImplicitConversionSequence& ICS, + bool Diagnose) { // Objective-C ARC: Determine whether we will allow the writeback conversion. bool AllowObjCWritebackConversion = getLangOptions().ObjCAutoRefCount && (Action == AA_Passing || Action == AA_Sending); - ICS = clang::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, @@ -930,6 +935,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, /*InOverloadResolution=*/false, /*CStyle=*/false, AllowObjCWritebackConversion); + if (!Diagnose && ICS.isFailure()) + return ExprError(); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -1113,10 +1120,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, return false; } } - // Lvalue-to-rvalue conversion (C++ 4.1): - // An lvalue (3.10) of a non-function, non-array type T can be - // converted to an rvalue. - bool argIsLValue = From->isLValue(); + // Lvalue-to-rvalue conversion (C++11 4.1): + // A glvalue (3.10) of a non-function, non-array type T can + // be converted to a prvalue. + bool argIsLValue = From->isGLValue(); if (argIsLValue && !FromType->isFunctionType() && !FromType->isArrayType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { @@ -1392,12 +1399,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. - bool FromIsSigned; + bool FromIsSigned = FromType->isSignedIntegerType(); uint64_t FromSize = Context.getTypeSize(FromType); - // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. - FromIsSigned = true; - // The types we'll try to promote to, in the appropriate // order. Try each of these types. QualType PromoteTypes[6] = { @@ -1465,10 +1469,10 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { /// FromType to ToType is a floating point promotion (C++ 4.6). If so, /// returns true and sets PromotedType to the promoted type. bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { - /// An rvalue of type float can be converted to an rvalue of type - /// double. (C++ 4.6p1). if (const BuiltinType *FromBuiltin = FromType->getAs<BuiltinType>()) if (const BuiltinType *ToBuiltin = ToType->getAs<BuiltinType>()) { + /// An rvalue of type float can be converted to an rvalue of type + /// double. (C++ 4.6p1). if (FromBuiltin->getKind() == BuiltinType::Float && ToBuiltin->getKind() == BuiltinType::Double) return true; @@ -1481,6 +1485,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { FromBuiltin->getKind() == BuiltinType::Double) && (ToBuiltin->getKind() == BuiltinType::LongDouble)) return true; + + // Half can be promoted to float. + if (FromBuiltin->getKind() == BuiltinType::Half && + ToBuiltin->getKind() == BuiltinType::Float) + return true; } return false; @@ -1668,7 +1677,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, } // MSVC allows implicit function to void* type conversion. - if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() && + if (getLangOptions().MicrosoftExt && FromPointeeType->isFunctionType() && ToPointeeType->isVoidType()) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, @@ -2073,6 +2082,11 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, // Argument types are too different. Abort. return false; } + if (LangOpts.ObjCAutoRefCount && + !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType, + ToFunctionType)) + return false; + ConvertedType = ToType; return true; } @@ -2136,8 +2150,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, PDiag(diag::warn_impcast_bool_to_null_pointer) << ToType << From->getSourceRange()); - if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) - if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { + if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { + if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) { QualType FromPointeeType = FromPtrType->getPointeeType(), ToPointeeType = ToPtrType->getPointeeType(); @@ -2155,16 +2169,23 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, Kind = CK_DerivedToBase; } } - if (const ObjCObjectPointerType *FromPtrType = - FromType->getAs<ObjCObjectPointerType>()) { - if (const ObjCObjectPointerType *ToPtrType = - ToType->getAs<ObjCObjectPointerType>()) { + } else if (const ObjCObjectPointerType *ToPtrType = + ToType->getAs<ObjCObjectPointerType>()) { + if (const ObjCObjectPointerType *FromPtrType = + FromType->getAs<ObjCObjectPointerType>()) { // Objective-C++ conversions are always okay. // FIXME: We should have a different class of conversions for the // Objective-C++ implicit conversions. if (FromPtrType->isObjCBuiltinType() || ToPtrType->isObjCBuiltinType()) return false; + } else if (FromType->isBlockPointerType()) { + Kind = CK_BlockPointerToObjCPointerCast; + } else { + Kind = CK_CPointerToObjCPointerCast; } + } else if (ToType->isBlockPointerType()) { + if (!FromType->isBlockPointerType()) + Kind = CK_AnyPointerToBlockPointerCast; } // We shouldn't fall into this case unless it's valid for other @@ -2483,6 +2504,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best, true)) { case OR_Success: @@ -2504,8 +2527,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, User.Before = Best->Conversions[0].Standard; User.EllipsisConversion = false; } + User.HadMultipleCandidates = HadMultipleCandidates; User.ConversionFunction = Constructor; - User.FoundConversionFunction = Best->FoundDecl.getDecl(); + User.FoundConversionFunction = Best->FoundDecl; User.After.setAsIdentityConversion(); User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType()); User.After.setAllToTypes(ToType); @@ -2521,8 +2545,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // conversion sequence converts the source type to the // implicit object parameter of the conversion function. User.Before = Best->Conversions[0].Standard; + User.HadMultipleCandidates = HadMultipleCandidates; User.ConversionFunction = Conversion; - User.FoundConversionFunction = Best->FoundDecl.getDecl(); + User.FoundConversionFunction = Best->FoundDecl; User.EllipsisConversion = false; // C++ [over.ics.user]p2: @@ -2862,6 +2887,25 @@ CompareStandardConversionSequences(Sema &S, } } + // In Microsoft mode, prefer an integral conversion to a + // floating-to-integral conversion if the integral conversion + // is between types of the same size. + // For example: + // void f(float); + // void f(int); + // int main { + // long a; + // f(a); + // } + // Here, MSVC will call f(int) instead of generating a compile error + // as clang will do in standard mode. + if (S.getLangOptions().MicrosoftMode && + SCS1.Second == ICK_Integral_Conversion && + SCS2.Second == ICK_Floating_Integral && + S.Context.getTypeSize(SCS1.getFromType()) == + S.Context.getTypeSize(SCS1.getToType(2))) + return ImplicitConversionSequence::Better; + return ImplicitConversionSequence::Indistinguishable; } @@ -3292,6 +3336,16 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, bool DerivedToBase = false; bool ObjCConversion = false; bool ObjCLifetimeConversion = false; + + // If we are initializing an rvalue reference, don't permit conversion + // functions that return lvalues. + if (!ConvTemplate && DeclType->isRValueReferenceType()) { + const ReferenceType *RefType + = Conv->getConversionType()->getAs<LValueReferenceType>(); + if (RefType && !RefType->getPointeeType()->isFunctionType()) + continue; + } + if (!ConvTemplate && S.CompareReferenceRelationship( DeclLoc, @@ -3322,6 +3376,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, DeclType, CandidateSet); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) { case OR_Success: @@ -3343,8 +3399,9 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, ICS.setUserDefined(); ICS.UserDefined.Before = Best->Conversions[0].Standard; ICS.UserDefined.After = Best->FinalConversion; + ICS.UserDefined.HadMultipleCandidates = HadMultipleCandidates; ICS.UserDefined.ConversionFunction = Best->Function; - ICS.UserDefined.FoundConversionFunction = Best->FoundDecl.getDecl(); + ICS.UserDefined.FoundConversionFunction = Best->FoundDecl; ICS.UserDefined.EllipsisConversion = false; assert(ICS.UserDefined.After.ReferenceBinding && ICS.UserDefined.After.DirectBinding && @@ -3611,12 +3668,25 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; ICS.Standard.ObjCLifetimeConversionBinding = false; } else if (ICS.isUserDefined()) { + // Don't allow rvalue references to bind to lvalues. + if (DeclType->isRValueReferenceType()) { + if (const ReferenceType *RefType + = ICS.UserDefined.ConversionFunction->getResultType() + ->getAs<LValueReferenceType>()) { + if (!RefType->getPointeeType()->isFunctionType()) { + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, + DeclType); + return ICS; + } + } + } + ICS.UserDefined.After.ReferenceBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = true; - ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; - ICS.Standard.ObjCLifetimeConversionBinding = false; + ICS.UserDefined.After.IsLvalueReference = !isRValRef; + ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.UserDefined.After.BindsToRvalue = true; + ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.UserDefined.After.ObjCLifetimeConversionBinding = false; } return ICS; @@ -3647,6 +3717,18 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, AllowObjCWritebackConversion); } +static bool TryCopyInitialization(const CanQualType FromQTy, + const CanQualType ToQTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + OpaqueValueExpr TmpExpr(Loc, FromQTy, FromVK); + ImplicitConversionSequence ICS = + TryCopyInitialization(S, &TmpExpr, ToQTy, true, true, false); + + return !ICS.isBad(); +} + /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. @@ -3852,25 +3934,57 @@ ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) { return ExprError(); } -/// TryContextuallyConvertToObjCId - Attempt to contextually convert the -/// expression From to 'id'. +/// dropPointerConversions - If the given standard conversion sequence +/// involves any pointer conversions, remove them. This may change +/// the result type of the conversion sequence. +static void dropPointerConversion(StandardConversionSequence &SCS) { + if (SCS.Second == ICK_Pointer_Conversion) { + SCS.Second = ICK_Identity; + SCS.Third = ICK_Identity; + SCS.ToTypePtrs[2] = SCS.ToTypePtrs[1] = SCS.ToTypePtrs[0]; + } +} + +/// TryContextuallyConvertToObjCPointer - Attempt to contextually +/// convert the expression From to an Objective-C pointer type. static ImplicitConversionSequence -TryContextuallyConvertToObjCId(Sema &S, Expr *From) { +TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { + // Do an implicit conversion to 'id'. QualType Ty = S.Context.getObjCIdType(); - return TryImplicitConversion(S, From, Ty, - // FIXME: Are these flags correct? - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, - /*InOverloadResolution=*/false, - /*CStyle=*/false, - /*AllowObjCWritebackConversion=*/false); + ImplicitConversionSequence ICS + = TryImplicitConversion(S, From, Ty, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); + + // Strip off any final conversions to 'id'. + switch (ICS.getKind()) { + case ImplicitConversionSequence::BadConversion: + case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::EllipsisConversion: + break; + + case ImplicitConversionSequence::UserDefinedConversion: + dropPointerConversion(ICS.UserDefined.After); + break; + + case ImplicitConversionSequence::StandardConversion: + dropPointerConversion(ICS.Standard); + break; + } + + return ICS; } -/// PerformContextuallyConvertToObjCId - Perform a contextual conversion -/// of the expression From to 'id'. -ExprResult Sema::PerformContextuallyConvertToObjCId(Expr *From) { +/// PerformContextuallyConvertToObjCPointer - Perform a contextual +/// conversion of the expression From to an Objective-C pointer type. +ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { QualType Ty = Context.getObjCIdType(); - ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From); + ImplicitConversionSequence ICS = + TryContextuallyConvertToObjCPointer(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Ty, ICS, AA_Converting); return ExprError(); @@ -3951,6 +4065,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions(); + bool HadMultipleCandidates = (Conversions->size() > 1); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; @@ -3978,7 +4094,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; - ConvTy.getAsStringInternal(TypeStr, Context.PrintingPolicy); + ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy()); Diag(Loc, ExplicitConvDiag) << T << ConvTy @@ -3995,7 +4111,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, return ExprError(); CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion); + ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); @@ -4022,8 +4139,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange(); } - ExprResult Result = BuildCXXMemberCallExpr(From, Found, - cast<CXXConversionDecl>(Found->getUnderlyingDecl())); + ExprResult Result = BuildCXXMemberCallExpr(From, Found, Conversion, + HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); @@ -4144,6 +4261,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, return; } + // (CUDA B.1): Check for invalid calls between targets. + if (getLangOptions().CUDA) + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) + if (CheckCUDATarget(Caller, Function)) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_target; + return; + } + // Determine the implicit conversion sequences for each of the // arguments. Candidate.Conversions.resize(NumArgs); @@ -4590,7 +4716,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, break; default: - assert(false && + llvm_unreachable( "Can only end up with a standard conversion sequence or failure"); } } @@ -4686,9 +4812,9 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[0].setUserDefined(); Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; + Candidate.Conversions[0].UserDefined.HadMultipleCandidates = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; - Candidate.Conversions[0].UserDefined.FoundConversionFunction - = FoundDecl.getDecl(); + Candidate.Conversions[0].UserDefined.FoundConversionFunction = FoundDecl; Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion(); @@ -4973,7 +5099,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, buildObjCPtr = true; } else - assert(false && "type was not a pointer type!"); + llvm_unreachable("type was not a pointer type!"); } else PointeeTy = PointerTy->getPointeeType(); @@ -5230,7 +5356,7 @@ class BuiltinOperatorOverloadBuilder { unsigned NumArgs; Qualifiers VisibleTypeConversionsQuals; bool HasArithmeticOrEnumeralCandidateType; - llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; + SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; OverloadCandidateSet &CandidateSet; // Define some constants used to index and iterate over the arithemetic types @@ -5366,7 +5492,7 @@ public: Sema &S, Expr **Args, unsigned NumArgs, Qualifiers VisibleTypeConversionsQuals, bool HasArithmeticOrEnumeralCandidateType, - llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, + SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, OverloadCandidateSet &CandidateSet) : S(S), Args(Args), NumArgs(NumArgs), VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), @@ -6235,7 +6361,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, bool HasNonRecordCandidateType = false; bool HasArithmeticOrEnumeralCandidateType = false; - llvm::SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; + SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), @@ -6254,7 +6380,11 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // Exit early when no non-record types have been added to the candidate set // for any of the arguments to the operator. - if (!HasNonRecordCandidateType) + // + // We can't exit early for !, ||, or &&, since there we have always have + // 'bool' overloads. + if (!HasNonRecordCandidateType && + !(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe)) return; // Setup an object to manage the common state for building overloads. @@ -6267,16 +6397,15 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, switch (Op) { case OO_None: case NUM_OVERLOADED_OPERATORS: - assert(false && "Expected an overloaded operator"); - break; + llvm_unreachable("Expected an overloaded operator"); case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: case OO_Call: - assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); - break; + llvm_unreachable( + "Special operators don't use AddBuiltinOperatorCandidates"); case OO_Comma: case OO_Arrow: @@ -6846,6 +6975,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + // Special diagnostic for failure to convert an initializer list, since + // telling the user that it has type void is not useful. + if (FromExpr && isa<InitListExpr>(FromExpr)) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + // Diagnose references or pointers to incomplete types differently, // since it's far from impossible that the incompleteness triggered // the failure. @@ -6902,11 +7042,34 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } - // TODO: specialize more based on the kind of mismatch - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) - << (unsigned) FnKind << FnDesc + if (isa<ObjCObjectPointerType>(CFromTy) && + isa<PointerType>(CToTy)) { + Qualifiers FromQs = CFromTy.getQualifiers(); + Qualifiers ToQs = CToTy.getQualifiers(); + if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + } + + // Emit the generic diagnostic and, optionally, add the hints to it. + PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); + FDiag << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + << FromTy << ToTy << (unsigned) isObjectArgument << I + 1 + << (unsigned) (Cand->Fix.Kind); + + // If we can fix the conversion, suggest the FixIts. + for (SmallVector<FixItHint, 1>::iterator + HI = Cand->Fix.Hints.begin(), HE = Cand->Fix.Hints.end(); + HI != HE; ++HI) + FDiag << *HI; + S.Diag(Fn->getLocation(), FDiag); + MaybeEmitInheritedConstructorNote(S, Fn); } @@ -7081,6 +7244,21 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, } } +/// CUDA: diagnose an invalid call across targets. +void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { + FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext); + FunctionDecl *Callee = Cand->Function; + + Sema::CUDAFunctionTarget CallerTarget = S.IdentifyCUDATarget(Caller), + CalleeTarget = S.IdentifyCUDATarget(Callee); + + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc); + + S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) + << (unsigned) FnKind << CalleeTarget << CallerTarget; +} + /// Generates a 'note' diagnostic for an overload candidate. We've /// already generated a primary error at the call site. /// @@ -7140,6 +7318,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // those conditions and diagnose them well. return S.NoteOverloadCandidate(Fn); } + + case ovl_fail_bad_target: + return DiagnoseBadTarget(S, Cand); } } @@ -7217,6 +7398,37 @@ SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { return SourceLocation(); } +static unsigned +RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) { + switch ((Sema::TemplateDeductionResult)DFI.Result) { + case Sema::TDK_Success: + llvm_unreachable("TDK_success while diagnosing bad deduction"); + + case Sema::TDK_Incomplete: + return 1; + + case Sema::TDK_Underqualified: + case Sema::TDK_Inconsistent: + return 2; + + case Sema::TDK_SubstitutionFailure: + case Sema::TDK_NonDeducedMismatch: + return 3; + + case Sema::TDK_InstantiationDepth: + case Sema::TDK_FailedOverloadResolution: + return 4; + + case Sema::TDK_InvalidExplicitArguments: + return 5; + + case Sema::TDK_TooManyArguments: + case Sema::TDK_TooFewArguments: + return 6; + } + llvm_unreachable("Unhandled deduction result"); +} + struct CompareOverloadCandidatesForDisplay { Sema &S; CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} @@ -7256,6 +7468,19 @@ struct CompareOverloadCandidatesForDisplay { if (R->FailureKind != ovl_fail_bad_conversion) return true; + // The conversion that can be fixed with a smaller number of changes, + // comes first. + unsigned numLFixes = L->Fix.NumConversionsFixed; + unsigned numRFixes = R->Fix.NumConversionsFixed; + numLFixes = (numLFixes == 0) ? UINT_MAX : numLFixes; + numRFixes = (numRFixes == 0) ? UINT_MAX : numRFixes; + if (numLFixes != numRFixes) { + if (numLFixes < numRFixes) + return true; + else + return false; + } + // If there's any ordering between the defined conversions... // FIXME: this might not be transitive. assert(L->Conversions.size() == R->Conversions.size()); @@ -7284,6 +7509,16 @@ struct CompareOverloadCandidatesForDisplay { } else if (R->FailureKind == ovl_fail_bad_conversion) return false; + if (L->FailureKind == ovl_fail_bad_deduction) { + if (R->FailureKind != ovl_fail_bad_deduction) + return true; + + if (L->DeductionFailure.Result != R->DeductionFailure.Result) + return RankDeductionFailure(L->DeductionFailure) + < RankDeductionFailure(R->DeductionFailure); + } else if (R->FailureKind == ovl_fail_bad_deduction) + return false; + // TODO: others? } @@ -7300,7 +7535,7 @@ struct CompareOverloadCandidatesForDisplay { }; /// CompleteNonViableCandidate - Normally, overload resolution only -/// computes up to the first +/// computes up to the first. Produces the FixIt set if possible. void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, Expr **Args, unsigned NumArgs) { assert(!Cand->Viable); @@ -7308,14 +7543,21 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, // Don't do anything on failures other than bad conversion. if (Cand->FailureKind != ovl_fail_bad_conversion) return; + // We only want the FixIts if all the arguments can be corrected. + bool Unfixable = false; + // Use a implicit copy initialization to check conversion fixes. + Cand->Fix.setConversionChecker(TryCopyInitialization); + // Skip forward to the first bad conversion. unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); unsigned ConvCount = Cand->Conversions.size(); while (true) { assert(ConvIdx != ConvCount && "no bad conversion in candidate"); ConvIdx++; - if (Cand->Conversions[ConvIdx - 1].isBad()) + if (Cand->Conversions[ConvIdx - 1].isBad()) { + Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S); break; + } } if (ConvIdx == ConvCount) @@ -7360,13 +7602,17 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, // Fill in the rest of the conversions. unsigned NumArgsInProto = Proto->getNumArgs(); for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { - if (ArgIdx < NumArgsInProto) + if (ArgIdx < NumArgsInProto) { Cand->Conversions[ConvIdx] = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), SuppressUserConversions, /*InOverloadResolution=*/true, /*AllowObjCWritebackConversion=*/ S.getLangOptions().ObjCAutoRefCount); + // Store the FixIt in the candidate if it exists. + if (!Unfixable && Cand->Conversions[ConvIdx].isBad()) + Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S); + } else Cand->Conversions[ConvIdx].setEllipsis(); } @@ -7384,7 +7630,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, SourceLocation OpLoc) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. - llvm::SmallVector<OverloadCandidate*, 32> Cands; + SmallVector<OverloadCandidate*, 32> Cands; if (OCD == OCD_AllCandidates) Cands.reserve(size()); for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { if (Cand->Viable) @@ -7403,8 +7649,9 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, bool ReportedAmbiguousConversions = false; - llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E; - const Diagnostic::OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); + SmallVectorImpl<OverloadCandidate*>::iterator I, E; + const DiagnosticsEngine::OverloadsShown ShowOverloads = + S.Diags.getShowOverloads(); unsigned CandsShown = 0; for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { OverloadCandidate *Cand = *I; @@ -7412,7 +7659,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, // Set an arbitrary limit on the number of candidate functions we'll spam // the user with. FIXME: This limit should depend on details of the // candidate list. - if (CandsShown >= 4 && ShowOverloads == Diagnostic::Ovl_Best) { + if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) { break; } ++CandsShown; @@ -7485,7 +7732,7 @@ class AddressOfFunctionResolver OverloadExpr::FindResult OvlExprInfo; OverloadExpr *OvlExpr; TemplateArgumentListInfo OvlExplicitTemplateArgs; - llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; + SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; public: AddressOfFunctionResolver(Sema &S, Expr* SourceExpr, @@ -7607,6 +7854,11 @@ private: return false; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { + if (S.getLangOptions().CUDA) + if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) + if (S.CheckCUDATarget(Caller, FunDecl)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || @@ -7873,25 +8125,31 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, -// Resolve and fix an overloaded expression that -// can be resolved because it identifies a single function -// template specialization +// Resolve and fix an overloaded expression that can be resolved +// because it identifies a single function template specialization. +// // Last three arguments should only be supplied if Complain = true -ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( - Expr *SrcExpr, bool doFunctionPointerConverion, bool complain, - const SourceRange& OpRangeForComplaining, +// +// Return true if it was logically possible to so resolve the +// expression, regardless of whether or not it succeeded. Always +// returns true if 'complain' is set. +bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization( + ExprResult &SrcExpr, bool doFunctionPointerConverion, + bool complain, const SourceRange& OpRangeForComplaining, QualType DestTypeForComplaining, unsigned DiagIDForComplaining) { - assert(SrcExpr->getType() == Context.OverloadTy); + assert(SrcExpr.get()->getType() == Context.OverloadTy); - OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr); + OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get()); DeclAccessPair found; ExprResult SingleFunctionExpression; if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( ovl.Expression, /*complain*/ false, &found)) { - if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin())) - return ExprError(); + if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getSourceRange().getBegin())) { + SrcExpr = ExprError(); + return true; + } // It is only correct to resolve to an instance method if we're // resolving a form that's permitted to be a pointer to member. @@ -7900,28 +8158,34 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( if (!ovl.HasFormOfMemberPointer && isa<CXXMethodDecl>(fn) && cast<CXXMethodDecl>(fn)->isInstance()) { - if (complain) { - Diag(ovl.Expression->getExprLoc(), - diag::err_invalid_use_of_bound_member_func) - << ovl.Expression->getSourceRange(); - // TODO: I believe we only end up here if there's a mix of - // static and non-static candidates (otherwise the expression - // would have 'bound member' type, not 'overload' type). - // Ideally we would note which candidate was chosen and why - // the static candidates were rejected. - } - - return ExprError(); + if (!complain) return false; + + Diag(ovl.Expression->getExprLoc(), + diag::err_bound_member_function) + << 0 << ovl.Expression->getSourceRange(); + + // TODO: I believe we only end up here if there's a mix of + // static and non-static candidates (otherwise the expression + // would have 'bound member' type, not 'overload' type). + // Ideally we would note which candidate was chosen and why + // the static candidates were rejected. + SrcExpr = ExprError(); + return true; } // Fix the expresion to refer to 'fn'. SingleFunctionExpression = - Owned(FixOverloadedFunctionReference(SrcExpr, found, fn)); + Owned(FixOverloadedFunctionReference(SrcExpr.take(), found, fn)); // If desired, do function-to-pointer decay. - if (doFunctionPointerConverion) + if (doFunctionPointerConverion) { SingleFunctionExpression = DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take()); + if (SingleFunctionExpression.isInvalid()) { + SrcExpr = ExprError(); + return true; + } + } } if (!SingleFunctionExpression.isUsable()) { @@ -7931,12 +8195,17 @@ ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( << DestTypeForComplaining << OpRangeForComplaining << ovl.Expression->getQualifierLoc().getSourceRange(); - NoteAllOverloadCandidates(SrcExpr); - } - return ExprError(); + NoteAllOverloadCandidates(SrcExpr.get()); + + SrcExpr = ExprError(); + return true; + } + + return false; } - return SingleFunctionExpression; + SrcExpr = SingleFunctionExpression; + return true; } /// \brief Add a single candidate to the overload set. @@ -8164,7 +8433,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, ExplicitTemplateArgs, Args, NumArgs) && (!EmptyLookup || - SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))) + SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression, + ExplicitTemplateArgs, Args, NumArgs))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -8214,7 +8484,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, if (ULE->decls_begin() + 1 == ULE->decls_end() && (F = dyn_cast<FunctionDecl>(*ULE->decls_begin())) && F->getBuiltinID() && F->isImplicit()) - assert(0 && "performing ADL for builtin"); + llvm_unreachable("performing ADL for builtin"); // We don't perform ADL in C. assert(getLangOptions().CPlusPlus && "ADL enabled in C"); @@ -8232,9 +8502,22 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, // If we found nothing, try to recover. // BuildRecoveryCallExpr diagnoses the error itself, so we just bail // out if it fails. - if (CandidateSet.empty()) + if (CandidateSet.empty()) { + // In Microsoft mode, if we are inside a template class member function then + // create a type dependent CallExpr. The goal is to postpone name lookup + // to instantiation time to be able to search into type dependent base + // classes. + if (getLangOptions().MicrosoftExt && CurContext->isDependentContext() && + isa<CXXMethodDecl>(CurContext)) { + CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs, + Context.DependentTy, VK_RValue, + RParenLoc); + CE->setTypeDependent(true); + return Owned(CE); + } return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, RParenLoc, /*EmptyLookup=*/true); + } OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { @@ -8379,6 +8662,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -8423,7 +8708,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates); if (FnExpr.isInvalid()) return ExprError(); @@ -8468,8 +8754,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << Input->getType() << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - Args, NumArgs, + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -8479,7 +8764,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs, + UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -8627,6 +8913,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -8688,7 +8976,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -8774,7 +9063,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << BinaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, + BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -8837,6 +9127,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Add builtin operator candidates. AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, LLoc, Best)) { @@ -8883,7 +9175,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, DeclarationNameLoc LocInfo; LocInfo.CXXOperatorName.BeginOpNameLoc = LLoc.getRawEncoding(); LocInfo.CXXOperatorName.EndOpNameLoc = RLoc.getRawEncoding(); - ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc, LocInfo); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, + HadMultipleCandidates, + LLoc, LocInfo); if (FnExpr.isInvalid()) return ExprError(); @@ -9059,7 +9353,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Microsoft supports direct constructor calls. - if (getLangOptions().Microsoft && isa<CXXConstructorDecl>(Func)) { + if (getLangOptions().MicrosoftExt && isa<CXXConstructorDecl>(Func)) { AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args, NumArgs, CandidateSet); } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) { @@ -9231,8 +9525,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, } // C++ [over.call.object]p2: - // In addition, for each conversion function declared in T of the - // form + // In addition, for each (non-explicit in C++0x) conversion function + // declared in T of the form // // operator conversion-type-id () cv-qualifier; // @@ -9262,18 +9556,23 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, continue; CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); - - // Strip the reference type (if any) and then the pointer type (if - // any) to get down to what might be a function type. - QualType ConvType = Conv->getConversionType().getNonReferenceType(); - if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) - ConvType = ConvPtrType->getPointeeType(); - - if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object.get(), Args, NumArgs, CandidateSet); + if (!Conv->isExplicit()) { + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); + + if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) + { + AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, + Object.get(), Args, NumArgs, CandidateSet); + } + } } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(), @@ -9332,7 +9631,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Create an implicit member expr to refer to the conversion operator. // and then call it. - ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, Conv); + ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, + Conv, HadMultipleCandidates); if (Call.isInvalid()) return ExprError(); @@ -9368,7 +9668,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) MethodArgs[ArgIdx + 1] = Args[ArgIdx]; - ExprResult NewFn = CreateFunctionRefExpr(*this, Method); + ExprResult NewFn = CreateFunctionRefExpr(*this, Method, + HadMultipleCandidates); if (NewFn.isInvalid()) return true; @@ -9498,6 +9799,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } + bool HadMultipleCandidates = (CandidateSet.size() > 1); + // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { @@ -9545,7 +9848,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { Base = BaseResult.take(); // Build the operator call. - ExprResult FnExpr = CreateFunctionRefExpr(*this, Method); + ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, + HadMultipleCandidates); if (FnExpr.isInvalid()) return ExprError(); @@ -9648,14 +9952,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, TemplateArgs = &TemplateArgsBuffer; } - return DeclRefExpr::Create(Context, - ULE->getQualifierLoc(), - Fn, - ULE->getNameLoc(), - Fn->getType(), - VK_LValue, - Found.getDecl(), - TemplateArgs); + DeclRefExpr *DRE = DeclRefExpr::Create(Context, + ULE->getQualifierLoc(), + Fn, + ULE->getNameLoc(), + Fn->getType(), + VK_LValue, + Found.getDecl(), + TemplateArgs); + DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); + return DRE; } if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) { @@ -9672,14 +9978,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, // implicit member access, rewrite to a simple decl ref. if (MemExpr->isImplicitAccess()) { if (cast<CXXMethodDecl>(Fn)->isStatic()) { - return DeclRefExpr::Create(Context, - MemExpr->getQualifierLoc(), - Fn, - MemExpr->getMemberLoc(), - Fn->getType(), - VK_LValue, - Found.getDecl(), - TemplateArgs); + DeclRefExpr *DRE = DeclRefExpr::Create(Context, + MemExpr->getQualifierLoc(), + Fn, + MemExpr->getMemberLoc(), + Fn->getType(), + VK_LValue, + Found.getDecl(), + TemplateArgs); + DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); + return DRE; } else { SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) @@ -9701,14 +10009,16 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, type = Context.BoundMemberTy; } - return MemberExpr::Create(Context, Base, - MemExpr->isArrow(), - MemExpr->getQualifierLoc(), - Fn, - Found, - MemExpr->getMemberNameInfo(), - TemplateArgs, - type, valueKind, OK_Ordinary); + MemberExpr *ME = MemberExpr::Create(Context, Base, + MemExpr->isArrow(), + MemExpr->getQualifierLoc(), + Fn, + Found, + MemExpr->getMemberNameInfo(), + TemplateArgs, + type, valueKind, OK_Ordinary); + ME->setHadMultipleCandidates(true); + return ME; } llvm_unreachable("Invalid reference to overloaded function"); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 65f431d..5351896 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -47,8 +47,8 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) { StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, - SourceLocation LeadingEmptyMacroLoc) { - return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacroLoc)); + bool HasLeadingEmptyMacro) { + return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro)); } StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, @@ -92,6 +92,56 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { } } +/// \brief Diagnose unused '==' and '!=' as likely typos for '=' or '|='. +/// +/// Adding a cast to void (or other expression wrappers) will prevent the +/// warning from firing. +static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { + SourceLocation Loc; + bool IsNotEqual, CanAssign; + + if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { + if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE) + return false; + + Loc = Op->getOperatorLoc(); + IsNotEqual = Op->getOpcode() == BO_NE; + CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue(); + } else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { + if (Op->getOperator() != OO_EqualEqual && + Op->getOperator() != OO_ExclaimEqual) + return false; + + Loc = Op->getOperatorLoc(); + IsNotEqual = Op->getOperator() == OO_ExclaimEqual; + CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue(); + } else { + // Not a typo-prone comparison. + return false; + } + + // Suppress warnings when the operator, suspicious as it may be, comes from + // a macro expansion. + if (Loc.isMacroID()) + return false; + + S.Diag(Loc, diag::warn_unused_comparison) + << (unsigned)IsNotEqual << E->getSourceRange(); + + // If the LHS is a plausible entity to assign to, provide a fixit hint to + // correct common typos. + if (CanAssign) { + if (IsNotEqual) + S.Diag(Loc, diag::note_inequality_comparison_to_or_assign) + << FixItHint::CreateReplacement(Loc, "|="); + else + S.Diag(Loc, diag::note_equality_comparison_to_assign) + << FixItHint::CreateReplacement(Loc, "="); + } + + return true; +} + void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) return DiagnoseUnusedExprResult(Label->getSubStmt()); @@ -114,6 +164,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) E = TempExpr->getSubExpr(); + if (DiagnoseUnusedComparison(*this, E)) + return; + E = E->IgnoreParenImpCasts(); if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (E->getType()->isVoidType()) @@ -123,7 +176,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // a more specific message to make it clear what is happening. if (const Decl *FD = CE->getCalleeDecl()) { if (FD->getAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + Diag(Loc, diag::warn_unused_result) << R1 << R2; return; } if (FD->getAttr<PureAttr>()) { @@ -142,7 +195,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD && MD->getAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + Diag(Loc, diag::warn_unused_result) << R1 << R2; return; } } else if (isa<ObjCPropertyRefExpr>(E)) { @@ -238,6 +291,8 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, /// ActOnCaseStmtBody - This installs a statement as the body of a case. void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) { + DiagnoseUnusedExprResult(SubStmt); + CaseStmt *CS = static_cast<CaseStmt*>(caseStmt); CS->setSubStmt(SubStmt); } @@ -245,6 +300,8 @@ void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) { StmtResult Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope) { + DiagnoseUnusedExprResult(SubStmt); + if (getCurFunction()->SwitchStack.empty()) { Diag(DefaultLoc, diag::err_default_not_in_switch); return Owned(SubStmt); @@ -407,13 +464,12 @@ static bool EqEnumVals(const std::pair<llvm::APSInt, EnumConstantDecl*>& lhs, /// GetTypeBeforeIntegralPromotion - Returns the pre-promotion type of /// potentially integral-promoted expression @p expr. -static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { - if (const CastExpr *ImplicitCast = dyn_cast<ImplicitCastExpr>(expr)) { - const Expr *ExprBeforePromotion = ImplicitCast->getSubExpr(); - QualType TypeBeforePromotion = ExprBeforePromotion->getType(); - if (TypeBeforePromotion->isIntegralOrEnumerationType()) { - return TypeBeforePromotion; - } +static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) { + if (ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(expr)) + expr = cleanups->getSubExpr(); + while (ImplicitCastExpr *impcast = dyn_cast<ImplicitCastExpr>(expr)) { + if (impcast->getCastKind() != CK_IntegralCast) break; + expr = impcast->getSubExpr(); } return expr->getType(); } @@ -449,6 +505,11 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + CondResult = UsualUnaryConversions(Cond); + if (CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); + if (!CondVar) { CheckImplicitConversions(Cond, SwitchLoc); CondResult = MaybeCreateExprWithCleanups(Cond); @@ -482,21 +543,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, SS->setBody(BodyStmt, SwitchLoc); getCurFunction()->SwitchStack.pop_back(); - if (SS->getCond() == 0) - return StmtError(); - Expr *CondExpr = SS->getCond(); - Expr *CondExprBeforePromotion = CondExpr; - QualType CondTypeBeforePromotion = - GetTypeBeforeIntegralPromotion(CondExpr); + if (!CondExpr) return StmtError(); - // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - ExprResult CondResult = UsualUnaryConversions(CondExpr); - if (CondResult.isInvalid()) - return StmtError(); - CondExpr = CondResult.take(); QualType CondType = CondExpr->getType(); - SS->setCond(CondExpr); + + Expr *CondExprBeforePromotion = CondExpr; + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExprBeforePromotion); // C++ 6.4.2.p2: // Integral promotions are performed (on the switch condition). @@ -533,7 +587,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Accumulate all of the case values in a vector so that we can sort them // and detect duplicates. This vector contains the APInt for the case after // it has been converted to the condition type. - typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; + typedef SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; CaseValsTy CaseVals; // Keep track of any GNU case ranges we see. The APSInt is the low value. @@ -572,7 +626,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, break; } - llvm::APSInt LoVal = Lo->EvaluateAsInt(Context); + llvm::APSInt LoVal = Lo->EvaluateKnownConstInt(Context); // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, @@ -651,7 +705,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); - llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); + llvm::APSInt HiVal = Hi->EvaluateKnownConstInt(Context); // Convert the value to the same width/sign as the condition. ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, @@ -750,7 +804,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); - typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> + typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; @@ -791,7 +845,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, << ED->getDeclName(); } - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + llvm::APSInt Hi = + RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); while (EI != EIend && EI->first < Hi) EI++; @@ -806,7 +861,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, CaseRangesTy::const_iterator RI = CaseRanges.begin(); bool hasCasesNotInSwitch = false; - llvm::SmallVector<DeclarationName,8> UnhandledNames; + SmallVector<DeclarationName,8> UnhandledNames; for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){ // Drop unneeded case values @@ -819,7 +874,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Drop unneeded case ranges for (; RI != CaseRanges.end(); RI++) { - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + llvm::APSInt Hi = + RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); if (EI->first <= Hi) break; @@ -965,6 +1021,76 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) { return Owned(static_cast<Stmt*>(Result.get())); } +ExprResult +Sema::ActOnObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { + assert(collection); + + // Bail out early if we've got a type-dependent expression. + if (collection->isTypeDependent()) return Owned(collection); + + // Perform normal l-value conversion. + ExprResult result = DefaultFunctionArrayLvalueConversion(collection); + if (result.isInvalid()) + return ExprError(); + collection = result.take(); + + // The operand needs to have object-pointer type. + // TODO: should we do a contextual conversion? + const ObjCObjectPointerType *pointerType = + collection->getType()->getAs<ObjCObjectPointerType>(); + if (!pointerType) + return Diag(forLoc, diag::err_collection_expr_type) + << collection->getType() << collection->getSourceRange(); + + // Check that the operand provides + // - countByEnumeratingWithState:objects:count: + const ObjCObjectType *objectType = pointerType->getObjectType(); + ObjCInterfaceDecl *iface = objectType->getInterface(); + + // If we have a forward-declared type, we can't do this check. + if (iface && iface->isForwardDecl()) { + // This is ill-formed under ARC. + if (getLangOptions().ObjCAutoRefCount) { + Diag(forLoc, diag::err_arc_collection_forward) + << pointerType->getPointeeType() << collection->getSourceRange(); + } + + // Otherwise, if we have any useful type information, check that + // the type declares the appropriate method. + } else if (iface || !objectType->qual_empty()) { + IdentifierInfo *selectorIdents[] = { + &Context.Idents.get("countByEnumeratingWithState"), + &Context.Idents.get("objects"), + &Context.Idents.get("count") + }; + Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]); + + ObjCMethodDecl *method = 0; + + // If there's an interface, look in both the public and private APIs. + if (iface) { + method = iface->lookupInstanceMethod(selector); + if (!method) method = LookupPrivateInstanceMethod(selector, iface); + } + + // Also check protocol qualifiers. + if (!method) + method = LookupMethodInQualifiedType(selector, pointerType, + /*instance*/ true); + + // If we didn't find it anywhere, give up. + if (!method) { + Diag(forLoc, diag::warn_collection_expr_type) + << collection->getType() << selector << collection->getSourceRange(); + } + + // TODO: check for an incompatible signature? + } + + // Wrap up any cleanups in the expression. + return Owned(MaybeCreateExprWithCleanups(collection)); +} + StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, @@ -1000,38 +1126,7 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second && !Second->isTypeDependent()) { - ExprResult Result = DefaultFunctionArrayLvalueConversion(Second); - if (Result.isInvalid()) - return StmtError(); - Second = Result.take(); - QualType SecondType = Second->getType(); - if (!SecondType->isObjCObjectPointerType()) - Diag(ForLoc, diag::err_collection_expr_type) - << SecondType << Second->getSourceRange(); - else if (const ObjCObjectPointerType *OPT = - SecondType->getAsObjCInterfacePointerType()) { - llvm::SmallVector<IdentifierInfo *, 4> KeyIdents; - IdentifierInfo* selIdent = - &Context.Idents.get("countByEnumeratingWithState"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("objects"); - KeyIdents.push_back(selIdent); - selIdent = &Context.Idents.get("count"); - KeyIdents.push_back(selIdent); - Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); - if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { - if (!IDecl->isForwardDecl() && - !IDecl->lookupInstanceMethod(CSelector) && - !LookupMethodInQualifiedType(CSelector, OPT, true)) { - // Must further look into private implementation methods. - if (!LookupPrivateInstanceMethod(CSelector, IDecl)) - Diag(ForLoc, diag::warn_collection_expr_type) - << SecondType << CSelector << Second->getSourceRange(); - } - } - } - } + return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc)); } @@ -1244,10 +1339,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { SourceLocation RangeLoc = RangeVar->getLocation(); - ExprResult RangeRef = BuildDeclRefExpr(RangeVar, - RangeVarType.getNonReferenceType(), - VK_LValue, ColonLoc); - if (RangeRef.isInvalid()) + const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); + + ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType, + VK_LValue, ColonLoc); + if (BeginRangeRef.isInvalid()) + return StmtError(); + + ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType, + VK_LValue, ColonLoc); + if (EndRangeRef.isInvalid()) return StmtError(); QualType AutoType = Context.getAutoDeductType(); @@ -1275,8 +1376,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, // the program is ill-formed; // begin-expr is __range. - BeginExpr = RangeRef; - if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc, + BeginExpr = BeginRangeRef; + if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc, diag::err_for_range_iter_deduction_failure)) { NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); return StmtError(); @@ -1294,12 +1395,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since // UnqAT is not incomplete and Range is not type-dependent. - assert(0 && "Unexpected array type in for-range"); - return StmtError(); + llvm_unreachable("Unexpected array type in for-range"); } // end-expr is __range + __bound. - EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(), + EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(), BoundExpr.get()); if (EndExpr.isInvalid()) return StmtError(); @@ -1340,13 +1440,14 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar, BEF_begin, BeginNameInfo, - BeginMemberLookup, RangeRef.get()); + BeginMemberLookup, + BeginRangeRef.get()); if (BeginExpr.isInvalid()) return StmtError(); EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar, BEF_end, EndNameInfo, - EndMemberLookup, RangeRef.get()); + EndMemberLookup, EndRangeRef.get()); if (EndExpr.isInvalid()) return StmtError(); } @@ -1366,11 +1467,16 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false); BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); - ExprResult BeginRef = BuildDeclRefExpr(BeginVar, - BeginType.getNonReferenceType(), + const QualType BeginRefNonRefType = BeginType.getNonReferenceType(); + ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(), VK_LValue, ColonLoc); + if (EndRef.isInvalid()) + return StmtError(); // Build and check __begin != __end expression. NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal, @@ -1385,6 +1491,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, } // Build and check ++__begin expression. + BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, + VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { @@ -1393,6 +1504,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, } // Build and check *__begin expression. + BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, + VK_LValue, ColonLoc); + if (BeginRef.isInvalid()) + return StmtError(); + ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get()); if (DerefExpr.isInvalid()) { NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); @@ -1651,54 +1767,49 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC // compatibility to worry about here. - ReturnStmt *Result = 0; - if (CurBlock->ReturnType->isVoidType()) { - if (RetValExp && !RetValExp->isTypeDependent() && - (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) { + const VarDecl *NRVOCandidate = 0; + if (FnRetType->isDependentType()) { + // Delay processing for now. TODO: there are lots of dependent + // types we can conclusively prove aren't void. + } else if (FnRetType->isVoidType()) { + if (RetValExp && + !(getLangOptions().CPlusPlus && + (RetValExp->isTypeDependent() || + RetValExp->getType()->isVoidType()))) { Diag(ReturnLoc, diag::err_return_block_has_expr); RetValExp = 0; } - Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); } else if (!RetValExp) { - if (!CurBlock->ReturnType->isDependentType()) - return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); - - Result = new (Context) ReturnStmt(ReturnLoc, 0, 0); - } else { - const VarDecl *NRVOCandidate = 0; - - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { - // we have a non-void block with an expression, continue checking - - // C99 6.8.6.4p3(136): The return statement is not an assignment. The - // overlap restriction of subclause 6.5.16.1 does not apply to the case of - // function return. - - // In C++ the return statement is handled via a copy initialization. - // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); - InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, - FnRetType, + return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + } else if (!RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, + FnRetType, NRVOCandidate != 0); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, - FnRetType, RetValExp); - if (Res.isInvalid()) { - // FIXME: Cleanup temporaries here, anyway? - return StmtError(); - } - - if (RetValExp) { - CheckImplicitConversions(RetValExp, ReturnLoc); - RetValExp = MaybeCreateExprWithCleanups(RetValExp); - } - - RetValExp = Res.takeAs<Expr>(); - if (RetValExp) - CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate, + FnRetType, RetValExp); + if (Res.isInvalid()) { + // FIXME: Cleanup temporaries here, anyway? + return StmtError(); } + RetValExp = Res.take(); + CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } - Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate); + if (RetValExp) { + CheckImplicitConversions(RetValExp, ReturnLoc); + RetValExp = MaybeCreateExprWithCleanups(RetValExp); } + ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, + NRVOCandidate); // If we need to check for the named return value optimization, save the // return statement in our scope for later processing. @@ -1883,7 +1994,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { /// isOperandMentioned - Return true if the specified operand # is mentioned /// anywhere in the decomposed asm string. static bool isOperandMentioned(unsigned OpNo, - llvm::ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { + ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; if (!Piece.isOperand()) continue; @@ -1910,25 +2021,25 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, StringLiteral *AsmString = cast<StringLiteral>(asmString); StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get()); - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. - if (AsmString->isWide()) + if (!AsmString->isAscii()) return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) << AsmString->getSourceRange()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef OutputName; + StringRef OutputName; if (Names[i]) OutputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); - if (!Context.Target.validateOutputConstraint(Info)) + if (!Context.getTargetInfo().validateOutputConstraint(Info)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); @@ -1944,20 +2055,20 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, OutputConstraintInfos.push_back(Info); } - llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; + SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef InputName; + StringRef InputName; if (Names[i]) InputName = Names[i]->getName(); TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); - if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(), + if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), NumOutputs, Info)) { return StmtError(Diag(Literal->getLocStart(), diag::err_asm_invalid_input_constraint) @@ -1995,13 +2106,13 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; - if (Literal->isWide()) + if (!Literal->isAscii()) return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) << Literal->getSourceRange()); - llvm::StringRef Clobber = Literal->getString(); + StringRef Clobber = Literal->getString(); - if (!Context.Target.isValidClobber(Clobber)) + if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); } @@ -2012,7 +2123,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, AsmString, NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. - llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; + SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; unsigned DiagOffs; if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) @@ -2033,6 +2144,10 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, unsigned InputOpNo = i+NumOutputs; Expr *OutputExpr = Exprs[TiedTo]; Expr *InputExpr = Exprs[InputOpNo]; + + if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) + continue; + QualType InTy = InputExpr->getType(); QualType OutTy = OutputExpr->getType(); if (Context.hasSameType(InTy, OutTy)) @@ -2154,6 +2269,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { if (Throw) { + Throw = MaybeCreateExprWithCleanups(Throw); ExprResult Result = DefaultLvalueConversion(Throw); if (Result.isInvalid()) return StmtError(); @@ -2188,29 +2304,36 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); } - + return BuildObjCAtThrowStmt(AtLoc, Throw); } -StmtResult -Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, - Stmt *SyncBody) { - getCurFunction()->setHasBranchProtectedScope(); - - ExprResult Result = DefaultLvalueConversion(SyncExpr); - if (Result.isInvalid()) - return StmtError(); +ExprResult +Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) { + ExprResult result = DefaultLvalueConversion(operand); + if (result.isInvalid()) + return ExprError(); + operand = result.take(); - SyncExpr = Result.take(); // Make sure the expression type is an ObjC pointer or "void *". - if (!SyncExpr->getType()->isDependentType() && - !SyncExpr->getType()->isObjCObjectPointerType()) { - const PointerType *PT = SyncExpr->getType()->getAs<PointerType>(); - if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) - << SyncExpr->getType() << SyncExpr->getSourceRange()); + QualType type = operand->getType(); + if (!type->isDependentType() && + !type->isObjCObjectPointerType()) { + const PointerType *pointerType = type->getAs<PointerType>(); + if (!pointerType || !pointerType->getPointeeType()->isVoidType()) + return Diag(atLoc, diag::error_objc_synchronized_expects_object) + << type << operand->getSourceRange(); } + // The operand to @synchronized is a full-expression. + return MaybeCreateExprWithCleanups(operand); +} + +StmtResult +Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, + Stmt *SyncBody) { + // We can't jump into or indirect-jump out of a @synchronized block. + getCurFunction()->setHasBranchProtectedScope(); return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody)); } @@ -2278,10 +2401,10 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, "The parser shouldn't call this if there are no handlers."); Stmt **Handlers = RawHandlers.get(); - llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers; + SmallVector<TypeWithHandler, 8> TypesWithHandlers; for (unsigned i = 0; i < NumHandlers; ++i) { - CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]); + CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]); if (!Handler->getExceptionDecl()) { if (i < NumHandlers - 1) return StmtError(Diag(Handler->getLocStart(), diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index 3ac190e..8dda34c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -344,10 +344,12 @@ void Sema::LookupTemplateName(LookupResult &Found, if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise - } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>()) { + } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() || + FoundOuter.isAmbiguous()) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise + FoundOuter.clear(); } else if (!Found.isSuppressingDiagnostics()) { // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, @@ -422,7 +424,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); // Microsoft Visual C++ permits template parameters to be shadowed. - if (getLangOptions().Microsoft) + if (getLangOptions().MicrosoftExt) return false; // C++ [temp.local]p4: @@ -712,7 +714,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, /// has been parsed. S is the current scope. Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, SourceLocation TmpLoc, - TemplateParamsTy *Params, + TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *Name, SourceLocation NameLoc, @@ -783,7 +785,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, /// ActOnTemplateParameterList - Builds a TemplateParameterList that /// contains the template parameters in Params/NumParams. -Sema::TemplateParamsTy * +TemplateParameterList * Sema::ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, @@ -809,7 +811,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, - AccessSpecifier AS, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList** OuterTemplateParamLists) { assert(TemplateParams && TemplateParams->size() > 0 && @@ -844,6 +846,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RequireCompleteDeclContext(SS, SemanticContext)) return true; + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, + // now that we know what the current instantiation is. + if (SemanticContext->isDependentContext()) { + ContextRAII SavedContext(*this, SemanticContext); + if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) + Invalid = true; + } + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; @@ -943,7 +954,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // definition, as part of error recovery? return true; } - } + } } else if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); @@ -997,7 +1008,17 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclarationName(Name), TemplateParams, NewClass, PrevClassTemplate); NewClass->setDescribedClassTemplate(NewTemplate); - + + if (PrevClassTemplate && PrevClassTemplate->isModulePrivate()) { + NewTemplate->setModulePrivate(); + } else if (ModulePrivateLoc.isValid()) { + if (PrevClassTemplate && !PrevClassTemplate->isModulePrivate()) + diagnoseModulePrivateRedeclaration(NewTemplate, PrevClassTemplate, + ModulePrivateLoc); + else + NewTemplate->setModulePrivate(); + } + // Build the type for the class template declaration now. QualType T = NewTemplate->getInjectedClassNameSpecialization(); T = Context.getInjectedClassNameType(NewClass, T); @@ -1519,7 +1540,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // The sequence of nested types to which we will match up the template // parameter lists. We first build this list by starting with the type named // by the nested-name-specifier and walking out until we run out of types. - llvm::SmallVector<QualType, 4> NestedTypes; + SmallVector<QualType, 4> NestedTypes; QualType T; if (SS.getScopeRep()) { if (CXXRecordDecl *Record @@ -1888,7 +1909,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, Converted)) return QualType(); @@ -1995,7 +2016,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), - ClassTemplate->getLocation(), + ClassTemplate->getTemplatedDecl()->getLocStart(), ClassTemplate->getLocation(), ClassTemplate, Converted.data(), @@ -2129,7 +2150,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) - return TypeResult(); + return TypeResult(true); // Check the tag kind if (const RecordType *RT = Result->getAs<RecordType>()) { @@ -2311,7 +2332,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, return TNK_Dependent_template_name; case UnqualifiedId::IK_LiteralOperatorId: - assert(false && "We don't support these; Parse shouldn't have allowed propagation"); + llvm_unreachable( + "We don't support these; Parse shouldn't have allowed propagation"); default: break; @@ -2327,7 +2349,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgumentLoc &AL, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. @@ -2408,7 +2430,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based @@ -2461,7 +2483,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2507,7 +2529,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted, + SmallVectorImpl<TemplateArgument> &Converted, NestedNameSpecifierLoc &QualifierLoc) { TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2543,7 +2565,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { if (!TypeParm->hasDefaultArgument()) return TemplateArgumentLoc(); @@ -2629,7 +2651,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, - llvm::SmallVectorImpl<TemplateArgument> &Converted, + SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) @@ -2669,8 +2691,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - return true; + llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Expression: { TemplateArgument Result; @@ -2792,8 +2813,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - return true; + llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: @@ -2834,7 +2854,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + SmallVectorImpl<TemplateArgument> &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); unsigned NumArgs = TemplateArgs.size(); @@ -2871,7 +2891,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // corresponding parameter declared by the template in its // template-parameter-list. bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); - llvm::SmallVector<TemplateArgument, 2> ArgumentPack; + SmallVector<TemplateArgument, 2> ArgumentPack; TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); unsigned ArgIdx = 0; @@ -3235,6 +3255,10 @@ bool UnnamedLocalNoLinkageFinder::VisitObjCObjectPointerType( return false; } +bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) { + return Visit(T->getValueType()); +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) @@ -3358,7 +3382,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } } - if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) { + if (S.getLangOptions().MicrosoftExt && isa<CXXUuidofExpr>(Arg)) { Converted = TemplateArgument(ArgIn); return false; } @@ -3820,8 +3844,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } Converted = TemplateArgument(Value, - ParamType->isEnumeralType() ? ParamType - : IntegerType); + ParamType->isEnumeralType() + ? Context.getCanonicalType(ParamType) + : IntegerType); return Owned(Arg); } @@ -3892,7 +3917,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, bool ObjCLifetimeConversion; if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), false, ObjCLifetimeConversion)) { - Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, + Arg->getValueKind()).take(); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { // We can't perform this conversion. @@ -3963,7 +3989,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Types match exactly: nothing more to do here. } else if (IsQualificationConversion(ArgType, ParamType, false, ObjCLifetimeConversion)) { - Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, + Arg->getValueKind()).take(); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -4131,10 +4158,22 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, assert(Arg.getKind() == TemplateArgument::Integral && "Operation is only valid for integral template arguments"); QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) + if (T->isAnyCharacterType()) { + CharacterLiteral::CharacterKind Kind; + if (T->isWideCharType()) + Kind = CharacterLiteral::Wide; + else if (T->isChar16Type()) + Kind = CharacterLiteral::UTF16; + else if (T->isChar32Type()) + Kind = CharacterLiteral::UTF32; + else + Kind = CharacterLiteral::Ascii; + return Owned(new (Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), T, Loc)); + Arg.getAsIntegral()->getZExtValue(), + Kind, T, Loc)); + } + if (T->isBooleanType()) return Owned(new (Context) CXXBoolLiteralExpr( Arg.getAsIntegral()->getBoolValue(), @@ -4496,9 +4535,18 @@ static bool CheckTemplateSpecializationScope(Sema &S, } if (S.CurContext->isRecord() && !IsPartialSpecialization) { - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; + if (S.getLangOptions().MicrosoftExt) { + // Do not warn for class scope explicit specialization during + // instantiation, warning was already emitted during pattern + // semantic analysis. + if (!S.ActiveTemplateInstantiations.size()) + S.Diag(Loc, diag::ext_function_specialization_in_class) + << Specialized; + } else { + S.Diag(Loc, diag::err_template_spec_decl_class_scope) + << Specialized; + return true; + } } // C++ [temp.class.spec]p6: @@ -4653,7 +4701,7 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, /// \returns true if there was an error, false otherwise. static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, TemplateParameterList *TemplateParams, - llvm::SmallVectorImpl<TemplateArgument> &TemplateArgs) { + SmallVectorImpl<TemplateArgument> &TemplateArgs) { const TemplateArgument *ArgList = TemplateArgs.data(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -4691,6 +4739,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, @@ -4821,7 +4870,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; @@ -4907,14 +4956,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // -- The argument list of the specialization shall not be identical // to the implicit argument list of the primary template. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) - << (TUK == TUK_Definition) - << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); + << (TUK == TUK_Definition) + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, Attr, TemplateParams, - AS_none, + AS_none, /*ModulePrivateLoc=*/SourceLocation(), TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); } @@ -4956,7 +5005,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // partial specialization are deducible from the template // arguments. If not, this class template partial specialization // will never be used. - llvm::SmallVector<bool, 8> DeducibleParams; + SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, TemplateParams->getDepth(), @@ -5056,6 +5105,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); + if (ModulePrivateLoc.isValid()) + Diag(Specialization->getLocation(), diag::err_module_private_specialization) + << (isPartialSpecialization? 1 : 0) + << FixItHint::CreateRemoval(ModulePrivateLoc); + // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -5105,7 +5159,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Decl *Sema::ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { - return HandleDeclarator(S, D, move(TemplateParameterLists), false); + return HandleDeclarator(S, D, move(TemplateParameterLists)); } Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, @@ -5120,9 +5174,9 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, Scope *ParentScope = FnBodyScope->getParent(); + D.setFunctionDefinition(true); Decl *DP = HandleDeclarator(ParentScope, D, - move(TemplateParameterLists), - /*IsFunctionDefinition=*/true); + move(TemplateParameterLists)); if (FunctionTemplateDecl *FunctionTemplate = dyn_cast_or_null<FunctionTemplateDecl>(DP)) return ActOnStartOfFunctionDef(FnBodyScope, @@ -5176,8 +5230,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, switch (NewTSK) { case TSK_Undeclared: case TSK_ImplicitInstantiation: - assert(false && "Don't check implicit instantiations here"); - return false; + llvm_unreachable("Don't check implicit instantiations here"); case TSK_ExplicitSpecialization: switch (PrevTSK) { @@ -5309,9 +5362,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, break; } - assert(false && "Missing specialization/instantiation case?"); - - return false; + llvm_unreachable("Missing specialization/instantiation case?"); } /// \brief Perform semantic analysis for the given dependent function @@ -5482,12 +5533,10 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Take copies of (semantic and syntactic) template argument lists. const TemplateArgumentList* TemplArgs = new (Context) TemplateArgumentList(Specialization->getTemplateSpecializationArgs()); - const TemplateArgumentListInfo* TemplArgsAsWritten = ExplicitTemplateArgs - ? new (Context) TemplateArgumentListInfo(*ExplicitTemplateArgs) : 0; FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/0, SpecInfo->getTemplateSpecializationKind(), - TemplArgsAsWritten); + ExplicitTemplateArgs); FD->setStorageClass(Specialization->getStorageClass()); // The "previous declaration" for this function template specialization is @@ -5793,7 +5842,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, false, Converted)) return true; @@ -5949,6 +5998,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, bool IsDependent = false; Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none, + /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(*this, 0, 0), Owned, IsDependent, false, false, TypeResult()); @@ -6114,9 +6164,12 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - <<FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - - // FIXME: check for constexpr specifier. + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + if (D.getDeclSpec().isConstexprSpecified()) + // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is + // not already specified. + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_explicit_instantiation_constexpr); // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation @@ -6658,6 +6711,45 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { return false; } +/// \brief Rebuild the template parameters now that we know we're in a current +/// instantiation. +bool Sema::RebuildTemplateParamsInCurrentInstantiation( + TemplateParameterList *Params) { + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + Decl *Param = Params->getParam(I); + + // There is nothing to rebuild in a type parameter. + if (isa<TemplateTypeParmDecl>(Param)) + continue; + + // Rebuild the template parameter list of a template template parameter. + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Param)) { + if (RebuildTemplateParamsInCurrentInstantiation( + TTP->getTemplateParameters())) + return true; + + continue; + } + + // Rebuild the type of a non-type template parameter. + NonTypeTemplateParmDecl *NTTP = cast<NonTypeTemplateParmDecl>(Param); + TypeSourceInfo *NewTSI + = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), + NTTP->getLocation(), + NTTP->getDeclName()); + if (!NewTSI) + return true; + + if (NewTSI != NTTP->getTypeSourceInfo()) { + NTTP->setTypeSourceInfo(NewTSI); + NTTP->setType(NewTSI->getType()); + } + } + + return false; +} + /// \brief Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string @@ -6692,7 +6784,7 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } Out << " = "; - Args[I].print(Context.PrintingPolicy, Out); + Args[I].print(getPrintingPolicy(), Out); } Out << ']'; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index dcb4ff2..93ea89d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -85,7 +85,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, TemplateArgument Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced); + SmallVectorImpl<DeducedTemplateArgument> &Deduced); /// \brief Whether template argument deduction for two reference parameters /// resulted in the argument type, parameter type, or neither type being more @@ -117,10 +117,10 @@ DeduceTemplateArguments(Sema &S, QualType Param, QualType Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering = false, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + SmallVectorImpl<RefParamPartialOrderingComparison> * RefParamComparisons = 0); static Sema::TemplateDeductionResult @@ -129,7 +129,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch = true); /// \brief If the given expression is of a form that permits the deduction @@ -288,7 +288,7 @@ DeduceNonTypeTemplateArgument(Sema &S, llvm::APSInt Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -316,7 +316,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Expr *Value, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && @@ -347,7 +347,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Decl *D, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -372,7 +372,7 @@ DeduceTemplateArguments(Sema &S, TemplateName Param, TemplateName Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -431,7 +431,7 @@ DeduceTemplateArguments(Sema &S, const TemplateSpecializationType *Param, QualType Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. @@ -546,11 +546,11 @@ static TemplateParameter makeTemplateParameter(Decl *D) { /// \brief Prepare to perform template argument deduction for all of the /// arguments in a set of argument packs. static void PrepareArgumentPackDeduction(Sema &S, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - const llvm::SmallVectorImpl<unsigned> &PackIndices, - llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, - llvm::SmallVectorImpl< - llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const SmallVectorImpl<unsigned> &PackIndices, + SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + SmallVectorImpl< + SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks) { // Save the deduced template arguments for each parameter pack expanded // by this pack expansion, then clear out the deduction. for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { @@ -581,11 +581,11 @@ static Sema::TemplateDeductionResult FinishArgumentPackDeduction(Sema &S, TemplateParameterList *TemplateParams, bool HasAnyArguments, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - const llvm::SmallVectorImpl<unsigned> &PackIndices, - llvm::SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, - llvm::SmallVectorImpl< - llvm::SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + const SmallVectorImpl<unsigned> &PackIndices, + SmallVectorImpl<DeducedTemplateArgument> &SavedPacks, + SmallVectorImpl< + SmallVector<DeducedTemplateArgument, 4> > &NewlyDeducedPacks, TemplateDeductionInfo &Info) { // Build argument packs for each of the parameter packs expanded by this // pack expansion. @@ -668,10 +668,10 @@ DeduceTemplateArguments(Sema &S, const QualType *Params, unsigned NumParams, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering = false, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> * + SmallVectorImpl<RefParamPartialOrderingComparison> * RefParamComparisons = 0) { // Fast-path check to see if we have too many/too few arguments. if (NumParams != NumArgs && @@ -733,11 +733,11 @@ DeduceTemplateArguments(Sema &S, // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; QualType Pattern = Expansion->getPattern(); { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -753,9 +753,9 @@ DeduceTemplateArguments(Sema &S, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -862,10 +862,10 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { + SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. QualType Param = S.Context.getCanonicalType(ParamIn); @@ -977,6 +977,10 @@ DeduceTemplateArguments(Sema &S, // cv-list T if (const TemplateTypeParmType *TemplateTypeParm = Param->getAs<TemplateTypeParmType>()) { + // Just skip any attempts to deduce from a placeholder type. + if (Arg->isPlaceholderType()) + return Sema::TDK_Success; + unsigned Index = TemplateTypeParm->getIndex(); bool RecanonicalizeArg = false; @@ -1018,6 +1022,17 @@ DeduceTemplateArguments(Sema &S, DeducedQs.removeObjCLifetime(); // Objective-C ARC: + // If template deduction would produce a lifetime qualifier on a type + // that is not a lifetime type, template argument deduction fails. + if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() && + !DeducedType->isDependentType()) { + Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); + return Sema::TDK_Underqualified; + } + + // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. if (S.getLangOptions().ObjCAutoRefCount && @@ -1101,7 +1116,17 @@ DeduceTemplateArguments(Sema &S, Info, Deduced, TDF); return Sema::TDK_NonDeducedMismatch; - + + // _Atomic T [extension] + case Type::Atomic: + if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>()) + return DeduceTemplateArguments(S, TemplateParams, + cast<AtomicType>(Param)->getValueType(), + AtomicArg->getValueType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; + // T * case Type::Pointer: { QualType PointeeType; @@ -1306,10 +1331,10 @@ DeduceTemplateArguments(Sema &S, // Visited contains the set of nodes we have already visited, while // ToVisit is our stack of records that we still need to visit. llvm::SmallPtrSet<const RecordType *, 8> Visited; - llvm::SmallVector<const RecordType *, 8> ToVisit; + SmallVector<const RecordType *, 8> ToVisit; ToVisit.push_back(RecordT); bool Successful = false; - llvm::SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0); + SmallVectorImpl<DeducedTemplateArgument> DeducedOrig(0); DeducedOrig = Deduced; while (!ToVisit.empty()) { // Retrieve the next class in the inheritance hierarchy. @@ -1515,7 +1540,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, TemplateArgument Arg, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { // If the template argument is a pack expansion, perform template argument // deduction against the pattern of that expansion. This only occurs during // partial ordering. @@ -1524,8 +1549,7 @@ DeduceTemplateArguments(Sema &S, switch (Param.getKind()) { case TemplateArgument::Null: - assert(false && "Null template argument in parameter list"); - break; + llvm_unreachable("Null template argument in parameter list"); case TemplateArgument::Type: if (Arg.getKind() == TemplateArgument::Type) @@ -1667,7 +1691,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch) { // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not @@ -1720,10 +1744,10 @@ DeduceTemplateArguments(Sema &S, // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -1742,9 +1766,9 @@ DeduceTemplateArguments(Sema &S, // Save the deduced template arguments for each parameter pack expanded // by this pack expansion, then clear out the deduction. - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -1799,7 +1823,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { return DeduceTemplateArguments(S, TemplateParams, ParamList.data(), ParamList.size(), ArgList.data(), ArgList.size(), @@ -1815,8 +1839,7 @@ static bool isSameTemplateArg(ASTContext &Context, switch (X.getKind()) { case TemplateArgument::Null: - assert(false && "Comparing NULL template argument"); - break; + llvm_unreachable("Comparing NULL template argument"); case TemplateArgument::Type: return Context.getCanonicalType(X.getAsType()) == @@ -1940,11 +1963,11 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, unsigned ArgumentPackIndex, TemplateDeductionInfo &Info, bool InFunctionTemplate, - llvm::SmallVectorImpl<TemplateArgument> &Output) { + SmallVectorImpl<TemplateArgument> &Output) { if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. - llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder; + SmallVector<TemplateArgument, 2> PackedArgsBuilder; for (TemplateArgument::pack_iterator PA = Arg.pack_begin(), PAEnd = Arg.pack_end(); PA != PAEnd; ++PA) { @@ -1996,7 +2019,7 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(Sema &S, ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info) { // Trap errors. Sema::SFINAETrap Trap(S); @@ -2006,7 +2029,7 @@ FinishTemplateArgumentDeduction(Sema &S, // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; TemplateParameterList *PartialParams = Partial->getTemplateParameters(); for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { NamedDecl *Param = PartialParams->getParam(I); @@ -2089,7 +2112,7 @@ FinishTemplateArgumentDeduction(Sema &S, return Sema::TDK_SubstitutionFailure; } - llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs; + SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), InstArgs, false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; @@ -2125,7 +2148,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // specialization can be deduced from the actual template argument // list (14.8.2). SFINAETrap Trap(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, @@ -2183,8 +2206,8 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, - llvm::SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info) { FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); @@ -2214,7 +2237,7 @@ Sema::SubstituteExplicitTemplateArguments( // declaration order of their corresponding template-parameters. The // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -2420,11 +2443,11 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, /// which the deduced argument types should be compared. Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, - llvm::SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) { + SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -2446,7 +2469,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - llvm::SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> Builder; for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NamedDecl *Param = TemplateParams->getParam(I); @@ -2566,7 +2589,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Specialization = cast_or_null<FunctionDecl>( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, MultiLevelTemplateArgumentList(*DeducedArgumentList))); - if (!Specialization) + if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == @@ -2578,6 +2601,14 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, !Trap.hasErrorOccurred()) Info.take(); + // There may have been an error that did not prevent us from constructing a + // declaration. Mark the declaration invalid and return with a substitution + // failure. + if (Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return TDK_SubstitutionFailure; + } + if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument @@ -2596,20 +2627,12 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } } - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; - } - // If we suppressed any diagnostics while performing template argument // deduction, and if we haven't already instantiated this declaration, // keep track of these diagnostics. They'll be emitted if this specialization // is actually used. if (Info.diag_begin() != Info.diag_end()) { - llvm::DenseMap<Decl *, llvm::SmallVector<PartialDiagnosticAt, 1> >::iterator + llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> >::iterator Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl()); if (Pos == SuppressedDiagnostics.end()) SuppressedDiagnostics[Specialization->getCanonicalDecl()] @@ -2710,7 +2733,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector<DeducedTemplateArgument, 8> + SmallVector<DeducedTemplateArgument, 8> Deduced(TemplateParams->size()); TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); Sema::TemplateDeductionResult Result @@ -2900,8 +2923,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, LocalInstantiationScope InstScope(*this); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; - llvm::SmallVector<QualType, 4> ParamTypes; + SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<QualType, 4> ParamTypes; unsigned NumExplicitlySpecified = 0; if (ExplicitTemplateArgs) { TemplateDeductionResult Result = @@ -2924,7 +2947,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); unsigned ArgIdx = 0; - llvm::SmallVector<OriginalCallArg, 4> OriginalCallArgs; + SmallVector<OriginalCallArg, 4> OriginalCallArgs; for (unsigned ParamIdx = 0, NumParams = ParamTypes.size(); ParamIdx != NumParams; ++ParamIdx) { QualType OrigParamType = ParamTypes[ParamIdx]; @@ -2946,16 +2969,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TDF)) continue; + // If we have nothing to deduce, we're done. + if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) + continue; + // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. - if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, - ArgType)); + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, + ArgType)); if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, TemplateParams, - ParamType, ArgType, Info, Deduced, - TDF)) + = ::DeduceTemplateArguments(*this, TemplateParams, + ParamType, ArgType, Info, Deduced, + TDF)) return Result; continue; @@ -2974,10 +3000,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, break; QualType ParamPattern = ParamExpansion->getPattern(); - llvm::SmallVector<unsigned, 2> PackIndices; + SmallVector<unsigned, 2> PackIndices; { llvm::BitVector SawIndices(TemplateParams->size()); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(ParamPattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; @@ -2993,9 +3019,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2> NewlyDeducedPacks(PackIndices.size()); - llvm::SmallVector<DeducedTemplateArgument, 2> + SmallVector<DeducedTemplateArgument, 2> SavedPacks(PackIndices.size()); PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks, NewlyDeducedPacks); @@ -3095,9 +3121,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; unsigned NumExplicitlySpecified = 0; - llvm::SmallVector<QualType, 4> ParamTypes; + SmallVector<QualType, 4> ParamTypes; if (ExplicitTemplateArgs) { if (TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, @@ -3205,7 +3231,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // A) as described in 14.8.2.4. TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.conv]p4: @@ -3226,7 +3252,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // both P and A are pointers or member pointers. In this case, we // just ignore cv-qualifiers completely). if ((P->isPointerType() && A->isPointerType()) || - (P->isMemberPointerType() && P->isMemberPointerType())) + (P->isMemberPointerType() && A->isMemberPointerType())) TDF |= TDF_IgnoreQualifiers; if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, TemplateParams, @@ -3342,7 +3368,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init, QualType FuncParam = FuncParamInfo->getType(); // Deduce type of TemplParam in Func(Init) - llvm::SmallVector<DeducedTemplateArgument, 1> Deduced; + SmallVector<DeducedTemplateArgument, 1> Deduced; Deduced.resize(1); QualType InitType = Init->getType(); unsigned TDF = 0; @@ -3380,12 +3406,12 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, unsigned Level, - llvm::SmallVectorImpl<bool> &Deduced); + SmallVectorImpl<bool> &Deduced); /// \brief If this is a non-static member function, static void MaybeAddImplicitObjectParameterType(ASTContext &Context, CXXMethodDecl *Method, - llvm::SmallVectorImpl<QualType> &ArgTypes) { + SmallVectorImpl<QualType> &ArgTypes) { if (Method->isStatic()) return; @@ -3414,7 +3440,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, - llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { + SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) { FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); @@ -3422,7 +3448,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, assert(Proto1 && Proto2 && "Function templates must have prototypes"); TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.partial]p3: @@ -3454,7 +3480,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // C++98/03 doesn't have this provision, so instead we drop the // first argument of the free function or static member, which // seems to match existing practice. - llvm::SmallVector<QualType, 4> Args1; + SmallVector<QualType, 4> Args1; unsigned Skip1 = !S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1; if (S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) @@ -3462,7 +3488,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.insert(Args1.end(), Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); - llvm::SmallVector<QualType, 4> Args2; + SmallVector<QualType, 4> Args2; Skip2 = !S.getLangOptions().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2; if (S.getLangOptions().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) @@ -3524,7 +3550,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, } // Figure out which template parameters were used. - llvm::SmallVector<bool, 4> UsedParameters; + SmallVector<bool, 4> UsedParameters; UsedParameters.resize(TemplateParams->size()); switch (TPOC) { case TPOC_Call: { @@ -3605,7 +3631,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments) { - llvm::SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons; + SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons; bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments, 0); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, @@ -3853,7 +3879,7 @@ Sema::getMoreSpecializedPartialSpecialization( // know that every template parameter is deducible from the class // template partial specialization's template arguments, for // example. - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + SmallVector<DeducedTemplateArgument, 4> Deduced; TemplateDeductionInfo Info(Context, Loc); QualType PT1 = PS1->getInjectedSpecializationType(); @@ -3899,7 +3925,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used); + SmallVectorImpl<bool> &Used); /// \brief Mark the template parameters that are used by the given /// expression. @@ -3908,7 +3934,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const Expr *E, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { // We can deduce from a pack expansion. if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); @@ -3939,7 +3965,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, NestedNameSpecifier *NNS, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (!NNS) return; @@ -3956,7 +3982,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, TemplateName Name, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) { @@ -3980,7 +4006,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { if (T.isNull()) return; @@ -4113,6 +4139,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::Atomic: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<AtomicType>(T)->getValueType(), + OnlyDeduced, Depth, Used); + break; + case Type::DependentName: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, @@ -4206,7 +4239,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: @@ -4251,7 +4284,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, - llvm::SmallVectorImpl<bool> &Used) { + SmallVectorImpl<bool> &Used) { // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a @@ -4269,7 +4302,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, /// call to the given function template. void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl<bool> &Deduced) { + SmallVectorImpl<bool> &Deduced) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); @@ -4289,7 +4322,7 @@ bool hasDeducibleTemplateParameters(Sema &S, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector<bool, 4> Deduced; + SmallVector<bool, 4> Deduced; Deduced.resize(TemplateParams->size()); ::MarkUsedTemplateParameters(S, T, true, TemplateParams->getDepth(), Deduced); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index 1988f14..301bf6a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -98,8 +98,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { if (!RelativeToPrimary && - Function->getTemplateSpecializationKind() - == TSK_ExplicitSpecialization) + (Function->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization && + !Function->getClassScopeSpecializationPattern())) break; if (const TemplateArgumentList *TemplateArgs @@ -428,7 +429,7 @@ void Sema::PrintInstantiationStack() { // FIXME: In all of these cases, we need to show the template arguments unsigned InstantiationIdx = 0; - for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator + for (SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; @@ -483,7 +484,7 @@ void Sema::PrintInstantiationStack() { = TemplateSpecializationType::PrintTemplateArgumentList( Active->TemplateArgs, Active->NumTemplateArgs, - Context.PrintingPolicy); + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << (Template->getNameAsString() + TemplateArgsStr) @@ -537,7 +538,7 @@ void Sema::PrintInstantiationStack() { = TemplateSpecializationType::PrintTemplateArgumentList( Active->TemplateArgs, Active->NumTemplateArgs, - Context.PrintingPolicy); + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << (FD->getNameAsString() + TemplateArgsStr) @@ -591,7 +592,6 @@ void Sema::PrintInstantiationStack() { } llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { - using llvm::SmallVector; if (InNonInstantiationSFINAEContext) return llvm::Optional<TemplateDeductionInfo *>(0); @@ -681,14 +681,12 @@ namespace { bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, llvm::Optional<unsigned> &NumExpansions) { return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, - NumUnexpanded, TemplateArgs, ShouldExpand, RetainExpansion, @@ -1535,8 +1533,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, bool Sema::SubstParmTypes(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<QualType> &ParamTypes, - llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) { + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -1558,7 +1556,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { bool Invalid = false; - llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; + SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; for (ClassTemplateSpecializationDecl::base_class_iterator Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { @@ -1572,7 +1570,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, if (Base->isPackExpansion()) { // This is a pack expansion. See whether we should expand it now, or // wait until later. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(), Unexpanded); bool ShouldExpand = false; @@ -1580,7 +1578,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, llvm::Optional<unsigned> NumExpansions; if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(), Base->getSourceRange(), - Unexpanded.data(), Unexpanded.size(), + Unexpanded, TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -1755,8 +1753,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Invalid = true; TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); - llvm::SmallVector<Decl*, 4> Fields; - llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> + SmallVector<Decl*, 4> Fields; + SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> FieldsWithMemberInitializers; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); @@ -1796,9 +1794,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, } // Finish checking fields. - ActOnFields(0, Instantiation->getLocation(), Instantiation, - Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), - 0); + ActOnFields(0, Instantiation->getLocation(), Instantiation, Fields, + SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Instantiation); // Attach any in-class member initializers now the class is complete. @@ -1806,39 +1803,24 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, FieldDecl *OldField = FieldsWithMemberInitializers[I].first; FieldDecl *NewField = FieldsWithMemberInitializers[I].second; Expr *OldInit = OldField->getInClassInitializer(); - ExprResult NewInit = SubstExpr(OldInit, TemplateArgs); - - // If the initialization is no longer dependent, check it now. - if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent() || - OldInit->isValueDependent()) && - !NewField->getType()->isDependentType() && - !NewInit.get()->isTypeDependent() && - !NewInit.get()->isValueDependent()) { - // FIXME: handle list-initialization - SourceLocation EqualLoc = NewField->getLocation(); - NewInit = PerformCopyInitialization( - InitializedEntity::InitializeMember(NewField), EqualLoc, - NewInit.release()); - - if (!NewInit.isInvalid()) { - CheckImplicitConversions(NewInit.get(), EqualLoc); - - // C++0x [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - NewInit = MaybeCreateExprWithCleanups(NewInit); - } - } - if (NewInit.isInvalid()) + SourceLocation LParenLoc, RParenLoc; + ASTOwningVector<Expr*> NewArgs(*this); + if (InstantiateInitializer(OldInit, TemplateArgs, LParenLoc, NewArgs, + RParenLoc)) NewField->setInvalidDecl(); - else - NewField->setInClassInitializer(NewInit.release()); + else { + assert(NewArgs.size() == 1 && "wrong number of in-class initializers"); + ActOnCXXInClassMemberInitializer(NewField, LParenLoc, NewArgs[0]); + } } if (!FieldsWithMemberInitializers.empty()) ActOnFinishDelayedMemberInitializers(Instantiation); + if (TSK == TSK_ImplicitInstantiation) + Instantiation->setRBraceLoc(Pattern->getRBraceLoc()); + if (Instantiation->isInvalidDecl()) Invalid = true; else { @@ -1931,8 +1913,8 @@ Sema::InstantiateClassTemplateSpecialization( // specialization with the template argument lists of the partial // specializations. typedef PartialSpecMatchResult MatchResult; - llvm::SmallVector<MatchResult, 4> Matched; - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + SmallVector<MatchResult, 4> Matched; + SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; Template->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; @@ -1954,10 +1936,10 @@ Sema::InstantiateClassTemplateSpecialization( // If we're dealing with a member template where the template parameters // have been instantiated, this provides the original template parameters // from which the member template's parameters were instantiated. - llvm::SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; if (Matched.size() >= 1) { - llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); + SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); if (Matched.size() == 1) { // -- If exactly one matching specialization is found, the // instantiation is generated from that specialization. @@ -1970,7 +1952,7 @@ Sema::InstantiateClassTemplateSpecialization( // specialized than all of the other matching // specializations, then the use of the class template is // ambiguous and the program is ill-formed. - for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, + for (SmallVector<MatchResult, 4>::iterator P = Best + 1, PEnd = Matched.end(); P != PEnd; ++P) { if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, @@ -1982,7 +1964,7 @@ Sema::InstantiateClassTemplateSpecialization( // Determine if the best partial specialization is more specialized than // the others. bool Ambiguous = false; - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); P != PEnd; ++P) { if (P != Best && @@ -2001,7 +1983,7 @@ Sema::InstantiateClassTemplateSpecialization( << ClassTemplateSpec; // Print the matching partial specializations. - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); P != PEnd; ++P) Diag(P->Partial->getLocation(), diag::note_partial_spec_match) @@ -2240,7 +2222,7 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<Expr *> &Outputs) { + SmallVectorImpl<Expr *> &Outputs) { if (NumExprs == 0) return false; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 29385e5..02a05d5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -29,14 +29,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, DeclaratorDecl *NewDecl) { if (!OldDecl->getQualifierLoc()) return false; - + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), TemplateArgs); - + if (!NewQualifierLoc) return true; - + NewDecl->setQualifierInfo(NewQualifierLoc); return false; } @@ -45,14 +45,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl) { if (!OldDecl->getQualifierLoc()) return false; - + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), TemplateArgs); - + if (!NewQualifierLoc) return true; - + NewDecl->setQualifierInfo(NewQualifierLoc); return false; } @@ -79,7 +79,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, else { TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(), TemplateArgs, - Aligned->getLocation(), + Aligned->getLocation(), DeclarationName()); if (Result) AddAlignedAttr(Aligned->getLocation(), New, Result); @@ -96,8 +96,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, Decl * TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - assert(false && "Translation units cannot be instantiated"); - return D; + llvm_unreachable("Translation units cannot be instantiated"); } Decl * @@ -110,8 +109,7 @@ TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { Decl * TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { - assert(false && "Namespaces cannot be instantiated"); - return D; + llvm_unreachable("Namespaces cannot be instantiated"); } Decl * @@ -165,13 +163,13 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, newTag->setTypedefNameForAnonDecl(Typedef); } } - + if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); if (!InstPrev) return 0; - + Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev)); } @@ -230,7 +228,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { if (!PrevAliasTemplate) Inst->setInstantiatedFromMemberTemplate(D); - + Owner->addDecl(Inst); return Inst; @@ -239,8 +237,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { /// \brief Instantiate an initializer, breaking it into separate /// initialization arguments. /// -/// \param S The semantic analysis object. -/// /// \param Init The initializer to instantiate. /// /// \param TemplateArgs Template arguments to be substituted into the @@ -249,11 +245,11 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { /// \param NewArgs Will be filled in with the instantiation arguments. /// /// \returns true if an error occurred, false otherwise -static bool InstantiateInitializer(Sema &S, Expr *Init, +bool Sema::InstantiateInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation &LParenLoc, - ASTOwningVector<Expr*> &NewArgs, - SourceLocation &RParenLoc) { + SourceLocation &LParenLoc, + ASTOwningVector<Expr*> &NewArgs, + SourceLocation &RParenLoc) { NewArgs.clear(); LParenLoc = SourceLocation(); RParenLoc = SourceLocation(); @@ -273,24 +269,24 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { LParenLoc = ParenList->getLParenLoc(); RParenLoc = ParenList->getRParenLoc(); - return S.SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), - true, TemplateArgs, NewArgs); + return SubstExprs(ParenList->getExprs(), ParenList->getNumExprs(), + true, TemplateArgs, NewArgs); } if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init)) { if (!isa<CXXTemporaryObjectExpr>(Construct)) { - if (S.SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, - TemplateArgs, NewArgs)) + if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, + TemplateArgs, NewArgs)) return true; // FIXME: Fake locations! - LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); + LParenLoc = PP.getLocForEndOfToken(Init->getLocStart()); RParenLoc = LParenLoc; return false; } } - - ExprResult Result = S.SubstExpr(Init, TemplateArgs); + + ExprResult Result = SubstExpr(Init, TemplateArgs); if (Result.isInvalid()) return true; @@ -319,7 +315,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { << D->isStaticDataMember() << DI->getType(); return 0; } - + // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), @@ -342,21 +338,20 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setAccess(D->getAccess()); - + if (!D->isStaticDataMember()) { Var->setUsed(D->isUsed(false)); Var->setReferenced(D->isReferenced()); } - + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. - bool Redeclaration = false; // FIXME: having to fake up a LookupResult is dumb. LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); if (D->isStaticDataMember()) SemaRef.LookupQualifiedName(Previous, Owner, false); - SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); + SemaRef.CheckVariableDeclaration(Var, Previous); if (D->isOutOfLine()) { if (!D->isStaticDataMember()) @@ -368,13 +363,13 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); } SemaRef.InstantiateAttrs(TemplateArgs, D, Var); - + // Link instantiations of static data members back to the template from // which they were instantiated. if (Var->isStaticDataMember()) - SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, + SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, TSK_ImplicitInstantiation); - + if (Var->getAnyInitializer()) { // We already have an initializer in the class. } else if (D->getInit()) { @@ -386,8 +381,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Instantiate the initializer. SourceLocation LParenLoc, RParenLoc; ASTOwningVector<Expr*> InitArgs(SemaRef); - if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc, - InitArgs, RParenLoc)) { + if (!SemaRef.InstantiateInitializer(D->getInit(), TemplateArgs, LParenLoc, + InitArgs, RParenLoc)) { bool TypeMayContainAuto = true; // Attach the initializer to the declaration, if we have one. if (InitArgs.size() == 0) @@ -409,7 +404,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // because of a bogus initializer. Var->setInvalidDecl(); } - + SemaRef.PopExpressionEvaluationContext(); } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && !Var->isCXXForRangeDecl()) @@ -489,14 +484,14 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } SemaRef.InstantiateAttrs(TemplateArgs, D, Field); - + if (Invalid) Field->setInvalidDecl(); if (!Field->getDeclName()) { // Keep track of where this decl came from. SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D); - } + } if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) { if (Parent->isAnonymousStructOrUnion() && Parent->getRedeclContext()->isFunctionOrMethod()) @@ -518,11 +513,11 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), PE = D->chain_end(); PI != PE; ++PI) { - NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI, + NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI, TemplateArgs); if (!Next) return 0; - + NamedChain[i++] = Next; } @@ -560,13 +555,13 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); if (!FD) return 0; - + FD->setAccess(AS_public); FD->setUnsupportedFriend(D->isUnsupportedFriend()); Owner->addDecl(FD); return FD; - } - + } + NamedDecl *ND = D->getFriendDecl(); assert(ND && "friend decl must be a decl or a type!"); @@ -578,7 +573,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { if (!NewND) return 0; FriendDecl *FD = - FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); FD->setUnsupportedFriend(D->isUnsupportedFriend()); @@ -620,7 +615,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { TemplateArgs, UnderlyingLoc, DeclarationName())); - + if (!Enum->getIntegerTypeSourceInfo()) Enum->setIntegerType(SemaRef.Context.IntTy); } @@ -641,8 +636,8 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { if (D->getDeclContext()->isFunctionOrMethod()) SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); - - llvm::SmallVector<Decl*, 4> Enumerators; + + SmallVector<Decl*, 4> Enumerators; EnumConstantDecl *LastEnumConst = 0; for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(), @@ -683,7 +678,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { Enum->addDecl(EnumConst); Enumerators.push_back(EnumConst); LastEnumConst = EnumConst; - + if (D->getDeclContext()->isFunctionOrMethod()) { // If the enumeration is within a function or method, record the enum // constant as a local. @@ -703,8 +698,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { - assert(false && "EnumConstantDecls can only occur within EnumDecls."); - return 0; + llvm_unreachable("EnumConstantDecls can only occur within EnumDecls."); } Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { @@ -789,7 +783,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // template parameters of the original declaration. In this one // case, we don't complain about the ill-formed friend // declaration. - if (isFriend && Pattern->getIdentifier() && + if (isFriend && Pattern->getIdentifier() && Pattern->getIdentifier()->isStr("_Map_base") && DC->isNamespace() && cast<NamespaceDecl>(DC)->getIdentifier() && @@ -812,7 +806,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Make sure the parameter lists match. if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, - Complain, + Complain, Sema::TPL_TemplateMatch)) { if (Complain) return 0; @@ -859,7 +853,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (!PrevClassTemplate) Inst->setInstantiatedFromMemberTemplate(D); } - + // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization()); @@ -869,14 +863,14 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } - + Owner->addDecl(Inst); if (!PrevClassTemplate) { // Queue up any out-of-line partial specializations of this member // class template; the client will force their instantiation once // the enclosing class has been instantiated. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; D->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) if (PartialSpecs[I]->isOutOfLine()) @@ -890,19 +884,19 @@ Decl * TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate(); - + // Lookup the already-instantiated declaration in the instantiation // of the class template and return that. DeclContext::lookup_result Found = Owner->lookup(ClassTemplate->getDeclName()); if (Found.first == Found.second) return 0; - + ClassTemplateDecl *InstClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first); if (!InstClassTemplate) return 0; - + if (ClassTemplatePartialSpecializationDecl *Result = InstClassTemplate->findPartialSpecInstantiatedFromMember(D)) return Result; @@ -914,7 +908,7 @@ Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Create a local instantiation scope for this function template, which // will contain the instantiations of the template parameters and then get - // merged with the local instantiation scope for the function template + // merged with the local instantiation scope for the function template // itself. LocalInstantiationScope Scope(SemaRef); @@ -922,16 +916,16 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - + FunctionDecl *Instantiated = 0; if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl())) - Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, + Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, InstParams)); else Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl( - D->getTemplatedDecl(), + D->getTemplatedDecl(), InstParams)); - + if (!Instantiated) return 0; @@ -939,10 +933,10 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Link the instantiated function template declaration to the function // template from which it was instantiated. - FunctionTemplateDecl *InstTemplate + FunctionTemplateDecl *InstTemplate = Instantiated->getDescribedFunctionTemplate(); InstTemplate->setAccess(D->getAccess()); - assert(InstTemplate && + assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None); @@ -952,7 +946,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!InstTemplate->getInstantiatedFromMemberTemplate() && !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); - + // Make declarations visible in the appropriate context. if (!isFriend) Owner->addDecl(InstTemplate); @@ -1018,7 +1012,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; if (FunctionTemplate && !TemplateParams) { - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); FunctionDecl *SpecFunc @@ -1038,11 +1032,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool MergeWithParentScope = (TemplateParams != 0) || Owner->isFunctionOrMethod() || - !(isa<Decl>(Owner) && + !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); - llvm::SmallVector<ParmVarDecl *, 4> Params; + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = D->getTypeSourceInfo(); TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1068,7 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, DC = SemaRef.computeDeclContext(SS); if (!DC) return 0; } else { - DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), + DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), TemplateArgs); } @@ -1076,7 +1070,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getLocation(), D->getDeclName(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), - D->isInlineSpecified(), D->hasWrittenPrototype()); + D->isInlineSpecified(), D->hasWrittenPrototype(), + /*isConstexpr*/ false); if (QualifierLoc) Function->setQualifierInfo(QualifierLoc); @@ -1110,7 +1105,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params.push_back(Param); } } - Function->setParams(Params.data(), Params.size()); + Function->setParams(Params); SourceLocation InstantiateAtPOI; if (TemplateParams) { @@ -1124,7 +1119,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // // X<int> x; // - // We are instantiating the friend function template "f" within X<int>, + // We are instantiating the friend function template "f" within X<int>, // which means substituting int for T, but leaving "f" as a friend function // template. // Build the function template itself. @@ -1144,25 +1139,28 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost.first, Innermost.second), InsertPos); - } else if (isFriend && D->isThisDeclarationADefinition()) { - // TODO: should we remember this connection regardless of whether - // the friend declaration provided a body? + } else if (isFriend) { + // Note, we need this connection even if the friend doesn't have a body. + // Its body may exist but not have been attached yet due to deferred + // parsing. + // FIXME: It might be cleaner to set this when attaching the body to the + // friend function declaration, however that would require finding all the + // instantiations and modifying them. Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - + if (InitFunctionInstantiation(Function, D)) Function->setInvalidDecl(); - bool Redeclaration = false; bool isExplicitSpecialization = false; - + LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); @@ -1194,15 +1192,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, &ExplicitArgs, Previous)) Function->setInvalidDecl(); - + isExplicitSpecialization = true; } else if (TemplateParams || !FunctionTemplate) { - // Look only into the namespace where the friend would be declared to - // find a previous declaration. This is the innermost enclosing namespace, + // Look only into the namespace where the friend would be declared to + // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. SemaRef.LookupQualifiedName(Previous, DC); - + // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a @@ -1210,9 +1208,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (Previous.isSingleTagDecl()) Previous.clear(); } - + SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - isExplicitSpecialization, Redeclaration); + isExplicitSpecialization); NamedDecl *PrincipalDecl = (TemplateParams ? cast<NamedDecl>(FunctionTemplate) @@ -1238,11 +1236,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, const FunctionDecl *Definition = 0; if (Function->isDefined(Definition) && Definition->getTemplateSpecializationKind() == TSK_Undeclared) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); - Function->setInvalidDecl(); - } + Function->setInvalidDecl(); + } // Check for redefinitions due to other instantiations of this or // a similar friend function. else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(), @@ -1269,7 +1267,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (const FunctionDecl *RPattern = R->getTemplateInstantiationPattern()) if (RPattern->isDefined(RPattern)) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) + SemaRef.Diag(Function->getLocation(), diag::err_redefinition) << Function->getDeclName(); SemaRef.Diag(R->getLocation(), diag::note_previous_definition); Function->setInvalidDecl(); @@ -1290,14 +1288,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Decl * TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams) { + TemplateParameterList *TemplateParams, + bool IsClassScopeSpecialization) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); void *InsertPos = 0; if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function // template. Check whether there is already a function template // specialization for this particular set of template arguments. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); FunctionDecl *SpecFunc @@ -1316,12 +1315,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, isFriend = (D->getFriendObjectKind() != Decl::FOK_None); bool MergeWithParentScope = (TemplateParams != 0) || - !(isa<Decl>(Owner) && + !(isa<Decl>(Owner) && cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); // Instantiate enclosing template arguments for friends. - llvm::SmallVector<TemplateParameterList *, 4> TempParamLists; + SmallVector<TemplateParameterList *, 4> TempParamLists; unsigned NumTempParamLists = 0; if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) { TempParamLists.set_size(NumTempParamLists); @@ -1334,7 +1333,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } } - llvm::SmallVector<ParmVarDecl *, 4> Params; + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = D->getTypeSourceInfo(); TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1352,18 +1351,18 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // synthesized in the method declaration. if (!isa<FunctionProtoType>(T.IgnoreParens())) { assert(!Params.size() && "Instantiating type could not yield parameters"); - llvm::SmallVector<QualType, 4> ParamTypes; - if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), - D->getNumParams(), TemplateArgs, ParamTypes, + SmallVector<QualType, 4> ParamTypes; + if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), + D->getNumParams(), TemplateArgs, ParamTypes, &Params)) - return 0; + return 0; } NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); - if (!QualifierLoc) + if (!QualifierLoc) return 0; } @@ -1396,7 +1395,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), - false); + false, /*isConstexpr*/ false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1407,6 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit(), + /*isConstexpr*/ false, Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, @@ -1414,7 +1414,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, D->isStatic(), D->getStorageClassAsWritten(), D->isInlineSpecified(), - D->getLocEnd()); + /*isConstexpr*/ false, D->getLocEnd()); } if (QualifierLoc) @@ -1446,7 +1446,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost + std::pair<const TemplateArgument *, unsigned> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, @@ -1457,7 +1457,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - + // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -1475,7 +1475,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Method); - Method->setParams(Params.data(), Params.size()); + Method->setParams(Params); if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); @@ -1494,8 +1494,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Previous.clear(); } - bool Redeclaration = false; - SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration); + if (!IsClassScopeSpecialization) + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -1514,7 +1514,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, : Method); if (isFriend) Record->makeDeclVisibleInContext(DeclToAdd); - else + else if (!IsClassScopeSpecialization) Owner->addDecl(DeclToAdd); } @@ -1558,14 +1558,14 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->wasDeclaredWithTypename(), D->isParameterPack()); Inst->setAccess(AS_public); - + if (D->hasDefaultArgument()) - Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); + Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); - // Introduce this template parameter's instantiation into the instantiation + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); - + return Inst; } @@ -1573,26 +1573,26 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc(); - llvm::SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; - llvm::SmallVector<QualType, 4> ExpandedParameterPackTypes; + SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; + SmallVector<QualType, 4> ExpandedParameterPackTypes; bool IsExpandedParameterPack = false; - TypeSourceInfo *DI; + TypeSourceInfo *DI; QualType T; bool Invalid = false; if (D->isExpandedParameterPack()) { - // The non-type template parameter pack is an already-expanded pack + // The non-type template parameter pack is an already-expanded pack // expansion of types. Substitute into each of the expanded types. ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes()); ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes()); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewDI) return 0; - + ExpandedParameterPackTypesAsWritten.push_back(NewDI); QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(), D->getLocation()); @@ -1600,7 +1600,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return 0; ExpandedParameterPackTypes.push_back(NewT); } - + IsExpandedParameterPack = true; DI = D->getTypeSourceInfo(); T = DI->getType(); @@ -1610,9 +1610,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( // types. PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL); TypeLoc Pattern = Expansion.getPatternLoc(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); - + // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; @@ -1622,22 +1622,21 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(), Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, TemplateArgs, - Expand, RetainExpansion, + Expand, RetainExpansion, NumExpansions)) return 0; - + if (Expand) { for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewDI) return 0; - + ExpandedParameterPackTypesAsWritten.push_back(NewDI); QualType NewT = SemaRef.CheckNonTypeTemplateParameterType( NewDI->getType(), @@ -1646,7 +1645,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return 0; ExpandedParameterPackTypes.push_back(NewT); } - + // Note that we have an expanded parameter pack. The "type" of this // expanded parameter pack is the original expansion type, but callers // will end up using the expanded parameter pack types for type-checking. @@ -1658,62 +1657,62 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( // pattern and create a new pack expansion type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs, - D->getLocation(), + D->getLocation(), D->getDeclName()); if (!NewPattern) return 0; - + DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(), NumExpansions); if (!DI) return 0; - + T = DI->getType(); } } else { // Simple case: substitution into a parameter that is not a parameter pack. - DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) return 0; - + // Check that this type is acceptable for a non-type template parameter. - T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), + T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), D->getLocation()); if (T.isNull()) { T = SemaRef.Context.IntTy; Invalid = true; } } - + NonTypeTemplateParmDecl *Param; if (IsExpandedParameterPack) - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes.data(), ExpandedParameterPackTypes.size(), ExpandedParameterPackTypesAsWritten.data()); else - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), T, + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), T, D->isParameterPack(), DI); - + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); - + Param->setDefaultArgument(D->getDefaultArgument(), false); - - // Introduce this template parameter's instantiation into the instantiation + + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); return Param; @@ -1732,34 +1731,34 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - } - + } + // Build the template template parameter. TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->isParameterPack(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); Param->setAccess(AS_public); - - // Introduce this template parameter's instantiation into the instantiation + + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); - + return Param; } Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { // Using directives are never dependent (and never contain any types or // expressions), so they require no explicit instantiation work. - + UsingDirectiveDecl *Inst = UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getNamespaceKeyLocation(), + D->getNamespaceKeyLocation(), D->getQualifierLoc(), - D->getIdentLocation(), - D->getNominatedNamespace(), + D->getIdentLocation(), + D->getNominatedNamespace(), D->getCommonAncestor()); Owner->addDecl(Inst); return Inst; @@ -1863,7 +1862,7 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), + = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); if (!QualifierLoc) return 0; @@ -1891,7 +1890,7 @@ Decl * TemplateDeclInstantiator = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); if (!QualifierLoc) return 0; - + CXXScopeSpec SS; SS.Adopt(QualifierLoc); @@ -1909,6 +1908,29 @@ Decl * TemplateDeclInstantiator return UD; } + +Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *Decl) { + CXXMethodDecl *OldFD = Decl->getSpecialization(); + CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, 0, true)); + + LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, + Sema::ForRedeclaration); + + SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext); + if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, 0, Previous)) { + NewFD->setInvalidDecl(); + return NewFD; + } + + // Associate the specialization with the pattern. + FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl()); + assert(Specialization && "Class scope Specialization is null"); + SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); + + return NewFD; +} + Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); @@ -1930,7 +1952,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { bool Invalid = false; unsigned N = L->size(); - typedef llvm::SmallVector<NamedDecl *, 8> ParamVector; + typedef SmallVector<NamedDecl *, 8> ParamVector; ParamVector Params; Params.reserve(N); for (TemplateParameterList::iterator PI = L->begin(), PE = L->end(); @@ -1951,13 +1973,13 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { return InstL; } -/// \brief Instantiate the declaration of a class template partial +/// \brief Instantiate the declaration of a class template partial /// specialization. /// /// \param ClassTemplate the (instantiated) class template that is partially // specialized by the instantiation of \p PartialSpec. /// -/// \param PartialSpec the (uninstantiated) class template partial +/// \param PartialSpec the (uninstantiated) class template partial /// specialization that we are instantiating. /// /// \returns The instantiated partial specialization, if successful; otherwise, @@ -1970,28 +1992,28 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // specialization, which will contain the instantiations of the template // parameters. LocalInstantiationScope Scope(SemaRef); - + // Substitute into the template parameters of the class template partial // specialization. TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return 0; - + // Substitute into the template arguments of the class template partial // specialization. TemplateArgumentListInfo InstTemplateArgs; // no angle locations - if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), - PartialSpec->getNumTemplateArgsAsWritten(), + if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), + PartialSpec->getNumTemplateArgsAsWritten(), InstTemplateArgs, TemplateArgs)) return 0; - + // Check that the template argument list is well-formed for this // class template. - llvm::SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList(ClassTemplate, + SmallVector<TemplateArgument, 4> Converted; + if (SemaRef.CheckTemplateArgumentList(ClassTemplate, PartialSpec->getLocation(), - InstTemplateArgs, + InstTemplateArgs, false, Converted)) return 0; @@ -2002,10 +2024,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplateSpecializationDecl *PrevDecl = ClassTemplate->findPartialSpecialization(Converted.data(), Converted.size(), InsertPos); - + // Build the canonical type that describes the converted template // arguments of the class template partial specialization. - QualType CanonType + QualType CanonType = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), Converted.data(), Converted.size()); @@ -2023,7 +2045,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( PartialSpec->getLocation(), InstTemplateArgs, CanonType); - + if (PrevDecl) { // We've already seen a partial specialization with the same template // parameters and template arguments. This can happen, for example, when @@ -2046,17 +2068,17 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( << SemaRef.Context.getTypeDeclType(PrevDecl); return 0; } - - + + // Create the class template partial specialization declaration. ClassTemplatePartialSpecializationDecl *InstPartialSpec - = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, PartialSpec->getTagKind(), - Owner, + Owner, PartialSpec->getLocStart(), PartialSpec->getLocation(), InstParams, - ClassTemplate, + ClassTemplate, Converted.data(), Converted.size(), InstTemplateArgs, @@ -2069,7 +2091,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); - + // Add this partial specialization to the set of class template partial // specializations. ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos); @@ -2078,7 +2100,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl<ParmVarDecl *> &Params) { + SmallVectorImpl<ParmVarDecl *> &Params) { TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); @@ -2104,7 +2126,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, if (!OldParam->isParameterPack() || (NewIdx < NumNewParams && NewProtoLoc->getArg(NewIdx)->isParameterPack())) { - // Simple case: normal parameter, or a parameter pack that's + // Simple case: normal parameter, or a parameter pack that's // instantiated to a (still-dependent) parameter pack. ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); Params.push_back(NewParam); @@ -2112,7 +2134,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, NewParam); continue; } - + // Parameter pack: make the instantiation an argument pack. SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack( OldParam); @@ -2184,43 +2206,42 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) { // The function has an exception specification or a "noreturn" // attribute. Substitute into each of the exception types. - llvm::SmallVector<QualType, 4> Exceptions; + SmallVector<QualType, 4> Exceptions; for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { // FIXME: Poor location information! if (const PackExpansionType *PackExpansion = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { // We have a pack expansion. Instantiate it. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), Unexpanded); - assert(!Unexpanded.empty() && + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); bool Expand = false; bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), SourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, TemplateArgs, - Expand, + Expand, RetainExpansion, NumExpansions)) break; if (!Expand) { // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion + // just substitute into the pattern and create a new pack expansion // type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), TemplateArgs, New->getLocation(), New->getDeclName()); if (T.isNull()) break; - + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); Exceptions.push_back(T); continue; @@ -2230,8 +2251,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, bool Invalid = false; for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), TemplateArgs, New->getLocation(), New->getDeclName()); if (T.isNull()) { @@ -2247,11 +2268,11 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, continue; } - + QualType T = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, New->getLocation(), New->getDeclName()); - if (T.isNull() || + if (T.isNull() || SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) continue; @@ -2262,10 +2283,24 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); if (E.isUsable()) + E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); + + if (E.isUsable()) { + SourceLocation ErrLoc; + llvm::APSInt NoexceptVal; NoexceptExpr = E.take(); + if (!NoexceptExpr->isTypeDependent() && + !NoexceptExpr->isValueDependent() && + !NoexceptExpr->isIntegerConstantExpr(NoexceptVal, SemaRef.Context, + &ErrLoc, /*evaluated=*/false)){ + SemaRef.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) + << NoexceptExpr->getSourceRange(); + NoexceptExpr = 0; + } + } } - // Rebuild the function type + // Rebuild the function type FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.ExceptionSpecType = Proto->getExceptionSpecType(); @@ -2283,6 +2318,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI)); } + // C++0x [dcl.constexpr]p6: If the instantiated template specialization of + // a constexpr function template satisfies the requirements for a constexpr + // function, then it is a constexpr function. + if (Tmpl->isConstexpr() && + SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation)) + New->setConstexpr(true); + const FunctionDecl* Definition = Tmpl; // Get the definition. Leaves the variable unchanged if undefined. @@ -2337,8 +2379,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Function->isInvalidDecl() || Function->isDefined()) return; - // Never instantiate an explicit specialization. - if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + // Never instantiate an explicit specialization except if it is a class scope + // explicit specialization. + if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + !Function->getClassScopeSpecializationPattern()) return; // Find the function body that we'll be substituting. @@ -2362,7 +2406,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } // Call the LateTemplateParser callback if there a need to late parse - // a templated function definition. + // a templated function definition. if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser) { LateTemplateParser(OpaqueParser, PatternDecl); @@ -2372,16 +2416,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_func_template) << Function->getPrimaryTemplate(); else - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 1 << Function->getDeclName() << Function->getDeclContext(); - + if (PatternDecl) - Diag(PatternDecl->getLocation(), + Diag(PatternDecl->getLocation(), diag::note_explicit_instantiation_here); Function->setInvalidDecl(); } else if (Function->getTemplateSpecializationKind() @@ -2404,19 +2448,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) - return; - + return; + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. - llvm::SmallVector<VTableUse, 16> SavedVTableUses; + SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; if (Recursive) { VTableUses.swap(SavedVTableUses); PendingInstantiations.swap(SavedPendingInstantiations); } - EnterExpressionEvaluationContext EvalContext(*this, + EnterExpressionEvaluationContext EvalContext(*this, Sema::PotentiallyEvaluated); ActOnStartOfFunctionDef(0, Function); @@ -2445,11 +2489,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ++FParamIdx; continue; } - + // Expand the parameter pack. Scope.MakeInstantiatedLocalArgPack(PatternParam); - for (unsigned NumFParams = Function->getNumParams(); - FParamIdx < NumFParams; + for (unsigned NumFParams = Function->getNumParams(); + FParamIdx < NumFParams; ++FParamIdx) { ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); FunctionParam->setDeclName(PatternParam->getDeclName()); @@ -2481,7 +2525,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Body.isInvalid()) Function->setInvalidDecl(); - + ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); } @@ -2545,7 +2589,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // Find the out-of-line definition of this static data member. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); Def = Def->getOutOfLineDefinition(); if (!Def) { @@ -2555,7 +2599,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // another translation unit. if (DefinitionRequired) { Def = Var->getInstantiatedFromStaticDataMember(); - Diag(PointOfInstantiation, + Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 2 << Var->getDeclName() << Var->getDeclContext(); Diag(Def->getLocation(), diag::note_explicit_instantiation_here); @@ -2571,12 +2615,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // Never instantiate an explicit specialization. if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; - + // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. - if (Var->getTemplateSpecializationKind() + if (Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return; @@ -2591,7 +2635,7 @@ void Sema::InstantiateStaticDataMemberDefinition( // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. - llvm::SmallVector<VTableUse, 16> SavedVTableUses; + SmallVector<VTableUse, 16> SavedVTableUses; std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; if (Recursive) { VTableUses.swap(SavedVTableUses); @@ -2639,14 +2683,26 @@ void Sema::InstantiateStaticDataMemberDefinition( } } +static MultiInitializer CreateMultiInitializer(SmallVectorImpl<Expr*> &Args, + const CXXCtorInitializer *Init) { + // FIXME: This is a hack that will do slightly the wrong thing for an + // initializer of the form foo({...}). + // The right thing to do would be to modify InstantiateInitializer to create + // the MultiInitializer. + if (Args.size() == 1 && isa<InitListExpr>(Args[0])) + return MultiInitializer(Args[0]); + return MultiInitializer(Init->getLParenLoc(), Args.data(), + Args.size(), Init->getRParenLoc()); +} + void Sema::InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs) { - llvm::SmallVector<MemInitTy*, 4> NewInits; + SmallVector<CXXCtorInitializer*, 4> NewInits; bool AnyErrors = false; - + // Instantiate all the initializers. for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), InitsEnd = Tmpl->init_end(); @@ -2662,20 +2718,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, ASTOwningVector<Expr*> NewArgs(*this); SourceLocation EllipsisLoc; - + if (Init->isPackExpansion()) { // This is a pack expansion. We should expand it now. TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; collectUnexpandedParameterPacks(BaseTL, Unexpanded); bool ShouldExpand = false; bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions; - if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), + if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), BaseTL.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), - TemplateArgs, ShouldExpand, + Unexpanded, + TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions)) { AnyErrors = true; @@ -2683,22 +2738,22 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } assert(ShouldExpand && "Partial instantiation of base initializer?"); - - // Loop over all of the arguments in the argument pack(s), + + // Loop over all of the arguments in the argument pack(s), for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); // Instantiate the initializer. - if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + if (InstantiateInitializer(Init->getInit(), TemplateArgs, LParenLoc, NewArgs, RParenLoc)) { AnyErrors = true; break; } // Instantiate the base type. - TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), - TemplateArgs, - Init->getSourceLocation(), + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), New->getDeclName()); if (!BaseTInfo) { AnyErrors = true; @@ -2706,52 +2761,45 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, } // Build the initializer. - MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), - BaseTInfo, - (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getLParenLoc(), - Init->getRParenLoc(), + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(), + BaseTInfo, MultiInit, New->getParent(), SourceLocation()); if (NewInit.isInvalid()) { AnyErrors = true; break; } - + NewInits.push_back(NewInit.get()); NewArgs.clear(); } - + continue; } // Instantiate the initializer. - if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + if (InstantiateInitializer(Init->getInit(), TemplateArgs, LParenLoc, NewArgs, RParenLoc)) { AnyErrors = true; continue; } - + MemInitResult NewInit; if (Init->isBaseInitializer()) { - TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), - TemplateArgs, - Init->getSourceLocation(), + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), New->getDeclName()); if (!BaseTInfo) { AnyErrors = true; New->setInvalidDecl(); continue; } - - NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, - (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getLParenLoc(), - Init->getRParenLoc(), - New->getParent(), - EllipsisLoc); + + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, MultiInit, + New->getParent(), EllipsisLoc); } else if (Init->isMemberInitializer()) { FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl( Init->getMemberLocation(), @@ -2763,11 +2811,9 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, continue; } - NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getSourceLocation(), - Init->getLParenLoc(), - Init->getRParenLoc()); + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildMemberInitializer(Member, MultiInit, + Init->getSourceLocation()); } else if (Init->isIndirectMemberInitializer()) { IndirectFieldDecl *IndirectMember = cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl( @@ -2777,14 +2823,12 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, if (!IndirectMember) { AnyErrors = true; New->setInvalidDecl(); - continue; + continue; } - - NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(), - NewArgs.size(), - Init->getSourceLocation(), - Init->getLParenLoc(), - Init->getRParenLoc()); + + MultiInitializer MultiInit(CreateMultiInitializer(NewArgs, Init)); + NewInit = BuildMemberInitializer(IndirectMember, MultiInit, + Init->getSourceLocation()); } if (NewInit.isInvalid()) { @@ -2794,7 +2838,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, // FIXME: It would be nice if ASTOwningVector had a release function. NewArgs.take(); - NewInits.push_back((MemInitTy *)NewInit.get()); + NewInits.push_back(NewInit.get()); } } @@ -2824,20 +2868,20 @@ static bool isInstantiationOf(ClassTemplateDecl *Pattern, static bool isInstantiationOf(FunctionTemplateDecl *Pattern, FunctionTemplateDecl *Instance) { Pattern = Pattern->getCanonicalDecl(); - + do { Instance = Instance->getCanonicalDecl(); if (Pattern == Instance) return true; Instance = Instance->getInstantiatedFromMemberTemplate(); } while (Instance); - + return false; } -static bool +static bool isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, ClassTemplatePartialSpecializationDecl *Instance) { - Pattern + Pattern = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl()); do { Instance = cast<ClassTemplatePartialSpecializationDecl>( @@ -2846,7 +2890,7 @@ isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, return true; Instance = Instance->getInstantiatedFromMember(); } while (Instance); - + return false; } @@ -3052,11 +3096,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found = CurrentInstantiationScope->findInstantiationOf(D); - + if (Found) { if (Decl *FD = Found->dyn_cast<Decl *>()) return cast<NamedDecl>(FD); - + unsigned PackIdx = ArgumentPackSubstitutionIndex; return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); } @@ -3064,10 +3108,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // If we didn't find the decl, then we must have a label decl that hasn't // been found yet. Lazily instantiate it and return it now. assert(isa<LabelDecl>(D)); - + Decl *Inst = SubstDecl(D, CurContext, TemplateArgs); assert(Inst && "Failed to instantiate label??"); - + CurrentInstantiationScope->InstantiatedLocal(D, Inst); return cast<LabelDecl>(Inst); } @@ -3075,7 +3119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { if (!Record->isDependentContext()) return D; - + // If the RecordDecl is actually the injected-class-name or a // "templated" declaration for a class template, class template // partial specialization, or a member class of a class template, @@ -3083,7 +3127,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // or partial specialization to find the new DeclContext. QualType T; ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); - + if (ClassTemplate) { T = ClassTemplate->getInjectedClassNameSpecialization(); } else if (ClassTemplatePartialSpecializationDecl *PartialSpec @@ -3096,26 +3140,26 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, assert(isa<InjectedClassNameType>(T) && "type of partial specialization is not an InjectedClassNameType"); T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); - } - + } + if (!T.isNull()) { // Substitute into the injected-class-name to get the type // corresponding to the instantiation we want, which may also be // the current instantiation (if we're in a template // definition). This substitution should never fail, since we // know we can instantiate the injected-class-name or we - // wouldn't have gotten to the injected-class-name! + // wouldn't have gotten to the injected-class-name! // FIXME: Can we use the CurrentInstantiationScope to avoid this // extra instantiation in the common case? T = SubstType(T, TemplateArgs, Loc, DeclarationName()); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); - + if (!T->isDependentType()) { assert(T->isRecordType() && "Instantiation must produce a record type"); return T->getAs<RecordType>()->getDecl(); } - + // We are performing "partial" template instantiation to create // the member declarations for the members of a class template // specialization. Therefore, D is actually referring to something @@ -3128,7 +3172,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, DC = DC->getParent()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) - if (isInstantiationOf(ClassTemplate, + if (isInstantiationOf(ClassTemplate, Spec->getSpecializedTemplate())) return Spec; @@ -3139,10 +3183,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // We're performing "instantiation" of a member of the current // instantiation while we are type-checking the // definition. Compute the declaration context and return that. - assert(!SawNonDependentContext && + assert(!SawNonDependentContext && "No dependent context while instantiating record"); DeclContext *DC = computeDeclContext(T); - assert(DC && + assert(DC && "Unable to find declaration for the current instantiation"); return cast<CXXRecordDecl>(DC); } @@ -3153,7 +3197,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!ParentDC->isDependentContext()) return D; - + ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs); if (!ParentDC) return 0; @@ -3207,7 +3251,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // declaration failed to instantiate. There's no point in complaining // further, since this is normal in invalid code. } else if (IsBeingInstantiated) { - // The class in which this member exists is currently being + // The class in which this member exists is currently being // instantiated, and we haven't gotten around to instantiating this // member yet. This can happen when the code uses forward declarations // of member classes, and introduces ordering dependencies via @@ -3221,7 +3265,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, llvm_unreachable("Unable to find instantiation of declaration!"); } } - + D = Result; } @@ -3231,6 +3275,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. void Sema::PerformPendingInstantiations(bool LocalOnly) { + // Load pending instantiations from the external source. + if (!LocalOnly && ExternalSource) { + SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending; + ExternalSource->ReadPendingInstantiations(Pending); + PendingInstantiations.insert(PendingInstantiations.begin(), + Pending.begin(), Pending.end()); + } + while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3267,7 +3319,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // and removed the need for implicit instantiation. switch (Var->getMostRecentDeclaration()->getTemplateSpecializationKind()) { case TSK_Undeclared: - assert(false && "Cannot instantitiate an undeclared specialization."); + llvm_unreachable("Cannot instantitiate an undeclared specialization."); case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitSpecialization: continue; // No longer need to instantiate this type. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index daa1523..e383db9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -32,11 +32,11 @@ namespace { typedef RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor> inherited; - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded; public: explicit CollectUnexpandedParameterPacksVisitor( - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) : Unexpanded(Unexpanded) { } bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -158,9 +158,9 @@ namespace { static void DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, Sema::UnexpandedParameterPackContext UPPC, - const llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { - llvm::SmallVector<SourceLocation, 4> Locations; - llvm::SmallVector<IdentifierInfo *, 4> Names; + const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVector<SourceLocation, 4> Locations; + SmallVector<IdentifierInfo *, 4> Names; llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown; for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { @@ -201,7 +201,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, if (!T->getType()->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc( T->getTypeLoc()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -217,7 +217,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, if (!E->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded); @@ -233,7 +233,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, !SS.getScopeRep()->containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseNestedNameSpecifier(SS.getScopeRep()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -270,7 +270,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, break; } - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseType(NameInfo.getName().getCXXNameType()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -285,7 +285,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, if (Template.isNull() || !Template.containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateName(Template); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -299,7 +299,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, !Arg.getArgument().containsUnexpandedParameterPack()) return false; - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgumentLoc(Arg); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); @@ -308,24 +308,24 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, } void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgument(Arg); } void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgumentLoc(Arg); } void Sema::collectUnexpandedParameterPacks(QualType T, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); } void Sema::collectUnexpandedParameterPacks(TypeLoc TL, - llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); } @@ -462,8 +462,7 @@ getDepthAndIndex(NamedDecl *ND) { bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + ArrayRef<UnexpandedParameterPack> Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, @@ -473,19 +472,21 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, std::pair<IdentifierInfo *, SourceLocation> FirstPack; bool HaveFirstPack = false; - for (unsigned I = 0; I != NumUnexpanded; ++I) { + for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(), + end = Unexpanded.end(); + i != end; ++i) { // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; bool IsFunctionParameterPack = false; if (const TemplateTypeParmType *TTP - = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + = i->first.dyn_cast<const TemplateTypeParmType *>()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); Name = TTP->getIdentifier(); } else { - NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + NamedDecl *ND = i->first.get<NamedDecl *>(); if (isa<ParmVarDecl>(ND)) IsFunctionParameterPack = true; else @@ -502,7 +503,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = CurrentInstantiationScope->findInstantiationOf( - Unexpanded[I].first.get<NamedDecl *>()); + i->first.get<NamedDecl *>()); if (Instantiation->is<DeclArgumentPack *>()) { // We could expand this function parameter pack. NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); @@ -545,7 +546,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, // Record it. NumExpansions = NewPackSize; FirstPack.first = Name; - FirstPack.second = Unexpanded[I].second; + FirstPack.second = i->second; HaveFirstPack = true; continue; } @@ -557,11 +558,11 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, if (HaveFirstPack) Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) << FirstPack.first << Name << *NumExpansions << NewPackSize - << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second); + << SourceRange(FirstPack.second) << SourceRange(i->second); else Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) << Name << *NumExpansions << NewPackSize - << SourceRange(Unexpanded[I].second); + << SourceRange(i->second); return true; } } @@ -572,7 +573,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, unsigned Sema::getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs) { QualType Pattern = cast<PackExpansionType>(T)->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { @@ -618,7 +619,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { switch (DS.getTypeSpecType()) { case TST_typename: case TST_typeofType: - case TST_underlyingType: { + case TST_underlyingType: + case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) return true; @@ -639,6 +641,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_char16: case TST_char32: case TST_int: + case TST_half: case TST_float: case TST_double: case TST_bool: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index f3e73ec..2b563a5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -52,18 +52,18 @@ static bool isOmittedBlockReturnType(const Declarator &D) { /// doesn't apply to the given type. static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, QualType type) { - bool useInstantiationLoc = false; + bool useExpansionLoc = false; unsigned diagID = 0; switch (attr.getKind()) { case AttributeList::AT_objc_gc: diagID = diag::warn_pointer_attribute_wrong_type; - useInstantiationLoc = true; + useExpansionLoc = true; break; case AttributeList::AT_objc_ownership: diagID = diag::warn_objc_object_attribute_wrong_type; - useInstantiationLoc = true; + useExpansionLoc = true; break; default: @@ -73,10 +73,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, } SourceLocation loc = attr.getLoc(); - llvm::StringRef name = attr.getName()->getName(); + StringRef name = attr.getName()->getName(); // The GC attributes are usually written with macros; special-case them. - if (useInstantiationLoc && loc.isMacroID() && attr.getParameterName()) { + if (useExpansionLoc && loc.isMacroID() && attr.getParameterName()) { if (attr.getParameterName()->isStr("strong")) { if (S.findMacroSpelling(loc, "__strong")) name = "__strong"; } else if (attr.getParameterName()->isStr("weak")) { @@ -125,11 +125,11 @@ namespace { bool hasSavedAttrs; /// The original set of attributes on the DeclSpec. - llvm::SmallVector<AttributeList*, 2> savedAttrs; + SmallVector<AttributeList*, 2> savedAttrs; /// A list of attributes to diagnose the uselessness of when the /// processing is complete. - llvm::SmallVector<AttributeList*, 2> ignoredTypeAttrs; + SmallVector<AttributeList*, 2> ignoredTypeAttrs; public: TypeProcessingState(Sema &sema, Declarator &declarator) @@ -183,7 +183,7 @@ namespace { /// Diagnose all the ignored type attributes, given that the /// declarator worked out to the given type. void diagnoseIgnoredTypeAttrs(QualType type) const { - for (llvm::SmallVectorImpl<AttributeList*>::const_iterator + for (SmallVectorImpl<AttributeList*>::const_iterator i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); i != e; ++i) diagnoseBadTypeAttribute(getSema(), **i, type); @@ -664,7 +664,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? if (S.getLangOptions().CPlusPlus && - !S.getLangOptions().Microsoft) { + !S.getLangOptions().MicrosoftExt) { S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); @@ -711,6 +711,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } + case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) @@ -856,6 +857,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.UnknownAnyTy; break; + case DeclSpec::TST_atomic: + Result = S.GetTypeFromParser(DS.getRepAsType()); + assert(!Result.isNull() && "Didn't get a type for _Atomic?"); + Result = S.BuildAtomicType(Result, DS.getTypeSpecTypeLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); @@ -1038,6 +1049,11 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type, } else if (type->isObjCARCImplicitlyUnretainedType()) { implicitLifetime = Qualifiers::OCL_ExplicitNone; + // If we are in an unevaluated context, like sizeof, assume ExplicitNone and + // don't give error. + } else if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + // If that failed, give an error and recover using __autoreleasing. } else { // These types can show up in private ivars in system headers, so @@ -1419,13 +1435,26 @@ QualType Sema::BuildFunctionType(QualType T, << T->isFunctionType() << T; return QualType(); } - + + // Functions cannot return half FP. + if (T->isHalfType()) { + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << + FixItHint::CreateInsertion(Loc, "*"); + return QualType(); + } + bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { + // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; + } else if (ParamType->isHalfType()) { + // Disallow half FP arguments. + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << + FixItHint::CreateInsertion(Loc, "*"); + Invalid = true; } ParamTypes[Idx] = ParamType; @@ -1492,7 +1521,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // type. In such cases, the compiler makes a worst-case assumption. // We make no such assumption right now, so emit an error if the // class isn't a complete type. - if (Context.Target.getCXXABI() == CXXABI_Microsoft && + if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft && RequireCompleteType(Loc, Class, diag::err_incomplete_type)) return QualType(); @@ -1745,9 +1774,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, switch (D.getContext()) { case Declarator::KNRTypeListContext: - assert(0 && "K&R type lists aren't allowed in C++"); + llvm_unreachable("K&R type lists aren't allowed in C++"); break; - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::PrototypeContext: Error = 0; // Function prototype break; @@ -1755,7 +1785,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { - case TTK_Enum: assert(0 && "unhandled tag kind"); break; + case TTK_Enum: llvm_unreachable("unhandled tag kind"); case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; case TTK_Class: Error = 3; /* Class member */ break; @@ -1825,7 +1855,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } if (SemaRef.getLangOptions().CPlusPlus && - OwnedTagDecl && OwnedTagDecl->isDefinition()) { + OwnedTagDecl && OwnedTagDecl->isCompleteDefinition()) { // Check the contexts where C++ forbids the declaration of a new class // or enumeration in a type-specifier-seq. switch (D.getContext()) { @@ -1856,7 +1886,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::PrototypeContext: - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::KNRTypeListContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. @@ -1916,7 +1947,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, state.setCurrentChunkIndex(chunkIndex); DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); switch (DeclType.Kind) { - default: assert(0 && "Unknown decltype!"); + default: llvm_unreachable("Unknown decltype!"); case DeclaratorChunk::Paren: T = S.BuildParenType(T); break; @@ -2045,6 +2076,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); } + // Do not allow returning half FP value. + // FIXME: This really should be in BuildFunctionType. + if (T->isHalfType()) { + S.Diag(D.getIdentifierLoc(), + diag::err_parameters_retval_cannot_have_fp16_type) << 1 + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); + D.setInvalidType(true); + } + // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && @@ -2077,7 +2117,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); - if (Tag->isDefinition()) + if (Tag->isCompleteDefinition()) S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) << Context.getTypeDeclType(Tag); } @@ -2127,10 +2167,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Otherwise, we have a function with an argument list that is // potentially variadic. - llvm::SmallVector<QualType, 16> ArgTys; + SmallVector<QualType, 16> ArgTys; ArgTys.reserve(FTI.NumArgs); - llvm::SmallVector<bool, 16> ConsumedArguments; + SmallVector<bool, 16> ConsumedArguments; ConsumedArguments.reserve(FTI.NumArgs); bool HasAnyConsumedArguments = false; @@ -2168,6 +2208,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Do not add 'void' to the ArgTys list. break; } + } else if (ArgTy->isHalfType()) { + // Disallow half FP arguments. + // FIXME: This really should be in BuildFunctionType. + S.Diag(Param->getLocation(), + diag::err_parameters_retval_cannot_have_fp16_type) << 0 + << FixItHint::CreateInsertion(Param->getLocation(), "*"); + D.setInvalidType(); } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); @@ -2192,7 +2239,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (HasAnyConsumedArguments) EPI.ConsumedArguments = ConsumedArguments.data(); - llvm::SmallVector<QualType, 4> Exceptions; + SmallVector<QualType, 4> Exceptions; EPI.ExceptionSpecType = FTI.getExceptionSpecType(); if (FTI.getExceptionSpecType() == EST_Dynamic) { Exceptions.reserve(FTI.NumExceptions); @@ -2320,6 +2367,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FreeFunction = (DC && !DC->isRecord()); } + // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that function to be const. + if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction && + D.getName().getKind() != UnqualifiedId::IK_ConstructorName && + D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId && + !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) { + // Rebuild function type adding a 'const' qualifier. + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + EPI.TypeQuals |= DeclSpec::TQ_const; + T = Context.getFunctionType(FnTy->getResultType(), + FnTy->arg_type_begin(), + FnTy->getNumArgs(), EPI); + } + // C++0x [dcl.fct]p6: // A ref-qualifier shall only be part of the function type for a // non-static member function, the function type to which a pointer to @@ -2457,13 +2518,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); - else if (!LangOpts.CPlusPlus0x) - S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); + else + S.Diag(D.getEllipsisLoc(), + LangOpts.CPlusPlus0x + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); break; case Declarator::FileContext: case Declarator::KNRTypeListContext: - case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? + case Declarator::ObjCParameterContext: // FIXME: special diagnostic here? + case Declarator::ObjCResultContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::CXXNewContext: case Declarator::AliasDeclContext: @@ -2850,6 +2915,14 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } + void VisitAtomicTypeLoc(AtomicTypeLoc TL) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. @@ -3030,7 +3103,7 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { void LocInfoType::getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const { - assert(false && "LocInfoType leaked into the type system; an opaque TypeTy*" + llvm_unreachable("LocInfoType leaked into the type system; an opaque TypeTy*" " was used directly instead of getting the QualType through" " GetTypeFromParser"); } @@ -3045,6 +3118,12 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { if (D.isInvalidType()) return true; + // Make sure there are no unused decl attributes on the declarator. + // We don't want to do this for ObjC parameters because we're going + // to apply them to the actual parameter declaration. + if (D.getContext() != Declarator::ObjCParameterContext) + checkUnusedDeclAttributes(D); + if (getLangOptions().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); @@ -3053,6 +3132,13 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { return CreateParsedType(T, TInfo); } +ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { + QualType T = Context.getObjCInstanceType(); + TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + return CreateParsedType(T, TInfo); +} + + //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// @@ -3064,14 +3150,22 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ // If this type is already address space qualified, reject it. - // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers - // for two or more different address spaces." + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by + // qualifiers for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); Attr.setInvalid(); return; } + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be + // qualified by an address-space qualifier." + if (Type->isFunctionType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_function_type); + Attr.setInvalid(); + return; + } + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -3122,15 +3216,18 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, return false; Sema &S = state.getSema(); + SourceLocation AttrLoc = attr.getLoc(); + if (AttrLoc.isMacroID()) + AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first; if (type.getQualifiers().getObjCLifetime()) { - S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant) + S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant) << type; return true; } if (!attr.getParameterName()) { - S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + S.Diag(AttrLoc, diag::err_attribute_argument_n_not_string) << "objc_ownership" << 1; attr.setInvalid(); return true; @@ -3146,7 +3243,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, else if (attr.getParameterName()->isStr("autoreleasing")) lifetime = Qualifiers::OCL_Autoreleasing; else { - S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) + S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << "objc_ownership" << attr.getParameterName(); attr.setInvalid(); return true; @@ -3164,7 +3261,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // If we have a valid source location for the attribute, use an // AttributedType instead. - if (attr.getLoc().isValid()) + if (AttrLoc.isValid()) type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, origType, type); @@ -3175,10 +3272,11 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // Actually, delay this until we know what we're parsing. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( - sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(), + sema::DelayedDiagnostic::makeForbiddenType( + S.getSourceManager().getExpansionLoc(AttrLoc), diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); } else { - S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime); + S.Diag(AttrLoc, diag::err_arc_weak_no_runtime); } attr.setInvalid(); @@ -3194,7 +3292,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); if (Class->isArcWeakrefUnavailable()) { - S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class); + S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); S.Diag(ObjT->getInterfaceDecl()->getLocation(), diag::note_class_declared); } @@ -3283,7 +3381,7 @@ namespace { QualType Original; const FunctionType *Fn; - llvm::SmallVector<unsigned char /*WrapKind*/, 8> Stack; + SmallVector<unsigned char /*WrapKind*/, 8> Stack; FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { while (true) { @@ -3474,7 +3572,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } - if (CCOld != CC_Default) { + if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : CC_Default)) { // Should we diagnose reapplications of the same convention? S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) @@ -3718,32 +3816,44 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, switch (attr.getKind()) { default: break; + case AttributeList::AT_may_alias: + // FIXME: This attribute needs to actually be handled, but if we ignore + // it it breaks large amounts of Linux software. + attr.setUsedAsTypeAttr(); + break; case AttributeList::AT_address_space: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) distributeObjCPointerTypeAttr(state, attr, type); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_vector_size: HandleVectorSizeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ext_vector_type: if (state.getDeclarator().getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) HandleExtVectorTypeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_vector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector, "neon_vector_type"); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_neon_polyvector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonPolyVector, "neon_polyvector_type"); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_opencl_image_access: HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); break; case AttributeList::AT_ns_returns_retained: @@ -3752,6 +3862,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // fallthrough into the function attrs FUNCTION_TYPE_ATTRS_CASELIST: + attr.setUsedAsTypeAttr(); + // Never process function type attributes as part of the // declaration-specifiers. if (isDeclSpec) @@ -3954,6 +4066,121 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, std::make_pair(SourceLocation(), PDiag(0))); } +/// @brief Ensure that the type T is a literal type. +/// +/// This routine checks whether the type @p T is a literal type. If @p T is an +/// incomplete type, an attempt is made to complete it. If @p T is a literal +/// type, or @p AllowIncompleteType is true and @p T is an incomplete type, +/// returns false. Otherwise, this routine issues the diagnostic @p PD (giving +/// it the type @p T), along with notes explaining why the type is not a +/// literal type, and returns true. +/// +/// @param Loc The location in the source that the non-literal type +/// diagnostic should refer to. +/// +/// @param T The type that this routine is examining for literalness. +/// +/// @param PD The partial diagnostic that will be printed out if T is not a +/// literal type. +/// +/// @param AllowIncompleteType If true, an incomplete type will be considered +/// acceptable. +/// +/// @returns @c true if @p T is not a literal type and a diagnostic was emitted, +/// @c false otherwise. +bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + bool AllowIncompleteType) { + assert(!T->isDependentType() && "type should not be dependent"); + + bool Incomplete = RequireCompleteType(Loc, T, 0); + if (T->isLiteralType() || (AllowIncompleteType && Incomplete)) + return false; + + if (PD.getDiagID() == 0) + return true; + + Diag(Loc, PD) << T; + + if (T->isVariableArrayType()) + return true; + + const RecordType *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>(); + if (!RT) + return true; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + // If the class has virtual base classes, then it's not an aggregate, and + // cannot have any constexpr constructors, so is non-literal. This is better + // to diagnose than the resulting absence of constexpr constructors. + if (RD->getNumVBases()) { + Diag(RD->getLocation(), diag::note_non_literal_virtual_base) + << RD->isStruct() << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getSourceRange().getBegin(), + diag::note_constexpr_virtual_base_here) << I->getSourceRange(); + } else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) { + Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD; + + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + break; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // If the base template had constexpr constructors which were + // instantiated as non-constexpr constructors, explain why. + for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), + E = RD->ctor_end(); I != E; ++I) { + if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor()) + continue; + + FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction(); + if (Base && Base->isConstexpr()) + CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation); + } + } + } else if (RD->hasNonLiteralTypeFieldsOrBases()) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (!I->getType()->isLiteralType()) { + Diag(I->getSourceRange().getBegin(), + diag::note_non_literal_base_class) + << RD << I->getType() << I->getSourceRange(); + return true; + } + } + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) { + if (!(*I)->getType()->isLiteralType()) { + Diag((*I)->getLocation(), diag::note_non_literal_field) + << RD << (*I) << (*I)->getType(); + return true; + } else if ((*I)->isMutable()) { + Diag((*I)->getLocation(), diag::note_non_literal_mutable_field) << RD; + return true; + } + } + } else if (!RD->hasTrivialDestructor()) { + // All fields and bases are of literal types, so have trivial destructors. + // If this class's destructor is non-trivial it must be user-declared. + CXXDestructorDecl *Dtor = RD->getDestructor(); + assert(Dtor && "class has literal fields and bases but no dtor?"); + if (!Dtor) + return true; + + Diag(Dtor->getLocation(), Dtor->isUserProvided() ? + diag::note_non_literal_user_provided_dtor : + diag::note_non_literal_nontrivial_dtor) << RD; + } + + return true; +} + /// \brief Retrieve a version of the type 'T' that is elaborated by Keyword /// and qualified by the nested-name-specifier contained in SS. QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, @@ -4015,3 +4242,36 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType, } llvm_unreachable("unknown unary transform type"); } + +QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { + if (!T->isDependentType()) { + int DisallowedKind = -1; + if (T->isIncompleteType()) + // FIXME: It isn't entirely clear whether incomplete atomic types + // are allowed or not; for simplicity, ban them for the moment. + DisallowedKind = 0; + else if (T->isArrayType()) + DisallowedKind = 1; + else if (T->isFunctionType()) + DisallowedKind = 2; + else if (T->isReferenceType()) + DisallowedKind = 3; + else if (T->isAtomicType()) + DisallowedKind = 4; + else if (T.hasQualifiers()) + DisallowedKind = 5; + else if (!T.isTriviallyCopyableType(Context)) + // Some other non-trivially-copyable type (probably a C++ class) + DisallowedKind = 6; + + if (DisallowedKind != -1) { + Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; + return QualType(); + } + + // FIXME: Do we need any handling for ARC here? + } + + // Build the pointer type. + return Context.getAtomicType(T); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp index ab697ee..aa0bc08 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp @@ -147,7 +147,8 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, return; } - D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getLoc(), S.Context)); + D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(), + S.Context)); } static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -168,7 +169,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Apparently Visual C++ thinks it is okay to not emit a warning // in this case, so only emit a warning when -fms-extensions is not // specified. - if (!S.getLangOptions().Microsoft) + if (!S.getLangOptions().MicrosoftExt) S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -236,7 +237,7 @@ namespace { X86AttributesSema() { } bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) const { - const llvm::Triple &Triple(S.Context.Target.getTriple()); + const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple()); if (Triple.getOS() == llvm::Triple::Win32 || Triple.getOS() == llvm::Triple::MinGW32) { switch (Attr.getKind()) { @@ -247,8 +248,9 @@ namespace { default: break; } } - if (Attr.getName()->getName() == "force_align_arg_pointer" || - Attr.getName()->getName() == "__force_align_arg_pointer__") { + if (Triple.getArch() != llvm::Triple::x86_64 && + (Attr.getName()->getName() == "force_align_arg_pointer" || + Attr.getName()->getName() == "__force_align_arg_pointer__")) { HandleX86ForceAlignArgPointerAttr(D, Attr, S); return true; } @@ -261,16 +263,16 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const { if (TheTargetAttributesSema) return *TheTargetAttributesSema; - const llvm::Triple &Triple(Context.Target.getTriple()); + const llvm::Triple &Triple(Context.getTargetInfo().getTriple()); switch (Triple.getArch()) { - default: - return *(TheTargetAttributesSema = new TargetAttributesSema); - case llvm::Triple::msp430: return *(TheTargetAttributesSema = new MSP430AttributesSema); case llvm::Triple::mblaze: return *(TheTargetAttributesSema = new MBlazeAttributesSema); case llvm::Triple::x86: + case llvm::Triple::x86_64: return *(TheTargetAttributesSema = new X86AttributesSema); + default: + return *(TheTargetAttributesSema = new TargetAttributesSema); } } diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index fa87217..bb49eee 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -31,6 +31,7 @@ #include "clang/Sema/Ownership.h" #include "clang/Sema/Designator.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include "TypeLocBuilder.h" #include <algorithm> @@ -244,8 +245,7 @@ public: /// must be set. bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, - const UnexpandedParameterPack *Unexpanded, - unsigned NumUnexpanded, + llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, llvm::Optional<unsigned> &NumExpansions) { @@ -345,7 +345,7 @@ public: /// /// \returns true if an error occurred, false otherwise. bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall, - llvm::SmallVectorImpl<Expr *> &Outputs, + SmallVectorImpl<Expr *> &Outputs, bool *ArgChanged = 0); /// \brief Transform the given declaration, which is referenced from a type @@ -520,8 +520,8 @@ public: bool TransformFunctionTypeParams(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const QualType *ParamTypes, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> *PVars); + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl*> *PVars); /// \brief Transforms a single function-type parameter. Return null /// on error. @@ -905,6 +905,12 @@ public: NumExpansions); } + /// \brief Build a new atomic type given its value type. + /// + /// By default, performs semantic analysis when building the atomic type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -1181,15 +1187,22 @@ public: return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } + /// \brief Rebuild the operand to an Objective-C @synchronized statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCAtSynchronizedOperand(SourceLocation atLoc, + Expr *object) { + return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object); + } + /// \brief Build a new Objective-C @synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, - Expr *Object, - Stmt *Body) { - return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, - Body); + Expr *Object, Stmt *Body) { + return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body); } /// \brief Build a new Objective-C @autoreleasepool statement. @@ -1200,7 +1213,16 @@ public: Stmt *Body) { return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); } - + + /// \brief Build the collection operand to a new Objective-C fast + /// enumeration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection) { + return getSema().ActOnObjCForCollectionOperand(forLoc, collection); + } /// \brief Build a new Objective-C fast enumeration statement. /// @@ -1712,8 +1734,7 @@ public: SubExpr, RParenLoc); default: - assert(false && "Invalid C++ named cast"); - break; + llvm_unreachable("Invalid C++ named cast"); } return ExprError(); @@ -2016,13 +2037,14 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXConstructExpr(QualType T, - SourceLocation Loc, - CXXConstructorDecl *Constructor, - bool IsElidable, - MultiExprArg Args, - bool RequiresZeroInit, + SourceLocation Loc, + CXXConstructorDecl *Constructor, + bool IsElidable, + MultiExprArg Args, + bool HadMultipleCandidates, + bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, - SourceRange ParenRange) { + SourceRange ParenRange) { ASTOwningVector<Expr*> ConvertedArgs(SemaRef); if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, ConvertedArgs)) @@ -2030,6 +2052,7 @@ public: return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, move_arg(ConvertedArgs), + HadMultipleCandidates, RequiresZeroInit, ConstructKind, ParenRange); } @@ -2117,10 +2140,15 @@ public: ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, SourceLocation RParenLoc, - unsigned Length) { + llvm::Optional<unsigned> Length) { + if (Length) + return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), + OperatorLoc, Pack, PackLoc, + RParenLoc, *Length); + return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), OperatorLoc, Pack, PackLoc, - RParenLoc, Length); + RParenLoc); } /// \brief Build a new Objective-C @encode expression. @@ -2137,7 +2165,7 @@ public: /// \brief Build a new Objective-C class message. ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -2145,14 +2173,14 @@ public: return SemaRef.BuildClassMessage(ReceiverTypeInfo, ReceiverTypeInfo->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, SelectorLoc, + Sel, Method, LBracLoc, SelectorLocs, RBracLoc, move(Args)); } /// \brief Build a new Objective-C instance message. ExprResult RebuildObjCMessageExpr(Expr *Receiver, Selector Sel, - SourceLocation SelectorLoc, + ArrayRef<SourceLocation> SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, @@ -2160,7 +2188,7 @@ public: return SemaRef.BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), - Sel, Method, LBracLoc, SelectorLoc, + Sel, Method, LBracLoc, SelectorLocs, RBracLoc, move(Args)); } @@ -2357,7 +2385,26 @@ public: llvm::Optional<unsigned> NumExpansions) { return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } - + + /// \brief Build a new atomic operation expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, + MultiExprArg SubExprs, + QualType RetTy, + AtomicExpr::AtomicOp Op, + SourceLocation RParenLoc) { + // Just create the expression; there is not any interesting semantic + // analysis here because we can't actually build an AtomicExpr until + // we are sure it is semantically sound. + unsigned NumSubExprs = SubExprs.size(); + Expr **Subs = (Expr **)SubExprs.release(); + return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs, + NumSubExprs, RetTy, Op, + RParenLoc); + } + private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, @@ -2424,7 +2471,7 @@ template<typename Derived> bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall, - llvm::SmallVectorImpl<Expr *> &Outputs, + SmallVectorImpl<Expr *> &Outputs, bool *ArgChanged) { for (unsigned I = 0; I != NumInputs; ++I) { // If requested, drop call arguments that need to be dropped. @@ -2438,7 +2485,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) { Expr *Pattern = Expansion->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); @@ -2451,8 +2498,7 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), Pattern->getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; @@ -2522,7 +2568,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, QualType ObjectType, NamedDecl *FirstQualifierInScope) { - llvm::SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; + SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; Qualifier = Qualifier.getPrefix()) Qualifiers.push_back(Qualifier); @@ -2666,8 +2712,7 @@ TreeTransform<Derived> } } - assert(0 && "Unknown name kind."); - return DeclarationNameInfo(); + llvm_unreachable("Unknown name kind."); } template<typename Derived> @@ -2887,7 +2932,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( } case TemplateArgument::Pack: { - llvm::SmallVector<TemplateArgument, 4> TransformedArgs; + SmallVector<TemplateArgument, 4> TransformedArgs; TransformedArgs.reserve(Arg.pack_size()); for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); @@ -3016,7 +3061,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, = In.getPackExpansionPattern(Ellipsis, OrigNumExpansions, getSema().Context); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); @@ -3027,8 +3072,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Ellipsis, Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, Expand, RetainExpansion, NumExpansions)) @@ -3809,8 +3853,8 @@ bool TreeTransform<Derived>:: TransformFunctionTypeParams(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const QualType *ParamTypes, - llvm::SmallVectorImpl<QualType> &OutParamTypes, - llvm::SmallVectorImpl<ParmVarDecl*> *PVars) { + SmallVectorImpl<QualType> &OutParamTypes, + SmallVectorImpl<ParmVarDecl*> *PVars) { int indexAdjustment = 0; for (unsigned i = 0; i != NumParams; ++i) { @@ -3821,7 +3865,7 @@ bool TreeTransform<Derived>:: ParmVarDecl *NewParm = 0; if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; // Find the parameter packs that could be expanded. TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc(); @@ -3838,8 +3882,7 @@ bool TreeTransform<Derived>:: NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -3921,15 +3964,14 @@ bool TreeTransform<Derived>:: = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); - llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; if (getDerived().TryExpandParameterPacks(Loc, SourceRange(), - Unexpanded.data(), - Unexpanded.size(), + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { @@ -4014,8 +4056,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, // parameters before the return type, since the return type can then refer // to the parameters themselves (via decltype, sizeof, etc.). // - llvm::SmallVector<QualType, 4> ParamTypes; - llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + SmallVector<QualType, 4> ParamTypes; + SmallVector<ParmVarDecl*, 4> ParamDecls; const FunctionProtoType *T = TL.getTypePtr(); QualType ResultType; @@ -4387,6 +4429,29 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); } +template<typename Derived> +QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB, + AtomicTypeLoc TL) { + QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); + if (ValueType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + ValueType != TL.getValueLoc().getType()) { + Result = getDerived().RebuildAtomicType(ValueType, TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + AtomicTypeLoc NewTL = TLB.push<AtomicTypeLoc>(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + + return Result; +} + namespace { /// \brief Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. @@ -5256,7 +5321,7 @@ template<typename Derived> StmtResult TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { bool DeclChanged = false; - llvm::SmallVector<Decl *, 4> Decls; + SmallVector<Decl *, 4> Decls; for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(), @@ -5283,7 +5348,7 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { ASTOwningVector<Expr*> Constraints(getSema()); ASTOwningVector<Expr*> Exprs(getSema()); - llvm::SmallVector<IdentifierInfo *, 4> Names; + SmallVector<IdentifierInfo *, 4> Names; ExprResult AsmString; ASTOwningVector<Expr*> Clobbers(getSema()); @@ -5470,6 +5535,11 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( ExprResult Object = getDerived().TransformExpr(S->getSynchExpr()); if (Object.isInvalid()) return StmtError(); + Object = + getDerived().RebuildObjCAtSynchronizedOperand(S->getAtSynchronizedLoc(), + Object.get()); + if (Object.isInvalid()) + return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getSynchBody()); @@ -5519,6 +5589,10 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt( ExprResult Collection = getDerived().TransformExpr(S->getCollection()); if (Collection.isInvalid()) return StmtError(); + Collection = getDerived().RebuildObjCForCollectionOperand(S->getForLoc(), + Collection.take()); + if (Collection.isInvalid()) + return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -5813,8 +5887,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { if (ControllingExpr.isInvalid()) return ExprError(); - llvm::SmallVector<Expr *, 4> AssocExprs; - llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes; + SmallVector<Expr *, 4> AssocExprs; + SmallVector<TypeSourceInfo *, 4> AssocTypes; for (unsigned i = 0; i != E->getNumAssocs(); ++i) { TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); if (TS) { @@ -5887,7 +5961,7 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { bool ExprChanged = false; typedef Sema::OffsetOfComponent Component; typedef OffsetOfExpr::OffsetOfNode Node; - llvm::SmallVector<Component, 4> Components; + SmallVector<Component, 4> Components; for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { const Node &ON = E->getComponent(I); Component Comp; @@ -6902,6 +6976,19 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew); if (OperatorDelete) SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); + + if (E->isArray() && Constructor && + !E->getAllocatedType()->isDependentType()) { + QualType ElementType + = SemaRef.Context.getBaseElementType(E->getAllocatedType()); + if (const RecordType *RecordT = ElementType->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl()); + if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor); + } + } + } + return SemaRef.Owned(E); } @@ -7313,6 +7400,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), move_arg(Args), + E->hadMultipleCandidates(), E->requiresZeroInitialization(), E->getConstructionKind(), E->getParenRange()); @@ -7640,19 +7728,28 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions; if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), - &Unexpanded, 1, + Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) return ExprError(); - if (!ShouldExpand || RetainExpansion) + if (RetainExpansion) return SemaRef.Owned(E); + + NamedDecl *Pack = E->getPack(); + if (!ShouldExpand) { + Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(), + Pack)); + if (!Pack) + return ExprError(); + } + // We now know the length of the parameter pack, so build a new expression // that stores that length. - return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), + return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(), - *NumExpansions); + NumExpansions); } template<typename Derived> @@ -7762,9 +7859,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { return SemaRef.Owned(E); // Build a new class message send. + SmallVector<SourceLocation, 16> SelLocs; + E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, E->getSelector(), - E->getSelectorLoc(), + SelLocs, E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -7785,9 +7884,11 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { return SemaRef.Owned(E); // Build a new instance message send. + SmallVector<SourceLocation, 16> SelLocs; + E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(Receiver.get(), E->getSelector(), - E->getSelectorLoc(), + SelLocs, E->getMethodDecl(), E->getLeftLoc(), move_arg(Args), @@ -7908,8 +8009,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { // expression. blockScope->CapturesCXXThis = oldBlock->capturesCXXThis(); - llvm::SmallVector<ParmVarDecl*, 4> params; - llvm::SmallVector<QualType, 4> paramTypes; + SmallVector<ParmVarDecl*, 4> params; + SmallVector<QualType, 4> paramTypes; // Parameter substitution. if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(), @@ -7951,7 +8052,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { // Set the parameters on the block decl. if (!params.empty()) - blockScope->TheDecl->setParams(params.data(), params.size()); + blockScope->TheDecl->setParams(params); // If the return type wasn't explicitly set, it will have been marked as a // dependent type (DependentTy); clear out the return type setting so @@ -8015,8 +8116,26 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) { - assert(false && "Cannot transform asType expressions yet"); - return SemaRef.Owned(E); + llvm_unreachable("Cannot transform asType expressions yet"); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { + QualType RetTy = getDerived().TransformType(E->getType()); + bool ArgumentChanged = false; + ASTOwningVector<Expr*> SubExprs(SemaRef); + SubExprs.reserve(E->getNumSubExprs()); + if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, + SubExprs, &ArgumentChanged)) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + !ArgumentChanged) + return SemaRef.Owned(E); + + return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs), + RetTy, E->getOp(), E->getRParenLoc()); } //===----------------------------------------------------------------------===// @@ -8239,6 +8358,12 @@ QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( } template<typename Derived> +QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType, + SourceLocation KWLoc) { + return SemaRef.BuildAtomicType(ValueType, KWLoc); +} + +template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, |