diff options
Diffstat (limited to 'lib/Sema')
44 files changed, 8992 insertions, 3441 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 213d6fb..f666a9b 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -530,44 +530,37 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - // FIXME: Function try block - if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case UnknownFallThrough: - break; + SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); + // Either in a function body compound statement, or a function-try-block. + switch (CheckFallThrough(AC)) { + case UnknownFallThrough: + break; - case MaybeFallThrough: - if (HasNoReturn) - S.Diag(Compound->getRBracLoc(), - CD.diag_MaybeFallThrough_HasNoReturn); - else if (!ReturnsVoid) - S.Diag(Compound->getRBracLoc(), - CD.diag_MaybeFallThrough_ReturnsNonVoid); - break; - case AlwaysFallThrough: - if (HasNoReturn) - S.Diag(Compound->getRBracLoc(), - CD.diag_AlwaysFallThrough_HasNoReturn); - else if (!ReturnsVoid) - S.Diag(Compound->getRBracLoc(), - CD.diag_AlwaysFallThrough_ReturnsNonVoid); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && 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); - } + case MaybeFallThrough: + if (HasNoReturn) + S.Diag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); + break; + case AlwaysFallThrough: + if (HasNoReturn) + S.Diag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; + } else { + S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); } - break; - case NeverFallThrough: - break; - } + } + break; + case NeverFallThrough: + break; } } @@ -923,7 +916,7 @@ namespace { // issue a warn_fallthrough_attr_unreachable for them. for (const auto *B : *Cfg) { const Stmt *L = B->getLabel(); - if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B)) + if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second) BlockQueue.push_back(B); } @@ -933,7 +926,7 @@ namespace { for (CFGBlock::const_succ_iterator I = P->succ_begin(), E = P->succ_end(); I != E; ++I) { - if (*I && ReachableBlocks.insert(*I)) + if (*I && ReachableBlocks.insert(*I).second) BlockQueue.push_back(*I); } } @@ -1444,13 +1437,51 @@ struct SortDiagBySourceLocation { // -Wthread-safety //===----------------------------------------------------------------------===// namespace clang { -namespace thread_safety { -namespace { -class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { +namespace threadSafety { + +class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { Sema &S; DiagList Warnings; SourceLocation FunLocation, FunEndLocation; + const FunctionDecl *CurrentFunction; + bool Verbose; + + OptionalNotes getNotes() const { + if (Verbose && CurrentFunction) { + PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), + S.PDiag(diag::note_thread_warning_in_fun) + << CurrentFunction->getNameAsString()); + return OptionalNotes(1, FNote); + } + return OptionalNotes(); + } + + OptionalNotes getNotes(const PartialDiagnosticAt &Note) const { + OptionalNotes ONS(1, Note); + if (Verbose && CurrentFunction) { + PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), + S.PDiag(diag::note_thread_warning_in_fun) + << CurrentFunction->getNameAsString()); + ONS.push_back(FNote); + } + return ONS; + } + + OptionalNotes getNotes(const PartialDiagnosticAt &Note1, + const PartialDiagnosticAt &Note2) const { + OptionalNotes ONS; + ONS.push_back(Note1); + ONS.push_back(Note2); + if (Verbose && CurrentFunction) { + PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), + S.PDiag(diag::note_thread_warning_in_fun) + << CurrentFunction->getNameAsString()); + ONS.push_back(FNote); + } + return ONS; + } + // Helper functions void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName, SourceLocation Loc) { @@ -1459,12 +1490,15 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { if (!Loc.isValid()) Loc = FunLocation; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); } public: ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) - : S(S), FunLocation(FL), FunEndLocation(FEL) {} + : S(S), FunLocation(FL), FunEndLocation(FEL), + CurrentFunction(nullptr), Verbose(false) {} + + void setVerbose(bool b) { Verbose = b; } /// \brief Emit all buffered diagnostics in order of sourcelocation. /// We need to output diagnostics produced while iterating through @@ -1482,12 +1516,14 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override { PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) << Loc); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); } + void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc) override { warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc); } + void handleIncorrectUnlockKind(StringRef Kind, Name LockName, LockKind Expected, LockKind Received, SourceLocation Loc) override { @@ -1496,8 +1532,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch) << Kind << LockName << Received << Expected); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); } + void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override { warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc); } @@ -1529,10 +1566,10 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { if (LocLocked.isValid()) { PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here) << Kind); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + Warnings.push_back(DelayedDiag(Warning, getNotes(Note))); return; } - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); } void handleExclusiveAndShared(StringRef Kind, Name LockName, @@ -1543,7 +1580,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { << Kind << LockName); PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) << Kind << LockName); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + Warnings.push_back(DelayedDiag(Warning, getNotes(Note))); } void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, @@ -1556,7 +1593,7 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { diag::warn_var_deref_requires_any_lock; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << D->getNameAsString() << getLockKindFromAccessKind(AK)); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); } void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, @@ -1575,13 +1612,25 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { case POK_FunctionCall: DiagID = diag::warn_fun_requires_lock_precise; break; + case POK_PassByRef: + DiagID = diag::warn_guarded_pass_by_reference; + break; + case POK_PtPassByRef: + DiagID = diag::warn_pt_guarded_pass_by_reference; + break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << D->getNameAsString() << LockName << LK); PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) << *PossibleMatch); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + if (Verbose && POK == POK_VarAccess) { + PartialDiagnosticAt VNote(D->getLocation(), + S.PDiag(diag::note_guarded_by_declared_here) + << D->getNameAsString()); + Warnings.push_back(DelayedDiag(Warning, getNotes(Note, VNote))); + } else + Warnings.push_back(DelayedDiag(Warning, getNotes(Note))); } else { switch (POK) { case POK_VarAccess: @@ -1593,22 +1642,52 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { case POK_FunctionCall: DiagID = diag::warn_fun_requires_lock; break; + case POK_PassByRef: + DiagID = diag::warn_guarded_pass_by_reference; + break; + case POK_PtPassByRef: + DiagID = diag::warn_pt_guarded_pass_by_reference; + break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << D->getNameAsString() << LockName << LK); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + if (Verbose && POK == POK_VarAccess) { + PartialDiagnosticAt Note(D->getLocation(), + S.PDiag(diag::note_guarded_by_declared_here) + << D->getNameAsString()); + Warnings.push_back(DelayedDiag(Warning, getNotes(Note))); + } else + Warnings.push_back(DelayedDiag(Warning, getNotes())); } } + + virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, + SourceLocation Loc) override { + PartialDiagnosticAt Warning(Loc, + S.PDiag(diag::warn_acquire_requires_negative_cap) + << Kind << LockName << Neg); + Warnings.push_back(DelayedDiag(Warning, getNotes())); + } + + void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, SourceLocation Loc) override { PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex) << Kind << FunName << LockName); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); + Warnings.push_back(DelayedDiag(Warning, getNotes())); + } + + void enterFunction(const FunctionDecl* FD) override { + CurrentFunction = FD; + } + + void leaveFunction(const FunctionDecl* FD) override { + CurrentFunction = 0; } }; -} + } } @@ -1896,11 +1975,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (P.enableThreadSafetyAnalysis) { SourceLocation FL = AC.getDecl()->getLocation(); SourceLocation FEL = AC.getDecl()->getLocEnd(); - thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL); + threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL); if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart())) Reporter.setIssueBetaWarnings(true); + if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getLocStart())) + Reporter.setVerbose(true); - thread_safety::runThreadSafetyAnalysis(AC, Reporter); + threadSafety::runThreadSafetyAnalysis(AC, Reporter); Reporter.emitDiagnostics(); } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index 476a22b..34af6cf 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -206,3 +206,11 @@ bool AttributeList::isKnownToGCC() const { unsigned AttributeList::getSemanticSpelling() const { return getInfo(*this).SpellingIndexToSemanticSpelling(*this); } + +bool AttributeList::hasVariadicArg() const { + // If the attribute has the maximum number of optional arguments, we will + // claim that as being variadic. If we someday get an attribute that + // legitimately bumps up against that maximum, we can use another bit to track + // whether it's truly variadic or not. + return getInfo(*this).OptArgs == 15; +} diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 7847d2c..4a772d8 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -21,6 +21,7 @@ add_clang_library(clangSema SemaChecking.cpp SemaCodeComplete.cpp SemaConsumer.cpp + SemaCUDA.cpp SemaDecl.cpp SemaDeclAttr.cpp SemaDeclCXX.cpp diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d7372b7..7bf3e51 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -18,6 +18,7 @@ #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency! #include "clang/Sema/LocInfoType.h" @@ -113,6 +114,18 @@ void CXXScopeSpec::MakeGlobal(ASTContext &Context, "NestedNameSpecifierLoc range computation incorrect"); } +void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Builder.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); + + Range.setBegin(SuperLoc); + Range.setEnd(ColonColonLoc); + + assert(Range == Builder.getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); +} + void CXXScopeSpec::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { Builder.MakeTrivial(Context, Qualifier, R); @@ -159,6 +172,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, SourceLocation ConstQualifierLoc, SourceLocation VolatileQualifierLoc, + SourceLocation + RestrictQualifierLoc, SourceLocation MutableLoc, ExceptionSpecificationType ESpecType, @@ -167,6 +182,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, SourceRange *ExceptionRanges, unsigned NumExceptions, Expr *NoexceptExpr, + CachedTokens *ExceptionSpecTokens, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -193,6 +209,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding(); I.Fun.VolatileQualifierLoc = VolatileQualifierLoc.getRawEncoding(); + I.Fun.RestrictQualifierLoc = RestrictQualifierLoc.getRawEncoding(); I.Fun.MutableLoc = MutableLoc.getRawEncoding(); I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); @@ -203,6 +220,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, TrailingReturnType.isInvalid(); I.Fun.TrailingReturnType = TrailingReturnType.get(); + assert(I.Fun.TypeQuals == TypeQuals && "bitfield overflow"); + assert(I.Fun.ExceptionSpecType == ESpecType && "bitfield overflow"); + // new[] a parameter array if needed. if (NumParams) { // If the 'InlineParams' in Declarator is unused and big enough, put our @@ -239,6 +259,10 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, case EST_ComputedNoexcept: I.Fun.NoexceptExpr = NoexceptExpr; break; + + case EST_Unparsed: + I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; + break; } return I; } @@ -484,14 +508,14 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, case SCS_private_extern: case SCS_static: if (S.getLangOpts().OpenCLVersion < 120) { - DiagID = diag::err_not_opencl_storage_class_specifier; + DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = getSpecifierName(SC); return true; } break; case SCS_auto: case SCS_register: - DiagID = diag::err_not_opencl_storage_class_specifier; + DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = getSpecifierName(SC); return true; default: @@ -553,12 +577,6 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, else if (W != TSW_longlong || TypeSpecWidth != TSW_long) return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; - if (TypeAltiVecVector && !TypeAltiVecBool && - ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); - DiagID = diag::warn_vector_long_decl_spec_combination; - return true; - } return false; } @@ -680,11 +698,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, } TypeSpecType = T; TypeSpecOwned = false; - if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); - DiagID = diag::err_invalid_vector_decl_spec; - return true; - } return false; } @@ -978,6 +991,16 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPoli if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; + } else if (TypeSpecType == TST_double) { + // vector long double and vector long long double are never allowed. + // vector double is OK for Power7 and later. + if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong) + Diag(D, TSWLoc, diag::err_invalid_vector_long_double_decl_spec); + else if (!PP.getTargetInfo().hasFeature("vsx")) + Diag(D, TSTLoc, diag::err_invalid_vector_double_decl_spec); + } else if (TypeSpecWidth == TSW_long) { + Diag(D, TSWLoc, diag::warn_vector_long_decl_spec_combination) + << getSpecifierName((TST)TypeSpecType, Policy); } if (TypeAltiVecPixel) { diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 2a5bacf..6586fb3 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -130,6 +130,9 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S, return false; } + // FIXME: If D is a local extern declaration, this check doesn't make sense; + // we should be checking its lexical context instead in that case, because + // that is its scope. DeclContext *DCtx = D->getDeclContext()->getRedeclContext(); return AllowInlineNamespace ? Ctx->InEnclosingNamespaceSetOf(DCtx) : Ctx->Equals(DCtx); diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 2558452..fd75c02 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -84,6 +84,7 @@ private: void CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, unsigned JumpDiag, unsigned JumpDiagWarning, unsigned JumpDiagCXX98Compat); + void CheckGotoStmt(GotoStmt *GS); unsigned GetDeepestCommonScope(unsigned A, unsigned B); }; @@ -489,10 +490,14 @@ 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::ext_goto_into_protected_scope, - diag::warn_cxx98_compat_goto_into_protected_scope); + // The label may not have a statement if it's coming from inline MS ASM. + if (GS->getLabel()->getStmt()) { + CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(), + diag::err_goto_into_protected_scope, + diag::ext_goto_into_protected_scope, + diag::warn_cxx98_compat_goto_into_protected_scope); + } + CheckGotoStmt(GS); continue; } @@ -789,6 +794,15 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc, } } +void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) { + if (GS->getLabel()->isMSAsmLabel()) { + S.Diag(GS->getGotoLoc(), diag::err_goto_ms_asm_label) + << GS->getLabel()->getIdentifier(); + S.Diag(GS->getLabel()->getLocation(), diag::note_goto_ms_asm_label) + << GS->getLabel()->getIdentifier(); + } +} + void Sema::DiagnoseInvalidJumps(Stmt *Body) { (void)JumpScopeChecker(Body, *this); } diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index 97237db..449ddf4 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -242,6 +242,12 @@ void MultiplexExternalSemaSource::ReadDynamicClasses( Sources[i]->ReadDynamicClasses(Decls); } +void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls); +} + void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls( SmallVectorImpl<NamedDecl*> &Decls) { for(size_t i = 0; i < Sources.size(); ++i) diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp index 35e2075..6c79778 100644 --- a/lib/Sema/Scope.cpp +++ b/lib/Sema/Scope.cpp @@ -39,9 +39,6 @@ void Scope::Init(Scope *parent, unsigned flags) { BlockParent = parent->BlockParent; TemplateParamParent = parent->TemplateParamParent; MSLocalManglingParent = parent->MSLocalManglingParent; - SEHTryParent = parent->SEHTryParent; - if (parent->Flags & SEHTryScope) - SEHTryParent = parent; if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope | FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) == 0) @@ -50,17 +47,13 @@ void Scope::Init(Scope *parent, unsigned flags) { Depth = 0; PrototypeDepth = 0; PrototypeIndex = 0; - SEHTryParent = MSLocalManglingParent = FnParent = BlockParent = nullptr; + MSLocalManglingParent = FnParent = BlockParent = nullptr; TemplateParamParent = nullptr; MSLocalManglingNumber = 1; } // If this scope is a function or contains breaks/continues, remember it. if (flags & FnScope) FnParent = this; - SEHTryIndexPool = 0; - SEHTryIndex = -1; - if (flags & SEHTryScope) - SEHTryIndex = FnParent ? FnParent->SEHTryIndexPool++ : -1; // The MS mangler uses the number of scopes that can hold declarations as // part of an external name. if (Flags & (ClassScope | FnScope)) { diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index 4d079e7..63ef3b2 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -14,6 +14,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -38,6 +39,7 @@ void FunctionScopeInfo::Clear() { ErrorTrap.reset(); PossiblyUnreachableDiags.clear(); WeakObjectUses.clear(); + ModifiedNonNullParams.clear(); } static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) { @@ -93,6 +95,21 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) { return BaseInfoTy(D, IsExact); } +bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const { + RecordDecl *RD = nullptr; + if (auto *LSI = dyn_cast<LambdaScopeInfo>(this)) + RD = LSI->Lambda; + else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(this)) + RD = CRSI->TheRecordDecl; + + if (RD) + for (auto *FD : RD->fields()) { + if (FD->hasCapturedVLAType() && FD->getCapturedVLAType() == VAT) + return true; + } + return false; +} + FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( const ObjCPropertyRefExpr *PropE) : Base(nullptr, true), Property(getBestPropertyDecl(PropE)) { @@ -159,6 +176,8 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { // Has this weak object been seen before? FunctionScopeInfo::WeakObjectUseMap::iterator Uses; if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (!RefExpr->isObjectReceiver()) + return; if (isa<OpaqueValueExpr>(RefExpr->getBase())) Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr)); else { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 2c65332..b9aaf16 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -69,8 +69,6 @@ PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, void Sema::ActOnTranslationUnitScope(Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); - - VAListTagName = PP.getIdentifierInfo("__va_list_tag"); } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, @@ -90,12 +88,14 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), IsBuildingRecoveryCallExpr(false), ExprNeedsCleanups(false), LateTemplateParser(nullptr), + LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), + MSAsmLabelNameCounter(0), GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0), @@ -151,6 +151,10 @@ void Sema::Initialize() { = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) ExternalSema->InitializeSema(*this); + // This needs to happen after ExternalSemaSource::InitializeSema(this) or we + // will not be able to merge any duplicate __va_list_tag decls correctly. + VAListTagName = PP.getIdentifierInfo("__va_list_tag"); + // Initialize predefined 128-bit integer types, if needed. if (Context.getTargetInfo().hasInt128Type()) { // If either of the 128-bit integer types are unavailable to name lookup, @@ -241,6 +245,8 @@ Sema::~Sema() { // Destroys data sharing attributes stack for OpenMP DestroyDataSharingAttributesStack(); + + assert(DelayedTypos.empty() && "Uncorrected typos!"); } /// makeUnavailableInSystemHeader - There is an error in the current @@ -538,7 +544,12 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M)); else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) - Complete = F->getTemplatedDecl()->isDefined(); + // If the template function is marked as late template parsed at this point, + // it has not been instantiated and therefore we have not performed semantic + // analysis on it yet, so we cannot know if the type can be considered + // complete. + Complete = !F->getTemplatedDecl()->isLateTemplateParsed() && + F->getTemplatedDecl()->isDefined(); else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) { if (R->isInjectedClassName()) continue; @@ -591,6 +602,19 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD, return Complete; } +void Sema::emitAndClearUnusedLocalTypedefWarnings() { + if (ExternalSource) + ExternalSource->ReadUnusedLocalTypedefNameCandidates( + UnusedLocalTypedefNameCandidates); + for (const TypedefNameDecl *TD : UnusedLocalTypedefNameCandidates) { + if (TD->isReferenced()) + continue; + Diag(TD->getLocation(), diag::warn_unused_local_typedef) + << isa<TypeAliasDecl>(TD) << TD->getDeclName(); + } + UnusedLocalTypedefNameCandidates.clear(); +} + /// 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. @@ -647,13 +671,16 @@ void Sema::ActOnEndOfTranslationUnit() { } PerformPendingInstantiations(); + if (LateTemplateParserCleanup) + LateTemplateParserCleanup(OpaqueParser); + CheckDelayedMemberExceptionSpecs(); } // All delayed member exception specs should be checked or we end up accepting // incompatible declarations. assert(DelayedDefaultedMemberExceptionSpecs.empty()); - assert(DelayedDestructorExceptionSpecChecks.empty()); + assert(DelayedExceptionSpecChecks.empty()); // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( @@ -713,6 +740,10 @@ void Sema::ActOnEndOfTranslationUnit() { } } + // Warnings emitted in ActOnEndOfTranslationUnit() should be emitted for + // modules when they are built, not every time they are used. + emitAndClearUnusedLocalTypedefWarnings(); + // Modules don't need any of the checking below. TUScope = nullptr; return; @@ -740,7 +771,7 @@ void Sema::ActOnEndOfTranslationUnit() { // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second // return value is false. - if (!VD || VD->isInvalidDecl() || !Seen.insert(VD)) + if (!VD || VD->isInvalidDecl() || !Seen.insert(VD).second) continue; if (const IncompleteArrayType *ArrayT @@ -788,8 +819,9 @@ void Sema::ActOnEndOfTranslationUnit() { !FD->isInlineSpecified() && !SourceMgr.isInMainFile( SourceMgr.getExpansionLoc(FD->getLocation()))) - Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) - << DiagD->getDeclName(); + Diag(DiagD->getLocation(), + diag::warn_unneeded_static_internal_decl) + << DiagD->getDeclName(); else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*function*/0 << DiagD->getDeclName(); @@ -820,6 +852,8 @@ void Sema::ActOnEndOfTranslationUnit() { if (ExternalSource) ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); checkUndefinedButUsed(*this); + + emitAndClearUnusedLocalTypedefWarnings(); } if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) { @@ -1432,8 +1466,8 @@ IdentifierInfo *Sema::getFloat128Identifier() const { void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K) { - CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), S, CD, RD, - CD->getContextParam(), K); + CapturingScopeInfo *CSI = new CapturedRegionScopeInfo( + getDiagnostics(), S, CD, RD, CD->getContextParam(), K); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); } diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index ffdb0aa..37240c2 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1749,14 +1749,14 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { return AR_accessible; CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction()); - assert(method->getQualifier()); AccessTarget entity(Context, AccessTarget::Member, cast<CXXRecordDecl>(target->getDeclContext()), DeclAccessPair::make(target, access), /*no instance context*/ QualType()); entity.setDiag(diag::err_access_friend_function) - << method->getQualifierLoc().getSourceRange(); + << (method->getQualifier() ? method->getQualifierLoc().getSourceRange() + : method->getNameInfo().getSourceRange()); // We need to bypass delayed-diagnostics because we might be called // while the ParsingDeclarator is active. diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index a7d606d..7629797 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -360,18 +360,18 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, } } -bool Sema::UnifySection(const StringRef &SectionName, +bool Sema::UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *Decl) { - auto Section = SectionInfos.find(SectionName); - if (Section == SectionInfos.end()) { - SectionInfos[SectionName] = - SectionInfo(Decl, SourceLocation(), SectionFlags); + auto Section = Context.SectionInfos.find(SectionName); + if (Section == Context.SectionInfos.end()) { + Context.SectionInfos[SectionName] = + ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags); return false; } // A pre-declared section takes precedence w/o diagnostic. if (Section->second.SectionFlags == SectionFlags || - !(Section->second.SectionFlags & PSF_Implicit)) + !(Section->second.SectionFlags & ASTContext::PSF_Implicit)) return false; auto OtherDecl = Section->second.Decl; Diag(Decl->getLocation(), diag::err_section_conflict) @@ -384,17 +384,17 @@ bool Sema::UnifySection(const StringRef &SectionName, if (auto A = OtherDecl->getAttr<SectionAttr>()) if (A->isImplicit()) Diag(A->getLocation(), diag::note_pragma_entered_here); - return false; + return true; } -bool Sema::UnifySection(const StringRef &SectionName, +bool Sema::UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation) { - auto Section = SectionInfos.find(SectionName); - if (Section != SectionInfos.end()) { + auto Section = Context.SectionInfos.find(SectionName); + if (Section != Context.SectionInfos.end()) { if (Section->second.SectionFlags == SectionFlags) return false; - if (!(Section->second.SectionFlags & PSF_Implicit)) { + if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) { Diag(PragmaSectionLocation, diag::err_section_conflict) << "this" << "a prior #pragma section"; Diag(Section->second.PragmaSectionLocation, @@ -402,8 +402,8 @@ bool Sema::UnifySection(const StringRef &SectionName, return true; } } - SectionInfos[SectionName] = - SectionInfo(nullptr, PragmaSectionLocation, SectionFlags); + Context.SectionInfos[SectionName] = + ASTContext::SectionInfo(nullptr, PragmaSectionLocation, SectionFlags); return false; } diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp new file mode 100644 index 0000000..64222fb --- /dev/null +++ b/lib/Sema/SemaCUDA.cpp @@ -0,0 +1,263 @@ +//===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief This file implements semantic analysis for CUDA constructs. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; + +ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, + SourceLocation GGGLoc) { + FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); + if (!ConfigDecl) + return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) + << "cudaConfigureCall"); + QualType ConfigQTy = ConfigDecl->getType(); + + DeclRefExpr *ConfigDR = new (Context) + DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); + MarkFunctionReferenced(LLLLoc, ConfigDecl); + + return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, + /*IsExecConfig=*/true); +} + +/// IdentifyCUDATarget - Determine the CUDA compilation target for this function +Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { + if (D->hasAttr<CUDAInvalidTargetAttr>()) + return CFT_InvalidTarget; + + if (D->hasAttr<CUDAGlobalAttr>()) + return CFT_Global; + + if (D->hasAttr<CUDADeviceAttr>()) { + if (D->hasAttr<CUDAHostAttr>()) + return CFT_HostDevice; + return CFT_Device; + } else if (D->hasAttr<CUDAHostAttr>()) { + return CFT_Host; + } else if (D->isImplicit()) { + // Some implicit declarations (like intrinsic functions) are not marked. + // Set the most lenient target on them for maximal flexibility. + return CFT_HostDevice; + } + + return CFT_Host; +} + +bool Sema::CheckCUDATarget(const FunctionDecl *Caller, + const FunctionDecl *Callee) { + CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller), + CalleeTarget = IdentifyCUDATarget(Callee); + + // If one of the targets is invalid, the check always fails, no matter what + // the other target is. + if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) + return true; + + // 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; + + // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together + // however, in which case the function is compiled for both the host and the + // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code + // paths between host and device." + if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) { + // If the caller is implicit then the check always passes. + if (Caller->isImplicit()) return false; + + bool InDeviceMode = getLangOpts().CUDAIsDevice; + if ((InDeviceMode && CalleeTarget != CFT_Device) || + (!InDeviceMode && CalleeTarget != CFT_Host)) + return true; + } + + return false; +} + +/// When an implicitly-declared special member has to invoke more than one +/// base/field special member, conflicts may occur in the targets of these +/// members. For example, if one base's member __host__ and another's is +/// __device__, it's a conflict. +/// This function figures out if the given targets \param Target1 and +/// \param Target2 conflict, and if they do not it fills in +/// \param ResolvedTarget with a target that resolves for both calls. +/// \return true if there's a conflict, false otherwise. +static bool +resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, + Sema::CUDAFunctionTarget Target2, + Sema::CUDAFunctionTarget *ResolvedTarget) { + if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) { + // TODO: this shouldn't happen, really. Methods cannot be marked __global__. + // Clang should detect this earlier and produce an error. Then this + // condition can be changed to an assertion. + return true; + } + + if (Target1 == Sema::CFT_HostDevice) { + *ResolvedTarget = Target2; + } else if (Target2 == Sema::CFT_HostDevice) { + *ResolvedTarget = Target1; + } else if (Target1 != Target2) { + return true; + } else { + *ResolvedTarget = Target1; + } + + return false; +} + +bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, + CXXSpecialMember CSM, + CXXMethodDecl *MemberDecl, + bool ConstRHS, + bool Diagnose) { + llvm::Optional<CUDAFunctionTarget> InferredTarget; + + // We're going to invoke special member lookup; mark that these special + // members are called from this one, and not from its caller. + ContextRAII MethodContext(*this, MemberDecl); + + // Look for special members in base classes that should be invoked from here. + // Infer the target of this member base on the ones it should call. + // Skip direct and indirect virtual bases for abstract classes. + llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases; + for (const auto &B : ClassDecl->bases()) { + if (!B.isVirtual()) { + Bases.push_back(&B); + } + } + + if (!ClassDecl->isAbstract()) { + for (const auto &VB : ClassDecl->vbases()) { + Bases.push_back(&VB); + } + } + + for (const auto *B : Bases) { + const RecordType *BaseType = B->getType()->getAs<RecordType>(); + if (!BaseType) { + continue; + } + + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + Sema::SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(BaseClassDecl, CSM, + /* ConstArg */ ConstRHS, + /* VolatileArg */ false, + /* RValueThis */ false, + /* ConstThis */ false, + /* VolatileThis */ false); + + if (!SMOR || !SMOR->getMethod()) { + continue; + } + + CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod()); + if (!InferredTarget.hasValue()) { + InferredTarget = BaseMethodTarget; + } else { + bool ResolutionError = resolveCalleeCUDATargetConflict( + InferredTarget.getValue(), BaseMethodTarget, + InferredTarget.getPointer()); + if (ResolutionError) { + if (Diagnose) { + Diag(ClassDecl->getLocation(), + diag::note_implicit_member_target_infer_collision) + << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget; + } + MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); + return true; + } + } + } + + // Same as for bases, but now for special members of fields. + for (const auto *F : ClassDecl->fields()) { + if (F->isInvalidDecl()) { + continue; + } + + const RecordType *FieldType = + Context.getBaseElementType(F->getType())->getAs<RecordType>(); + if (!FieldType) { + continue; + } + + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl()); + Sema::SpecialMemberOverloadResult *SMOR = + LookupSpecialMember(FieldRecDecl, CSM, + /* ConstArg */ ConstRHS && !F->isMutable(), + /* VolatileArg */ false, + /* RValueThis */ false, + /* ConstThis */ false, + /* VolatileThis */ false); + + if (!SMOR || !SMOR->getMethod()) { + continue; + } + + CUDAFunctionTarget FieldMethodTarget = + IdentifyCUDATarget(SMOR->getMethod()); + if (!InferredTarget.hasValue()) { + InferredTarget = FieldMethodTarget; + } else { + bool ResolutionError = resolveCalleeCUDATargetConflict( + InferredTarget.getValue(), FieldMethodTarget, + InferredTarget.getPointer()); + if (ResolutionError) { + if (Diagnose) { + Diag(ClassDecl->getLocation(), + diag::note_implicit_member_target_infer_collision) + << (unsigned)CSM << InferredTarget.getValue() + << FieldMethodTarget; + } + MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); + return true; + } + } + } + + if (InferredTarget.hasValue()) { + if (InferredTarget.getValue() == CFT_Device) { + MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + } else if (InferredTarget.getValue() == CFT_Host) { + MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); + } else { + MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); + } + } else { + // If no target was inferred, mark this member as __host__ __device__; + // it's the least restrictive option that can be invoked from any target. + MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); + } + + return false; +} diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index a70aca2..3e56e67 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -148,6 +148,9 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); + + case NestedNameSpecifier::Super: + return NNS->getAsRecordDecl(); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); @@ -240,12 +243,43 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, return true; } -bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, +bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS) { SS.MakeGlobal(Context, CCLoc); return false; } +bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, + SourceLocation ColonColonLoc, + CXXScopeSpec &SS) { + CXXRecordDecl *RD = nullptr; + for (Scope *S = getCurScope(); S; S = S->getParent()) { + if (S->isFunctionScope()) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(S->getEntity())) + RD = MD->getParent(); + break; + } + if (S->isClassScope()) { + RD = cast<CXXRecordDecl>(S->getEntity()); + break; + } + } + + if (!RD) { + Diag(SuperLoc, diag::err_invalid_super_scope); + return true; + } else if (RD->isLambda()) { + Diag(SuperLoc, diag::err_super_in_lambda_unsupported); + return true; + } else if (RD->getNumBases() == 0) { + Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); + return true; + } + + SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); + return false; +} + /// \brief Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) { @@ -376,9 +410,6 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { /// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// -/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in -/// that it contains an extra parameter \p ScopeLookupResult. -/// /// \param S Scope in which the nested-name-specifier occurs. /// \param Identifier Identifier in the sequence "identifier" "::". /// \param IdentifierLoc Location of the \p Identifier. @@ -541,12 +572,11 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); - NestedNameSpecifierValidatorCCC Validator(*this); Found.clear(); - if (TypoCorrection Corrected = - CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, - &SS, Validator, CTK_ErrorRecovery, LookupCtx, - EnteringContext)) { + if (TypoCorrection Corrected = CorrectTypo( + Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, + llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this), + CTK_ErrorRecovery, LookupCtx, EnteringContext)) { if (LookupCtx) { bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && @@ -612,10 +642,17 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, } } + if (auto *TD = dyn_cast_or_null<TypedefNameDecl>(SD)) + MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); + // If we're just performing this lookup for error-recovery purposes, // don't extend the nested-name-specifier. Just return now. if (ErrorRecoveryLookup) return false; + + // The use of a nested name specifier may trigger deprecation warnings. + DiagnoseUseOfDecl(SD, CCLoc); + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) { SS.Extend(Context, Namespace, IdentifierLoc, CCLoc); @@ -703,8 +740,13 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (getLangOpts().MSVCCompat) { DeclContext *DC = LookupCtx ? LookupCtx : CurContext; if (DC->isDependentContext() && DC->isFunctionOrMethod()) { - SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); - return false; + CXXRecordDecl *ContainingClass = dyn_cast<CXXRecordDecl>(DC->getParent()); + if (ContainingClass && ContainingClass->hasAnyDependentBases()) { + Diag(IdentifierLoc, diag::ext_undeclared_unqual_id_with_dependent_base) + << &Identifier << ContainingClass; + SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + return false; + } } } @@ -945,6 +987,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::Super: // These are never namespace scopes. return true; } diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index ae5436c..a4c2d9b 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -142,9 +142,6 @@ namespace { }; } -static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, - bool CheckCVR, bool CheckObjCLifetime); - // The Try functions attempt a specific way of casting. If they succeed, they // return TC_Success. If their way of casting is not appropriate for the given // arguments, they return TC_NotApplicable and *may* set diag to a diagnostic @@ -243,10 +240,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, QualType DestType = DestTInfo->getType(); // 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() || - Ex.get()->isValueDependent(); + bool TypeDependent = + DestType->isDependentType() || Ex.get()->isTypeDependent(); CastOperation Op(*this, DestType, E); Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); @@ -462,7 +457,10 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { /// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers. static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, - bool CheckCVR, bool CheckObjCLifetime) { + bool CheckCVR, bool CheckObjCLifetime, + QualType *TheOffendingSrcType = nullptr, + QualType *TheOffendingDestType = nullptr, + Qualifiers *CastAwayQualifiers = nullptr) { // If the only checking we care about is for Objective-C lifetime qualifiers, // and we're not in ARC mode, there's nothing to check. if (!CheckCVR && CheckObjCLifetime && @@ -487,6 +485,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, // Find the qualifiers. We only care about cvr-qualifiers for the // purpose of this check, because other qualifiers (address spaces, // Objective-C GC, etc.) are part of the type's identity. + QualType PrevUnwrappedSrcType = UnwrappedSrcType; + QualType PrevUnwrappedDestType = UnwrappedDestType; while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { // Determine the relevant qualifiers at this level. Qualifiers SrcQuals, DestQuals; @@ -497,6 +497,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, if (CheckCVR) { RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers()); RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers()); + + if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType && + TheOffendingDestType && CastAwayQualifiers) { + *TheOffendingSrcType = PrevUnwrappedSrcType; + *TheOffendingDestType = PrevUnwrappedDestType; + *CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals; + } } if (CheckObjCLifetime && @@ -505,6 +512,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, cv1.push_back(RetainedSrcQuals); cv2.push_back(RetainedDestQuals); + + PrevUnwrappedSrcType = UnwrappedSrcType; + PrevUnwrappedDestType = UnwrappedDestType; } if (cv1.empty()) return false; @@ -2200,8 +2210,8 @@ void CastOperation::CheckCStyleCast() { // address space B is illegal. if (Self.getLangOpts().OpenCL && DestType->isPointerType() && SrcType->isPointerType()) { - if (DestType->getPointeeType().getAddressSpace() != - SrcType->getPointeeType().getAddressSpace()) { + const PointerType *DestPtr = DestType->getAs<PointerType>(); + if (!DestPtr->isAddressSpaceOverlapping(*SrcType->getAs<PointerType>())) { Self.Diag(OpRange.getBegin(), diag::err_typecheck_incompatible_address_space) << SrcType << DestType << Sema::AA_Casting @@ -2371,6 +2381,30 @@ void CastOperation::CheckCStyleCast() { if (Kind == CK_BitCast) checkCastAlign(); + + // -Wcast-qual + QualType TheOffendingSrcType, TheOffendingDestType; + Qualifiers CastAwayQualifiers; + if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() && + CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers)) { + int qualifiers = -1; + if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { + qualifiers = 0; + } else if (CastAwayQualifiers.hasConst()) { + qualifiers = 1; + } else if (CastAwayQualifiers.hasVolatile()) { + qualifiers = 2; + } + // This is a variant of int **x; const int **y = (const int **)x; + if (qualifiers == -1) + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) << + SrcType << DestType; + else + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) << + TheOffendingSrcType << TheOffendingDestType << qualifiers; + } } ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 66be962..9fc2bec 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -111,8 +111,100 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { return false; } +static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, + CallExpr *TheCall, unsigned SizeIdx, + unsigned DstSizeIdx) { + if (TheCall->getNumArgs() <= SizeIdx || + TheCall->getNumArgs() <= DstSizeIdx) + return; + + const Expr *SizeArg = TheCall->getArg(SizeIdx); + const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx); + + llvm::APSInt Size, DstSize; + + // find out if both sizes are known at compile time + if (!SizeArg->EvaluateAsInt(Size, S.Context) || + !DstSizeArg->EvaluateAsInt(DstSize, S.Context)) + return; + + if (Size.ule(DstSize)) + return; + + // confirmed overflow so generate the diagnostic. + IdentifierInfo *FnName = FDecl->getIdentifier(); + SourceLocation SL = TheCall->getLocStart(); + SourceRange SR = TheCall->getSourceRange(); + + S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName; +} + +static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { + if (checkArgCount(S, BuiltinCall, 2)) + return true; + + SourceLocation BuiltinLoc = BuiltinCall->getLocStart(); + Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts(); + Expr *Call = BuiltinCall->getArg(0); + Expr *Chain = BuiltinCall->getArg(1); + + if (Call->getStmtClass() != Stmt::CallExprClass) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) + << Call->getSourceRange(); + return true; + } + + auto CE = cast<CallExpr>(Call); + if (CE->getCallee()->getType()->isBlockPointerType()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) + << Call->getSourceRange(); + return true; + } + + const Decl *TargetDecl = CE->getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) + if (FD->getBuiltinID()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) + << Call->getSourceRange(); + return true; + } + + if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) + << Call->getSourceRange(); + return true; + } + + ExprResult ChainResult = S.UsualUnaryConversions(Chain); + if (ChainResult.isInvalid()) + return true; + if (!ChainResult.get()->getType()->isPointerType()) { + S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) + << Chain->getSourceRange(); + return true; + } + + QualType ReturnTy = CE->getCallReturnType(); + QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() }; + QualType BuiltinTy = S.Context.getFunctionType( + ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo()); + QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy); + + Builtin = + S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get(); + + BuiltinCall->setType(CE->getType()); + BuiltinCall->setValueKind(CE->getValueKind()); + BuiltinCall->setObjectKind(CE->getObjectKind()); + BuiltinCall->setCallee(Builtin); + BuiltinCall->setArg(1, ChainResult.get()); + + return false; +} + ExprResult -Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, + CallExpr *TheCall) { ExprResult TheCallResult(TheCall); // Find out if any arguments are required to be integer constant expressions. @@ -189,9 +281,14 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return ExprError(); break; case Builtin::BI__assume: + case Builtin::BI__builtin_assume: if (SemaBuiltinAssume(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_assume_aligned: + if (SemaBuiltinAssumeAligned(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_object_size: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); @@ -239,6 +336,12 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: @@ -269,6 +372,12 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: @@ -327,6 +436,31 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { // so ensure that they are declared. DeclareGlobalNewDelete(); break; + + // check secure string manipulation functions where overflows + // are detectable at compile time + case Builtin::BI__builtin___memcpy_chk: + case Builtin::BI__builtin___memmove_chk: + case Builtin::BI__builtin___memset_chk: + case Builtin::BI__builtin___strlcat_chk: + case Builtin::BI__builtin___strlcpy_chk: + case Builtin::BI__builtin___strncat_chk: + case Builtin::BI__builtin___strncpy_chk: + case Builtin::BI__builtin___stpncpy_chk: + SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3); + break; + case Builtin::BI__builtin___memccpy_chk: + SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4); + break; + case Builtin::BI__builtin___snprintf_chk: + case Builtin::BI__builtin___vsnprintf_chk: + SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); + break; + + case Builtin::BI__builtin_call_with_static_chain: + if (SemaBuiltinCallWithStaticChain(*this, TheCall)) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those @@ -342,8 +476,6 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: - case llvm::Triple::arm64: - case llvm::Triple::arm64_be: if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; @@ -468,8 +600,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { QualType RHSTy = RHS.get()->getType(); llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); - bool IsPolyUnsigned = - Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::arm64; + bool IsPolyUnsigned = Arch == llvm::Triple::aarch64; bool IsInt64Long = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong; QualType EltTy = @@ -627,6 +758,11 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); } + if (BuiltinID == ARM::BI__builtin_arm_prefetch) { + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + } + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -641,7 +777,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break; case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: - case ARM::BI__builtin_arm_isb: l = 0; u = 15; break; + case ARM::BI__builtin_arm_isb: + case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break; } // FIXME: VFP Intrinsics should error if VFP not present. @@ -659,6 +796,13 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); } + if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) || + SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); + } + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; @@ -672,7 +816,6 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; } - // FIXME: VFP Intrinsics should error if VFP not present. return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } @@ -693,12 +836,16 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { - case X86::BI_mm_prefetch: - // This is declared to take (const char*, int) - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + default: return false; + case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break; + case X86::BI__builtin_ia32_cmpps: + case X86::BI__builtin_ia32_cmpss: + case X86::BI__builtin_ia32_cmppd: + case X86::BI__builtin_ia32_cmpsd: i = 2; l = 0; u = 31; break; } - return false; + return SemaBuiltinConstantArgRange(TheCall, i, l, u); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -753,14 +900,79 @@ static void CheckNonNullArgument(Sema &S, S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange(); } +bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { + FormatStringInfo FSI; + if ((GetFormatStringType(Format) == FST_NSString) && + getFormatStringInfo(Format, false, &FSI)) { + Idx = FSI.FormatIdx; + return true; + } + return false; +} +/// \brief Diagnose use of %s directive in an NSString which is being passed +/// as formatting string to formatting method. +static void +DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, + const NamedDecl *FDecl, + Expr **Args, + unsigned NumArgs) { + unsigned Idx = 0; + bool Format = false; + ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily(); + if (SFFamily == ObjCStringFormatFamily::SFF_CFString) { + Idx = 2; + Format = true; + } + else + for (const auto *I : FDecl->specific_attrs<FormatAttr>()) { + if (S.GetFormatNSStringIdx(I, Idx)) { + Format = true; + break; + } + } + if (!Format || NumArgs <= Idx) + return; + const Expr *FormatExpr = Args[Idx]; + if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr)) + FormatExpr = CSCE->getSubExpr(); + const StringLiteral *FormatString; + if (const ObjCStringLiteral *OSL = + dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) + FormatString = OSL->getString(); + else + FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts()); + if (!FormatString) + return; + if (S.FormatStringHasSArg(FormatString)) { + S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) + << "%s" << 1 << 1; + S.Diag(FDecl->getLocation(), diag::note_entity_declared_at) + << FDecl->getDeclName(); + } +} + static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, - const Expr * const *ExprArgs, + ArrayRef<const Expr *> Args, SourceLocation CallSiteLoc) { // Check the attributes attached to the method/function itself. + llvm::SmallBitVector NonNullArgs; for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) { - for (const auto &Val : NonNull->args()) - CheckNonNullArgument(S, ExprArgs[Val], CallSiteLoc); + if (!NonNull->args_size()) { + // Easy case: all pointer arguments are nonnull. + for (const auto *Arg : Args) + if (S.isValidPointerAttrType(Arg->getType())) + CheckNonNullArgument(S, Arg, CallSiteLoc); + return; + } + + for (unsigned Val : NonNull->args()) { + if (Val >= Args.size()) + continue; + if (NonNullArgs.empty()) + NonNullArgs.resize(Args.size()); + NonNullArgs.set(Val); + } } // Check the attributes on the parameters. @@ -770,13 +982,19 @@ static void CheckNonNullArguments(Sema &S, else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl)) parms = MD->parameters(); - unsigned argIndex = 0; + unsigned ArgIndex = 0; for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); - I != E; ++I, ++argIndex) { + I != E; ++I, ++ArgIndex) { const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>()) - CheckNonNullArgument(S, ExprArgs[argIndex], CallSiteLoc); + if (PVD->hasAttr<NonNullAttr>() || + (ArgIndex < NonNullArgs.size() && NonNullArgs[ArgIndex])) + CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); } + + // In case this is a variadic call, check any remaining arguments. + for (/**/; ArgIndex < NonNullArgs.size(); ++ArgIndex) + if (NonNullArgs[ArgIndex]) + CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); } /// Handles the checks for format strings, non-POD arguments to vararg @@ -814,7 +1032,7 @@ void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args, } if (FDecl) { - CheckNonNullArguments(*this, FDecl, Args.data(), Loc); + CheckNonNullArguments(*this, FDecl, Args, Loc); // Type safety checking. for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>()) @@ -854,7 +1072,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, ++Args; --NumArgs; } - checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs), NumParams, + checkCall(FDecl, llvm::makeArrayRef(Args, NumArgs), NumParams, IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -865,6 +1083,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, return false; CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo); + if (getLangOpts().ObjC1) + DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); unsigned CMId = FDecl->getMemoryFunctionKind(); if (CMId == 0) @@ -913,8 +1133,8 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, } unsigned NumParams = Proto ? Proto->getNumParams() : 0; - checkCall(NDecl, llvm::makeArrayRef<const Expr *>(TheCall->getArgs(), - TheCall->getNumArgs()), + checkCall(NDecl, llvm::makeArrayRef(TheCall->getArgs(), + TheCall->getNumArgs()), NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -929,8 +1149,7 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { unsigned NumParams = Proto ? Proto->getNumParams() : 0; checkCall(/*FDecl=*/nullptr, - llvm::makeArrayRef<const Expr *>(TheCall->getArgs(), - TheCall->getNumArgs()), + llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -1383,12 +1602,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BUILTIN_ROW(__sync_fetch_and_or), BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), + BUILTIN_ROW(__sync_fetch_and_nand), BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), + BUILTIN_ROW(__sync_nand_and_fetch), BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), @@ -1418,6 +1639,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // as the number of fixed args. unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; + bool WarnAboutSemanticsChange = false; switch (BuiltinID) { default: llvm_unreachable("Unknown overloaded atomic builtin!"); case Builtin::BI__sync_fetch_and_add: @@ -1465,13 +1687,23 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BuiltinIndex = 4; break; + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_fetch_and_nand_1: + case Builtin::BI__sync_fetch_and_nand_2: + case Builtin::BI__sync_fetch_and_nand_4: + case Builtin::BI__sync_fetch_and_nand_8: + case Builtin::BI__sync_fetch_and_nand_16: + BuiltinIndex = 5; + WarnAboutSemanticsChange = true; + break; + case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: - BuiltinIndex = 5; + BuiltinIndex = 6; break; case Builtin::BI__sync_sub_and_fetch: @@ -1480,7 +1712,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: - BuiltinIndex = 6; + BuiltinIndex = 7; break; case Builtin::BI__sync_and_and_fetch: @@ -1489,7 +1721,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: - BuiltinIndex = 7; + BuiltinIndex = 8; break; case Builtin::BI__sync_or_and_fetch: @@ -1498,7 +1730,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: - BuiltinIndex = 8; + BuiltinIndex = 9; break; case Builtin::BI__sync_xor_and_fetch: @@ -1507,7 +1739,17 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: - BuiltinIndex = 9; + BuiltinIndex = 10; + break; + + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_nand_and_fetch_1: + case Builtin::BI__sync_nand_and_fetch_2: + case Builtin::BI__sync_nand_and_fetch_4: + case Builtin::BI__sync_nand_and_fetch_8: + case Builtin::BI__sync_nand_and_fetch_16: + BuiltinIndex = 11; + WarnAboutSemanticsChange = true; break; case Builtin::BI__sync_val_compare_and_swap: @@ -1516,7 +1758,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: case Builtin::BI__sync_val_compare_and_swap_16: - BuiltinIndex = 10; + BuiltinIndex = 12; NumFixed = 2; break; @@ -1526,7 +1768,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: case Builtin::BI__sync_bool_compare_and_swap_16: - BuiltinIndex = 11; + BuiltinIndex = 13; NumFixed = 2; ResultType = Context.BoolTy; break; @@ -1537,7 +1779,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: - BuiltinIndex = 12; + BuiltinIndex = 14; break; case Builtin::BI__sync_lock_release: @@ -1546,7 +1788,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_lock_release_4: case Builtin::BI__sync_lock_release_8: case Builtin::BI__sync_lock_release_16: - BuiltinIndex = 13; + BuiltinIndex = 15; NumFixed = 0; ResultType = Context.VoidTy; break; @@ -1557,7 +1799,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - BuiltinIndex = 14; + BuiltinIndex = 16; break; } @@ -1570,6 +1812,11 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + if (WarnAboutSemanticsChange) { + Diag(TheCall->getLocEnd(), diag::warn_sync_fetch_and_nand_semantics_change) + << TheCall->getCallee()->getSourceRange(); + } + // Get the decl for the concrete builtin from this, we can tell what the // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; @@ -2031,7 +2278,46 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { if (Arg->HasSideEffects(Context)) return Diag(Arg->getLocStart(), diag::warn_assume_side_effects) - << Arg->getSourceRange(); + << Arg->getSourceRange() + << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier(); + + return false; +} + +/// Handle __builtin_assume_aligned. This is declared +/// as (const void*, size_t, ...) and can take one optional constant int arg. +bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs > 3) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 3 << NumArgs + << TheCall->getSourceRange(); + + // The alignment must be a constant integer. + Expr *Arg = TheCall->getArg(1); + + // We can't check the value of a dependent argument. + if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + + if (!Result.isPowerOf2()) + return Diag(TheCall->getLocStart(), + diag::err_alignment_not_power_of_two) + << Arg->getSourceRange(); + } + + if (NumArgs > 2) { + ExprResult Arg(TheCall->getArg(2)); + InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, + Context.getSizeType(), false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) return true; + TheCall->setArg(2, Arg.get()); + } return false; } @@ -3178,6 +3464,61 @@ static bool requiresParensToAddCast(const Expr *E) { } } +static std::pair<QualType, StringRef> +shouldNotPrintDirectly(const ASTContext &Context, + QualType IntendedTy, + const Expr *E) { + // Use a 'while' to peel off layers of typedefs. + QualType TyTy = IntendedTy; + while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { + StringRef Name = UserTy->getDecl()->getName(); + QualType CastTy = llvm::StringSwitch<QualType>(Name) + .Case("NSInteger", Context.LongTy) + .Case("NSUInteger", Context.UnsignedLongTy) + .Case("SInt32", Context.IntTy) + .Case("UInt32", Context.UnsignedIntTy) + .Default(QualType()); + + if (!CastTy.isNull()) + return std::make_pair(CastTy, Name); + + TyTy = UserTy->desugar(); + } + + // Strip parens if necessary. + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) + return shouldNotPrintDirectly(Context, + PE->getSubExpr()->getType(), + PE->getSubExpr()); + + // If this is a conditional expression, then its result type is constructed + // via usual arithmetic conversions and thus there might be no necessary + // typedef sugar there. Recurse to operands to check for NSInteger & + // Co. usage condition. + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + QualType TrueTy, FalseTy; + StringRef TrueName, FalseName; + + std::tie(TrueTy, TrueName) = + shouldNotPrintDirectly(Context, + CO->getTrueExpr()->getType(), + CO->getTrueExpr()); + std::tie(FalseTy, FalseName) = + shouldNotPrintDirectly(Context, + CO->getFalseExpr()->getType(), + CO->getFalseExpr()); + + if (TrueTy == FalseTy) + return std::make_pair(TrueTy, TrueName); + else if (TrueTy.isNull()) + return std::make_pair(FalseTy, FalseName); + else if (FalseTy.isNull()) + return std::make_pair(TrueTy, TrueName); + } + + return std::make_pair(QualType(), StringRef()); +} + bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, @@ -3269,25 +3610,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // Special-case some of Darwin's platform-independence types by suggesting // casts to primitive types that are known to be large enough. - bool ShouldNotPrintDirectly = false; + bool ShouldNotPrintDirectly = false; StringRef CastTyName; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { - // Use a 'while' to peel off layers of typedefs. - QualType TyTy = IntendedTy; - while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) { - StringRef Name = UserTy->getDecl()->getName(); - QualType CastTy = llvm::StringSwitch<QualType>(Name) - .Case("NSInteger", S.Context.LongTy) - .Case("NSUInteger", S.Context.UnsignedLongTy) - .Case("SInt32", S.Context.IntTy) - .Case("UInt32", S.Context.UnsignedIntTy) - .Default(QualType()); - - if (!CastTy.isNull()) { - ShouldNotPrintDirectly = true; - IntendedTy = CastTy; - break; - } - TyTy = UserTy->desugar(); + QualType CastTy; + std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); + if (!CastTy.isNull()) { + IntendedTy = CastTy; + ShouldNotPrintDirectly = true; } } @@ -3304,7 +3633,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); - if (IntendedTy == ExprTy) { + if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { // In this case, the specifier is wrong and should be changed to match // the argument. EmitFormatDiagnostic( @@ -3358,8 +3687,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // The expression has a type that should not be printed directly. // We extract the name from the typedef because we don't want to show // the underlying type in the diagnostic. - StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName(); - + StringRef Name; + if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(ExprTy)) + Name = TypedefTy->getDecl()->getName(); + else + Name = CastTyName; EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) << Name << IntendedTy << IsEnum << E->getSourceRange(), @@ -3395,6 +3727,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, break; case Sema::VAK_Undefined: + case Sema::VAK_MSVCUndefined: EmitFormatDiagnostic( S.PDiag(diag::warn_non_pod_vararg_with_format_string) << S.getLangOpts().CPlusPlus11 @@ -3672,6 +4005,20 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } // TODO: handle other formats } +bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) { + // Str - The format string. NOTE: this is NOT null-terminated! + StringRef StrRef = FExpr->getString(); + const char *Str = StrRef.data(); + // Account for cases where the string literal is truncated in a declaration. + const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); + assert(T && "String literal not of constant array type!"); + size_t TypeSize = T->getSize().getZExtValue(); + size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); + return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen, + getLangOpts(), + Context.getTargetInfo()); +} + //===--- CHECK: Warn on use of wrong absolute value function. -------------===// // Returns the related absolute value function that is larger, of 0 if one @@ -4346,7 +4693,8 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName) { // Don't crash if the user has the wrong number of arguments - if (Call->getNumArgs() != 3) + unsigned NumArgs = Call->getNumArgs(); + if ((NumArgs != 3) && (NumArgs != 4)) return; const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context); @@ -4628,7 +4976,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, DeclRefExpr *DR = cast<DeclRefExpr>(E); // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingLocal()) + if (DR->refersToEnclosingVariableOrCapture()) return nullptr; if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) @@ -4795,7 +5143,7 @@ do { DeclRefExpr *DR = cast<DeclRefExpr>(E); // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingLocal()) + if (DR->refersToEnclosingVariableOrCapture()) return nullptr; if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { @@ -5660,8 +6008,13 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { static void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); - assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()) - && "comparison with mismatched types"); + + // Only analyze comparison operators where both sides have been converted to + // the same type. + if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())) + return AnalyzeImpConvsInComparison(S, E); + + // Don't analyze value-dependent comparisons directly. if (E->isValueDependent()) return AnalyzeImpConvsInComparison(S, E); @@ -5932,6 +6285,41 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, } } +static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { + if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, + E->getExprLoc())) + return; + + // Check for NULL (GNUNull) or nullptr (CXX11_nullptr). + const Expr::NullPointerConstantKind NullKind = + E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull); + if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr) + return; + + // Return if target type is a safe conversion. + if (T->isAnyPointerType() || T->isBlockPointerType() || + T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType()) + return; + + SourceLocation Loc = E->getSourceRange().getBegin(); + + // __null is usually wrapped in a macro. Go up a macro if that is the case. + if (NullKind == Expr::NPCK_GNUNull) { + if (Loc.isMacroID()) + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; + } + + // Only warn if the null and context location are in the same macro expansion. + if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC)) + return; + + S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) + << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC) + << FixItHint::CreateReplacement(Loc, + S.getFixItZeroLiteralForType(T, Loc)); +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -6074,19 +6462,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } - if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) - == Expr::NPCK_GNUNull) && !Target->isAnyPointerType() - && !Target->isBlockPointerType() && !Target->isMemberPointerType() - && Target->isScalarType() && !Target->isNullPtrType()) { - SourceLocation Loc = E->getSourceRange().getBegin(); - if (Loc.isMacroID()) - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; - if (!Loc.isMacroID() || CC.isMacroID()) - S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) - << T << clang::SourceRange(CC) - << FixItHint::CreateReplacement(Loc, - S.getFixItZeroLiteralForType(T, Loc)); - } + DiagnoseNullConversion(S, E, T, CC); if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -6196,7 +6572,7 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T, void CheckConditionalOperator(Sema &S, ConditionalOperator *E, SourceLocation CC, QualType T) { - AnalyzeImplicitConversions(S, E->getCond(), CC); + AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); bool Suspicious = false; CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); @@ -6222,6 +6598,14 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, E->getType(), CC, &Suspicious); } +/// CheckBoolLikeConversion - Check conversion of given expression to boolean. +/// Input argument E is a logical expression. +static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { + if (S.getLangOpts().Bool) + return; + CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); +} + /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. @@ -6301,6 +6685,20 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { continue; AnalyzeImplicitConversions(S, ChildExpr, CC); } + + if (BO && BO->isLogicalOp()) { + Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts(); + if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr)) + ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); + + SubExpr = BO->getRHS()->IgnoreParenImpCasts(); + if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr)) + ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); + } + + if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) + if (U->getOpcode() == UO_LNot) + ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } } // end anonymous namespace @@ -6343,6 +6741,22 @@ static bool CheckForReference(Sema &SemaRef, const Expr *E, return true; } +// Returns true if the SourceLocation is expanded from any macro body. +// Returns false if the SourceLocation is invalid, is from not in a macro +// expansion, or is from expanded from a top-level macro argument. +static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { + if (Loc.isInvalid()) + return false; + + while (Loc.isMacroID()) { + if (SM.isMacroBodyExpansion(Loc)) + return true; + Loc = SM.getImmediateMacroCallerLoc(Loc); + } + + return false; +} + /// \brief Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is @@ -6356,8 +6770,12 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, return; // Don't warn inside macros. - if (E->getExprLoc().isMacroID()) + if (E->getExprLoc().isMacroID()) { + const SourceManager &SM = getSourceManager(); + if (IsInAnyMacroBody(SM, E->getExprLoc()) || + IsInAnyMacroBody(SM, Range.getBegin())) return; + } E = E->IgnoreImpCasts(); const bool IsCompare = NullKind != Expr::NPCK_NotNull; @@ -6400,7 +6818,40 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, // Weak Decls can be null. if (!D || D->isWeak()) return; - + + // Check for parameter decl with nonnull attribute + if (const ParmVarDecl* PV = dyn_cast<ParmVarDecl>(D)) { + if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV)) + if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + unsigned NumArgs = FD->getNumParams(); + llvm::SmallBitVector AttrNonNull(NumArgs); + for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { + if (!NonNull->args_size()) { + AttrNonNull.set(0, NumArgs); + break; + } + for (unsigned Val : NonNull->args()) { + if (Val >= NumArgs) + continue; + AttrNonNull.set(Val); + } + } + if (!AttrNonNull.empty()) + for (unsigned i = 0; i < NumArgs; ++i) + if (FD->getParamDecl(i) == PV && + (AttrNonNull[i] || PV->hasAttr<NonNullAttr>())) { + std::string Str; + llvm::raw_string_ostream S(Str); + E->printPretty(S, nullptr, getPrintingPolicy()); + unsigned DiagID = IsCompare ? diag::warn_nonnull_parameter_compare + : diag::warn_cast_nonnull_to_bool; + Diag(E->getExprLoc(), DiagID) << S.str() << E->getSourceRange() + << Range << IsEqual; + return; + } + } + } + QualType T = D->getType(); const bool IsArray = T->isArrayType(); const bool IsFunction = T->isFunctionType(); @@ -6496,11 +6947,17 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { AnalyzeImplicitConversions(*this, E, CC); } +/// CheckBoolLikeConversion - Check conversion of given expression to boolean. +/// Input argument E is a logical expression. +void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { + ::CheckBoolLikeConversion(*this, E, CC); +} + /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow void Sema::CheckForIntOverflow (Expr *E) { - if (isa<BinaryOperator>(E->IgnoreParens())) - E->EvaluateForOverflow(Context); + if (isa<BinaryOperator>(E->IgnoreParenCasts())) + E->IgnoreParenCasts()->EvaluateForOverflow(Context); } namespace { @@ -6630,11 +7087,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { Self.ModAsSideEffect = &ModAsSideEffect; } ~SequencedSubexpression() { - for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) { - UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first]; - U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second; - Self.addUsage(U, ModAsSideEffect[I].first, - ModAsSideEffect[I].second.Use, UK_ModAsValue); + for (auto MI = ModAsSideEffect.rbegin(), ME = ModAsSideEffect.rend(); + MI != ME; ++MI) { + UsageInfo &U = Self.UsageMap[MI->first]; + auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; + Self.addUsage(U, MI->first, SideEffectUsage.Use, UK_ModAsValue); + SideEffectUsage = MI->second; } Self.ModAsSideEffect = OldModAsSideEffect; } @@ -7867,6 +8325,96 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, } } +//===--- CHECK: Warn on self move with std::move. -------------------------===// + +/// DiagnoseSelfMove - Emits a warning if a value is moved to itself. +void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, + SourceLocation OpLoc) { + + if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) + return; + + if (!ActiveTemplateInstantiations.empty()) + return; + + // Strip parens and casts away. + LHSExpr = LHSExpr->IgnoreParenImpCasts(); + RHSExpr = RHSExpr->IgnoreParenImpCasts(); + + // Check for a call expression + const CallExpr *CE = dyn_cast<CallExpr>(RHSExpr); + if (!CE || CE->getNumArgs() != 1) + return; + + // Check for a call to std::move + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || + !FD->getIdentifier()->isStr("move")) + return; + + // Get argument from std::move + RHSExpr = CE->getArg(0); + + const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr); + const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr); + + // Two DeclRefExpr's, check that the decls are the same. + if (LHSDeclRef && RHSDeclRef) { + if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) + return; + if (LHSDeclRef->getDecl()->getCanonicalDecl() != + RHSDeclRef->getDecl()->getCanonicalDecl()) + return; + + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + return; + } + + // Member variables require a different approach to check for self moves. + // MemberExpr's are the same if every nested MemberExpr refers to the same + // Decl and that the base Expr's are DeclRefExpr's with the same Decl or + // the base Expr's are CXXThisExpr's. + const Expr *LHSBase = LHSExpr; + const Expr *RHSBase = RHSExpr; + const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr); + const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr); + if (!LHSME || !RHSME) + return; + + while (LHSME && RHSME) { + if (LHSME->getMemberDecl()->getCanonicalDecl() != + RHSME->getMemberDecl()->getCanonicalDecl()) + return; + + LHSBase = LHSME->getBase(); + RHSBase = RHSME->getBase(); + LHSME = dyn_cast<MemberExpr>(LHSBase); + RHSME = dyn_cast<MemberExpr>(RHSBase); + } + + LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase); + RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase); + if (LHSDeclRef && RHSDeclRef) { + if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) + return; + if (LHSDeclRef->getDecl()->getCanonicalDecl() != + RHSDeclRef->getDecl()->getCanonicalDecl()) + return; + + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); + return; + } + + if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase)) + Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() + << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); +} + //===--- Layout compatibility ----------------------------------------------// namespace { diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3d250e3..48bdd2a 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -292,7 +292,7 @@ namespace { void MaybeAddResult(Result R, DeclContext *CurContext = nullptr); /// \brief Add a new result to this result set, where we already know - /// the hiding declation (if any). + /// the hiding declaration (if any). /// /// \param R the result to add (if it is unique). /// @@ -894,7 +894,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { } // Make sure that any given declaration only shows up in the result set once. - if (!AllDeclsFound.insert(CanonDecl)) + if (!AllDeclsFound.insert(CanonDecl).second) return; // If the filter is for nested-name-specifiers, then this result starts a @@ -957,7 +957,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, return; // Make sure that any given declaration only shows up in the result set once. - if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl())) + if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()).second) return; // If the filter is for nested-name-specifiers, then this result starts a @@ -2575,11 +2575,12 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, const MacroDirective *MD = PP.getMacroDirectiveHistory(Macro); assert(MD && "Not a macro?"); const MacroInfo *MI = MD->getMacroInfo(); + assert((!MD->isDefined() || MI) && "missing MacroInfo for define"); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Macro->getName())); - if (!MI->isFunctionLike()) + if (!MI || !MI->isFunctionLike()) return Result.TakeString(); // Format a function-like macro with placeholders for the arguments. @@ -3466,7 +3467,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, // Add properties in this container. for (const auto *P : Container->properties()) - if (AddedProperties.insert(P->getIdentifier())) + if (AddedProperties.insert(P->getIdentifier()).second) Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr), CurContext); @@ -3477,7 +3478,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, for (auto *M : Container->methods()) { if (M->getSelector().isUnarySelector()) if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) - if (AddedProperties.insert(Name)) { + if (AddedProperties.insert(Name).second) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); AddResultTypeChunk(Context, Policy, M, Builder); @@ -4235,7 +4236,8 @@ void Sema::CodeCompleteConstructorInitializer( bool SawLastInitializer = Initializers.empty(); CXXRecordDecl *ClassDecl = Constructor->getParent(); for (const auto &Base : ClassDecl->bases()) { - if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) { + if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) + .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isBaseInitializer() && @@ -4258,7 +4260,8 @@ void Sema::CodeCompleteConstructorInitializer( // Add completions for virtual base classes. for (const auto &Base : ClassDecl->vbases()) { - if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) { + if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) + .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isBaseInitializer() && @@ -4281,7 +4284,8 @@ void Sema::CodeCompleteConstructorInitializer( // Add completions for members. for (auto *Field : ClassDecl->fields()) { - if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))) { + if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl())) + .second) { SawLastInitializer = !Initializers.empty() && Initializers.back()->isAnyMemberInitializer() && @@ -4348,7 +4352,7 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, Var->hasAttr<BlocksAttr>()) continue; - if (Known.insert(Var->getIdentifier())) + if (Known.insert(Var->getIdentifier()).second) Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration), CurContext, nullptr, false); } @@ -4817,7 +4821,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength)) continue; - if (!Selectors.insert(M->getSelector())) + if (!Selectors.insert(M->getSelector()).second) continue; Result R = Result(M, Results.getBasePriority(M), nullptr); @@ -5400,13 +5404,13 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, MEnd = SemaRef.MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; - MethList && MethList->Method; + MethList && MethList->getMethod(); MethList = MethList->getNext()) { - if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents)) + if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; - Result R(MethList->Method, Results.getBasePriority(MethList->Method), - nullptr); + Result R(MethList->getMethod(), + Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; Results.MaybeAddResult(R, SemaRef.CurContext); @@ -5573,16 +5577,16 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, MEnd = MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; - MethList && MethList->Method; + MethList && MethList->getMethod(); MethList = MethList->getNext()) { - if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents)) + if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; - if (!Selectors.insert(MethList->Method->getSelector())) + if (!Selectors.insert(MethList->getMethod()->getSelector()).second) continue; - Result R(MethList->Method, Results.getBasePriority(MethList->Method), - nullptr); + Result R(MethList->getMethod(), + Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; Results.MaybeAddResult(R, CurContext); @@ -5858,7 +5862,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); for (const auto *D : TU->decls()) if (const auto *Category = dyn_cast<ObjCCategoryDecl>(D)) - if (CategoryNames.insert(Category->getIdentifier())) + if (CategoryNames.insert(Category->getIdentifier()).second) Results.AddResult(Result(Category, Results.getBasePriority(Category), nullptr), CurContext, nullptr, false); @@ -5896,7 +5900,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, while (Class) { for (const auto *Cat : Class->visible_categories()) { if ((!IgnoreImplemented || !Cat->getImplementation()) && - CategoryNames.insert(Cat->getIdentifier())) + CategoryNames.insert(Cat->getIdentifier()).second) Results.AddResult(Result(Cat, Results.getBasePriority(Cat), nullptr), CurContext, nullptr, false); } @@ -6217,7 +6221,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add the normal accessor -(type)key. if (IsInstanceMethod && - KnownSelectors.insert(Selectors.getNullarySelector(PropName)) && + KnownSelectors.insert(Selectors.getNullarySelector(PropName)).second && ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) { if (ReturnType.isNull()) AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, @@ -6238,7 +6242,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Property->getType()->isBooleanType())))) { std::string SelectorName = (Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) + .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); @@ -6257,7 +6262,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, !Property->getSetterMethodDecl()) { std::string SelectorName = (Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6309,7 +6314,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isIntegerType())) { std::string SelectorName = (Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) + .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); @@ -6332,7 +6338,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("objectIn") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("id"); @@ -6359,7 +6365,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); @@ -6384,7 +6390,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("range") }; - if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6418,7 +6424,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName) }; - if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6450,7 +6456,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("atIndexes") }; - if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6478,7 +6484,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6500,7 +6506,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6526,7 +6532,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("withObject") }; - if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6559,7 +6565,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName2) }; - if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) { + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6592,7 +6598,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getName() == "NSEnumerator"))) { std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) + .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSEnumerator *"); @@ -6610,7 +6617,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); @@ -6641,7 +6648,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("add") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6663,7 +6670,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6685,7 +6692,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("remove") + UpperKey + Twine("Object")).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6707,7 +6714,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6728,7 +6735,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("intersect") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); @@ -6756,7 +6763,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) + .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); @@ -6777,7 +6785,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); - if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) { + if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) + .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("BOOL"); @@ -6985,16 +6994,18 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, M != MEnd; ++M) { for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; - MethList && MethList->Method; + MethList && MethList->getMethod(); MethList = MethList->getNext()) { - if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents)) + if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; if (AtParameterName) { // Suggest parameter names we've seen before. unsigned NumSelIdents = SelIdents.size(); - if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) { - ParmVarDecl *Param = MethList->Method->parameters()[NumSelIdents-1]; + if (NumSelIdents && + NumSelIdents <= MethList->getMethod()->param_size()) { + ParmVarDecl *Param = + MethList->getMethod()->parameters()[NumSelIdents - 1]; if (Param->getIdentifier()) { CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -7007,8 +7018,8 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, continue; } - Result R(MethList->Method, Results.getBasePriority(MethList->Method), - nullptr); + Result R(MethList->getMethod(), + Results.getBasePriority(MethList->getMethod()), nullptr); R.StartParameter = SelIdents.size(); R.AllParametersAreInformative = false; R.DeclaringEntity = true; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8716227..0074703 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -152,7 +152,10 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, auto *TD = TST->getTemplateName().getAsTemplateDecl(); if (!TD) continue; - auto *BasePrimaryTemplate = cast<CXXRecordDecl>(TD->getTemplatedDecl()); + auto *BasePrimaryTemplate = + dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl()); + if (!BasePrimaryTemplate) + continue; // FIXME: Allow lookup into non-dependent bases of dependent bases, possibly // by calling or integrating with the main LookupQualifiedName mechanism. for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) { @@ -283,10 +286,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { - TypeNameValidatorCCC Validator(true, isClassName); - TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), - Kind, S, SS, Validator, - CTK_ErrorRecovery); + TypoCorrection Correction = CorrectTypo( + Result.getLookupNameInfo(), Kind, S, SS, + llvm::make_unique<TypeNameValidatorCCC>(true, isClassName), + CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; @@ -377,6 +380,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); + MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); // NOTE: avoid constructing an ElaboratedType(Loc) if this is a // constructor or destructor name (in such a case, the scope specifier @@ -494,6 +498,9 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { + if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) + return true; + const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext); @@ -516,10 +523,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. - TypeNameValidatorCCC Validator(false, false, AllowClassTemplates); - if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), - LookupOrdinaryName, S, SS, - Validator, CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = + CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, + llvm::make_unique<TypeNameValidatorCCC>( + false, false, AllowClassTemplates), + CTK_ErrorRecovery)) { if (Corrected.isKeyword()) { // We corrected to a keyword. diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II); @@ -679,13 +687,11 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } -Sema::NameClassification Sema::ClassifyName(Scope *S, - CXXScopeSpec &SS, - IdentifierInfo *&Name, - SourceLocation NameLoc, - const Token &NextToken, - bool IsAddressOfOperand, - CorrectionCandidateCallback *CCC) { +Sema::NameClassification +Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, + SourceLocation NameLoc, const Token &NextToken, + bool IsAddressOfOperand, + std::unique_ptr<CorrectionCandidateCallback> CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); @@ -762,7 +768,7 @@ Corrected: SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - &SS, *CCC, + &SS, std::move(CCC), CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; @@ -925,6 +931,7 @@ Corrected: NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); @@ -1392,10 +1399,22 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (isa<LabelDecl>(D)) return true; + + // Except for labels, we only care about unused decls that are local to + // functions. + bool WithinFunction = D->getDeclContext()->isFunctionOrMethod(); + if (const auto *R = dyn_cast<CXXRecordDecl>(D->getDeclContext())) + // For dependent types, the diagnostic is deferred. + WithinFunction = + WithinFunction || (R->isLocalClass() && !R->isDependentType()); + if (!WithinFunction) + return false; + + if (isa<TypedefNameDecl>(D)) + return true; // White-list anything that isn't a local variable. - if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) || - !D->getDeclContext()->isFunctionOrMethod()) + if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) return false; // Types of valid local variables should be complete, so this should succeed. @@ -1458,11 +1477,30 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, return; } +void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) { + if (D->getTypeForDecl()->isDependentType()) + return; + + for (auto *TmpD : D->decls()) { + if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD)) + DiagnoseUnusedDecl(T); + else if(const auto *R = dyn_cast<RecordDecl>(TmpD)) + DiagnoseUnusedNestedTypedefs(R); + } +} + /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { if (!ShouldDiagnoseUnusedDecl(D)) return; + + if (auto *TD = dyn_cast<TypedefNameDecl>(D)) { + // typedefs can be referenced later on, so the diagnostics are emitted + // at end-of-translation-unit. + UnusedLocalTypedefNameCandidates.insert(TD); + return; + } FixItHint Hint; GenerateFixForUnusedDecl(D, Context, Hint); @@ -1481,8 +1519,14 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { static void CheckPoppedLabel(LabelDecl *L, Sema &S) { // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd - // definitions are indicated with a null substmt. - if (L->getStmt() == nullptr) + // definitions are indicated with a null substmt which is also not a resolved + // MS inline assembly label name. + bool Diagnose = false; + if (L->isMSAsmLabel()) + Diagnose = !L->isResolvedMSAsmLabel(); + else + Diagnose = L->getStmt() == nullptr; + if (Diagnose) S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName(); } @@ -1502,8 +1546,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (!S->hasUnrecoverableErrorOccurred()) + if (!S->hasUnrecoverableErrorOccurred()) { DiagnoseUnusedDecl(D); + if (const auto *RD = dyn_cast<RecordDecl>(D)) + DiagnoseUnusedNestedTypedefs(RD); + } // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) @@ -1537,10 +1584,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - DeclFilterCCC<ObjCInterfaceDecl> Validator; - if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), - LookupOrdinaryName, TUScope, nullptr, - Validator, CTK_ErrorRecovery)) { + if (TypoCorrection C = CorrectTypo( + DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr, + llvm::make_unique<DeclFilterCCC<ObjCInterfaceDecl>>(), + CTK_ErrorRecovery)) { diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id); IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>(); Id = IDecl->getIdentifier(); @@ -1620,32 +1667,30 @@ static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) { /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the /// built-in. -NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, +NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc) { LookupPredefedObjCSuperType(*this, S, II); - - Builtin::ID BID = (Builtin::ID)bid; ASTContext::GetBuiltinTypeError Error; - QualType R = Context.GetBuiltinType(BID, Error); + QualType R = Context.GetBuiltinType(ID, Error); if (Error) { if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_sysheader) << getHeaderName(Error) - << Context.BuiltinInfo.GetName(BID); + << Context.BuiltinInfo.GetName(ID); return nullptr; } - if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) { + if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) - << Context.BuiltinInfo.GetName(BID) + << Context.BuiltinInfo.GetName(ID) << R; - if (Context.BuiltinInfo.getHeaderName(BID) && + if (Context.BuiltinInfo.getHeaderName(ID) && !Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc)) Diag(Loc, diag::note_include_header_or_declare) - << Context.BuiltinInfo.getHeaderName(BID) - << Context.BuiltinInfo.GetName(BID); + << Context.BuiltinInfo.getHeaderName(ID) + << Context.BuiltinInfo.GetName(ID); } DeclContext *Parent = Context.getTranslationUnitDecl(); @@ -1725,6 +1770,43 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, filter.done(); } +/// Typedef declarations don't have linkage, but they still denote the same +/// entity if their types are the same. +/// FIXME: This is notionally doing the same thing as ASTReaderDecl's +/// isSameEntity. +static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context, + TypedefNameDecl *Decl, + LookupResult &Previous) { + // This is only interesting when modules are enabled. + if (!Context.getLangOpts().Modules) + return; + + // Empty sets are uninteresting. + if (Previous.empty()) + return; + + LookupResult::Filter Filter = Previous.makeFilter(); + while (Filter.hasNext()) { + NamedDecl *Old = Filter.next(); + + // Non-hidden declarations are never ignored. + if (!Old->isHidden()) + continue; + + // Declarations of the same entity are not ignored, even if they have + // different linkages. + if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old)) + if (Context.hasSameType(OldTD->getUnderlyingType(), + Decl->getUnderlyingType())) + continue; + + if (!Old->isExternallyVisible()) + Filter.erase(); + } + + Filter.done(); +} + bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { QualType OldType; if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old)) @@ -2072,6 +2154,14 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), AttrSpellingListIndex, IA->getSemanticSpelling()); + else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr)) + NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), + &S.Context.Idents.get(AA->getSpelling()), + AttrSpellingListIndex); + else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr)) + NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); + else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr)) + NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); else if (isa<AlignedAttr>(Attr)) // AlignedAttrs are handled separately, because we need to handle all // such attributes on a declaration at the same time. @@ -3149,8 +3239,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } // Merge the types. - MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous)); + VarDecl *MostRecent = Old->getMostRecentDecl(); + if (MostRecent != Old) { + MergeVarDeclTypes(New, MostRecent, + mergeTypeWithPrevious(*this, New, MostRecent, Previous)); + if (New->isInvalidDecl()) + return; + } + MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous)); if (New->isInvalidDecl()) return; @@ -3195,12 +3292,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Check if extern is followed by non-extern and vice-versa. if (New->hasExternalStorage() && - !Old->hasLinkage() && Old->isLocalVarDecl()) { + !Old->hasLinkage() && Old->isLocalVarDeclOrParm()) { Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } - if (Old->hasLinkage() && New->isLocalVarDecl() && + if (Old->hasLinkage() && New->isLocalVarDeclOrParm() && !New->hasExternalStorage()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); @@ -3407,21 +3504,39 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } } - // Check for Microsoft C extension: anonymous struct member. - if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus && - CurContext->isRecord() && + // C11 6.7.2.1p2: + // A struct-declaration that does not declare an anonymous structure or + // anonymous union shall contain a struct-declarator-list. + // + // This rule also existed in C89 and C99; the grammar for struct-declaration + // did not permit a struct-declaration without a struct-declarator-list. + if (!getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { - // Handle 2 kinds of anonymous struct: + // Check for Microsoft C extension: anonymous struct/union member. + // Handle 2 kinds of anonymous struct/union: // struct STRUCT; + // union UNION; // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. - RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag); - if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || - (DS.getTypeSpecType() == DeclSpec::TST_typename && - DS.getRepAsType().get()->isStructureType())) { - Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct) - << DS.getSourceRange(); - return BuildMicrosoftCAnonymousStruct(S, DS, Record); + // UNION_TYPE; <- where UNION_TYPE is a typedef union. + if ((Tag && Tag->getDeclName()) || + DS.getTypeSpecType() == DeclSpec::TST_typename) { + RecordDecl *Record = nullptr; + if (Tag) + Record = dyn_cast<RecordDecl>(Tag); + else if (const RecordType *RT = + DS.getRepAsType().get()->getAsStructureType()) + Record = RT->getDecl(); + else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) + Record = UT->getDecl(); + + if (Record && getLangOpts().MicrosoftExt) { + Diag(DS.getLocStart(), diag::ext_ms_anonymous_record) + << Record->isUnion() << DS.getSourceRange(); + return BuildMicrosoftCAnonymousStruct(S, DS, Record); + } + + DeclaresAnything = false; } } @@ -3622,10 +3737,12 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, for (unsigned i = 0; i < Chaining.size(); i++) NamedChain[i] = Chaining[i]; - IndirectFieldDecl* IndirectField = - IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(), - VD->getIdentifier(), VD->getType(), - NamedChain, Chaining.size()); + IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( + SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(), + VD->getType(), NamedChain, Chaining.size()); + + for (const auto *Attr : VD->attrs()) + IndirectField->addAttr(Attr->clone(SemaRef.Context)); IndirectField->setAccess(AS); IndirectField->setImplicit(); @@ -3893,7 +4010,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, FieldCollector->Add(cast<FieldDecl>(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); + StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here @@ -3962,28 +4079,28 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// /// void foo() { /// B var; -/// var.a = 3; +/// var.a = 3; /// } /// Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) { - - // If there is no Record, get the record via the typedef. - if (!Record) - Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); + assert(Record && "expected a record!"); // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); + auto *ParentDecl = cast<RecordDecl>(CurContext); + QualType RecTy = Context.getTypeDeclType(Record); + // Create a declaration for this anonymous struct. NamedDecl *Anon = FieldDecl::Create(Context, - cast<RecordDecl>(CurContext), + ParentDecl, DS.getLocStart(), DS.getLocStart(), /*IdentifierInfo=*/nullptr, - Context.getTypeDeclType(Record), + RecTy, TInfo, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); @@ -3999,10 +4116,13 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, Chain.push_back(Anon); RecordDecl *RecordDef = Record->getDefinition(); - if (!RecordDef || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, - RecordDef, AS_none, - Chain, true)) + if (RequireCompleteType(Anon->getLocation(), RecTy, + diag::err_field_incomplete) || + InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, + AS_none, Chain, true)) { Anon->setInvalidDecl(); + ParentDecl->setInvalidDecl(); + } return Anon; } @@ -4835,7 +4955,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, // in an outer scope, it isn't the same thing. FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false, /*AllowInlineNamespace*/false); - filterNonConflictingPreviousDecls(Context, NewTD, Previous); + filterNonConflictingPreviousTypedefDecls(Context, NewTD, Previous); if (!Previous.empty()) { Redeclaration = true; MergeTypedefNameDecl(NewTD, Previous); @@ -4995,14 +5115,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } // dll attributes require external linkage. - if (const DLLImportAttr *Attr = ND.getAttr<DLLImportAttr>()) { - if (!ND.isExternallyVisible()) { - S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern) - << &ND << Attr; - ND.setInvalidDecl(); - } - } - if (const DLLExportAttr *Attr = ND.getAttr<DLLExportAttr>()) { + if (const InheritableAttr *Attr = getDLLAttr(&ND)) { if (!ND.isExternallyVisible()) { S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern) << &ND << Attr; @@ -5064,17 +5177,22 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, } // A redeclaration is not allowed to drop a dllimport attribute, the only - // exception being inline function definitions. + // exceptions being inline function definitions, local extern declarations, + // and qualified friend declarations. // NB: MSVC converts such a declaration to dllexport. - bool IsInline = false, IsStaticDataMember = false; + bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) // Ignore static data because out-of-line definitions are diagnosed // separately. IsStaticDataMember = VD->isStaticDataMember(); - else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) + else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) { IsInline = FD->isInlined(); + IsQualifiedFriend = FD->getQualifier() && + FD->getFriendObjectKind() == Decl::FOK_Declared; + } - if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember) { + if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember && + !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) << NewDecl << OldImportAttr; @@ -5082,6 +5200,14 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); OldDecl->dropAttr<DLLImportAttr>(); NewDecl->dropAttr<DLLImportAttr>(); + } else if (IsInline && OldImportAttr && + !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // In MinGW, seeing a function declared inline drops the dllimport attribute. + OldDecl->dropAttr<DLLImportAttr>(); + NewDecl->dropAttr<DLLImportAttr>(); + S.Diag(NewDecl->getLocation(), + diag::warn_dllimport_dropped_from_inline_function) + << NewDecl << OldImportAttr; } } @@ -5222,8 +5348,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, DeclarationName Name = GetNameForDeclarator(D).getName(); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); - VarDecl::StorageClass SC = - StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); + StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); // dllimport globals without explicit storage class are treated as extern. We // have to change the storage class this early to get the right DeclContext. @@ -5434,7 +5559,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Only C++1y supports variable templates (N3651). Diag(D.getIdentifierLoc(), - getLangOpts().CPlusPlus1y + getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_variable_template : diag::ext_variable_template); } @@ -5503,22 +5628,20 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setLocalExternDecl(); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { - if (NewVD->hasLocalStorage()) { - // C++11 [dcl.stc]p4: - // When thread_local is applied to a variable of block scope the - // storage-class-specifier static is implied if it does not appear - // explicitly. - // Core issue: 'static' is not implied if the variable is declared - // 'extern'. - if (SCSpec == DeclSpec::SCS_unspecified && - TSCS == DeclSpec::TSCS_thread_local && - DC->isFunctionOrMethod()) - NewVD->setTSCSpec(TSCS); - else - Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), - diag::err_thread_non_global) - << DeclSpec::getSpecifierName(TSCS); - } else if (!Context.getTargetInfo().isTLSSupported()) + // C++11 [dcl.stc]p4: + // When thread_local is applied to a variable of block scope the + // storage-class-specifier static is implied if it does not appear + // explicitly. + // Core issue: 'static' is not implied if the variable is declared + // 'extern'. + if (NewVD->hasLocalStorage() && + (SCSpec != DeclSpec::SCS_unspecified || + TSCS != DeclSpec::TSCS_thread_local || + !DC->isFunctionOrMethod())) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_thread_non_global) + << DeclSpec::getSpecifierName(TSCS); + else if (!Context.getTargetInfo().isTLSSupported()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); else @@ -6198,7 +6321,7 @@ static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { - // Look for virtual methods in base classes that this method might override. + // Look for methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethodData Data; Data.Method = MD; @@ -6320,8 +6443,6 @@ static NamedDecl *DiagnoseInvalidRedeclaration( assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); - DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD, - MD ? MD->getParent() : nullptr); if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { @@ -6337,9 +6458,11 @@ static NamedDecl *DiagnoseInvalidRedeclaration( } // If the qualified name lookup yielded nothing, try typo correction } else if ((Correction = SemaRef.CorrectTypo( - Prev.getLookupNameInfo(), Prev.getLookupKind(), S, - &ExtraArgs.D.getCXXScopeSpec(), Validator, - Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) { + Prev.getLookupNameInfo(), Prev.getLookupKind(), S, + &ExtraArgs.D.getCXXScopeSpec(), + llvm::make_unique<DifferentNameValidatorCCC>( + SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr), + Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) { // Set up everything for the call to ActOnFunctionDeclarator ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); @@ -6436,8 +6559,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration( return nullptr; } -static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, - Declarator &D) { +static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: @@ -6475,7 +6597,7 @@ static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, DeclContext *DC, QualType &R, TypeSourceInfo *TInfo, - FunctionDecl::StorageClass SC, + StorageClass SC, bool &IsVirtualOkay) { DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -6500,9 +6622,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, if (D.isInvalidType()) NewFD->setInvalidDecl(); - // Set the lexical context. - NewFD->setLexicalDeclContext(SemaRef.CurContext); - return NewFD; } @@ -6602,6 +6721,11 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, IsVirtualOkay = !Ret->isStatic(); return Ret; } else { + bool isFriend = + SemaRef.getLangOpts().CPlusPlus && D.getDeclSpec().isFriendSpecified(); + if (!isFriend && SemaRef.CurContext->isRecord()) + return nullptr; + // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), @@ -6655,7 +6779,7 @@ static void checkIsValidOpenCLKernelParameter( Sema &S, Declarator &D, ParmVarDecl *Param, - llvm::SmallPtrSet<const Type *, 16> &ValidTypes) { + llvm::SmallPtrSetImpl<const Type *> &ValidTypes) { QualType PT = Param->getType(); // Cache the valid types we encounter to avoid rechecking structs that are @@ -6802,7 +6926,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); - FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); + StorageClass SC = getFunctionStorageClass(*this, D); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), @@ -6990,12 +7114,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setVirtualAsWritten(true); } - if (getLangOpts().CPlusPlus1y && + if (getLangOpts().CPlusPlus14 && NewFD->getReturnType()->isUndeducedType()) Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } - if (getLangOpts().CPlusPlus1y && + if (getLangOpts().CPlusPlus14 && (NewFD->isDependentContext() || (isFriend && CurContext->isDependentContext())) && NewFD->getReturnType()->isUndeducedType()) { @@ -7126,12 +7250,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, const FunctionProtoType *FPT = R->getAs<FunctionProtoType>(); if ((Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) && - getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) { - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_BasicNoexcept; - NewFD->setType(Context.getFunctionType(FPT->getReturnType(), - FPT->getParamTypes(), EPI)); - } + getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) + NewFD->setType(Context.getFunctionType( + FPT->getReturnType(), FPT->getParamTypes(), + FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } // Filter out previous declarations that don't match the scope. @@ -7232,7 +7354,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CodeSegStack.CurrentValue->getString(), CodeSegStack.CurrentPragmaLocation)); if (UnifySection(CodeSegStack.CurrentValue->getString(), - PSF_Implicit | PSF_Execute | PSF_Read, NewFD)) + ASTContext::PSF_Implicit | ASTContext::PSF_Execute | + ASTContext::PSF_Read, + NewFD)) NewFD->dropAttr<SectionAttr>(); } @@ -7283,6 +7407,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + + // Diagnose no-prototype function declarations with calling conventions that + // don't support variadic calls. Only do this in C and do it after merging + // possibly prototyped redeclarations. + const FunctionType *FT = NewFD->getType()->castAs<FunctionType>(); + if (isa<FunctionNoProtoType>(FT) && !D.isFunctionDefinition()) { + CallingConv CC = FT->getExtInfo().getCC(); + if (!supportsVariadicCall(CC)) { + // Windows system headers sometimes accidentally use stdcall without + // (void) parameters, so we relax this to a warning. + int DiagID = + CC == CC_X86StdCall ? diag::warn_cconv_knr : diag::err_cconv_knr; + Diag(NewFD->getLocation(), DiagID) + << FunctionType::getNameForCallConv(CC); + } + } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. @@ -7749,12 +7889,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // This rule is not present in C++1y, so we produce a backwards // compatibility warning whenever it happens in C++11. CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); - if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() && + if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() && !MD->isStatic() && !isa<CXXConstructorDecl>(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = nullptr; if (OldDecl) - OldMD = dyn_cast<CXXMethodDecl>(OldDecl->getAsFunction()); + OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction()); if (!OldMD || !OldMD->isStatic()) { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); @@ -7771,7 +7911,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, .IgnoreParens().getAs<FunctionTypeLoc>()) AddConstLoc = getLocForEndOfToken(FTL.getRParenLoc()); - Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const) + Diag(MD->getLocation(), diag::warn_cxx14_compat_constexpr_not_const) << FixItHint::CreateInsertion(AddConstLoc, " const"); } } @@ -7838,6 +7978,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } // Semantic checking for this function declaration (in isolation). + if (getLangOpts().CPlusPlus) { // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { @@ -7918,7 +8059,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // the function returns a UDT (class, struct, or union type) that is not C // compatible, and if it does, warn the user. // But, issue any diagnostic on the first declaration only. - if (NewFD->isExternC() && Previous.empty()) { + if (Previous.empty() && NewFD->isExternC()) { QualType R = NewFD->getReturnType(); if (R->isIncompleteType() && !R->isVoidType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete) @@ -8120,6 +8261,8 @@ namespace { bool isPODType; bool isReferenceType; + bool isInitList; + llvm::SmallVector<unsigned, 4> InitFieldIndex; public: typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; @@ -8128,6 +8271,7 @@ namespace { isPODType = false; isRecordType = false; isReferenceType = false; + isInitList = false; if (ValueDecl *VD = dyn_cast<ValueDecl>(OrigDecl)) { isPODType = VD->getType().isPODType(S.Context); isRecordType = VD->getType()->isRecordType(); @@ -8135,25 +8279,122 @@ namespace { } } + // For most expressions, just call the visitor. For initializer lists, + // track the index of the field being initialized since fields are + // initialized in order allowing use of previously initialized fields. + void CheckExpr(Expr *E) { + InitListExpr *InitList = dyn_cast<InitListExpr>(E); + if (!InitList) { + Visit(E); + return; + } + + // Track and increment the index here. + isInitList = true; + InitFieldIndex.push_back(0); + for (auto Child : InitList->children()) { + CheckExpr(cast<Expr>(Child)); + ++InitFieldIndex.back(); + } + InitFieldIndex.pop_back(); + } + + // Returns true if MemberExpr is checked and no futher checking is needed. + // Returns false if additional checking is required. + bool CheckInitListMemberExpr(MemberExpr *E, bool CheckReference) { + llvm::SmallVector<FieldDecl*, 4> Fields; + Expr *Base = E; + bool ReferenceField = false; + + // Get the field memebers used. + while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { + FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); + if (!FD) + return false; + Fields.push_back(FD); + if (FD->getType()->isReferenceType()) + ReferenceField = true; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + + // Keep checking only if the base Decl is the same. + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base); + if (!DRE || DRE->getDecl() != OrigDecl) + return false; + + // A reference field can be bound to an unininitialized field. + if (CheckReference && !ReferenceField) + return true; + + // Convert FieldDecls to their index number. + llvm::SmallVector<unsigned, 4> UsedFieldIndex; + for (auto I = Fields.rbegin(), E = Fields.rend(); I != E; ++I) { + UsedFieldIndex.push_back((*I)->getFieldIndex()); + } + + // See if a warning is needed by checking the first difference in index + // numbers. If field being used has index less than the field being + // initialized, then the use is safe. + for (auto UsedIter = UsedFieldIndex.begin(), + UsedEnd = UsedFieldIndex.end(), + OrigIter = InitFieldIndex.begin(), + OrigEnd = InitFieldIndex.end(); + UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) { + if (*UsedIter < *OrigIter) + return true; + if (*UsedIter > *OrigIter) + break; + } + + // TODO: Add a different warning which will print the field names. + HandleDeclRefExpr(DRE); + return true; + } + // For most expressions, the cast is directly above the DeclRefExpr. // For conditional operators, the cast can be outside the conditional // operator if both expressions are DeclRefExpr's. void HandleValue(Expr *E) { - if (isReferenceType) - return; - E = E->IgnoreParenImpCasts(); + E = E->IgnoreParens(); if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) { HandleDeclRefExpr(DRE); return; } if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + Visit(CO->getCond()); HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); return; } + if (BinaryConditionalOperator *BCO = + dyn_cast<BinaryConditionalOperator>(E)) { + Visit(BCO->getCond()); + HandleValue(BCO->getFalseExpr()); + return; + } + + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { + HandleValue(OVE->getSourceExpr()); + return; + } + + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->getOpcode() == BO_Comma) { + Visit(BO->getLHS()); + HandleValue(BO->getRHS()); + return; + } + } + if (isa<MemberExpr>(E)) { + if (isInitList) { + if (CheckInitListMemberExpr(cast<MemberExpr>(E), + false /*CheckReference*/)) + return; + } + Expr *Base = E->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { // Check for static member variables and don't warn on them. @@ -8165,24 +8406,32 @@ namespace { HandleDeclRefExpr(DRE); return; } + + Visit(E); } - // Reference types are handled here since all uses of references are - // bad, not just r-value uses. + // Reference types not handled in HandleValue are handled here since all + // uses of references are bad, not just r-value uses. void VisitDeclRefExpr(DeclRefExpr *E) { if (isReferenceType) HandleDeclRefExpr(E); } void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if (E->getCastKind() == CK_LValueToRValue || - (isRecordType && E->getCastKind() == CK_NoOp)) + if (E->getCastKind() == CK_LValueToRValue) { HandleValue(E->getSubExpr()); + return; + } Inherited::VisitImplicitCastExpr(E); } void VisitMemberExpr(MemberExpr *E) { + if (isInitList) { + if (CheckInitListMemberExpr(E, true /*CheckReference*/)) + return; + } + // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; @@ -8209,11 +8458,14 @@ namespace { } void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - if (E->getNumArgs() > 0) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0))) - HandleDeclRefExpr(DRE); + Expr *Callee = E->getCallee(); - Inherited::VisitCXXOperatorCallExpr(E); + if (isa<UnresolvedLookupExpr>(Callee)) + return Inherited::VisitCXXOperatorCallExpr(E); + + Visit(Callee); + for (auto Arg: E->arguments()) + HandleValue(Arg->IgnoreParenImpCasts()); } void VisitUnaryOperator(UnaryOperator *E) { @@ -8224,11 +8476,65 @@ namespace { HandleValue(E->getSubExpr()); return; } + + if (E->isIncrementDecrementOp()) { + HandleValue(E->getSubExpr()); + return; + } + Inherited::VisitUnaryOperator(E); } void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } + void VisitCXXConstructExpr(CXXConstructExpr *E) { + if (E->getConstructor()->isCopyConstructor()) { + Expr *ArgExpr = E->getArg(0); + if (InitListExpr *ILE = dyn_cast<InitListExpr>(ArgExpr)) + if (ILE->getNumInits() == 1) + ArgExpr = ILE->getInit(0); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr)) + if (ICE->getCastKind() == CK_NoOp) + ArgExpr = ICE->getSubExpr(); + HandleValue(ArgExpr); + return; + } + Inherited::VisitCXXConstructExpr(E); + } + + void VisitCallExpr(CallExpr *E) { + // Treat std::move as a use. + if (E->getNumArgs() == 1) { + if (FunctionDecl *FD = E->getDirectCallee()) { + if (FD->isInStdNamespace() && FD->getIdentifier() && + FD->getIdentifier()->isStr("move")) { + HandleValue(E->getArg(0)); + return; + } + } + } + + Inherited::VisitCallExpr(E); + } + + void VisitBinaryOperator(BinaryOperator *E) { + if (E->isCompoundAssignmentOp()) { + HandleValue(E->getLHS()); + Visit(E->getRHS()); + return; + } + + Inherited::VisitBinaryOperator(E); + } + + // A custom visitor for BinaryConditionalOperator is needed because the + // regular visitor would check the condition and true expression separately + // but both point to the same place giving duplicate diagnostics. + void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { + Visit(E->getCond()); + Visit(E->getFalseExpr()); + } + void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; @@ -8268,7 +8574,7 @@ namespace { if (DRE->getDecl() == OrigDecl) return; - SelfReferenceChecker(S, OrigDecl).Visit(E); + SelfReferenceChecker(S, OrigDecl).CheckExpr(E); } } @@ -8279,8 +8585,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. - if (!RealDecl || RealDecl->isInvalidDecl()) + if (!RealDecl || RealDecl->isInvalidDecl()) { + CorrectDelayedTyposInExpr(Init); return; + } if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { // With declarators parsed the way they are, the parser cannot @@ -8511,6 +8819,21 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, Args = MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs()); + // Try to correct any TypoExprs in the initialization arguments. + for (size_t Idx = 0; Idx < Args.size(); ++Idx) { + ExprResult Res = + CorrectDelayedTyposInExpr(Args[Idx], [this, Entity, Kind](Expr *E) { + InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); + return Init.Failed() ? ExprError() : E; + }); + if (Res.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + if (Res.get() != Args[Idx]) + Args[Idx] = Res.get(); + } + InitializationSequence InitSeq(*this, Entity, Kind, Args); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { @@ -9124,15 +9447,15 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isThisDeclarationADefinition() && ActiveTemplateInstantiations.empty()) { PragmaStack<StringLiteral *> *Stack = nullptr; - int SectionFlags = PSF_Implicit | PSF_Read; + int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read; if (var->getType().isConstQualified()) Stack = &ConstSegStack; else if (!var->getInit()) { Stack = &BSSSegStack; - SectionFlags |= PSF_Write; + SectionFlags |= ASTContext::PSF_Write; } else { Stack = &DataSegStack; - SectionFlags |= PSF_Write; + SectionFlags |= ASTContext::PSF_Write; } if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue) var->addAttr( @@ -9244,7 +9567,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { // Static locals inherit dll attributes from their function. if (VD->isStaticLocal()) { if (FunctionDecl *FD = - dyn_cast<FunctionDecl>(VD->getParentFunctionOrMethod())) { + dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod())) { if (Attr *A = getDLLAttr(FD)) { auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext())); NewAttr->setInherited(true); @@ -9253,8 +9576,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } + // Grab the dllimport or dllexport attribute off of the VarDecl. + const InheritableAttr *DLLAttr = getDLLAttr(VD); + // Imported static data members cannot be defined out-of-line. - if (const DLLImportAttr *IA = VD->getAttr<DLLImportAttr>()) { + if (const auto *IA = dyn_cast_or_null<DLLImportAttr>(DLLAttr)) { if (VD->isStaticDataMember() && VD->isOutOfLine() && VD->isThisDeclarationADefinition()) { // We allow definitions of dllimport class template static data members @@ -9275,6 +9601,14 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } + // dllimport/dllexport variables cannot be thread local, their TLS index + // isn't exported with the variable. + if (DLLAttr && VD->getTLSKind()) { + Diag(VD->getLocation(), diag::err_attribute_dll_thread_local) << VD + << DLLAttr; + VD->setInvalidDecl(); + } + if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; @@ -9466,12 +9800,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. // C++03 [dcl.stc]p2 also permits 'auto'. - VarDecl::StorageClass StorageClass = SC_None; + StorageClass SC = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { - StorageClass = SC_Register; + SC = SC_Register; } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { - StorageClass = SC_Auto; + SC = SC_Auto; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); @@ -9545,7 +9879,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { D.getLocStart(), D.getIdentifierLoc(), II, parmDeclType, TInfo, - StorageClass); + SC); if (D.isInvalidType()) New->setInvalidDecl(); @@ -9637,7 +9971,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, - VarDecl::StorageClass StorageClass) { + StorageClass SC) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && @@ -9663,8 +9997,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), - TSInfo, - StorageClass, nullptr); + TSInfo, SC, nullptr); // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once @@ -9850,6 +10183,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, // Add the captures to the LSI so they can be noted as already // captured within tryCaptureVar. + auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { VarDecl *VD = C.getCapturedVar(); @@ -9858,7 +10192,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, - /*RefersToEnclosingLocal*/true, C.getLocation(), + /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), CaptureType, /*Expr*/ nullptr); @@ -9866,7 +10200,10 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), S.getCurrentThisType(), /*Expr*/ nullptr); + } else { + LSI->addVLATypeCapture(C.getLocation(), I->getType()); } + ++I; } } @@ -10107,7 +10444,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); - if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && Body && + if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body && !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { // If the function has a deduced result type but contains no 'return' // statements, the result type as written must be exactly 'auto', and @@ -10118,8 +10455,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, FD->setInvalidDecl(); } else { // Substitute 'void' for the 'auto' in the type. - TypeLoc ResultType = FD->getTypeSourceInfo()->getTypeLoc(). - IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc(); + TypeLoc ResultType = getReturnTypeLoc(FD); Context.adjustDeducedFunctionResultType( FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); } @@ -10154,9 +10490,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), FD->getReturnType(), FD); - // If this is a constructor, we need a vtable. + // If this is a structor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); + else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD)) + MarkVTableUsed(FD->getLocation(), Destructor->getParent()); // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around @@ -10265,7 +10603,19 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, !CheckConstexprFunctionBody(FD, Body))) FD->setInvalidDecl(); - assert(ExprCleanupObjects.empty() && "Leftover temporaries in function"); + if (FD && FD->hasAttr<NakedAttr>()) { + for (const Stmt *S : Body->children()) { + if (!isa<AsmStmt>(S) && !isa<NullStmt>(S)) { + Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function); + Diag(FD->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); + FD->setInvalidDecl(); + break; + } + } + } + + assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects + && "Leftover temporaries in function"); assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); assert(MaybeODRUseExprs.empty() && "Leftover expressions for odr-use checking"); @@ -10329,10 +10679,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { TypoCorrection Corrected; - DeclFilterCCC<FunctionDecl> Validator; - if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc), - LookupOrdinaryName, S, nullptr, Validator, - CTK_NonError))) + if (S && + (Corrected = CorrectTypo( + DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr, + llvm::make_unique<DeclFilterCCC<FunctionDecl>>(), CTK_NonError))) diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), /*ErrorRecovery*/false); } @@ -10360,6 +10710,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*RefQualifierLoc=*/NoLoc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, + /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecLoc=*/NoLoc, @@ -10367,6 +10718,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, Loc, Loc, D), DS.getAttributes(), SourceLocation()); @@ -11262,9 +11614,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // If the type is currently being defined, complain // about a nested redefinition. - const TagType *Tag - = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); - if (Tag->isBeingDefined()) { + auto *TD = Context.getTagDeclType(PrevTagDecl)->getAsTagDecl(); + if (TD->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); @@ -11454,7 +11805,7 @@ CreateNewDecl: // CheckMemberSpecialization, below. if (!isExplicitSpecialization && (TUK == TUK_Definition || TUK == TUK_Declaration) && - diagnoseQualifiedDeclaration(SS, DC, OrigName, NameLoc)) + diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); @@ -12430,8 +12781,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, continue; } // Okay, we have a legal flexible array member at the end of the struct. - if (Record) - Record->setHasFlexibleArrayMember(true); + Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { @@ -12440,11 +12790,11 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, EnclosingDecl->setInvalidDecl(); continue; } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) { - if (FDTTy->getDecl()->hasFlexibleArrayMember()) { - // If this is a member of a union, then entire union becomes "flexible". - if (Record && Record->isUnion()) { - Record->setHasFlexibleArrayMember(true); - } else { + if (Record && FDTTy->getDecl()->hasFlexibleArrayMember()) { + // A type which contains a flexible array member is considered to be a + // flexible array member. + Record->setHasFlexibleArrayMember(true); + if (!Record->isUnion()) { // 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. @@ -12456,8 +12806,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // other structs as an extension. Diag(FD->getLocation(), diag::ext_flexible_array_in_struct) << FD->getDeclName(); - if (Record) - Record->setHasFlexibleArrayMember(true); } } } @@ -13171,6 +13519,49 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, } } +bool +Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, + bool AllowMask) const { + FlagEnumAttr *FEAttr = ED->getAttr<FlagEnumAttr>(); + assert(FEAttr && "looking for value in non-flag enum"); + + llvm::APInt FlagMask = ~FEAttr->getFlagBits(); + unsigned Width = FlagMask.getBitWidth(); + + // We will try a zero-extended value for the regular check first. + llvm::APInt ExtVal = Val.zextOrSelf(Width); + + // A value is in a flag enum if either its bits are a subset of the enum's + // flag bits (the first condition) or we are allowing masks and the same is + // true of its complement (the second condition). When masks are allowed, we + // allow the common idiom of ~(enum1 | enum2) to be a valid enum value. + // + // While it's true that any value could be used as a mask, the assumption is + // that a mask will have all of the insignificant bits set. Anything else is + // likely a logic error. + if (!(FlagMask & ExtVal)) + return true; + + if (AllowMask) { + // Try a one-extended value instead. This can happen if the enum is wider + // than the constant used, in C with extensions to allow for wider enums. + // The mask will still have the correct behaviour, so we give the user the + // benefit of the doubt. + // + // FIXME: This heuristic can cause weird results if the enum was extended + // to a larger type and is signed, because then bit-masks of smaller types + // that get extended will fall out of range (e.g. ~0x1u). We currently don't + // detect that case and will get a false positive for it. In most cases, + // though, it can be fixed by making it a signed type (e.g. ~0x1), so it may + // be fine just to accept this as a warning. + ExtVal |= llvm::APInt::getHighBitsSet(Width, Width - Val.getBitWidth()); + if (!(FlagMask & ~ExtVal)) + return true; + } + + return false; +} + void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, ArrayRef<Decl *> Elements, @@ -13256,10 +13647,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestPromotionType = Context.getPromotedIntegerType(BestType); else BestPromotionType = BestType; - // We don't need to set BestWidth, because BestType is going to be the type - // of the enumerators, but we do anyway because otherwise some compilers - // warn that it might be used uninitialized. - BestWidth = CharWidth; + + BestWidth = Context.getIntWidth(BestType); } else if (NumNegativeBits) { // If there is a negative value, figure out the smallest integer type (of @@ -13324,10 +13713,15 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, } } + FlagEnumAttr *FEAttr = Enum->getAttr<FlagEnumAttr>(); + if (FEAttr) + FEAttr->getFlagBits() = llvm::APInt(BestWidth, 0); + // Loop over all of the enumerator constants, changing their types to match - // the type of the enum if needed. - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); + // the type of the enum if needed. If we have a flag type, we also prepare the + // FlagBits cache. + for (auto *D : Elements) { + auto *ECD = cast_or_null<EnumConstantDecl>(D); if (!ECD) continue; // Already issued a diagnostic. // Standard C says the enumerators have int type, but we allow, as an @@ -13357,7 +13751,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // enum-specifier, each enumerator has the type of its // enumeration. ECD->setType(EnumType); - continue; + goto flagbits; } else { NewTy = BestType; NewWidth = BestWidth; @@ -13384,8 +13778,32 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(EnumType); else ECD->setType(NewTy); + +flagbits: + // Check to see if we have a constant with exactly one bit set. Note that x + // & (x - 1) will be nonzero if and only if x has more than one bit set. + if (FEAttr) { + llvm::APInt ExtVal = InitVal.zextOrSelf(BestWidth); + if (ExtVal != 0 && !(ExtVal & (ExtVal - 1))) { + FEAttr->getFlagBits() |= ExtVal; + } + } } + if (FEAttr) { + for (Decl *D : Elements) { + EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(D); + if (!ECD) continue; // Already issued a diagnostic. + + llvm::APSInt InitVal = ECD->getInitVal(); + if (InitVal != 0 && !IsValueInFlagEnum(Enum, InitVal, true)) + Diag(ECD->getLocation(), diag::warn_flag_enum_constant_out_of_range) + << ECD << Enum; + } + } + + + Enum->completeDefinition(BestType, BestPromotionType, NumPositiveBits, NumNegativeBits); @@ -13455,6 +13873,9 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule) Diag(ImportLoc, diag::err_module_self_import) << Mod->getFullModuleName() << getLangOpts().CurrentModule; + else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule) + Diag(ImportLoc, diag::err_module_import_in_implementation) + << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule; SmallVector<SourceLocation, 2> IdentifierLocs; Module *ModCheck = Mod; @@ -13575,5 +13996,6 @@ AvailabilityResult Sema::getCurContextAvailability() const { dyn_cast<ObjCImplementationDecl>(D)) { D = ID->getClassInterface(); } - return D->getAvailability(); + // Recover from user error. + return D ? D->getAvailability() : AR_Available; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 61683cd..17a849e 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -29,6 +29,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MathExtras.h" using namespace clang; using namespace sema; @@ -88,21 +89,39 @@ static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); } +static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getParamDecl(Idx)->getSourceRange(); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->parameters()[Idx]->getSourceRange(); + if (const auto *BD = dyn_cast<BlockDecl>(D)) + return BD->getParamDecl(Idx)->getSourceRange(); + return SourceRange(); +} + static QualType getFunctionOrMethodResultType(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionType>(FnTy)->getReturnType(); return cast<ObjCMethodDecl>(D)->getReturnType(); } +static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getReturnTypeSourceRange(); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->getReturnTypeSourceRange(); + return SourceRange(); +} + static bool isFunctionOrMethodVariadic(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); - } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) - return BD->isVariadic(); - else { - return cast<ObjCMethodDecl>(D)->isVariadic(); } + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + return BD->isVariadic(); + + return cast<ObjCMethodDecl>(D)->isVariadic(); } static bool isInstanceMethod(const Decl *D) { @@ -148,30 +167,43 @@ static unsigned getNumAttributeArgs(const AttributeList &Attr) { return Attr.getNumArgs() + Attr.hasParsedType(); } -/// \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 Num) { - if (getNumAttributeArgs(Attr) != Num) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << Num; +template <typename Compare> +static bool checkAttributeNumArgsImpl(Sema &S, const AttributeList &Attr, + unsigned Num, unsigned Diag, + Compare Comp) { + if (Comp(getNumAttributeArgs(Attr), Num)) { + S.Diag(Attr.getLoc(), Diag) << Attr.getName() << Num; return false; } return true; } +/// \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 Num) { + return checkAttributeNumArgsImpl(S, Attr, Num, + diag::err_attribute_wrong_number_arguments, + std::not_equal_to<unsigned>()); +} + /// \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 Num) { - if (getNumAttributeArgs(Attr) < Num) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) - << Attr.getName() << Num; - return false; - } + return checkAttributeNumArgsImpl(S, Attr, Num, + diag::err_attribute_too_few_arguments, + std::less<unsigned>()); +} - return true; +/// \brief Check if the attribute has at most as many args as Num. May +/// output an error. +static bool checkAttributeAtMostNumArgs(Sema &S, const AttributeList &Attr, + unsigned Num) { + return checkAttributeNumArgsImpl(S, Attr, Num, + diag::err_attribute_too_many_arguments, + std::greater<unsigned>()); } /// \brief If Expr is a valid integer constant, get the value of the integer @@ -192,6 +224,13 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, << Expr->getSourceRange(); return false; } + + if (!I.isIntN(32)) { + S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) + << I.toString(10, false) << 32 << /* Unsigned */ 1; + return false; + } + Val = (uint32_t)I.getZExtValue(); return true; } @@ -528,10 +567,6 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Attribute Implementations //===----------------------------------------------------------------------===// -// FIXME: All this manual attribute parsing code is gross. At the -// least add some helper functions to check most argument patterns (# -// and types of args). - static void handlePtGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!threadSafetyCheckIsPointer(S, D, Attr)) @@ -706,11 +741,9 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) return; - D->addAttr(::new (S.Context) - ExclusiveTrylockFunctionAttr(Attr.getRange(), S.Context, - Attr.getArgAsExpr(0), - Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( + Attr.getRange(), S.Context, Attr.getArgAsExpr(0), Args.data(), + Args.size(), Attr.getAttributeSpellingListIndex())); } static void handleLockReturnedAttr(Sema &S, Decl *D, @@ -828,8 +861,14 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, StringRef StateString; SourceLocation Loc; - if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc)) - return; + if (Attr.isArgIdent(ArgIndex)) { + IdentifierLoc *Ident = Attr.getArgAsIdent(ArgIndex); + StateString = Ident->Ident->getName(); + Loc = Ident->Loc; + } else { + if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc)) + return; + } if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, CallableState)) { @@ -849,8 +888,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, static void handleParamTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) return; - ParamTypestateAttr::ConsumedState ParamState; if (Attr.isArgIdent(0)) { @@ -889,8 +926,6 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) return; - ReturnTypestateAttr::ConsumedState ReturnState; if (Attr.isArgIdent(0)) { @@ -939,9 +974,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) - return; - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -967,9 +999,6 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) static void handleTestTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) - return; - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1101,30 +1130,39 @@ static void handleIBOutletCollection(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void possibleTransparentUnionPointerType(QualType &T) { - if (const RecordType *UT = T->getAsUnionType()) +bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { + if (RefOkay) { + if (T->isReferenceType()) + return true; + } else { + T = T.getNonReferenceType(); + } + + // The nonnull attribute, and other similar attributes, can be applied to a + // transparent union that contains a pointer type. + if (const RecordType *UT = T->getAsUnionType()) { if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) { RecordDecl *UD = UT->getDecl(); for (const auto *I : UD->fields()) { QualType QT = I->getType(); - if (QT->isAnyPointerType() || QT->isBlockPointerType()) { - T = QT; - return; - } + if (QT->isAnyPointerType() || QT->isBlockPointerType()) + return true; } } + } + + return T->isAnyPointerType() || T->isBlockPointerType(); } static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, - SourceRange R, bool isReturnValue = false) { - T = T.getNonReferenceType(); - possibleTransparentUnionPointerType(T); - - if (!T->isAnyPointerType() && !T->isBlockPointerType()) { - S.Diag(Attr.getLoc(), - isReturnValue ? diag::warn_attribute_return_pointers_only - : diag::warn_attribute_pointers_only) - << Attr.getName() << R; + SourceRange AttrParmRange, + SourceRange TypeRange, + bool isReturnValue = false) { + if (!S.isValidPointerAttrType(T)) { + S.Diag(Attr.getLoc(), isReturnValue + ? diag::warn_attribute_return_pointers_only + : diag::warn_attribute_pointers_only) + << Attr.getName() << AttrParmRange << TypeRange; return false; } return true; @@ -1132,46 +1170,45 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { SmallVector<unsigned, 8> NonNullArgs; - for (unsigned i = 0; i < Attr.getNumArgs(); ++i) { - Expr *Ex = Attr.getArgAsExpr(i); + for (unsigned I = 0; I < Attr.getNumArgs(); ++I) { + Expr *Ex = Attr.getArgAsExpr(I); uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, i + 1, Ex, Idx)) + if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? - // FIXME: Should also highlight argument in decl in the diagnostic. - if (!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, - Ex->getSourceRange())) + if (Idx < getFunctionOrMethodNumParams(D) && + !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, + Ex->getSourceRange(), + getFunctionOrMethodParamRange(D, Idx))) continue; NonNullArgs.push_back(Idx); } // If no arguments were specified to __attribute__((nonnull)) then all pointer - // arguments have a nonnull attribute. - if (NonNullArgs.empty()) { - for (unsigned i = 0, e = getFunctionOrMethodNumParams(D); i != e; ++i) { - QualType T = getFunctionOrMethodParamType(D, i).getNonReferenceType(); - possibleTransparentUnionPointerType(T); - if (T->isAnyPointerType() || T->isBlockPointerType()) - NonNullArgs.push_back(i); + // arguments have a nonnull attribute; warn if there aren't any. Skip this + // check if the attribute came from a macro expansion or a template + // instantiation. + if (NonNullArgs.empty() && Attr.getLoc().isFileID() && + S.ActiveTemplateInstantiations.empty()) { + bool AnyPointers = isFunctionOrMethodVariadic(D); + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); + I != E && !AnyPointers; ++I) { + QualType T = getFunctionOrMethodParamType(D, I); + if (T->isDependentType() || S.isValidPointerAttrType(T)) + AnyPointers = true; } - // No pointer arguments? - if (NonNullArgs.empty()) { - // Warn the trivial case only if attribute is not coming from a - // macro instantiation. - if (Attr.getLoc().isFileID()) - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); - return; - } + if (!AnyPointers) + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); } - unsigned *start = &NonNullArgs[0]; - unsigned size = NonNullArgs.size(); - llvm::array_pod_sort(start, start + size); + unsigned *Start = NonNullArgs.data(); + unsigned Size = NonNullArgs.size(); + llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, start, size, + NonNullAttr(Attr.getRange(), S.Context, Start, Size, Attr.getAttributeSpellingListIndex())); } @@ -1188,7 +1225,8 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, } // Is the argument a pointer type? - if (!attrNonNullArgCheck(S, D->getType(), Attr, D->getSourceRange())) + if (!attrNonNullArgCheck(S, D->getType(), Attr, SourceRange(), + D->getSourceRange())) return; D->addAttr(::new (S.Context) @@ -1199,7 +1237,8 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, static void handleReturnsNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { QualType ResultType = getFunctionOrMethodResultType(D); - if (!attrNonNullArgCheck(S, ResultType, Attr, Attr.getRange(), + SourceRange SR = getFunctionOrMethodResultSourceRange(D); + if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR, /* isReturnValue */ true)) return; @@ -1208,6 +1247,65 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleAssumeAlignedAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + Expr *E = Attr.getArgAsExpr(0), + *OE = Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr; + S.AddAssumeAlignedAttr(Attr.getRange(), D, E, OE, + Attr.getAttributeSpellingListIndex()); +} + +void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, + Expr *OE, unsigned SpellingListIndex) { + QualType ResultType = getFunctionOrMethodResultType(D); + SourceRange SR = getFunctionOrMethodResultSourceRange(D); + + AssumeAlignedAttr TmpAttr(AttrRange, Context, E, OE, SpellingListIndex); + SourceLocation AttrLoc = AttrRange.getBegin(); + + if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) { + Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only) + << &TmpAttr << AttrRange << SR; + return; + } + + if (!E->isValueDependent()) { + llvm::APSInt I(64); + if (!E->isIntegerConstantExpr(I, Context)) { + if (OE) + Diag(AttrLoc, diag::err_attribute_argument_n_type) + << &TmpAttr << 1 << AANT_ArgumentIntegerConstant + << E->getSourceRange(); + else + Diag(AttrLoc, diag::err_attribute_argument_type) + << &TmpAttr << AANT_ArgumentIntegerConstant + << E->getSourceRange(); + return; + } + + if (!I.isPowerOf2()) { + Diag(AttrLoc, diag::err_alignment_not_power_of_two) + << E->getSourceRange(); + return; + } + } + + if (OE) { + if (!OE->isValueDependent()) { + llvm::APSInt I(64); + if (!OE->isIntegerConstantExpr(I, Context)) { + Diag(AttrLoc, diag::err_attribute_argument_n_type) + << &TmpAttr << 2 << AANT_ArgumentIntegerConstant + << OE->getSourceRange(); + return; + } + } + } + + D->addAttr(::new (Context) + AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex)); +} + static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { // This attribute must be applied to a function declaration. The first // argument to the attribute must be an identifier, the name of the resource, @@ -1286,13 +1384,26 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { // Check we don't have a conflict with another ownership attribute. for (const auto *I : D->specific_attrs<OwnershipAttr>()) { - // FIXME: A returns attribute should conflict with any returns attribute - // with a different index too. + // Cannot have two ownership attributes of different kinds for the same + // index. if (I->getOwnKind() != K && I->args_end() != std::find(I->args_begin(), I->args_end(), Idx)) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL.getName() << I; return; + } else if (K == OwnershipAttr::Returns && + I->getOwnKind() == OwnershipAttr::Returns) { + // A returns attribute conflicts with any other returns attribute using + // a different index. Note, diagnostic reporting is 1-based, but stored + // argument indexes are 0-based. + if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) { + S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch) + << *(I->args_begin()) + 1; + if (I->args_size()) + S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch) + << (unsigned)Idx + 1 << Ex->getSourceRange(); + return; + } } } OwnershipArgs.push_back(Idx); @@ -1586,15 +1697,8 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; - return; - } - uint32_t priority = ConstructorAttr::DefaultPriority; - if (Attr.getNumArgs() > 0 && + if (Attr.getNumArgs() && !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) return; @@ -1604,15 +1708,8 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; - return; - } - uint32_t priority = DestructorAttr::DefaultPriority; - if (Attr.getNumArgs() > 0 && + if (Attr.getNumArgs() && !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) return; @@ -1624,16 +1721,9 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { template <typename AttrTy> static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr) { - unsigned NumArgs = Attr.getNumArgs(); - if (NumArgs > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; - return; - } - // Handle the case where the attribute has a text message. StringRef Str; - if (NumArgs == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (Attr.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) return; D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str, @@ -2036,13 +2126,6 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (Attr.getNumArgs() > 2) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 2; - return; - } - unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (Attr.getNumArgs() > 0) { Expr *E = Attr.getArgAsExpr(0); @@ -2349,10 +2432,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << (not_nsstring_type ? "a string type" : "an NSString") - << IdxExpr->getSourceRange(); + << (not_nsstring_type ? "a string type" : "an NSString") + << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } Ty = getFunctionOrMethodResultType(D); @@ -2360,10 +2442,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) - << (not_nsstring_type ? "string type" : "NSString") - << IdxExpr->getSourceRange(); + << (not_nsstring_type ? "string type" : "NSString") + << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } @@ -2534,23 +2615,24 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << "a CFString" << IdxExpr->getSourceRange(); + << "a CFString" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (Kind == NSStringFormat) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { - // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << "an NSString" << IdxExpr->getSourceRange(); + << "an NSString" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { - // FIXME: Should highlight the actual expression that has the wrong type. S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << "a string type" << IdxExpr->getSourceRange(); + << "a string type" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } @@ -2679,6 +2761,58 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleAlignValueAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), + Attr.getAttributeSpellingListIndex()); +} + +void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, + unsigned SpellingListIndex) { + AlignValueAttr TmpAttr(AttrRange, Context, E, SpellingListIndex); + SourceLocation AttrLoc = AttrRange.getBegin(); + + QualType T; + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + T = TD->getUnderlyingType(); + else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + T = VD->getType(); + else + llvm_unreachable("Unknown decl type for align_value"); + + if (!T->isDependentType() && !T->isAnyPointerType() && + !T->isReferenceType() && !T->isMemberPointerType()) { + Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only) + << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange(); + return; + } + + if (!E->isValueDependent()) { + llvm::APSInt Alignment(32); + ExprResult ICE + = VerifyIntegerConstantExpression(E, &Alignment, + diag::err_align_value_attribute_argument_not_int, + /*AllowFold*/ false); + if (ICE.isInvalid()) + return; + + if (!Alignment.isPowerOf2()) { + Diag(AttrLoc, diag::err_alignment_not_power_of_two) + << E->getSourceRange(); + return; + } + + D->addAttr(::new (Context) + AlignValueAttr(AttrRange, Context, ICE.get(), + SpellingListIndex)); + return; + } + + // Save dependent expressions in the AST to be instantiated. + D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); + return; +} + static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { @@ -2773,7 +2907,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, // An alignment specification of zero has no effect. if (!(TmpAttr.isAlignas() && !Alignment) && !llvm::isPowerOf2_64(Alignment.getZExtValue())) { - Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two) + Diag(AttrLoc, diag::err_alignment_not_power_of_two) << E->getSourceRange(); return; } @@ -3006,24 +3140,75 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident; + Diag(Optnone->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + + if (D->hasAttr<AlwaysInlineAttr>()) + return nullptr; + + return ::new (Context) AlwaysInlineAttr(Range, Context, + AttrSpellingListIndex); +} + +MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'"; + Diag(Optnone->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + + if (D->hasAttr<MinSizeAttr>()) + return nullptr; + + return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex); +} + +OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { + Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline; + Diag(Range.getBegin(), diag::note_conflicting_attribute); + D->dropAttr<AlwaysInlineAttr>(); + } + if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) { + Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize; + Diag(Range.getBegin(), diag::note_conflicting_attribute); + D->dropAttr<MinSizeAttr>(); + } + + if (D->hasAttr<OptimizeNoneAttr>()) + return nullptr; + + return ::new (Context) OptimizeNoneAttr(Range, Context, + AttrSpellingListIndex); +} + static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr)) - return; + if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( + D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(Inline); +} - D->addAttr(::new (S.Context) - AlwaysInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); +static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (MinSizeAttr *MinSize = S.mergeMinSizeAttr( + D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D->addAttr(MinSize); } static void handleOptimizeNoneAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr)) - return; - - D->addAttr(::new (S.Context) - OptimizeNoneAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr( + D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D->addAttr(Optnone); } static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3039,7 +3224,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + Attr.getAttributeSpellingListIndex())); } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3096,6 +3281,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { PascalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; + case AttributeList::AT_VectorCall: + D->addAttr(::new (S.Context) + VectorCallAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); + return; case AttributeList::AT_MSABI: D->addAttr(::new (S.Context) MSABIAttr(Attr.getRange(), S.Context, @@ -3158,6 +3348,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break; case AttributeList::AT_Pascal: CC = CC_X86Pascal; break; + case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; case AttributeList::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_X86_64Win64; @@ -3242,14 +3433,6 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // check the attribute arguments. - if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { - // FIXME: 0 is not okay. - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 2; - return; - } - uint32_t MaxThreads, MinBlocks = 0; if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1)) return; @@ -3440,29 +3623,24 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, default: llvm_unreachable("invalid ownership attribute"); case AttributeList::AT_NSReturnsAutoreleased: - D->addAttr(::new (S.Context) - NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; case AttributeList::AT_CFReturnsNotRetained: - D->addAttr(::new (S.Context) - CFReturnsNotRetainedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; case AttributeList::AT_NSReturnsNotRetained: - D->addAttr(::new (S.Context) - NSReturnsNotRetainedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; case AttributeList::AT_CFReturnsRetained: - D->addAttr(::new (S.Context) - CFReturnsRetainedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CFReturnsRetainedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; case AttributeList::AT_NSReturnsRetained: - D->addAttr(::new (S.Context) - NSReturnsRetainedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NSReturnsRetainedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; }; } @@ -3491,9 +3669,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, return; } - D->addAttr(::new (S.Context) - ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context, - attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr( + attr.getRange(), S.Context, attr.getAttributeSpellingListIndex())); } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, @@ -3587,7 +3764,8 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, static void handleObjCDesignatedInitializer(Sema &S, Decl *D, const AttributeList &Attr) { ObjCInterfaceDecl *IFace; - if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (ObjCCategoryDecl *CatDecl = + dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) IFace = CatDecl->getClassInterface(); else IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); @@ -3812,6 +3990,32 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { handleARMInterruptAttr(S, D, Attr); } +static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint32_t NumRegs; + Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs)) + return; + + D->addAttr(::new (S.Context) + AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, + NumRegs, + Attr.getAttributeSpellingListIndex())); +} + +static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint32_t NumRegs; + Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs)) + return; + + D->addAttr(::new (S.Context) + AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, + NumRegs, + Attr.getAttributeSpellingListIndex())); +} + static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, const AttributeList& Attr) { // If we try to apply it to a function pointer, don't warn, but don't @@ -3871,6 +4075,16 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { return; } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport && + !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // MinGW doesn't allow dllimport on inline functions. + S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) + << A.getName(); + return; + } + } + unsigned Index = A.getAttributeSpellingListIndex(); Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) @@ -4001,6 +4215,19 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D, D->addAttr(RCA); } +static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (auto *NSD = dyn_cast<NamespaceDecl>(D)) { + if (NSD->isAnonymousNamespace()) { + S.Diag(Attr.getLoc(), diag::warn_deprecated_anonymous_namespace); + // Do not want to attach the attribute to the namespace because that will + // cause confusing diagnostic reports for uses of declarations within the + // namespace. + return; + } + } + handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -4020,11 +4247,20 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, if (!Attr.diagnoseLangOpts(S)) return true; - // If there are no optional arguments, then checking for the argument count - // is trivial. - if (Attr.getMinArgs() == Attr.getMaxArgs() && - !checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) - return true; + if (Attr.getMinArgs() == Attr.getMaxArgs()) { + // If there are no optional arguments, then checking for the argument count + // is trivial. + if (!checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) + return true; + } else { + // There are optional arguments, so checking is slightly more involved. + if (Attr.getMinArgs() && + !checkAttributeAtLeastNumArgs(S, Attr, Attr.getMinArgs())) + return true; + else if (!Attr.hasVariadicArg() && Attr.getMaxArgs() && + !checkAttributeAtMostNumArgs(S, Attr, Attr.getMaxArgs())) + return true; + } // Check whether the attribute appertains to the given subject. if (!Attr.diagnoseAppertainsTo(S, D)) @@ -4087,6 +4323,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoMips16: handleSimpleAttribute<NoMips16Attr>(S, D, Attr); break; + case AttributeList::AT_AMDGPUNumVGPR: + handleAMDGPUNumVGPRAttr(S, D, Attr); + break; + case AttributeList::AT_AMDGPUNumSGPR: + handleAMDGPUNumSGPRAttr(S, D, Attr); + break; case AttributeList::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, Attr); break; @@ -4102,6 +4344,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Aligned: handleAlignedAttr(S, D, Attr); break; + case AttributeList::AT_AlignValue: + handleAlignValueAttr(S, D, Attr); + break; case AttributeList::AT_AlwaysInline: handleAlwaysInlineAttr(S, D, Attr); break; @@ -4133,7 +4378,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); break; case AttributeList::AT_Deprecated: - handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); + handleDeprecatedAttr(S, D, Attr); break; case AttributeList::AT_Destructor: handleDestructorAttr(S, D, Attr); @@ -4145,11 +4390,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleExtVectorTypeAttr(S, scope, D, Attr); break; case AttributeList::AT_MinSize: - handleSimpleAttribute<MinSizeAttr>(S, D, Attr); + handleMinSizeAttr(S, D, Attr); break; case AttributeList::AT_OptimizeNone: handleOptimizeNoneAttr(S, D, Attr); break; + case AttributeList::AT_FlagEnum: + handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); + break; case AttributeList::AT_Flatten: handleSimpleAttribute<FlattenAttr>(S, D, Attr); break; @@ -4198,6 +4446,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReturnsNonNull: handleReturnsNonNullAttr(S, D, Attr); break; + case AttributeList::AT_AssumeAligned: + handleAssumeAlignedAttr(S, D, Attr); + break; case AttributeList::AT_Overloadable: handleSimpleAttribute<OverloadableAttr>(S, D, Attr); break; @@ -4392,6 +4643,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FastCall: case AttributeList::AT_ThisCall: case AttributeList::AT_Pascal: + case AttributeList::AT_VectorCall: case AttributeList::AT_MSABI: case AttributeList::AT_SysVABI: case AttributeList::AT_Pcs: @@ -4553,19 +4805,31 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, return; } + // FIXME: We should be able to handle this in TableGen as well. It would be + // good to have a way to specify "these attributes must appear as a group", + // for these. Additionally, it would be good to have a way to specify "these + // attribute must never appear as a group" for attributes like cold and hot. if (!D->hasAttr<OpenCLKernelAttr>()) { // These attributes cannot be applied to a non-kernel function. if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) { + // FIXME: This emits a different error message than + // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction. Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } - if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + } else if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } - if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); + } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (Attr *A = D->getAttr<AMDGPUNumSGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); } } } @@ -4576,7 +4840,7 @@ 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); + ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute()); } else { Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); return true; @@ -4774,61 +5038,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, diag.Triggered = true; } -void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { - assert(DelayedDiagnostics.getCurrentPool()); - DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool(); - DelayedDiagnostics.popWithoutEmitting(state); - - // When delaying diagnostics to run in the context of a parsed - // declaration, we only want to actually emit anything if parsing - // succeeds. - if (!decl) return; - - // We emit all the active diagnostics in this pool or any of its - // parents. In general, we'll get one pool for the decl spec - // and a child pool for each declarator; in a decl group like: - // deprecated_typedef foo, *bar, baz(); - // only the declarator pops will be passed decls. This is correct; - // we really do need to consider delayed diagnostics from the decl spec - // for each of the different declarations. - const DelayedDiagnosticPool *pool = &poppedPool; - do { - for (DelayedDiagnosticPool::pool_iterator - i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) { - // This const_cast is a bit lame. Really, Triggered should be mutable. - DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i); - if (diag.Triggered) - continue; - - switch (diag.Kind) { - case DelayedDiagnostic::Deprecation: - case DelayedDiagnostic::Unavailable: - // Don't bother giving deprecation/unavailable diagnostics if - // the decl is invalid. - if (!decl->isInvalidDecl()) - HandleDelayedAvailabilityCheck(diag, decl); - break; - - case DelayedDiagnostic::Access: - HandleDelayedAccessCheck(diag, decl); - break; - - case DelayedDiagnostic::ForbiddenType: - handleDelayedForbiddenType(*this, diag, decl); - break; - } - } - } while ((pool = pool->getParent())); -} - -/// Given a set of delayed diagnostics, re-emit them as if they had -/// been delayed in the current context instead of in the given pool. -/// Essentially, this just moves them to the current pool. -void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { - DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool(); - assert(curPool && "re-emitting in undelayed context not supported"); - curPool->steal(pool); -} static bool isDeclDeprecated(Decl *D) { do { @@ -4852,17 +5061,12 @@ static bool isDeclUnavailable(Decl *D) { return false; } -static void -DoEmitAvailabilityWarning(Sema &S, - DelayedDiagnostic::DDKind K, - Decl *Ctx, - const NamedDecl *D, - StringRef Message, - SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess) { - +static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, + Decl *Ctx, const NamedDecl *D, + StringRef Message, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess) { // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; @@ -4874,65 +5078,116 @@ DoEmitAvailabilityWarning(Sema &S, // Don't warn if our current context is deprecated or unavailable. switch (K) { - case DelayedDiagnostic::Deprecation: - if (isDeclDeprecated(Ctx)) - return; - diag = !ObjCPropertyAccess ? diag::warn_deprecated - : diag::warn_property_method_deprecated; - diag_message = diag::warn_deprecated_message; - diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; - property_note_select = /* deprecated */ 0; - available_here_select_kind = /* deprecated */ 2; - break; + case DelayedDiagnostic::Deprecation: + if (isDeclDeprecated(Ctx)) + return; + diag = !ObjCPropertyAccess ? diag::warn_deprecated + : diag::warn_property_method_deprecated; + diag_message = diag::warn_deprecated_message; + diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; + property_note_select = /* deprecated */ 0; + available_here_select_kind = /* deprecated */ 2; + break; - case DelayedDiagnostic::Unavailable: - if (isDeclUnavailable(Ctx)) - return; - diag = !ObjCPropertyAccess ? diag::err_unavailable - : diag::err_property_method_unavailable; - diag_message = diag::err_unavailable_message; - diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; - property_note_select = /* unavailable */ 1; - available_here_select_kind = /* unavailable */ 0; - break; + case DelayedDiagnostic::Unavailable: + if (isDeclUnavailable(Ctx)) + return; + diag = !ObjCPropertyAccess ? diag::err_unavailable + : diag::err_property_method_unavailable; + diag_message = diag::err_unavailable_message; + diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; + property_note_select = /* unavailable */ 1; + available_here_select_kind = /* unavailable */ 0; + break; - default: - llvm_unreachable("Neither a deprecation or unavailable kind"); + default: + llvm_unreachable("Neither a deprecation or unavailable kind"); } - DeclarationName Name = D->getDeclName(); if (!Message.empty()) { - S.Diag(Loc, diag_message) << Name << Message; + S.Diag(Loc, diag_message) << D << Message; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) - << ObjCProperty->getDeclName() << property_note_select; + << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << Name; + S.Diag(Loc, diag) << D; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) - << ObjCProperty->getDeclName() << property_note_select; + << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << Name; + S.Diag(Loc, diag_fwdclass_message) << D; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } S.Diag(D->getLocation(), diag::note_availability_specified_here) - << D << available_here_select_kind; + << D << available_here_select_kind; } -void Sema::HandleDelayedAvailabilityCheck(DelayedDiagnostic &DD, - Decl *Ctx) { +static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, + Decl *Ctx) { DD.Triggered = true; - DoEmitAvailabilityWarning(*this, - (DelayedDiagnostic::DDKind) DD.Kind, - Ctx, - DD.getDeprecationDecl(), - DD.getDeprecationMessage(), - DD.Loc, - DD.getUnknownObjCClass(), + DoEmitAvailabilityWarning(S, (DelayedDiagnostic::DDKind)DD.Kind, Ctx, + DD.getDeprecationDecl(), DD.getDeprecationMessage(), + DD.Loc, DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } +void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { + assert(DelayedDiagnostics.getCurrentPool()); + DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool(); + DelayedDiagnostics.popWithoutEmitting(state); + + // When delaying diagnostics to run in the context of a parsed + // declaration, we only want to actually emit anything if parsing + // succeeds. + if (!decl) return; + + // We emit all the active diagnostics in this pool or any of its + // parents. In general, we'll get one pool for the decl spec + // and a child pool for each declarator; in a decl group like: + // deprecated_typedef foo, *bar, baz(); + // only the declarator pops will be passed decls. This is correct; + // we really do need to consider delayed diagnostics from the decl spec + // for each of the different declarations. + const DelayedDiagnosticPool *pool = &poppedPool; + do { + for (DelayedDiagnosticPool::pool_iterator + i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) { + // This const_cast is a bit lame. Really, Triggered should be mutable. + DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i); + if (diag.Triggered) + continue; + + switch (diag.Kind) { + case DelayedDiagnostic::Deprecation: + case DelayedDiagnostic::Unavailable: + // Don't bother giving deprecation/unavailable diagnostics if + // the decl is invalid. + if (!decl->isInvalidDecl()) + handleDelayedAvailabilityCheck(*this, diag, decl); + break; + + case DelayedDiagnostic::Access: + HandleDelayedAccessCheck(diag, decl); + break; + + case DelayedDiagnostic::ForbiddenType: + handleDelayedForbiddenType(*this, diag, decl); + break; + } + } + } while ((pool = pool->getParent())); +} + +/// Given a set of delayed diagnostics, re-emit them as if they had +/// been delayed in the current context instead of in the given pool. +/// Essentially, this just moves them to the current pool. +void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { + DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool(); + assert(curPool && "re-emitting in undelayed context not supported"); + curPool->steal(pool); +} + void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -4941,11 +5196,9 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { - DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(AD, Loc, D, - UnknownObjCClass, - ObjCProperty, - Message, - ObjCPropertyAccess)); + DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( + AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, + ObjCPropertyAccess)); return; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c5cd83d..510738e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -36,6 +36,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include <map> @@ -212,7 +213,7 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, ComputedEST = EST_Dynamic; // Record the exceptions in this function's exception specification. for (const auto &E : Proto->exceptions()) - if (ExceptionsSeen.insert(Self->Context.getCanonicalType(E))) + if (ExceptionsSeen.insert(Self->Context.getCanonicalType(E)).second) Exceptions.push_back(E); } @@ -353,7 +354,9 @@ void Sema::ActOnParamDefaultArgumentError(Decl *param, Param->setInvalidDecl(); UnparsedDefaultArgLocs.erase(Param); Param->setDefaultArg(new(Context) - OpaqueValueExpr(EqualLoc, Param->getType(), VK_RValue)); + OpaqueValueExpr(EqualLoc, + Param->getType().getNonReferenceType(), + VK_RValue)); } /// CheckExtraCXXDefaultArguments - Check for any extra default @@ -385,9 +388,14 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { ParmVarDecl *Param = cast<ParmVarDecl>(chunk.Fun.Params[argIdx].Param); if (Param->hasUnparsedDefaultArg()) { CachedTokens *Toks = chunk.Fun.Params[argIdx].DefaultArgTokens; + SourceRange SR; + if (Toks->size() > 1) + SR = SourceRange((*Toks)[1].getLocation(), + Toks->back().getLocation()); + else + SR = UnparsedDefaultArgLocs[Param]; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) - << SourceRange((*Toks)[1].getLocation(), - Toks->back().getLocation()); + << SR; delete Toks; chunk.Fun.Params[argIdx].DefaultArgTokens = nullptr; } else if (Param->getDefaultArg()) { @@ -446,20 +454,24 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, bool OldParamHasDfl = OldParam->hasDefaultArg(); bool NewParamHasDfl = NewParam->hasDefaultArg(); - NamedDecl *ND = Old; - // The declaration context corresponding to the scope is the semantic // parent, unless this is a local function declaration, in which case // it is that surrounding function. - DeclContext *ScopeDC = New->getLexicalDeclContext(); - if (!ScopeDC->isFunctionOrMethod()) - ScopeDC = New->getDeclContext(); - if (S && !isDeclInScope(ND, ScopeDC, S) && + DeclContext *ScopeDC = New->isLocalExternDecl() + ? New->getLexicalDeclContext() + : New->getDeclContext(); + if (S && !isDeclInScope(Old, ScopeDC, S) && !New->getDeclContext()->isRecord()) // Ignore default parameters of old decl if they are not in // the same scope and this is not an out-of-line definition of // a member function. OldParamHasDfl = false; + if (New->isLocalExternDecl() != Old->isLocalExternDecl()) + // If only one of these is a local function declaration, then they are + // declared in different scopes, even though isDeclInScope may think + // they're in the same scope. (If both are local, the scope check is + // sufficent, and if neither is local, then they are in the same scope.) + OldParamHasDfl = false; if (OldParamHasDfl && NewParamHasDfl) { @@ -855,7 +867,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, // C++1y allows types to be defined, not just declared. if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) SemaRef.Diag(DS->getLocStart(), - SemaRef.getLangOpts().CPlusPlus1y + SemaRef.getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_constexpr_type_definition : diag::ext_constexpr_type_definition) << isa<CXXConstructorDecl>(Dcl); @@ -896,7 +908,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, } } SemaRef.Diag(VD->getLocation(), - SemaRef.getLangOpts().CPlusPlus1y + SemaRef.getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_constexpr_local_var : diag::ext_constexpr_local_var) << isa<CXXConstructorDecl>(Dcl); @@ -1041,7 +1053,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, case Stmt::ContinueStmtClass: // C++1y allows all of these. We don't allow them as extensions in C++11, // because they don't make sense without variable mutation. - if (!SemaRef.getLangOpts().CPlusPlus1y) + if (!SemaRef.getLangOpts().CPlusPlus14) break; if (!Cxx1yLoc.isValid()) Cxx1yLoc = S->getLocStart(); @@ -1115,7 +1127,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { if (Cxx1yLoc.isValid()) Diag(Cxx1yLoc, - getLangOpts().CPlusPlus1y + getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt : diag::ext_constexpr_body_invalid_stmt) << isa<CXXConstructorDecl>(Dcl); @@ -1180,7 +1192,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { // statement. We still do, unless the return type might be void, because // otherwise if there's no return statement, the function cannot // be used in a core constant expression. - bool OK = getLangOpts().CPlusPlus1y && + bool OK = getLangOpts().CPlusPlus14 && (Dcl->getReturnType()->isVoidType() || Dcl->getReturnType()->isDependentType()); Diag(Dcl->getLocation(), @@ -1190,7 +1202,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { } if (ReturnStmts.size() > 1) { Diag(ReturnStmts.back(), - getLangOpts().CPlusPlus1y + getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_constexpr_body_multiple_return : diag::ext_constexpr_body_multiple_return); for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) @@ -1881,7 +1893,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { } // C++11 [class.virtual]p5: - // If a virtual function is marked with the virt-specifier override and + // If a function is marked with the virt-specifier override and // does not override a member function of a base class, the program is // ill-formed. bool HasOverriddenMethods = @@ -1891,6 +1903,30 @@ void Sema::CheckOverrideControl(NamedDecl *D) { << MD->getDeclName(); } +void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { + if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>()) + return; + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); + if (!MD || MD->isImplicit() || MD->hasAttr<FinalAttr>() || + isa<CXXDestructorDecl>(MD)) + return; + + SourceLocation Loc = MD->getLocation(); + SourceLocation SpellingLoc = Loc; + if (getSourceManager().isMacroArgExpansion(Loc)) + SpellingLoc = getSourceManager().getImmediateExpansionRange(Loc).first; + SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc); + if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc)) + return; + + if (MD->size_overridden_methods() > 0) { + Diag(MD->getLocation(), diag::warn_function_marked_not_override_overriding) + << MD->getDeclName(); + const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); + Diag(OMD->getLocation(), diag::note_overridden_virtual_function); + } +} + /// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member /// function overrides a virtual member function marked 'final', according to /// C++11 [class.virtual]p4. @@ -2133,7 +2169,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (BitWidth) { if (Member->isInvalidDecl()) { // don't emit another diagnostic. - } else if (isa<VarDecl>(Member)) { + } else if (isa<VarDecl>(Member) || isa<VarTemplateDecl>(Member)) { // C++ 9.6p3: A bit-field shall not be a static member. // "static member 'A' cannot be a bit-field" Diag(Loc, diag::err_static_not_bitfield) @@ -2205,18 +2241,73 @@ namespace { Sema &S; // List of Decls to generate a warning on. Also remove Decls that become // initialized. - llvm::SmallPtrSet<ValueDecl*, 4> &Decls; + llvm::SmallPtrSetImpl<ValueDecl*> &Decls; + // List of base classes of the record. Classes are removed after their + // initializers. + llvm::SmallPtrSetImpl<QualType> &BaseClasses; + // Vector of decls to be removed from the Decl set prior to visiting the + // nodes. These Decls may have been initialized in the prior initializer. + llvm::SmallVector<ValueDecl*, 4> DeclsToRemove; // If non-null, add a note to the warning pointing back to the constructor. const CXXConstructorDecl *Constructor; + // Variables to hold state when processing an initializer list. When + // InitList is true, special case initialization of FieldDecls matching + // InitListFieldDecl. + bool InitList; + FieldDecl *InitListFieldDecl; + llvm::SmallVector<unsigned, 4> InitFieldIndex; + public: typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited; UninitializedFieldVisitor(Sema &S, - llvm::SmallPtrSet<ValueDecl*, 4> &Decls, - const CXXConstructorDecl *Constructor) - : Inherited(S.Context), S(S), Decls(Decls), - Constructor(Constructor) { } + llvm::SmallPtrSetImpl<ValueDecl*> &Decls, + llvm::SmallPtrSetImpl<QualType> &BaseClasses) + : Inherited(S.Context), S(S), Decls(Decls), BaseClasses(BaseClasses), + Constructor(nullptr), InitList(false), InitListFieldDecl(nullptr) {} + + // Returns true if the use of ME is not an uninitialized use. + bool IsInitListMemberExprInitialized(MemberExpr *ME, + bool CheckReferenceOnly) { + llvm::SmallVector<FieldDecl*, 4> Fields; + bool ReferenceField = false; + while (ME) { + FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); + if (!FD) + return false; + Fields.push_back(FD); + if (FD->getType()->isReferenceType()) + ReferenceField = true; + ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParenImpCasts()); + } + + // Binding a reference to an unintialized field is not an + // uninitialized use. + if (CheckReferenceOnly && !ReferenceField) + return true; - void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly) { + llvm::SmallVector<unsigned, 4> UsedFieldIndex; + // Discard the first field since it is the field decl that is being + // initialized. + for (auto I = Fields.rbegin() + 1, E = Fields.rend(); I != E; ++I) { + UsedFieldIndex.push_back((*I)->getFieldIndex()); + } + + for (auto UsedIter = UsedFieldIndex.begin(), + UsedEnd = UsedFieldIndex.end(), + OrigIter = InitFieldIndex.begin(), + OrigEnd = InitFieldIndex.end(); + UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) { + if (*UsedIter < *OrigIter) + return true; + if (*UsedIter > *OrigIter) + break; + } + + return false; + } + + void HandleMemberExpr(MemberExpr *ME, bool CheckReferenceOnly, + bool AddressOf) { if (isa<EnumConstantDecl>(ME->getMemberDecl())) return; @@ -2224,33 +2315,63 @@ namespace { // or union. MemberExpr *FieldME = ME; + bool AllPODFields = FieldME->getType().isPODType(S.Context); + Expr *Base = ME; - while (isa<MemberExpr>(Base)) { - ME = cast<MemberExpr>(Base); + while (MemberExpr *SubME = + dyn_cast<MemberExpr>(Base->IgnoreParenImpCasts())) { - if (isa<VarDecl>(ME->getMemberDecl())) + if (isa<VarDecl>(SubME->getMemberDecl())) return; - if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) + if (FieldDecl *FD = dyn_cast<FieldDecl>(SubME->getMemberDecl())) if (!FD->isAnonymousStructOrUnion()) - FieldME = ME; + FieldME = SubME; + + if (!FieldME->getType().isPODType(S.Context)) + AllPODFields = false; - Base = ME->getBase(); + Base = SubME->getBase(); } - if (!isa<CXXThisExpr>(Base)) + if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts())) + return; + + if (AddressOf && AllPODFields) return; ValueDecl* FoundVD = FieldME->getMemberDecl(); + if (ImplicitCastExpr *BaseCast = dyn_cast<ImplicitCastExpr>(Base)) { + while (isa<ImplicitCastExpr>(BaseCast->getSubExpr())) { + BaseCast = cast<ImplicitCastExpr>(BaseCast->getSubExpr()); + } + + if (BaseCast->getCastKind() == CK_UncheckedDerivedToBase) { + QualType T = BaseCast->getType(); + if (T->isPointerType() && + BaseClasses.count(T->getPointeeType())) { + S.Diag(FieldME->getExprLoc(), diag::warn_base_class_is_uninit) + << T->getPointeeType() << FoundVD; + } + } + } + if (!Decls.count(FoundVD)) return; const bool IsReference = FoundVD->getType()->isReferenceType(); - // Prevent double warnings on use of unbounded references. - if (IsReference != CheckReferenceOnly) - return; + if (InitList && !AddressOf && FoundVD == InitListFieldDecl) { + // Special checking for initializer lists. + if (IsInitListMemberExprInitialized(ME, CheckReferenceOnly)) { + return; + } + } else { + // Prevent double warnings on use of unbounded references. + if (CheckReferenceOnly && !IsReference) + return; + } unsigned diag = IsReference ? diag::warn_reference_field_is_uninit @@ -2263,74 +2384,160 @@ namespace { } - void HandleValue(Expr *E) { + void HandleValue(Expr *E, bool AddressOf) { E = E->IgnoreParens(); if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - HandleMemberExpr(ME, false /*CheckReferenceOnly*/); + HandleMemberExpr(ME, false /*CheckReferenceOnly*/, + AddressOf /*AddressOf*/); return; } if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { - HandleValue(CO->getTrueExpr()); - HandleValue(CO->getFalseExpr()); + Visit(CO->getCond()); + HandleValue(CO->getTrueExpr(), AddressOf); + HandleValue(CO->getFalseExpr(), AddressOf); return; } if (BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(E)) { - HandleValue(BCO->getCommon()); - HandleValue(BCO->getFalseExpr()); + Visit(BCO->getCond()); + HandleValue(BCO->getFalseExpr(), AddressOf); + return; + } + + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { + HandleValue(OVE->getSourceExpr(), AddressOf); return; } if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { default: - return; + break; case(BO_PtrMemD): case(BO_PtrMemI): - HandleValue(BO->getLHS()); + HandleValue(BO->getLHS(), AddressOf); + Visit(BO->getRHS()); return; case(BO_Comma): - HandleValue(BO->getRHS()); + Visit(BO->getLHS()); + HandleValue(BO->getRHS(), AddressOf); return; } } + + Visit(E); + } + + void CheckInitListExpr(InitListExpr *ILE) { + InitFieldIndex.push_back(0); + for (auto Child : ILE->children()) { + if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) { + CheckInitListExpr(SubList); + } else { + Visit(Child); + } + ++InitFieldIndex.back(); + } + InitFieldIndex.pop_back(); + } + + void CheckInitializer(Expr *E, const CXXConstructorDecl *FieldConstructor, + FieldDecl *Field, const Type *BaseClass) { + // Remove Decls that may have been initialized in the previous + // initializer. + for (ValueDecl* VD : DeclsToRemove) + Decls.erase(VD); + DeclsToRemove.clear(); + + Constructor = FieldConstructor; + InitListExpr *ILE = dyn_cast<InitListExpr>(E); + + if (ILE && Field) { + InitList = true; + InitListFieldDecl = Field; + InitFieldIndex.clear(); + CheckInitListExpr(ILE); + } else { + InitList = false; + Visit(E); + } + + if (Field) + Decls.erase(Field); + if (BaseClass) + BaseClasses.erase(BaseClass->getCanonicalTypeInternal()); } void VisitMemberExpr(MemberExpr *ME) { // All uses of unbounded reference fields will warn. - HandleMemberExpr(ME, true /*CheckReferenceOnly*/); - - Inherited::VisitMemberExpr(ME); + HandleMemberExpr(ME, true /*CheckReferenceOnly*/, false /*AddressOf*/); } void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if (E->getCastKind() == CK_LValueToRValue) - HandleValue(E->getSubExpr()); + if (E->getCastKind() == CK_LValueToRValue) { + HandleValue(E->getSubExpr(), false /*AddressOf*/); + return; + } Inherited::VisitImplicitCastExpr(E); } void VisitCXXConstructExpr(CXXConstructExpr *E) { - if (E->getConstructor()->isCopyConstructor()) - if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E->getArg(0))) + if (E->getConstructor()->isCopyConstructor()) { + Expr *ArgExpr = E->getArg(0); + if (InitListExpr *ILE = dyn_cast<InitListExpr>(ArgExpr)) + if (ILE->getNumInits() == 1) + ArgExpr = ILE->getInit(0); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr)) if (ICE->getCastKind() == CK_NoOp) - if (MemberExpr *ME = dyn_cast<MemberExpr>(ICE->getSubExpr())) - HandleMemberExpr(ME, false /*CheckReferenceOnly*/); - + ArgExpr = ICE->getSubExpr(); + HandleValue(ArgExpr, false /*AddressOf*/); + return; + } Inherited::VisitCXXConstructExpr(E); } void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { Expr *Callee = E->getCallee(); - if (isa<MemberExpr>(Callee)) - HandleValue(Callee); + if (isa<MemberExpr>(Callee)) { + HandleValue(Callee, false /*AddressOf*/); + for (auto Arg : E->arguments()) + Visit(Arg); + return; + } Inherited::VisitCXXMemberCallExpr(E); } + void VisitCallExpr(CallExpr *E) { + // Treat std::move as a use. + if (E->getNumArgs() == 1) { + if (FunctionDecl *FD = E->getDirectCallee()) { + if (FD->isInStdNamespace() && FD->getIdentifier() && + FD->getIdentifier()->isStr("move")) { + HandleValue(E->getArg(0), false /*AddressOf*/); + return; + } + } + } + + Inherited::VisitCallExpr(E); + } + + void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + Expr *Callee = E->getCallee(); + + if (isa<UnresolvedLookupExpr>(Callee)) + return Inherited::VisitCXXOperatorCallExpr(E); + + Visit(Callee); + for (auto Arg : E->arguments()) + HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/); + } + void VisitBinaryOperator(BinaryOperator *E) { // If a field assignment is detected, remove the field from the // uninitiailized field set. @@ -2338,30 +2545,32 @@ namespace { if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getLHS())) if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) if (!FD->getType()->isReferenceType()) - Decls.erase(FD); + DeclsToRemove.push_back(FD); + + if (E->isCompoundAssignmentOp()) { + HandleValue(E->getLHS(), false /*AddressOf*/); + Visit(E->getRHS()); + return; + } Inherited::VisitBinaryOperator(E); } - }; - static void CheckInitExprContainsUninitializedFields( - Sema &S, Expr *E, llvm::SmallPtrSet<ValueDecl*, 4> &Decls, - const CXXConstructorDecl *Constructor) { - if (Decls.size() == 0) - return; - - if (!E) - return; - if (CXXDefaultInitExpr *Default = dyn_cast<CXXDefaultInitExpr>(E)) { - E = Default->getExpr(); - if (!E) + void VisitUnaryOperator(UnaryOperator *E) { + if (E->isIncrementDecrementOp()) { + HandleValue(E->getSubExpr(), false /*AddressOf*/); return; - // In class initializers will point to the constructor. - UninitializedFieldVisitor(S, Decls, Constructor).Visit(E); - } else { - UninitializedFieldVisitor(S, Decls, nullptr).Visit(E); + } + if (E->getOpcode() == UO_AddrOf) { + if (MemberExpr *ME = dyn_cast<MemberExpr>(E->getSubExpr())) { + HandleValue(ME->getBase(), true /*AddressOf*/); + return; + } + } + + Inherited::VisitUnaryOperator(E); } - } + }; // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) @@ -2382,6 +2591,9 @@ namespace { const CXXRecordDecl *RD = Constructor->getParent(); + if (RD->getDescribedClassTemplate()) + return; + // Holds fields that are uninitialized. llvm::SmallPtrSet<ValueDecl*, 4> UninitializedFields; @@ -2394,14 +2606,39 @@ namespace { } } + llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses; + for (auto I : RD->bases()) + UninitializedBaseClasses.insert(I.getType().getCanonicalType()); + + if (UninitializedFields.empty() && UninitializedBaseClasses.empty()) + return; + + UninitializedFieldVisitor UninitializedChecker(SemaRef, + UninitializedFields, + UninitializedBaseClasses); + for (const auto *FieldInit : Constructor->inits()) { - Expr *InitExpr = FieldInit->getInit(); + if (UninitializedFields.empty() && UninitializedBaseClasses.empty()) + break; - CheckInitExprContainsUninitializedFields( - SemaRef, InitExpr, UninitializedFields, Constructor); + Expr *InitExpr = FieldInit->getInit(); + if (!InitExpr) + continue; - if (FieldDecl *Field = FieldInit->getAnyMember()) - UninitializedFields.erase(Field); + if (CXXDefaultInitExpr *Default = + dyn_cast<CXXDefaultInitExpr>(InitExpr)) { + InitExpr = Default->getExpr(); + if (!InitExpr) + continue; + // In class initializers will point to the constructor. + UninitializedChecker.CheckInitializer(InitExpr, Constructor, + FieldInit->getAnyMember(), + FieldInit->getBaseClass()); + } else { + UninitializedChecker.CheckInitializer(InitExpr, nullptr, + FieldInit->getAnyMember(), + FieldInit->getBaseClass()); + } } } } // namespace @@ -2424,13 +2661,14 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, // Pop the notional constructor scope we created earlier. PopFunctionScopeInfo(nullptr, D); - FieldDecl *FD = cast<FieldDecl>(D); - assert(FD->getInClassInitStyle() != ICIS_NoInit && + FieldDecl *FD = dyn_cast<FieldDecl>(D); + assert((isa<MSPropertyDecl>(D) || FD->getInClassInitStyle() != ICIS_NoInit) && "must set init style when field is created"); if (!InitExpr) { - FD->setInvalidDecl(); - FD->removeInClassInitializer(); + D->setInvalidDecl(); + if (FD) + FD->removeInClassInitializer(); return; } @@ -2581,6 +2819,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc) { + ExprResult Res = CorrectDelayedTyposInExpr(Init); + if (!Res.isUsable()) + return true; + Init = Res.get(); + if (!ConstructorD) return true; @@ -2610,8 +2853,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, // using a qualified name. ] if (!SS.getScopeRep() && !TemplateTypeTy) { // Look for a member, first. - DeclContext::lookup_result Result - = ClassDecl->lookup(MemberOrBase); + DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); if (!Result.empty()) { ValueDecl *Member; if ((Member = dyn_cast<FieldDecl>(Result.front())) || @@ -2666,10 +2908,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD, // If no results were found, try to correct typos. TypoCorrection Corr; - MemInitializerValidatorCCC Validator(ClassDecl); if (R.empty() && BaseType.isNull() && - (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, - Validator, CTK_ErrorRecovery, ClassDecl))) { + (Corr = CorrectTypo( + R.getLookupNameInfo(), R.getLookupKind(), S, &SS, + llvm::make_unique<MemInitializerValidatorCCC>(ClassDecl), + CTK_ErrorRecovery, ClassDecl))) { if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) { // We have found a non-static data member with a similar // name to what was typed; complain and initialize that @@ -2713,6 +2956,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) { BaseType = Context.getTypeDeclType(TyD); + MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false); if (SS.isSet()) // FIXME: preserve source range information BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(), @@ -3528,19 +3772,19 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, return false; if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { - Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, - Info.Ctor->getLocation(), Field); + ExprResult DIE = + SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field); + if (DIE.isInvalid()) + return true; CXXCtorInitializer *Init; if (Indirect) - Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, - SourceLocation(), - SourceLocation(), DIE, - SourceLocation()); + Init = new (SemaRef.Context) + CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), + SourceLocation(), DIE.get(), SourceLocation()); else - Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, - SourceLocation(), - SourceLocation(), DIE, - SourceLocation()); + Init = new (SemaRef.Context) + CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), + SourceLocation(), DIE.get(), SourceLocation()); return Info.addFieldInitializer(Init); } @@ -3582,6 +3826,8 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, DelegatingCtorDecls.push_back(Constructor); + DiagnoseUninitializedFields(*this, Constructor); + return false; } @@ -4234,7 +4480,7 @@ void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { if (!SO->second.front().Method->isPure()) continue; - if (!SeenPureMethods.insert(SO->second.front().Method)) + if (!SeenPureMethods.insert(SO->second.front().Method).second) continue; Diag(SO->second.front().Method->getLocation(), @@ -4415,10 +4661,53 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, /// \brief Check class-level dllimport/dllexport attribute. static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); + + // MSVC inherits DLL attributes to partial class template specializations. + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && !ClassAttr) { + if (auto *Spec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Class)) { + if (Attr *TemplateAttr = + getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) { + auto *A = cast<InheritableAttr>(TemplateAttr->clone(S.getASTContext())); + A->setInherited(true); + ClassAttr = A; + } + } + } + if (!ClassAttr) return; - bool ClassExported = ClassAttr->getKind() == attr::DLLExport; + if (!Class->isExternallyVisible()) { + S.Diag(Class->getLocation(), diag::err_attribute_dll_not_extern) + << Class << ClassAttr; + return; + } + + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && + !ClassAttr->isInherited()) { + // Diagnose dll attributes on members of class with dll attribute. + for (Decl *Member : Class->decls()) { + if (!isa<VarDecl>(Member) && !isa<CXXMethodDecl>(Member)) + continue; + InheritableAttr *MemberAttr = getDLLAttr(Member); + if (!MemberAttr || MemberAttr->isInherited() || Member->isInvalidDecl()) + continue; + + S.Diag(MemberAttr->getLocation(), + diag::err_attribute_dll_member_of_dll_class) + << MemberAttr << ClassAttr; + S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute); + Member->setInvalidDecl(); + } + } + + if (Class->getDescribedClassTemplate()) + // Don't inherit dll attribute until the template is instantiated. + return; + + // The class is either imported or exported. + const bool ClassExported = ClassAttr->getKind() == attr::DLLExport; + const bool ClassImported = !ClassExported; // Force declaration of implicit members so they can inherit the attribute. S.ForceDeclarationOfImplicitMembers(Class); @@ -4426,6 +4715,9 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { // FIXME: MSVC's docs say all bases must be exportable, but this doesn't // seem to be true in practice? + TemplateSpecializationKind TSK = + Class->getTemplateSpecializationKind(); + for (Decl *Member : Class->decls()) { VarDecl *VD = dyn_cast<VarDecl>(Member); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member); @@ -4434,50 +4726,57 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { if (!VD && !MD) continue; - // Don't process deleted methods. - if (MD && MD->isDeleted()) - continue; + if (MD) { + // Don't process deleted methods. + if (MD->isDeleted()) + continue; - if (MD && MD->isMoveAssignmentOperator() && !ClassExported && - MD->isInlined()) { - // Current MSVC versions don't export the move assignment operators, so - // don't attempt to import them if we have a definition. - continue; - } + if (MD->isMoveAssignmentOperator() && ClassImported && MD->isInlined()) { + // Current MSVC versions don't export the move assignment operators, so + // don't attempt to import them if we have a definition. + continue; + } - if (InheritableAttr *MemberAttr = getDLLAttr(Member)) { - if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && - !MemberAttr->isInherited() && !ClassAttr->isInherited()) { - S.Diag(MemberAttr->getLocation(), - diag::err_attribute_dll_member_of_dll_class) - << MemberAttr << ClassAttr; - S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute); - Member->setInvalidDecl(); + if (MD->isInlined() && ClassImported && + !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // MinGW does not import inline functions. continue; } - } else { + } + + if (!getDLLAttr(Member)) { auto *NewAttr = cast<InheritableAttr>(ClassAttr->clone(S.getASTContext())); NewAttr->setInherited(true); Member->addAttr(NewAttr); } - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { - if (ClassExported) { - if (MD->isUserProvided()) { - // Instantiate non-default methods. - S.MarkFunctionReferenced(Class->getLocation(), MD); - } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || - MD->isCopyAssignmentOperator() || - MD->isMoveAssignmentOperator()) { - // Instantiate non-trivial or explicitly defaulted methods, and the - // copy assignment / move assignment operators. - S.MarkFunctionReferenced(Class->getLocation(), MD); - // Resolve its exception specification; CodeGen needs it. - auto *FPT = MD->getType()->getAs<FunctionProtoType>(); - S.ResolveExceptionSpec(Class->getLocation(), FPT); - S.ActOnFinishInlineMethodDef(MD); - } + if (MD && ClassExported) { + if (MD->isUserProvided()) { + // Instantiate non-default class member functions ... + + // .. except for certain kinds of template specializations. + if (TSK == TSK_ExplicitInstantiationDeclaration) + continue; + if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) + continue; + + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // The function will be passed to the consumer when its definition is + // encountered. + } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || + MD->isCopyAssignmentOperator() || + MD->isMoveAssignmentOperator()) { + // Synthesize and instantiate non-trivial implicit methods, explicitly + // defaulted methods, and the copy and move assignment operators. The + // latter are exported even if they are trivial, because the address of + // an operator can be taken and should compare equal accross libraries. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // There is no later point when we will see the definition of this + // function, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); } } } @@ -4563,13 +4862,18 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + bool HasMethodWithOverrideControl = false, + HasOverridingMethodWithoutOverrideControl = false; if (!Record->isDependentType()) { for (auto *M : Record->methods()) { // See if a method overloads virtual methods in a base // class without overriding any. if (!M->isStatic()) DiagnoseHiddenVirtualMethods(M); - + if (M->hasAttr<OverrideAttr>()) + HasMethodWithOverrideControl = true; + else if (M->size_overridden_methods() > 0) + HasOverridingMethodWithoutOverrideControl = true; // Check whether the explicitly-defaulted special members are valid. if (!M->isInvalidDecl() && M->isExplicitlyDefaulted()) CheckExplicitlyDefaultedSpecialMember(M); @@ -4588,41 +4892,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - // C++11 [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. - // - // 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. - // - // We delay this until we know whether an explicitly-defaulted (or deleted) - // destructor for the class is trivial. - if (LangOpts.CPlusPlus11 && !Record->isDependentType() && - !Record->isLiteral() && !Record->getNumVBases()) { - for (const auto *M : Record->methods()) { - if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(M)) { - 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. - continue; - - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - RequireLiteralType(M->getLocation(), Context.getRecordType(Record), - diag::err_constexpr_method_non_literal); - break; - } - - // Only produce one error per class. - break; - } - } + if (HasMethodWithOverrideControl && + HasOverridingMethodWithoutOverrideControl) { + // At least one method has the 'override' control declared. + // Diagnose all other overridden methods which do not have 'override' specified on them. + for (auto *M : Record->methods()) + DiagnoseAbsenceOfOverrideControl(M); } // ms_struct is a request to use the same ABI rules as MSVC. Check @@ -4723,7 +4998,7 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, case Sema::CXXCopyAssignment: case Sema::CXXMoveAssignment: - if (!S.getLangOpts().CPlusPlus1y) + if (!S.getLangOpts().CPlusPlus14) return false; // In C++1y, we need to perform overload resolution. Ctor = false; @@ -4818,8 +5093,8 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, FunctionProtoType::ExtProtoInfo EPI; // Build an exception specification pointing back at this member. - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = MD; + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = MD; // Set the calling convention to the default for C++ instance methods. EPI.ExtInfo = EPI.ExtInfo.withCallingConv( @@ -4834,14 +5109,10 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) return; // Evaluate the exception specification. - ImplicitExceptionSpecification ExceptSpec = - computeImplicitExceptionSpec(*this, Loc, MD); - - FunctionProtoType::ExtProtoInfo EPI; - ExceptSpec.getEPI(EPI); + auto ESI = computeImplicitExceptionSpec(*this, Loc, MD).getExceptionSpec(); // Update the type of the special member to use it. - UpdateExceptionSpec(MD, EPI); + UpdateExceptionSpec(MD, ESI); // A user-provided destructor can be defined outside the class. When that // happens, be sure to update the exception specification on both @@ -4849,7 +5120,7 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) const FunctionProtoType *CanonicalFPT = MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>(); if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated) - UpdateExceptionSpec(MD->getCanonicalDecl(), EPI); + UpdateExceptionSpec(MD->getCanonicalDecl(), ESI); } void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { @@ -4911,7 +5182,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // A defaulted special member cannot have cv-qualifiers. if (Type->getTypeQuals()) { Diag(MD->getLocation(), diag::err_defaulted_special_member_quals) - << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus1y; + << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus14; HadError = true; } } @@ -4960,7 +5231,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // destructors in C++1y), this is checked elsewhere. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); - if ((getLangOpts().CPlusPlus1y ? !isa<CXXDestructorDecl>(MD) + if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) : isa<CXXConstructorDecl>(MD)) && MD->isConstexpr() && !Constexpr && MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { @@ -4995,10 +5266,10 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // -- it is implicitly considered to have the same exception-specification // as if it had been implicitly declared, FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = MD; + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = MD; MD->setType(Context.getFunctionType(ReturnType, - ArrayRef<QualType>(&ArgType, + llvm::makeArrayRef(&ArgType, ExpectedParams), EPI)); } @@ -5026,11 +5297,18 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { /// C++11 [dcl.fct.def.default]p2. void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) { + // If the exception specification was explicitly specified but hadn't been + // parsed when the method was defaulted, grab it now. + if (SpecifiedType->getExceptionSpecType() == EST_Unparsed) + SpecifiedType = + MD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); + // Compute the implicit exception specification. CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false, /*IsCXXMethod=*/true); FunctionProtoType::ExtProtoInfo EPI(CC); - computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); + EPI.ExceptionSpec = computeImplicitExceptionSpec(*this, MD->getLocation(), MD) + .getExceptionSpec(); const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( Context.getFunctionType(Context.VoidTy, None, EPI)); @@ -5043,27 +5321,21 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( } void Sema::CheckDelayedMemberExceptionSpecs() { - SmallVector<std::pair<const CXXDestructorDecl *, const CXXDestructorDecl *>, - 2> Checks; - SmallVector<std::pair<CXXMethodDecl *, const FunctionProtoType *>, 2> Specs; + decltype(DelayedExceptionSpecChecks) Checks; + decltype(DelayedDefaultedMemberExceptionSpecs) Specs; - std::swap(Checks, DelayedDestructorExceptionSpecChecks); + std::swap(Checks, DelayedExceptionSpecChecks); std::swap(Specs, DelayedDefaultedMemberExceptionSpecs); // Perform any deferred checking of exception specifications for virtual // destructors. - for (unsigned i = 0, e = Checks.size(); i != e; ++i) { - const CXXDestructorDecl *Dtor = Checks[i].first; - assert(!Dtor->getParent()->isDependentType() && - "Should not ever add destructors of templates into the list."); - CheckOverridingFunctionExceptionSpec(Dtor, Checks[i].second); - } + for (auto &Check : Checks) + CheckOverridingFunctionExceptionSpec(Check.first, Check.second); // Check that any explicitly-defaulted methods have exception specifications // compatible with their implicit exception specifications. - for (unsigned I = 0, N = Specs.size(); I != N; ++I) - CheckExplicitlyDefaultedMemberExceptionSpec(Specs[I].first, - Specs[I].second); + for (auto &Spec : Specs) + CheckExplicitlyDefaultedMemberExceptionSpec(Spec.first, Spec.second); } namespace { @@ -5491,6 +5763,13 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, if (SMI.shouldDeleteForAllConstMembers()) return true; + if (getLangOpts().CUDA) { + // We should delete the special member in CUDA mode if target inference + // failed. + return inferCUDATargetForImplicitSpecialMember(RD, CSM, MD, SMI.ConstArg, + Diagnose); + } + return false; } @@ -5907,7 +6186,7 @@ namespace { /// \brief Check whether any most overriden method from MD in Methods static bool CheckMostOverridenMethods(const CXXMethodDecl *MD, - const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) { + const llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { if (MD->size_overridden_methods() == 0) return Methods.count(MD->getCanonicalDecl()); for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), @@ -5945,7 +6224,14 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, if (!MD->isVirtual()) continue; // If the method we are checking overrides a method from its base - // don't warn about the other overloaded methods. + // don't warn about the other overloaded methods. Clang deviates from GCC + // by only diagnosing overloads of inherited virtual functions that do not + // override any other virtual functions in the base. GCC's + // -Woverloaded-virtual diagnoses any derived function hiding a virtual + // function from a base class. These cases may be better served by a + // warning (not specific to virtual functions) on call sites when the call + // would select a different function from the base class, were it visible. + // See FIXME in test/SemaCXX/warn-overload-virtual.cpp for an example. if (!Data.S->IsOverload(Data.Method, MD, false)) return true; // Collect the overload only if its hidden. @@ -5962,7 +6248,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, /// \brief Add the most overriden methods from MD to Methods static void AddMostOverridenMethods(const CXXMethodDecl *MD, - llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) { + llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { if (MD->size_overridden_methods() == 0) Methods.insert(MD->getCanonicalDecl()); for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), @@ -6515,6 +6801,22 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, return Context.getFunctionType(Context.VoidTy, None, EPI); } +static void extendLeft(SourceRange &R, const SourceRange &Before) { + if (Before.isInvalid()) + return; + R.setBegin(Before.getBegin()); + if (R.getEnd().isInvalid()) + R.setEnd(Before.getEnd()); +} + +static void extendRight(SourceRange &R, const SourceRange &After) { + if (After.isInvalid()) + return; + if (R.getBegin().isInvalid()) + R.setBegin(After.getBegin()); + R.setEnd(After.getEnd()); +} + /// CheckConversionDeclarator - Called by ActOnDeclarator to check the /// well-formednes of the conversion function declarator @p D with /// type @p R. If there are any errors in the declarator, this routine @@ -6536,7 +6838,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, SC = SC_None; } - QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); + TypeSourceInfo *ConvTSI = nullptr; + QualType ConvType = + GetTypeFromParser(D.getName().ConversionFunctionId, &ConvTSI); if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will @@ -6570,9 +6874,75 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Diagnose "&operator bool()" and other such nonsense. This // is actually a gcc extension which we don't support. if (Proto->getReturnType() != ConvType) { - Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) - << Proto->getReturnType(); - D.setInvalidType(); + bool NeedsTypedef = false; + SourceRange Before, After; + + // Walk the chunks and extract information on them for our diagnostic. + bool PastFunctionChunk = false; + for (auto &Chunk : D.type_objects()) { + switch (Chunk.Kind) { + case DeclaratorChunk::Function: + if (!PastFunctionChunk) { + if (Chunk.Fun.HasTrailingReturnType) { + TypeSourceInfo *TRT = nullptr; + GetTypeFromParser(Chunk.Fun.getTrailingReturnType(), &TRT); + if (TRT) extendRight(After, TRT->getTypeLoc().getSourceRange()); + } + PastFunctionChunk = true; + break; + } + // Fall through. + case DeclaratorChunk::Array: + NeedsTypedef = true; + extendRight(After, Chunk.getSourceRange()); + break; + + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + extendLeft(Before, Chunk.getSourceRange()); + break; + + case DeclaratorChunk::Paren: + extendLeft(Before, Chunk.Loc); + extendRight(After, Chunk.EndLoc); + break; + } + } + + SourceLocation Loc = Before.isValid() ? Before.getBegin() : + After.isValid() ? After.getBegin() : + D.getIdentifierLoc(); + auto &&DB = Diag(Loc, diag::err_conv_function_with_complex_decl); + DB << Before << After; + + if (!NeedsTypedef) { + DB << /*don't need a typedef*/0; + + // If we can provide a correct fix-it hint, do so. + if (After.isInvalid() && ConvTSI) { + SourceLocation InsertLoc = + PP.getLocForEndOfToken(ConvTSI->getTypeLoc().getLocEnd()); + DB << FixItHint::CreateInsertion(InsertLoc, " ") + << FixItHint::CreateInsertionFromRange( + InsertLoc, CharSourceRange::getTokenRange(Before)) + << FixItHint::CreateRemoval(Before); + } + } else if (!Proto->getReturnType()->isDependentType()) { + DB << /*typedef*/1 << Proto->getReturnType(); + } else if (getLangOpts().CPlusPlus11) { + DB << /*alias template*/2 << Proto->getReturnType(); + } else { + DB << /*might not be fixable*/3; + } + + // Recover by incorporating the other type chunks into the result type. + // Note, this does *not* change the name of the function. This is compatible + // with the GCC extension: + // struct S { &operator int(); } s; + // int &r = s.operator int(); // ok in GCC + // S::operator int&() {} // error in GCC, function name is 'operator int'. ConvType = Proto->getReturnType(); } @@ -6893,7 +7263,7 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { /*PrevDecl=*/nullptr); getStdNamespace()->setImplicit(true); } - + return getStdNamespace(); } @@ -7054,12 +7424,11 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { - NamespaceValidatorCCC Validator; R.clear(); - if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(), - R.getLookupKind(), Sc, &SS, - Validator, - Sema::CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = + S.CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), Sc, &SS, + llvm::make_unique<NamespaceValidatorCCC>(), + Sema::CTK_ErrorRecovery)) { if (DeclContext *DC = S.computeDeclContext(SS, false)) { std::string CorrectedStr(Corrected.getAsString(S.getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && @@ -7124,6 +7493,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S, NamedDecl *Named = R.getFoundDecl(); assert((isa<NamespaceDecl>(Named) || isa<NamespaceAliasDecl>(Named)) && "expected namespace decl"); + + // The use of a nested name specifier may trigger deprecation warnings. + DiagnoseUseOfDecl(Named, IdentLoc); + // C++ [namespace.udir]p1: // A using-directive specifies that the names in the nominated // namespace can be used in the scope in which the @@ -7685,11 +8058,12 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Try to correct typos if possible. if (R.empty()) { - UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), - dyn_cast<CXXRecordDecl>(CurContext)); - if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(), - R.getLookupKind(), S, &SS, CCC, - CTK_ErrorRecovery)){ + if (TypoCorrection Corrected = CorrectTypo( + R.getLookupNameInfo(), R.getLookupKind(), S, &SS, + llvm::make_unique<UsingValidatorCCC>( + HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), + dyn_cast<CXXRecordDecl>(CurContext)), + CTK_ErrorRecovery)) { // We reject any correction for which ND would be NULL. NamedDecl *ND = Corrected.getCorrectionDecl(); @@ -7874,7 +8248,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, // If we weren't able to compute a valid scope, it must be a // dependent class scope. if (!NamedContext || NamedContext->isRecord()) { - auto *RD = dyn_cast<CXXRecordDecl>(NamedContext); + auto *RD = dyn_cast_or_null<CXXRecordDecl>(NamedContext); if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD)) RD = nullptr; @@ -8164,6 +8538,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc, Name.Identifier, TemplateParams, NewTD); + NewTD->setDescribedAliasTemplate(NewDecl); NewDecl->setAccess(AS); @@ -8185,57 +8560,65 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, return NewND; } -Decl *Sema::ActOnNamespaceAliasDef(Scope *S, - SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *Ident) { +Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident) { // Lookup the namespace name. LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); LookupParsedName(R, S, &SS); + if (R.isAmbiguous()) + return nullptr; + + if (R.empty()) { + if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) { + Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); + return nullptr; + } + } + assert(!R.isAmbiguous() && !R.empty()); + // Check if we have a previous declaration with the same name. - NamedDecl *PrevDecl - = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, - ForRedeclaration); + NamedDecl *PrevDecl = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) PrevDecl = nullptr; + NamedDecl *ND = R.getFoundDecl(); + if (PrevDecl) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same - // namespace, so don't create a new one. - // FIXME: At some point, we'll want to create the (redundant) - // declaration to maintain better source information. - if (!R.isAmbiguous() && !R.empty() && - AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) + // namespace; check that it matches. + if (!AD->getNamespace()->Equals(getNamespaceDecl(ND))) { + Diag(AliasLoc, diag::err_redefinition_different_namespace_alias) + << Alias; + Diag(PrevDecl->getLocation(), diag::note_previous_namespace_alias) + << AD->getNamespace(); return nullptr; - } - - unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition : - diag::err_redefinition_different_kind; - Diag(AliasLoc, DiagID) << Alias; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - return nullptr; - } - - if (R.isAmbiguous()) - return nullptr; - - if (R.empty()) { - if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) { - Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); + } + } else { + unsigned DiagID = isa<NamespaceDecl>(PrevDecl) + ? diag::err_redefinition + : diag::err_redefinition_different_kind; + Diag(AliasLoc, DiagID) << Alias; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); return nullptr; } } + // The use of a nested name specifier may trigger deprecation warnings. + DiagnoseUseOfDecl(ND, IdentLoc); + NamespaceAliasDecl *AliasDecl = NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, Alias, SS.getWithLocInContext(Context), - IdentLoc, R.getFoundDecl()); + IdentLoc, ND); + if (PrevDecl) + AliasDecl->setPreviousDecl(cast<NamespaceAliasDecl>(PrevDecl)); PushOnScopeChains(AliasDecl, S); return AliasDecl; @@ -8285,22 +8668,6 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, if (F->hasInClassInitializer()) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); - else if (!F->isInvalidDecl()) - // DR1351: - // If the brace-or-equal-initializer of a non-static data member - // invokes a defaulted default constructor of its class or of an - // enclosing class in a potentially evaluated subexpression, the - // program is ill-formed. - // - // This resolution is unworkable: the exception specification of the - // default constructor can be needed in an unevaluated context, in - // particular, in the operand of a noexcept-expression, and we can be - // unable to compute an exception specification for an enclosed class. - // - // We do not allow an in-class initializer to require the evaluation - // of the exception specification for any in-class initializer whose - // definition is not lexically complete. - Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -8368,9 +8735,6 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { if (F->hasInClassInitializer()) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); - else if (!F->isInvalidDecl()) - Diag(CD->getLocation(), - diag::err_in_class_initializer_references_def_ctor) << CD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -8392,7 +8756,7 @@ struct DeclaringSpecialMember { DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM) : S(S), D(RD, CSM) { - WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D); + WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second; if (WasAlreadyBeingDeclared) // This almost never happens, but if it does, ensure that our cache // doesn't contain a stale result. @@ -8421,7 +8785,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( // user-declared constructor for class X, a default constructor is // implicitly declared. An implicitly-declared default constructor // is an inline public member of its class. - assert(ClassDecl->needsImplicitDefaultConstructor() && + assert(ClassDecl->needsImplicitDefaultConstructor() && "Should not build implicit default constructor!"); DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor); @@ -8445,7 +8809,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*isImplicitlyDeclared=*/true, Constexpr); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); - DefaultCon->setImplicit(); + + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor, + DefaultCon, + /* ConstRHS */ false, + /* Diagnose */ false); + } // Build an exception specification pointing back at this constructor. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon); @@ -8488,6 +8858,11 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, return; } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Constructor->getType()->castAs<FunctionProtoType>()); + SourceLocation Loc = Constructor->getLocEnd().isValid() ? Constructor->getLocEnd() : Constructor->getLocation(); @@ -8597,7 +8972,7 @@ private: void inherit(const CXXConstructorDecl *Ctor) { const FunctionProtoType *CtorType = Ctor->getType()->castAs<FunctionProtoType>(); - ArrayRef<QualType> ArgTypes(CtorType->getParamTypes()); + ArrayRef<QualType> ArgTypes = CtorType->getParamTypes(); FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo(); SourceLocation UsingLoc = getUsingLoc(Ctor->getParent()); @@ -8737,8 +9112,8 @@ private: // Build an unevaluated exception specification for this constructor. const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = DerivedCtor; + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = DerivedCtor; DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); @@ -8900,7 +9275,13 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setDefaulted(); - Destructor->setImplicit(); + + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor, + Destructor, + /* ConstRHS */ false, + /* Diagnose */ false); + } // Build an exception specification pointing back at this destructor. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor); @@ -8952,6 +9333,11 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, return; } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Destructor->getType()->castAs<FunctionProtoType>()); + SourceLocation Loc = Destructor->getLocEnd().isValid() ? Destructor->getLocEnd() : Destructor->getLocation(); @@ -8971,7 +9357,7 @@ void Sema::ActOnFinishCXXMemberDecls() { if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) { if (Record->isInvalidDecl()) { DelayedDefaultedMemberExceptionSpecs.clear(); - DelayedDestructorExceptionSpecChecks.clear(); + DelayedExceptionSpecChecks.clear(); return; } } @@ -8995,8 +9381,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, // 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 = EST_Unevaluated; - EPI.ExceptionSpecDecl = Destructor; + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = Destructor; Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created @@ -9032,7 +9418,7 @@ class RefBuilder: public ExprBuilder { QualType VarType; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).get()); } @@ -9042,7 +9428,7 @@ public: class ThisBuilder: public ExprBuilder { public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.ActOnCXXThis(Loc).getAs<Expr>()); } }; @@ -9054,7 +9440,7 @@ class CastBuilder: public ExprBuilder { const CXXCastPath &Path; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.ImpCastExprToType(Builder.build(S, Loc), Type, CK_UncheckedDerivedToBase, Kind, &Path).get()); @@ -9069,7 +9455,7 @@ class DerefBuilder: public ExprBuilder { const ExprBuilder &Builder; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull( S.CreateBuiltinUnaryOp(Loc, UO_Deref, Builder.build(S, Loc)).get()); } @@ -9085,7 +9471,7 @@ class MemberBuilder: public ExprBuilder { LookupResult &MemberLookup; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.BuildMemberReferenceExpr( Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(), nullptr, MemberLookup, nullptr).get()); @@ -9101,7 +9487,7 @@ class MoveCastBuilder: public ExprBuilder { const ExprBuilder &Builder; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(CastForMoving(S, Builder.build(S, Loc))); } @@ -9112,7 +9498,7 @@ class LvalueConvBuilder: public ExprBuilder { const ExprBuilder &Builder; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull( S.DefaultLvalueConversion(Builder.build(S, Loc)).get()); } @@ -9125,7 +9511,7 @@ class SubscriptBuilder: public ExprBuilder { const ExprBuilder &Index; public: - virtual Expr *build(Sema &S, SourceLocation Loc) const override { + Expr *build(Sema &S, SourceLocation Loc) const override { return assertNotNull(S.CreateBuiltinArraySubscriptExpr( Base.build(S, Loc), Loc, Index.build(S, Loc), Loc).get()); } @@ -9521,6 +9907,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setDefaulted(); CopyAssignment->setImplicit(); + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyAssignment, + CopyAssignment, + /* ConstRHS */ Const, + /* Diagnose */ false); + } + // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, CopyAssignment); @@ -9795,6 +10188,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyAssignOperator->getType()->castAs<FunctionProtoType>()); + if (Invalid) { CopyAssignOperator->setInvalidDecl(); return; @@ -9898,6 +10296,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setDefaulted(); MoveAssignment->setImplicit(); + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveAssignment, + MoveAssignment, + /* ConstRHS */ false, + /* Diagnose */ false); + } + // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, MoveAssignment); @@ -10217,6 +10622,11 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveAssignOperator->getType()->castAs<FunctionProtoType>()); + if (Invalid) { MoveAssignOperator->setInvalidDecl(); return; @@ -10319,6 +10729,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyConstructor, + CopyConstructor, + /* ConstRHS */ Const, + /* Diagnose */ false); + } + // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, CopyConstructor); @@ -10386,6 +10803,11 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + CopyConstructor->getType()->castAs<FunctionProtoType>()); + CopyConstructor->markUsed(Context); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -10484,6 +10906,13 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); + if (getLangOpts().CUDA) { + inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveConstructor, + MoveConstructor, + /* ConstRHS */ false, + /* Diagnose */ false); + } + // Build an exception specification pointing back at this member. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, MoveConstructor); @@ -10546,6 +10975,11 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); } + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + MoveConstructor->getType()->castAs<FunctionProtoType>()); + MoveConstructor->markUsed(Context); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -10765,6 +11199,56 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, ParenRange); } +ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { + assert(Field->hasInClassInitializer()); + + // If we already have the in-class initializer nothing needs to be done. + if (Field->getInClassInitializer()) + return CXXDefaultInitExpr::Create(Context, Loc, Field); + + // Maybe we haven't instantiated the in-class initializer. Go check the + // pattern FieldDecl to see if it has one. + CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent()); + + if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { + CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + assert(Lookup.size() == 1); + FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + if (InstantiateInClassInitializer(Loc, Field, Pattern, + getTemplateInstantiationArgs(Field))) + return ExprError(); + return CXXDefaultInitExpr::Create(Context, Loc, Field); + } + + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // Any attempt to resolve the exception specification of a defaulted default + // constructor before the initializer is lexically complete will ultimately + // come here at which point we can diagnose it. + RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); + if (OutermostClass == ParentRD) { + Diag(Field->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) + << ParentRD << Field; + } else { + Diag(Field->getLocEnd(), + diag::err_in_class_initializer_not_yet_parsed_outer_class) + << ParentRD << OutermostClass << Field; + } + + return ExprError(); +} + void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; @@ -10834,8 +11318,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, DiagnoseSentinelCalls(Constructor, Loc, AllArgs); CheckConstructorCall(Constructor, - llvm::makeArrayRef<const Expr *>(AllArgs.data(), - AllArgs.size()), + llvm::makeArrayRef(AllArgs.data(), AllArgs.size()), Proto, Loc); return Invalid; @@ -12118,8 +12601,12 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, } // Mark templated-scope function declarations as unsupported. - if (FD->getNumTemplateParameterLists()) + if (FD->getNumTemplateParameterLists() && SS.isValid()) { + Diag(FD->getLocation(), diag::warn_template_qualified_friend_unsupported) + << SS.getScopeRep() << SS.getRange() + << cast<CXXRecordDecl>(CurContext); FrD->setUnsupportedFriend(true); + } } return ND; @@ -12220,11 +12707,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { CheckExplicitlyDefaultedSpecialMember(MD); - // The exception specification is needed because we are defining the - // function. - ResolveExceptionSpec(DefaultLoc, - MD->getType()->castAs<FunctionProtoType>()); - if (MD->isInvalidDecl()) return; @@ -12538,7 +13020,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); if (!Pos.second) { // If we already had an entry, check to see if we are promoting this vtable - // to required a definition. If so, we need to reappend to the VTableUses + // to require a definition. If so, we need to reappend to the VTableUses // list, since we may have already processed the first entry. if (DefinitionRequired && !Pos.first->second) { Pos.first->second = true; @@ -12739,10 +13221,10 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { AllToInit.push_back(Member); // Be sure that the destructor is accessible and is marked as referenced. - if (const RecordType *RecordTy - = Context.getBaseElementType(Field->getType()) - ->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (const RecordType *RecordTy = + Context.getBaseElementType(Field->getType()) + ->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { MarkFunctionReferenced(Field->getLocation(), Destructor); CheckDestructorAccess(Field->getLocation(), Destructor, @@ -12780,7 +13262,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor, // Avoid dereferencing a null pointer here. *TCanonical = Target? Target->getCanonicalDecl() : nullptr; - if (!Current.insert(Canonical)) + if (!Current.insert(Canonical).second) return; // We know that beyond here, we aren't chaining into a cycle. @@ -12898,6 +13380,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { FindCXXThisExpr Finder(*this); switch (Proto->getExceptionSpecType()) { + case EST_Unparsed: case EST_Uninstantiated: case EST_Unevaluated: case EST_BasicNoexcept: @@ -12934,27 +13417,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { else if (const auto *G = dyn_cast<PtGuardedByAttr>(A)) Arg = G->getArg(); else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A)) - Args = ArrayRef<Expr *>(AA->args_begin(), AA->args_size()); + Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size()); else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A)) - Args = ArrayRef<Expr *>(AB->args_begin(), AB->args_size()); + Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size()); else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) { Arg = ETLF->getSuccessValue(); - Args = ArrayRef<Expr *>(ETLF->args_begin(), ETLF->args_size()); + Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size()); } else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) { Arg = STLF->getSuccessValue(); - Args = ArrayRef<Expr *>(STLF->args_begin(), STLF->args_size()); + Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size()); } else if (const auto *LR = dyn_cast<LockReturnedAttr>(A)) Arg = LR->getArg(); else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A)) - Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size()); + Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size()); else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A)) - Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size()); + Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A)) - Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size()); + Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A)) - Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size()); + Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A)) - Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size()); + Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); if (Arg && !Finder.TraverseStmt(Arg)) return true; @@ -12968,28 +13451,29 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { return false; } -void -Sema::checkExceptionSpecification(ExceptionSpecificationType EST, - ArrayRef<ParsedType> DynamicExceptions, - ArrayRef<SourceRange> DynamicExceptionRanges, - Expr *NoexceptExpr, - SmallVectorImpl<QualType> &Exceptions, - FunctionProtoType::ExtProtoInfo &EPI) { +void Sema::checkExceptionSpecification( + bool IsTopLevel, ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr, + SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExceptionSpecInfo &ESI) { Exceptions.clear(); - EPI.ExceptionSpecType = EST; + ESI.Type = EST; if (EST == EST_Dynamic) { Exceptions.reserve(DynamicExceptions.size()); for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) { // FIXME: Preserve type source info. QualType ET = GetTypeFromParser(DynamicExceptions[ei]); - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - collectUnexpandedParameterPacks(ET, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), - UPPC_ExceptionType, - Unexpanded); - continue; + if (IsTopLevel) { + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(ET, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks( + DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType, + Unexpanded); + continue; + } } // Check that the type is valid for an exception spec, and @@ -12997,11 +13481,10 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST, if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei])) Exceptions.push_back(ET); } - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); + ESI.Exceptions = Exceptions; return; } - + if (EST == EST_ComputedNoexcept) { // If an error occurred, there's no expression here. if (NoexceptExpr) { @@ -13009,59 +13492,59 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST, NoexceptExpr->getType()->getCanonicalTypeUnqualified() == Context.BoolTy) && "Parser should have made sure that the expression is boolean"); - if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { - EPI.ExceptionSpecType = EST_BasicNoexcept; + if (IsTopLevel && NoexceptExpr && + DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + ESI.Type = EST_BasicNoexcept; return; } - + if (!NoexceptExpr->isValueDependent()) NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr, diag::err_noexcept_needs_constant_expression, /*AllowFold*/ false).get(); - EPI.NoexceptExpr = NoexceptExpr; + ESI.NoexceptExpr = NoexceptExpr; } return; } } -/// 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; +void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, + ExceptionSpecificationType EST, + SourceRange SpecificationRange, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr) { + if (!MethodD) + return; - if (D->hasAttr<CUDADeviceAttr>()) { - if (D->hasAttr<CUDAHostAttr>()) - return CFT_HostDevice; - return CFT_Device; - } + // Dig out the method we're referring to. + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(MethodD)) + MethodD = FunTmpl->getTemplatedDecl(); - return CFT_Host; -} + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(MethodD); + if (!Method) + return; -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; + // Check the exception specification. + llvm::SmallVector<QualType, 4> Exceptions; + FunctionProtoType::ExceptionSpecInfo ESI; + checkExceptionSpecification(/*IsTopLevel*/true, EST, DynamicExceptions, + DynamicExceptionRanges, NoexceptExpr, Exceptions, + ESI); - // 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; + // Update the exception specification on the function type. + Context.adjustExceptionSpec(Method, ESI, /*AsWritten*/true); - if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) - return true; + if (Method->isStatic()) + checkThisInStaticMemberFunctionExceptionSpec(Method); - return false; + if (Method->isVirtual()) { + // Check overrides, which we previously had to delay. + for (CXXMethodDecl::method_iterator O = Method->begin_overridden_methods(), + OEnd = Method->end_overridden_methods(); + O != OEnd; ++O) + CheckOverridingFunctionExceptionSpec(Method, *O); + } } /// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index b5205b3..7e3da94 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -118,10 +118,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, // a suitable return type, but the new (overriding) method does not have // a suitable return type. QualType ResultType = NewMethod->getReturnType(); - SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo = - NewMethod->getReturnTypeSourceInfo()) - ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + SourceRange ResultTypeRange = NewMethod->getReturnTypeSourceRange(); // Figure out which class this method is part of, if any. ObjCInterfaceDecl *CurrentClass @@ -204,15 +201,13 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { case OMF_autorelease: case OMF_retainCount: case OMF_self: + case OMF_initialize: case OMF_performSelector: return false; case OMF_dealloc: if (!Context.hasSameType(method->getReturnType(), Context.VoidTy)) { - SourceRange ResultTypeRange; - if (const TypeSourceInfo *ResultTypeInfo = - method->getReturnTypeSourceInfo()) - ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange(); + SourceRange ResultTypeRange = method->getReturnTypeSourceRange(); if (ResultTypeRange.isInvalid()) Diag(method->getLocation(), diag::error_dealloc_bad_result_type) << method->getReturnType() @@ -359,6 +354,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { case OMF_copy: case OMF_new: case OMF_self: + case OMF_initialize: case OMF_performSelector: break; } @@ -520,10 +516,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (!PrevDecl) { // Try to correct for a typo in the superclass name without correcting // to the class we're defining. - ObjCInterfaceValidatorCCC Validator(IDecl); - if (TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope, - nullptr, Validator, CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = + CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), + LookupOrdinaryName, TUScope, nullptr, + llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), + CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) << SuperName << ClassName); PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); @@ -790,10 +787,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); if (!PDecl) { - DeclFilterCCC<ObjCProtocolDecl> Validator; TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second), - LookupObjCProtocolName, TUScope, nullptr, Validator, + LookupObjCProtocolName, TUScope, nullptr, + llvm::make_unique<DeclFilterCCC<ObjCProtocolDecl>>(), CTK_ErrorRecovery); if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest) @@ -1031,11 +1028,9 @@ Decl *Sema::ActOnStartClassImplementation( } else { // We did not find anything with the name ClassName; try to correct for // typos in the class name. - ObjCInterfaceValidatorCCC Validator; - TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc), - LookupOrdinaryName, TUScope, nullptr, Validator, - CTK_NonError); + TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope, + nullptr, llvm::make_unique<ObjCInterfaceValidatorCCC>(), CTK_NonError); if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { // Suggest the (potentially) correct interface name. Don't provide a // code-modification hint or use the typo name for recovery, because @@ -1362,9 +1357,9 @@ static bool CheckMethodOverrideReturn(Sema &S, ? diag::warn_conflicting_overriding_ret_type_modifiers : diag::warn_conflicting_ret_type_modifiers)) << MethodImpl->getDeclName() - << getTypeRange(MethodImpl->getReturnTypeSourceInfo()); + << MethodImpl->getReturnTypeSourceRange(); S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) - << getTypeRange(MethodDecl->getReturnTypeSourceInfo()); + << MethodDecl->getReturnTypeSourceRange(); } else return false; @@ -1402,11 +1397,11 @@ static bool CheckMethodOverrideReturn(Sema &S, S.Diag(MethodImpl->getLocation(), DiagID) << MethodImpl->getDeclName() << MethodDecl->getReturnType() << MethodImpl->getReturnType() - << getTypeRange(MethodImpl->getReturnTypeSourceInfo()); + << MethodImpl->getReturnTypeSourceRange(); S.Diag(MethodDecl->getLocation(), IsOverridingMode ? diag::note_previous_declaration : diag::note_previous_definition) - << getTypeRange(MethodDecl->getReturnTypeSourceInfo()); + << MethodDecl->getReturnTypeSourceRange(); return false; } @@ -1521,6 +1516,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, case OMF_finalize: case OMF_retainCount: case OMF_self: + case OMF_initialize: case OMF_performSelector: // Mismatches for these methods don't change ownership // conventions, so we don't care. @@ -1819,7 +1815,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, // Check and see if instance methods in class interface have been // implemented in the implementation class. If so, their types match. for (auto *I : CDecl->instance_methods()) { - if (!InsMapSeen.insert(I->getSelector())) + if (!InsMapSeen.insert(I->getSelector()).second) continue; if (!I->isPropertyAccessor() && !InsMap.count(I->getSelector())) { @@ -1846,7 +1842,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, // Check and see if class methods in class interface have been // implemented in the implementation class. If so, their types match. for (auto *I : CDecl->class_methods()) { - if (!ClsMapSeen.insert(I->getSelector())) + if (!ClsMapSeen.insert(I->getSelector()).second) continue; if (!ClsMap.count(I->getSelector())) { if (ImmediateClass) @@ -2008,13 +2004,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, IncompleteImpl, InsMap, ClsMap, CDecl, ExplicitImplProtocols); DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, - /* SynthesizeProperties */ false); + /*SynthesizeProperties=*/false); } } else llvm_unreachable("invalid ObjCContainerDecl type."); } -/// ActOnForwardClassDeclaration - Sema::DeclGroupPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, @@ -2041,10 +2036,11 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, } else { // a forward class declaration matching a typedef name of a class refers // to the underlying class. Just ignore the forward class with a warning - // as this will force the intended behavior which is to lookup the typedef - // name. + // as this will force the intended behavior which is to lookup the + // typedef name. if (isa<ObjCObjectType>(TDD->getUnderlyingType())) { - Diag(AtClassLoc, diag::warn_forward_class_redefinition) << IdentList[i]; + Diag(AtClassLoc, diag::warn_forward_class_redefinition) + << IdentList[i]; Diag(PrevDecl->getLocation(), diag::note_previous_definition); continue; } @@ -2107,7 +2103,12 @@ static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy, // validate the basic, low-level compatibility of the two types. // As a minimum, require the sizes and alignments to match. - if (Context.getTypeInfo(left) != Context.getTypeInfo(right)) + TypeInfo LeftTI = Context.getTypeInfo(left); + TypeInfo RightTI = Context.getTypeInfo(right); + if (LeftTI.Width != RightTI.Width) + return false; + + if (LeftTI.Align != RightTI.Align) return false; // Consider all the kinds of non-dependent canonical types: @@ -2159,7 +2160,13 @@ static bool tryMatchRecordTypes(ASTContext &Context, return false; // Require size and alignment to match. - if (Context.getTypeInfo(lt) != Context.getTypeInfo(rt)) return false; + TypeInfo LeftTI = Context.getTypeInfo(lt); + TypeInfo RightTI = Context.getTypeInfo(rt); + if (LeftTI.Width != RightTI.Width) + return false; + + if (LeftTI.Align != RightTI.Align) + return false; // Require fields to match. RecordDecl::field_iterator li = left->field_begin(), le = left->field_end(); @@ -2210,21 +2217,22 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, return true; } -void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { +void Sema::addMethodToGlobalList(ObjCMethodList *List, + ObjCMethodDecl *Method) { // Record at the head of the list whether there were 0, 1, or >= 2 methods // inside categories. - if (ObjCCategoryDecl * - CD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) + if (ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) if (!CD->IsClassExtension() && List->getBits() < 2) - List->setBits(List->getBits()+1); + List->setBits(List->getBits() + 1); // If the list is empty, make it a singleton list. - if (List->Method == nullptr) { - List->Method = Method; + if (List->getMethod() == nullptr) { + List->setMethod(Method); List->setNext(nullptr); return; } - + // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; @@ -2233,35 +2241,42 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty()) continue; - if (!MatchTwoMethodDeclarations(Method, List->Method)) + if (!MatchTwoMethodDeclarations(Method, List->getMethod())) continue; - - ObjCMethodDecl *PrevObjCMethod = List->Method; + + ObjCMethodDecl *PrevObjCMethod = List->getMethod(); // Propagate the 'defined' bit. if (Method->isDefined()) PrevObjCMethod->setDefined(true); - + else { + // Objective-C doesn't allow an @interface for a class after its + // @implementation. So if Method is not defined and there already is + // an entry for this type signature, Method has to be for a different + // class than PrevObjCMethod. + List->setHasMoreThanOneDecl(true); + } + // If a method is deprecated, push it in the global pool. // This is used for better diagnostics. if (Method->isDeprecated()) { if (!PrevObjCMethod->isDeprecated()) - List->Method = Method; + List->setMethod(Method); } - // If new method is unavailable, push it into global pool + // If the new method is unavailable, push it into global pool // unless previous one is deprecated. if (Method->isUnavailable()) { if (PrevObjCMethod->getAvailability() < AR_Deprecated) - List->Method = Method; + List->setMethod(Method); } - + return; } - + // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); - Previous->setNext(new (Mem) ObjCMethodList(Method, nullptr)); + Previous->setNext(new (Mem) ObjCMethodList(Method)); } /// \brief Read the contents of the method pool for a given selector from @@ -2284,7 +2299,7 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, if (Pos == MethodPool.end()) Pos = MethodPool.insert(std::make_pair(Method->getSelector(), GlobalMethods())).first; - + Method->setDefined(impl); ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; @@ -2310,6 +2325,32 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, return (chosen->getReturnType()->isIntegerType()); } +bool Sema::CollectMultipleMethodsInGlobalPool( + Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) { + if (ExternalSource) + ReadMethodPool(Sel); + + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); + if (Pos == MethodPool.end()) + return false; + // Gather the non-hidden methods. + ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + for (ObjCMethodList *M = &MethList; M; M = M->getNext()) + if (M->getMethod() && !M->getMethod()->isHidden()) + Methods.push_back(M->getMethod()); + return Methods.size() > 1; +} + +bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, bool instance) { + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); + // Test for no method in the pool which should not trigger any warning by + // caller. + if (Pos == MethodPool.end()) + return true; + ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + return MethList.hasMoreThanOneDecl(); +} + ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool warn, bool instance) { @@ -2324,12 +2365,12 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; SmallVector<ObjCMethodDecl *, 4> Methods; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { - if (M->Method && !M->Method->isHidden()) { + if (M->getMethod() && !M->getMethod()->isHidden()) { // If we're not supposed to warn about mismatches, we're done. if (!warn) - return M->Method; + return M->getMethod(); - Methods.push_back(M->Method); + Methods.push_back(M->getMethod()); } } @@ -2401,13 +2442,13 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { GlobalMethods &Methods = Pos->second; for (const ObjCMethodList *Method = &Methods.first; Method; Method = Method->getNext()) - if (Method->Method && Method->Method->isDefined()) - return Method->Method; + if (Method->getMethod() && Method->getMethod()->isDefined()) + return Method->getMethod(); for (const ObjCMethodList *Method = &Methods.second; Method; Method = Method->getNext()) - if (Method->Method && Method->Method->isDefined()) - return Method->Method; + if (Method->getMethod() && Method->getMethod()->isDefined()) + return Method->getMethod(); return nullptr; } @@ -2470,25 +2511,27 @@ Sema::SelectorsForTypoCorrection(Selector Sel, e = MethodPool.end(); b != e; b++) { // instance methods for (ObjCMethodList *M = &b->second.first; M; M=M->getNext()) - if (M->Method && - (M->Method->getSelector().getNumArgs() == NumArgs) && - (M->Method->getSelector() != Sel)) { + if (M->getMethod() && + (M->getMethod()->getSelector().getNumArgs() == NumArgs) && + (M->getMethod()->getSelector() != Sel)) { if (ObjectIsId) - Methods.push_back(M->Method); + Methods.push_back(M->getMethod()); else if (!ObjectIsClass && - HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType)) - Methods.push_back(M->Method); + HelperIsMethodInObjCType(*this, M->getMethod()->getSelector(), + ObjectType)) + Methods.push_back(M->getMethod()); } // class methods for (ObjCMethodList *M = &b->second.second; M; M=M->getNext()) - if (M->Method && - (M->Method->getSelector().getNumArgs() == NumArgs) && - (M->Method->getSelector() != Sel)) { + if (M->getMethod() && + (M->getMethod()->getSelector().getNumArgs() == NumArgs) && + (M->getMethod()->getSelector() != Sel)) { if (ObjectIsClass) - Methods.push_back(M->Method); + Methods.push_back(M->getMethod()); else if (!ObjectIsId && - HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType)) - Methods.push_back(M->Method); + HelperIsMethodInObjCType(*this, M->getMethod()->getSelector(), + ObjectType)) + Methods.push_back(M->getMethod()); } } @@ -2818,7 +2861,7 @@ public: } ObjCMethodList &list = method->isInstanceMethod() ? it->second.first : it->second.second; - if (!list.Method) return; + if (!list.getMethod()) return; ObjCContainerDecl *container = cast<ObjCContainerDecl>(method->getDeclContext()); @@ -3237,6 +3280,7 @@ Decl *Sema::ActOnMethodDeclaration( case OMF_mutableCopy: case OMF_release: case OMF_retainCount: + case OMF_initialize: case OMF_performSelector: break; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index b92fcbd..2387325 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -35,6 +35,33 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T) return T->getAs<FunctionProtoType>(); } +/// HACK: libstdc++ has a bug where it shadows std::swap with a member +/// swap function then tries to call std::swap unqualified from the exception +/// specification of that function. This function detects whether we're in +/// such a case and turns off delay-parsing of exception specifications. +bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { + auto *RD = dyn_cast<CXXRecordDecl>(CurContext); + + // All the problem cases are member functions named "swap" within class + // templates declared directly within namespace std. + if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() || + !RD->getIdentifier() || !RD->getDescribedClassTemplate() || + !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) + return false; + + // Only apply this hack within a system header. + if (!Context.getSourceManager().isInSystemHeader(D.getLocStart())) + return false; + + return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) + .Case("array", true) + .Case("pair", true) + .Case("priority_queue", true) + .Case("stack", true) + .Case("queue", true) + .Default(false); +} + /// CheckSpecifiedExceptionType - Check if the given type is valid in an /// exception specification. Incomplete types, or pointers to incomplete types /// other than void are not allowed. @@ -112,6 +139,11 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { const FunctionProtoType * Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { + if (FPT->getExceptionSpecType() == EST_Unparsed) { + Diag(Loc, diag::err_exception_spec_not_parsed); + return nullptr; + } + if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) return FPT; @@ -132,21 +164,14 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { return SourceDecl->getType()->castAs<FunctionProtoType>(); } -void Sema::UpdateExceptionSpec(FunctionDecl *FD, - const FunctionProtoType::ExtProtoInfo &EPI) { - const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>(); - - // Overwrite the exception spec and rebuild the function type. - FunctionProtoType::ExtProtoInfo NewEPI = Proto->getExtProtoInfo(); - NewEPI.ExceptionSpecType = EPI.ExceptionSpecType; - NewEPI.NumExceptions = EPI.NumExceptions; - NewEPI.Exceptions = EPI.Exceptions; - NewEPI.NoexceptExpr = EPI.NoexceptExpr; - FD->setType(Context.getFunctionType(Proto->getReturnType(), - Proto->getParamTypes(), NewEPI)); +void +Sema::UpdateExceptionSpec(FunctionDecl *FD, + const FunctionProtoType::ExceptionSpecInfo &ESI) { + for (auto *Redecl : FD->redecls()) + Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); // If we've fully resolved the exception specification, notify listeners. - if (!isUnresolvedExceptionSpec(EPI.ExceptionSpecType)) + if (!isUnresolvedExceptionSpec(ESI.Type)) if (auto *Listener = getASTMutationListener()) Listener->ResolvedExceptionSpec(FD); } @@ -227,32 +252,28 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { (Old->getLocation().isInvalid() || Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { - FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_DynamicNone; - QualType NewType = Context.getFunctionType(NewProto->getReturnType(), - NewProto->getParamTypes(), EPI); - New->setType(NewType); + New->setType(Context.getFunctionType( + NewProto->getReturnType(), NewProto->getParamTypes(), + NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); return false; } const FunctionProtoType *OldProto = Old->getType()->castAs<FunctionProtoType>(); - FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = OldProto->getExceptionSpecType(); - if (EPI.ExceptionSpecType == EST_Dynamic) { - EPI.NumExceptions = OldProto->getNumExceptions(); - EPI.Exceptions = OldProto->exception_begin(); - } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); + if (ESI.Type == EST_Dynamic) { + ESI.Exceptions = OldProto->exceptions(); + } else if (ESI.Type == EST_ComputedNoexcept) { // FIXME: We can't just take the expression from the old prototype. It // likely contains references to the old prototype's parameters. } // Update the type of the function with the appropriate exception // specification. - QualType NewType = Context.getFunctionType(NewProto->getReturnType(), - NewProto->getParamTypes(), EPI); - New->setType(NewType); + New->setType(Context.getFunctionType( + NewProto->getReturnType(), NewProto->getParamTypes(), + NewProto->getExtProtoInfo().withExceptionSpec(ESI))); // Warn about the lack of exception specification. SmallString<128> ExceptionSpecString; @@ -723,10 +744,11 @@ static bool CheckSpecForTypesEquivalent(Sema &S, /// assignment and override compatibility check. We do not check the parameters /// of parameter function pointers recursively, as no sane programmer would /// even be able to write such a function type. -bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, - const FunctionProtoType *Target, SourceLocation TargetLoc, - const FunctionProtoType *Source, SourceLocation SourceLoc) -{ +bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, + const FunctionProtoType *Target, + SourceLocation TargetLoc, + const FunctionProtoType *Source, + SourceLocation SourceLoc) { if (CheckSpecForTypesEquivalent( *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(), Target->getReturnType(), TargetLoc, Source->getReturnType(), @@ -747,23 +769,30 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, return false; } -bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) -{ +bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { // First we check for applicability. // Target type must be a function, function pointer or function reference. const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); - if (!ToFunc) + if (!ToFunc || ToFunc->hasDependentExceptionSpec()) return false; // SourceType must be a function or function pointer. const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); - if (!FromFunc) + if (!FromFunc || FromFunc->hasDependentExceptionSpec()) return false; // Now we've got the correct types on both sides, check their compatibility. // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. + // + // FIXME: If there is a nested dependent exception specification, we should + // not be checking it here. This is fine: + // template<typename T> void f() { + // void (*p)(void (*) throw(T)); + // void (*q)(void (*) throw(int)) = p; + // } + // ... because it might be instantiated with T=int. return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), PDiag(), ToFunc, From->getSourceRange().getBegin(), @@ -772,6 +801,11 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { + // If the new exception specification hasn't been parsed yet, skip the check. + // We'll get called again once it's been parsed. + if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == + EST_Unparsed) + return false; if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) { // Don't check uninstantiated template destructors at all. We can only // synthesize correct specs after the template is instantiated. @@ -780,11 +814,18 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, if (New->getParent()->isBeingDefined()) { // The destructor might be updated once the definition is finished. So // remember it and check later. - DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( - cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old))); + DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); return false; } } + // If the old exception specification hasn't been parsed yet, remember that + // we need to perform this check when we get to the end of the outermost + // lexically-surrounding class. + if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == + EST_Unparsed) { + DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); + return false; + } unsigned DiagID = diag::err_override_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::ext_override_exception_spec; @@ -1051,6 +1092,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CXXDependentScopeMemberExprClass: case Expr::CXXUnresolvedConstructExprClass: case Expr::DependentScopeDeclRefExprClass: + case Expr::CXXFoldExprClass: return CT_Dependent; case Expr::AsTypeExprClass: @@ -1071,6 +1113,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::UnaryExprOrTypeTraitExprClass: case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: + case Expr::TypoExprClass: // FIXME: Can any of the above throw? If so, when? return CT_Cannot; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 35dad82..fba7a2d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -42,6 +42,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/Template.h" +#include "llvm/Support/ConvertUTF.h" using namespace clang; using namespace sema; @@ -59,7 +60,7 @@ bool Sema::CanUseDecl(NamedDecl *D) { // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. - if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() && + if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false)) return false; } @@ -302,7 +303,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. - if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() && + if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, Loc)) return true; } @@ -397,8 +398,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, if (sentinelExpr->isValueDependent()) return; if (Context.isSentinelNullExpr(sentinelExpr)) return; - // Pick a reasonable string to insert. Optimistically use 'nil' or - // 'NULL' if those are actually defined in the context. Only use + // Pick a reasonable string to insert. Optimistically use 'nil', 'nullptr', + // 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 @@ -407,6 +408,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, if (calleeType == CT_Method && PP.getIdentifierInfo("nil")->hasMacroDefinition()) NullValue = "nil"; + else if (getLangOpts().CPlusPlus11) + NullValue = "nullptr"; else if (PP.getIdentifierInfo("NULL")->hasMacroDefinition()) NullValue = "NULL"; else @@ -800,6 +803,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { if (Ty->isObjCObjectType()) return VAK_Invalid; + if (getLangOpts().MSVCCompat) + return VAK_MSVCUndefined; + // FIXME: In C++11, these cases are conditionally-supported, meaning we're // permitted to reject them. We should consider doing so. return VAK_Undefined; @@ -829,6 +835,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { break; case VAK_Undefined: + case VAK_MSVCUndefined: DiagRuntimeBehavior( E->getLocStart(), nullptr, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) @@ -933,68 +940,6 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, return false; } -/// \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 (!IsCompAssign) - LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingComplexCast); - return RHSType; - } - if (order > 0) - // _Complex float -> _Complex double - RHS = S.ImpCastExprToType(RHS.get(), 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.get(), fp, CK_FloatingCast); - OtherExpr = S.ImpCastExprToType(OtherExpr.get(), 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.get(), result, - CK_FloatingRealToComplex); - - // _Complex float -> _Complex double - if (ConvertComplexExpr && order < 0) - ComplexExpr = S.ImpCastExprToType(ComplexExpr.get(), result, - CK_FloatingComplexCast); - - return result; -} - /// \brief Handle arithmetic conversion with complex types. Helper function of /// UsualArithmeticConversions() static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, @@ -1020,26 +965,35 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, // 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); + // Compute the rank of the two types, regardless of whether they are complex. + int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); + + auto *LHSComplexType = dyn_cast<ComplexType>(LHSType); + auto *RHSComplexType = dyn_cast<ComplexType>(RHSType); + QualType LHSElementType = + LHSComplexType ? LHSComplexType->getElementType() : LHSType; + QualType RHSElementType = + RHSComplexType ? RHSComplexType->getElementType() : RHSType; + + QualType ResultType = S.Context.getComplexType(LHSElementType); + if (Order < 0) { + // Promote the precision of the LHS if not an assignment. + ResultType = S.Context.getComplexType(RHSElementType); + if (!IsCompAssign) { + if (LHSComplexType) + LHS = + S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast); + else + LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast); + } + } else if (Order > 0) { + // Promote the precision of the RHS. + if (RHSComplexType) + RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast); + else + RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); + } + return ResultType; } /// \brief Hande arithmetic conversion from integer to float. Helper function @@ -1336,6 +1290,13 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, ControllingExpr = result.get(); } + // The controlling expression is an unevaluated operand, so side effects are + // likely unintended. + if (ActiveTemplateInstantiations.empty() && + ControllingExpr->HasSideEffects(Context, false)) + Diag(ControllingExpr->getExprLoc(), + diag::warn_side_effects_unevaluated_context); + bool TypeErrorFound = false, IsResultDependent = ControllingExpr->isTypeDependent(), ContainsUnexpandedParameterPack @@ -1636,40 +1597,37 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, if (getLangOpts().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)) { + if (CheckCUDATarget(Caller, Callee)) { Diag(NameInfo.getLoc(), diag::err_ref_bad_target) - << CalleeTarget << D->getIdentifier() << CallerTarget; + << IdentifyCUDATarget(Callee) << D->getIdentifier() + << IdentifyCUDATarget(Caller); Diag(D->getLocation(), diag::note_previous_decl) << D->getIdentifier(); return ExprError(); } } - bool refersToEnclosingScope = - (CurContext != D->getDeclContext() && - D->getDeclContext()->isFunctionOrMethod()) || - (isa<VarDecl>(D) && - cast<VarDecl>(D)->isInitCapture()); + bool RefersToCapturedVariable = + isa<VarDecl>(D) && + NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); DeclRefExpr *E; if (isa<VarTemplateSpecializationDecl>(D)) { VarTemplateSpecializationDecl *VarSpec = cast<VarTemplateSpecializationDecl>(D); - E = DeclRefExpr::Create( - Context, - SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), - VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope, - NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs); + E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context) + : NestedNameSpecifierLoc(), + VarSpec->getTemplateKeywordLoc(), D, + RefersToCapturedVariable, NameInfo.getLoc(), Ty, VK, + FoundD, TemplateArgs); } else { assert(!TemplateArgs && "No template arguments for non-variable" " template specialization references"); - E = DeclRefExpr::Create( - Context, - SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), - SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD); + E = DeclRefExpr::Create(Context, SS ? SS->getWithLocInContext(Context) + : NestedNameSpecifierLoc(), + SourceLocation(), D, RefersToCapturedVariable, + NameInfo, Ty, VK, FoundD); } MarkDeclRefReferenced(E); @@ -1719,13 +1677,48 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, } } +static void emitEmptyLookupTypoDiagnostic( + const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS, + DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args, + unsigned DiagnosticID, unsigned DiagnosticSuggestID) { + DeclContext *Ctx = + SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); + if (!TC) { + // Emit a special diagnostic for failed member lookups. + // FIXME: computing the declaration context might fail here (?) + if (Ctx) + SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx + << SS.getRange(); + else + SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; + return; + } + + std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); + bool DroppedSpecifier = + TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; + unsigned NoteID = + (TC.getCorrectionDecl() && isa<ImplicitParamDecl>(TC.getCorrectionDecl())) + ? diag::note_implicit_param_decl + : diag::note_previous_decl; + if (!Ctx) + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, + SemaRef.PDiag(NoteID)); + else + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) + << Typo << Ctx << DroppedSpecifier + << SS.getRange(), + SemaRef.PDiag(NoteID)); +} + /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found -bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, - CorrectionCandidateCallback &CCC, - TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args) { +bool +Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + std::unique_ptr<CorrectionCandidateCallback> CCC, + TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -1842,8 +1835,22 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // We didn't find anything, so try to correct for a typo. TypoCorrection Corrected; - if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), - S, &SS, CCC, CTK_ErrorRecovery))) { + if (S && Out) { + SourceLocation TypoLoc = R.getNameLoc(); + assert(!ExplicitTemplateArgs && + "Diagnosing an empty lookup with explicit template args!"); + *Out = CorrectTypoDelayed( + R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC), + [=](const TypoCorrection &TC) { + emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, + diagnostic, diagnostic_suggest); + }, + nullptr, CTK_ErrorRecovery); + if (*Out) + return true; + } else if (S && (Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, + &SS, std::move(CCC), CTK_ErrorRecovery))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -1990,14 +1997,12 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, TemplateArgs); } -ExprResult Sema::ActOnIdExpression(Scope *S, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - UnqualifiedId &Id, - bool HasTrailingLParen, - bool IsAddressOfOperand, - CorrectionCandidateCallback *CCC, - bool IsInlineAsmIdentifier) { +ExprResult +Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, UnqualifiedId &Id, + bool HasTrailingLParen, bool IsAddressOfOperand, + std::unique_ptr<CorrectionCandidateCallback> CCC, + bool IsInlineAsmIdentifier, Token *KeywordReplacement) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) @@ -2109,12 +2114,43 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. - CorrectionCandidateCallback DefaultValidator; - DefaultValidator.IsAddressOfOperand = IsAddressOfOperand; + TypoExpr *TE = nullptr; + auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>( + II, SS.isValid() ? SS.getScopeRep() : nullptr); + DefaultValidator->IsAddressOfOperand = IsAddressOfOperand; assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) && "Typo correction callback misconfigured"); - if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator)) - return ExprError(); + if (CCC) { + // Make sure the callback knows what the typo being diagnosed is. + CCC->setTypoName(II); + if (SS.isValid()) + CCC->setTypoNNS(SS.getScopeRep()); + } + if (DiagnoseEmptyLookup(S, SS, R, + CCC ? std::move(CCC) : std::move(DefaultValidator), + nullptr, None, &TE)) { + if (TE && KeywordReplacement) { + auto &State = getTypoExprState(TE); + auto BestTC = State.Consumer->getNextCorrection(); + if (BestTC.isKeyword()) { + auto *II = BestTC.getCorrectionAsIdentifierInfo(); + if (State.DiagHandler) + State.DiagHandler(BestTC); + KeywordReplacement->startToken(); + KeywordReplacement->setKind(II->getTokenID()); + KeywordReplacement->setIdentifierInfo(II); + KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin()); + // Clean up the state associated with the TypoExpr, since it has + // now been diagnosed (without a call to CorrectDelayedTyposInExpr). + clearDelayedTypo(TE); + // Signal that a correction to a keyword was performed by returning a + // valid-but-null ExprResult. + return (Expr*)nullptr; + } + State.Consumer->resetCorrectionStream(); + } + return TE ? TE : ExprError(); + } assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); @@ -2364,10 +2400,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); - ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), - Loc, IV->getLocation(), - SelfExpr.get(), - true, true); + ObjCIvarRefExpr *Result = new (Context) + ObjCIvarRefExpr(IV, IV->getType(), Loc, IV->getLocation(), + SelfExpr.get(), true, true); if (getLangOpts().ObjCAutoRefCount) { if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -2660,15 +2695,15 @@ static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { return false; } -ExprResult -Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, - LookupResult &R, - bool NeedsADL) { +ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, bool NeedsADL, + bool AcceptInvalidDecl) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>()) return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), - R.getRepresentativeDecl()); + R.getRepresentativeDecl(), nullptr, + AcceptInvalidDecl); // We only need to check the declaration if there's exactly one // result, because in the overloaded case the results can only be @@ -2695,7 +2730,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, /// \brief Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, - NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, + bool AcceptInvalidDecl) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa<FunctionTemplateDecl>(D) && "Cannot refer unambiguously to a function template"); @@ -2730,7 +2766,7 @@ ExprResult Sema::BuildDeclarationNameExpr( return ExprError(); // Only create DeclRefExpr's for valid Decl's. - if (VD->isInvalidDecl()) + if (VD->isInvalidDecl() && !AcceptInvalidDecl) return ExprError(); // Handle members of anonymous structs and unions. If we got here, @@ -2902,6 +2938,17 @@ ExprResult Sema::BuildDeclarationNameExpr( } } +static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, + SmallString<32> &Target) { + Target.resize(CharByteWidth * (Source.size() + 1)); + char *ResultPtr = &Target[0]; + const UTF8 *ErrorPtr; + bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr); + (void)success; + assert(success); + Target.resize(ResultPtr - &Target[0]); +} + ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentType IT) { // Pick the current block, lambda, captured statement or function. @@ -2921,22 +2968,35 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, } QualType ResTy; + StringLiteral *SL = nullptr; if (cast<DeclContext>(currentDecl)->isDependentContext()) ResTy = Context.DependentTy; else { // Pre-defined identifiers are of type char[x], where x is the length of // the string. - unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length(); + auto Str = PredefinedExpr::ComputeName(IT, currentDecl); + unsigned Length = Str.length(); llvm::APInt LengthI(32, Length + 1); - if (IT == PredefinedExpr::LFunction) + if (IT == PredefinedExpr::LFunction) { ResTy = Context.WideCharTy.withConst(); - else + SmallString<32> RawChars; + ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), + Str, RawChars); + ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, + /*IndexTypeQuals*/ 0); + SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, + /*Pascal*/ false, ResTy, Loc); + } else { ResTy = Context.CharTy.withConst(); - ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); + ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, + /*IndexTypeQuals*/ 0); + SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, + /*Pascal*/ false, ResTy, Loc); + } } - return new (Context) PredefinedExpr(Loc, ResTy, IT); + return new (Context) PredefinedExpr(Loc, ResTy, IT, SL); } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { @@ -3046,6 +3106,34 @@ static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc); } +bool Sema::CheckLoopHintExpr(Expr *E, SourceLocation Loc) { + assert(E && "Invalid expression"); + + if (E->isValueDependent()) + return false; + + QualType QT = E->getType(); + if (!QT->isIntegerType() || QT->isBooleanType() || QT->isCharType()) { + Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_type) << QT; + return true; + } + + llvm::APSInt ValueAPS; + ExprResult R = VerifyIntegerConstantExpression(E, &ValueAPS); + + if (R.isInvalid()) + return true; + + bool ValueIsPositive = ValueAPS.isStrictlyPositive(); + if (!ValueIsPositive || ValueAPS.getActiveBits() > 31) { + Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_value) + << ValueAPS.toString(10) << ValueIsPositive; + return true; + } + + return false; +} + ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // Fast path for a single digit (which is quite common). A single digit // cannot have a trigraph, escaped newline, radix prefix, or suffix. @@ -3117,7 +3205,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0); if (Literal.GetIntegerValue(ResultVal)) - Diag(Tok.getLocation(), diag::err_integer_too_large); + Diag(Tok.getLocation(), diag::err_integer_literal_too_large) + << /* Unsigned */ 1; Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy, Tok.getLocation()); } @@ -3210,7 +3299,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Literal.GetIntegerValue(ResultVal)) { // If this value didn't fit into uintmax_t, error and force to ull. - Diag(Tok.getLocation(), diag::err_integer_too_large); + Diag(Tok.getLocation(), diag::err_integer_literal_too_large) + << /* Unsigned */ 1; Ty = Context.UnsignedLongLongTy; assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() && "long long is not intmax_t?"); @@ -3290,7 +3380,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // If we still couldn't decide a type, we probably have something that // does not fit in a signed long long, but has no U suffix. if (Ty.isNull()) { - Diag(Tok.getLocation(), diag::ext_integer_too_large_for_signed); + Diag(Tok.getLocation(), diag::ext_integer_literal_too_large_for_signed); Ty = Context.UnsignedLongLongTy; Width = Context.getTargetInfo().getLongLongWidth(); } @@ -3442,6 +3532,12 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return true; } + // The operand for sizeof and alignof is in an unevaluated expression context, + // so side effects could result in unintended consequences. + if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) && + ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false)) + Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); + if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return true; @@ -4083,11 +4179,12 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, MemberExpr *ME = dyn_cast<MemberExpr>(Fn); DeclarationName FuncName = FDecl->getDeclName(); SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getLocStart(); - FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME); if (TypoCorrection Corrected = S.CorrectTypo( DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName, - S.getScopeForContext(S.CurContext), nullptr, CCC, + S.getScopeForContext(S.CurContext), nullptr, + llvm::make_unique<FunctionCallCCC>(S, FuncName.getAsIdentifierInfo(), + Args.size(), ME), Sema::CTK_ErrorRecovery)) { if (NamedDecl *ND = Corrected.getCorrectionDecl()) { if (Corrected.isOverloaded()) { @@ -4454,6 +4551,8 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { ExprResult result = S.CheckPlaceholderExpr(args[i]); if (result.isInvalid()) hasInvalid = true; else args[i] = result.get(); + } else if (hasInvalid) { + (void)S.CorrectDelayedTyposInExpr(args[i]); } } return hasInvalid; @@ -4587,23 +4686,6 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, ExecConfig, IsExecConfig); } -ExprResult -Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, - MultiExprArg ExecConfig, SourceLocation GGGLoc) { - FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); - if (!ConfigDecl) - return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) - << "cudaConfigureCall"); - QualType ConfigQTy = ConfigDecl->getType(); - - DeclRefExpr *ConfigDR = new (Context) DeclRefExpr( - ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); - MarkFunctionReferenced(LLLLoc, ConfigDecl); - - return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, - /*IsExecConfig=*/true); -} - /// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. /// /// __builtin_astype( value, dst type ) @@ -4680,8 +4762,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, VK_RValue, RParenLoc); // Bail out early if calling a builtin with custom typechecking. - if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) - return CheckBuiltinFunctionCall(BuiltinID, TheCall); + if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) { + ExprResult Res = CorrectDelayedTyposInExpr(TheCall); + if (!Res.isUsable() || !isa<CallExpr>(Res.get())) + return Res; + return CheckBuiltinFunctionCall(FDecl, BuiltinID, cast<CallExpr>(Res.get())); + } retry: const FunctionType *FuncT; @@ -4809,7 +4895,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, return ExprError(); if (BuiltinID) - return CheckBuiltinFunctionCall(BuiltinID, TheCall); + return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); } else if (NDecl) { if (CheckPointerCall(NDecl, TheCall, Proto)) return ExprError(); @@ -5227,6 +5313,12 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, if (getLangOpts().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); + } else { + // Make sure any TypoExprs have been dealt with. + ExprResult Res = CorrectDelayedTyposInExpr(CastExpr); + if (!Res.isUsable()) + return ExprError(); + CastExpr = Res.get(); } checkUnusedDeclAttributes(D); @@ -5693,6 +5785,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprObjectKind &OK, SourceLocation QuestionLoc) { + if (!getLangOpts().CPlusPlus) { + // C cannot handle TypoExpr nodes on either side of a binop because it + // doesn't handle dependent types properly, so make sure any TypoExprs have + // been dealt with before checking the operands. + ExprResult CondResult = CorrectDelayedTyposInExpr(Cond); + if (!CondResult.isUsable()) return QualType(); + Cond = CondResult; + } + ExprResult LHSResult = CheckPlaceholderExpr(LHS.get()); if (!LHSResult.isUsable()) return QualType(); LHS = LHSResult; @@ -5720,7 +5821,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, RHS.get()->getType()->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false); - UsualArithmeticConversions(LHS, RHS); + QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -5737,8 +5838,12 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. - if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) - return LHS.get()->getType(); + if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { + LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); + RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); + + return ResTy; + } // If both operands are the same structure or union type, the result is that // type. @@ -6161,7 +6266,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { if (!lhq.compatiblyIncludes(rhq)) { // Treat address-space mismatches as fatal. TODO: address subspaces - if (lhq.getAddressSpace() != rhq.getAddressSpace()) + if (!lhq.isAddressSpaceSupersetOf(rhq)) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; // It's okay to add or remove GC or lifetime qualifiers when converting to @@ -6446,7 +6551,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* if (isa<PointerType>(RHSType)) { - Kind = CK_BitCast; + unsigned AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); + unsigned AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); + Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -6754,6 +6861,15 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } + Expr *PRE = RHS.get()->IgnoreParenCasts(); + if (ObjCProtocolExpr *OPE = dyn_cast<ObjCProtocolExpr>(PRE)) { + ObjCProtocolDecl *PDecl = OPE->getProtocol(); + if (PDecl && !PDecl->hasDefinition()) { + Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName(); + Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; + } + } + CastKind Kind = CK_Invalid; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind); @@ -7120,6 +7236,19 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType(); if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); + // if both are pointers check if operation is valid wrt address spaces + if (isLHSPointer && isRHSPointer) { + const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>(); + const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>(); + if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { + S.Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); + return false; + } + } + // Check for arithmetic on pointers to incomplete types. bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); @@ -7163,7 +7292,7 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc, bool IsStringPlusInt = StrExpr && IndexExpr->getType()->isIntegralOrUnscopedEnumerationType(); - if (!IsStringPlusInt) + if (!IsStringPlusInt || IndexExpr->isValueDependent()) return; llvm::APSInt index; @@ -7193,13 +7322,13 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc, /// \brief Emit a warning when adding a char literal to a string. static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { - const DeclRefExpr *StringRefExpr = - dyn_cast<DeclRefExpr>(LHSExpr->IgnoreImpCasts()); + const Expr *StringRefExpr = LHSExpr; const CharacterLiteral *CharExpr = dyn_cast<CharacterLiteral>(RHSExpr->IgnoreImpCasts()); - if (!StringRefExpr) { - StringRefExpr = dyn_cast<DeclRefExpr>(RHSExpr->IgnoreImpCasts()); + + if (!CharExpr) { CharExpr = dyn_cast<CharacterLiteral>(LHSExpr->IgnoreImpCasts()); + StringRefExpr = RHSExpr; } if (!CharExpr || !StringRefExpr) @@ -7417,7 +7546,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, } static bool isScopedEnumerationType(QualType T) { - if (const EnumType *ET = dyn_cast<EnumType>(T)) + if (const EnumType *ET = T->getAs<EnumType>()) return ET->getDecl()->isScoped(); return false; } @@ -8048,6 +8177,13 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } if (LCanPointeeTy != RCanPointeeTy) { + const PointerType *lhsPtr = LHSType->getAs<PointerType>(); + if (!lhsPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) { + Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSType << RHSType << 0 /* comparison */ + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + } unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace(); unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace(); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion @@ -8462,7 +8598,7 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { // Must be a reference to a declaration from an enclosing scope. DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); if (!DRE) return NCCK_None; - if (!DRE->refersToEnclosingLocal()) return NCCK_None; + if (!DRE->refersToEnclosingVariableOrCapture()) return NCCK_None; // The declaration must be a variable which is not declared 'const'. VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl()); @@ -8494,19 +8630,19 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { if (IsLV == Expr::MLV_Valid) return false; - unsigned Diag = 0; + unsigned DiagID = 0; bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 case Expr::MLV_ConstQualified: - Diag = diag::err_typecheck_assign_const; + DiagID = diag::err_typecheck_assign_const; // Use a specialized diagnostic when we're assigning to an object // from an enclosing function or block. if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) { if (NCCK == NCCK_Block) - Diag = diag::err_block_decl_ref_not_modifiable_lvalue; + DiagID = diag::err_block_decl_ref_not_modifiable_lvalue; else - Diag = diag::err_lambda_decl_ref_not_modifiable_lvalue; + DiagID = diag::err_lambda_decl_ref_not_modifiable_lvalue; break; } @@ -8526,18 +8662,18 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { // - self ObjCMethodDecl *method = S.getCurMethodDecl(); if (method && var == method->getSelfDecl()) - Diag = method->isClassMethod() + DiagID = method->isClassMethod() ? diag::err_typecheck_arc_assign_self_class_method : diag::err_typecheck_arc_assign_self; // - fast enumeration variables else - Diag = diag::err_typecheck_arr_assign_enumeration; + DiagID = diag::err_typecheck_arr_assign_enumeration; SourceRange Assign; if (Loc != OrigLoc) Assign = SourceRange(OrigLoc, OrigLoc); - S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; // We need to preserve the AST regardless, so migration tool // can do its job. return false; @@ -8548,37 +8684,37 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { break; case Expr::MLV_ArrayType: case Expr::MLV_ArrayTemporary: - Diag = diag::err_typecheck_array_not_modifiable_lvalue; + DiagID = diag::err_typecheck_array_not_modifiable_lvalue; NeedType = true; break; case Expr::MLV_NotObjectType: - Diag = diag::err_typecheck_non_object_not_modifiable_lvalue; + DiagID = diag::err_typecheck_non_object_not_modifiable_lvalue; NeedType = true; break; case Expr::MLV_LValueCast: - Diag = diag::err_typecheck_lvalue_casts_not_supported; + DiagID = diag::err_typecheck_lvalue_casts_not_supported; break; case Expr::MLV_Valid: llvm_unreachable("did not take early return for MLV_Valid"); case Expr::MLV_InvalidExpression: case Expr::MLV_MemberFunction: case Expr::MLV_ClassTemporary: - Diag = diag::err_typecheck_expression_not_modifiable_lvalue; + DiagID = diag::err_typecheck_expression_not_modifiable_lvalue; break; case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E); case Expr::MLV_DuplicateVectorComponents: - Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; + DiagID = diag::err_typecheck_duplicate_vector_components_not_mlvalue; break; case Expr::MLV_NoSetterProperty: llvm_unreachable("readonly properties should be processed differently"); case Expr::MLV_InvalidMessageExpression: - Diag = diag::error_readonly_message_assignment; + DiagID = diag::error_readonly_message_assignment; break; case Expr::MLV_SubObjCPropertySetting: - Diag = diag::error_no_subobject_property_setting; + DiagID = diag::error_no_subobject_property_setting; break; } @@ -8586,9 +8722,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { if (Loc != OrigLoc) Assign = SourceRange(OrigLoc, OrigLoc); if (NeedType) - S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign; + S.Diag(Loc, DiagID) << E->getType() << E->getSourceRange() << Assign; else - S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; return true; } @@ -8754,6 +8890,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation OpLoc, bool IsInc, bool IsPrefix) { if (Op->isTypeDependent()) @@ -8799,7 +8936,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } else if (ResType->isPlaceholderType()) { ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); - return CheckIncrementDecrementOperand(S, PR.get(), VK, OpLoc, + return CheckIncrementDecrementOperand(S, PR.get(), VK, OK, OpLoc, IsInc, IsPrefix); } else if (S.getLangOpts().AltiVec && ResType->isVectorType()) { // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) @@ -8820,6 +8957,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // operand. if (IsPrefix && S.getLangOpts().CPlusPlus) { VK = VK_LValue; + OK = Op->getObjectKind(); return ResType; } else { VK = VK_RValue; @@ -9104,6 +9242,24 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { return Context.getPointerType(op->getType()); } +static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp); + if (!DRE) + return; + const Decl *D = DRE->getDecl(); + if (!D) + return; + const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D); + if (!Param) + return; + if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(Param->getDeclContext())) + if (!FD->hasAttr<NonNullAttr>() && !Param->hasAttr<NonNullAttr>()) + return; + if (FunctionScopeInfo *FD = S.getCurFunction()) + if (!FD->ModifiedNonNullParams.count(Param)) + FD->ModifiedNonNullParams.insert(Param); +} + /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, SourceLocation OpLoc) { @@ -9164,8 +9320,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, return Result; } -static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode( - tok::TokenKind Kind) { +BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) { BinaryOperatorKind Opc; switch (Kind) { default: llvm_unreachable("Unknown binop!"); @@ -9334,6 +9489,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + if (!getLangOpts().CPlusPlus) { + // C cannot handle TypoExpr nodes on either side of a binop because it + // doesn't handle dependent types properly, so make sure any TypoExprs have + // been dealt with before checking the operands. + LHS = CorrectDelayedTyposInExpr(LHSExpr); + RHS = CorrectDelayedTyposInExpr(RHSExpr); + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprError(); + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); @@ -9342,8 +9507,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, VK = LHS.get()->getValueKind(); OK = LHS.get()->getObjectKind(); } - if (!ResultTy.isNull()) + if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); + DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); + } + RecordModifiableNonNullParam(*this, LHS.get()); break; case BO_PtrMemD: case BO_PtrMemI: @@ -9503,7 +9671,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, StringRef OpStr = isLeftComp ? LHSBO->getOpcodeStr() : RHSBO->getOpcodeStr(); SourceRange ParensRange = isLeftComp ? SourceRange(LHSBO->getRHS()->getLocStart(), RHSExpr->getLocEnd()) - : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocStart()); + : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocEnd()); Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) << DiagRange << BinaryOperator::getOpcodeStr(Opc) << OpStr; @@ -9709,7 +9877,7 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); - if (Sc && OverOp != OO_None) + if (Sc && OverOp != OO_None && OverOp != OO_Equal) S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(), RHS->getType(), Functions); @@ -9808,7 +9976,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_PreDec: case UO_PostInc: case UO_PostDec: - resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OpLoc, + resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OK, + OpLoc, Opc == UO_PreInc || Opc == UO_PostInc, Opc == UO_PreInc || @@ -9816,6 +9985,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, break; case UO_AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); + RecordModifiableNonNullParam(*this, InputExpr); break; case UO_Deref: { Input = DefaultFunctionArrayLvalueConversion(Input.get()); @@ -10107,11 +10277,6 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, assert(!ExprNeedsCleanups && "cleanups within StmtExpr not correctly bound!"); PopExpressionEvaluationContext(); - bool isFileScope - = (getCurFunctionOrMethodDecl() == nullptr) && (getCurBlock() == nullptr); - if (isFileScope) - return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope)); - // FIXME: there are a variety of strange constraints to enforce here, for // example, it is not possible to goto into a stmt expression apparently. // More semantic analysis is needed. @@ -10998,7 +11163,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, PartialDiagnostic FDiag = PDiag(DiagKind); if (Action == AA_Passing_CFAudited) - FDiag << FirstType << SecondType << SrcExpr->getSourceRange(); + FDiag << FirstType << SecondType << AA_Passing << SrcExpr->getSourceRange(); else FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange(); @@ -11285,6 +11450,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); + unsigned NumTypos = Rec.NumTypos; if (!Rec.Lambdas.empty()) { if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { @@ -11301,19 +11467,14 @@ void Sema::PopExpressionEvaluationContext() { // evaluate [...] a lambda-expression. D = diag::err_lambda_in_constant_expression; } - for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I) - Diag(Rec.Lambdas[I]->getLocStart(), D); + for (const auto *L : Rec.Lambdas) + Diag(L->getLocStart(), D); } else { // Mark the capture expressions odr-used. This was deferred // during lambda expression creation. - for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I) { - LambdaExpr *Lambda = Rec.Lambdas[I]; - for (LambdaExpr::capture_init_iterator - C = Lambda->capture_init_begin(), - CEnd = Lambda->capture_init_end(); - C != CEnd; ++C) { - MarkDeclarationsReferencedInExpr(*C); - } + for (auto *Lambda : Rec.Lambdas) { + for (auto *C : Lambda->capture_inits()) + MarkDeclarationsReferencedInExpr(C); } } } @@ -11337,6 +11498,12 @@ void Sema::PopExpressionEvaluationContext() { // Pop the current expression evaluation context off the stack. ExprEvalContexts.pop_back(); + + if (!ExprEvalContexts.empty()) + ExprEvalContexts.back().NumTypos += NumTypos; + else + assert(NumTypos == 0 && "There are outstanding typos after popping the " + "last ExpressionEvaluationContextRecord"); } void Sema::DiscardCleanupsInEvaluationContext() { @@ -11385,7 +11552,8 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) -void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { +void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, + bool OdrUse) { assert(Func && "No function?"); Func->setReferenced(); @@ -11484,6 +11652,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); + if (!OdrUse) return; + // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -11636,7 +11806,7 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl * const bool Diagnose, Sema &S) { if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - else { + else if (Var->hasLocalStorage()) { if (Diagnose) diagnoseUncapturableValueReference(S, Loc, Var, DC); } @@ -11665,13 +11835,10 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, return false; } - // Prohibit variably-modified types; they're difficult to deal with. - if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) { + // Prohibit variably-modified types in blocks; they're difficult to deal with. + if (Var->getType()->isVariablyModifiedType() && IsBlock) { if (Diagnose) { - if (IsBlock) - S.Diag(Loc, diag::err_ref_vm_type); - else - S.Diag(Loc, diag::err_lambda_capture_vm_type) << Var->getDeclName(); + S.Diag(Loc, diag::err_ref_vm_type); S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } @@ -11807,7 +11974,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, - const bool RefersToEnclosingLocal, + const bool RefersToCapturedVariable, Sema &S) { // By default, capture variables by reference. @@ -11829,7 +11996,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, Field->setAccess(AS_private); RD->addDecl(Field); - CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, + CopyExpr = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); Var->markUsed(S.Context); @@ -11837,7 +12004,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, // Actually capture the variable. if (BuildAndDiagnose) - RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToEnclosingLocal, Loc, + RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc, SourceLocation(), CaptureType, CopyExpr); @@ -11851,7 +12018,7 @@ static ExprResult addAsFieldToClosureType(Sema &S, VarDecl *Var, QualType FieldType, QualType DeclRefType, SourceLocation Loc, - bool RefersToEnclosingLocal) { + bool RefersToCapturedVariable) { CXXRecordDecl *Lambda = LSI->Lambda; // Build the non-static data member. @@ -11880,7 +12047,7 @@ static ExprResult addAsFieldToClosureType(Sema &S, // C++ [expr.prim.labda]p12: // An entity captured by a lambda-expression is odr-used (3.2) in // the scope containing the lambda-expression. - Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, + Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToCapturedVariable, DeclRefType, VK_LValue, Loc); Var->setReferenced(true); Var->markUsed(S.Context); @@ -11974,7 +12141,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, - const bool RefersToEnclosingLocal, + const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, SourceLocation EllipsisLoc, const bool IsTopScope, @@ -12048,7 +12215,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, if (BuildAndDiagnose) { ExprResult Result = addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc, - RefersToEnclosingLocal); + RefersToCapturedVariable); if (!Result.isInvalid()) CopyExpr = Result.get(); } @@ -12069,20 +12236,19 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // Add the capture. if (BuildAndDiagnose) - LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToEnclosingLocal, + LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable, Loc, EllipsisLoc, CaptureType, CopyExpr); return true; } - bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { - bool Nested = false; + bool Nested = Var->isInitCapture(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -12100,8 +12266,13 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, // If the variable is declared in the current context (and is not an // init-capture), there is no need to capture it. - if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true; - if (!Var->hasLocalStorage()) return true; + if (!Nested && Var->getDeclContext() == DC) return true; + + // Capture global variables if it is required to use private copy of this + // variable. + bool IsGlobal = !Var->hasLocalStorage(); + if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var))) + return true; // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -12122,8 +12293,17 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, ExprLoc, BuildAndDiagnose, *this); - if (!ParentDC) return true; - + // We need to check for the parent *first* because, if we *have* + // private-captured a global variable, we need to recursively capture it in + // intermediate blocks, lambdas, etc. + if (!ParentDC) { + if (IsGlobal) { + FunctionScopesIndex = MaxFunctionScopesIndex - 1; + break; + } + return true; + } + FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI); @@ -12212,14 +12392,37 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc, break; case Type::VariableArray: { // Losing element qualification here is fine. - const VariableArrayType *Vat = cast<VariableArrayType>(Ty); + const VariableArrayType *VAT = cast<VariableArrayType>(Ty); // Unknown size indication requires no size computation. // Otherwise, evaluate and record it. - if (Expr *Size = Vat->getSizeExpr()) { - MarkDeclarationsReferencedInExpr(Size); + if (auto Size = VAT->getSizeExpr()) { + if (!CSI->isVLATypeCaptured(VAT)) { + RecordDecl *CapRecord = nullptr; + if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) { + CapRecord = LSI->Lambda; + } else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) { + CapRecord = CRSI->TheRecordDecl; + } + if (CapRecord) { + auto ExprLoc = Size->getExprLoc(); + auto SizeType = Context.getSizeType(); + // Build the non-static data member. + auto Field = FieldDecl::Create( + Context, CapRecord, ExprLoc, ExprLoc, + /*Id*/ nullptr, SizeType, /*TInfo*/ nullptr, + /*BW*/ nullptr, /*Mutable*/ false, + /*InitStyle*/ ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + Field->setCapturedVLAType(VAT); + CapRecord->addDecl(Field); + + CSI->addVLATypeCapture(ExprLoc, SizeType); + } + } } - QTy = Vat->getElementType(); + QTy = VAT->getElementType(); break; } case Type::FunctionProto: @@ -12326,6 +12529,14 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, DeclRefType, nullptr); } +bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { + QualType CaptureType; + QualType DeclRefType; + return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), + /*BuildAndDiagnose=*/false, CaptureType, + DeclRefType, nullptr); +} + QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; @@ -12388,6 +12599,8 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) { } ExprResult Sema::ActOnConstantExpression(ExprResult Res) { + Res = CorrectDelayedTyposInExpr(Res); + if (!Res.isUsable()) return Res; @@ -12412,7 +12625,7 @@ void Sema::CleanupVarDeclMarking() { Var = cast<VarDecl>(ME->getMemberDecl()); Loc = ME->getMemberLoc(); } else { - llvm_unreachable("Unexpcted expression"); + llvm_unreachable("Unexpected expression"); } MarkVarDeclODRUsed(Var, Loc, *this, @@ -12429,6 +12642,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, "Invalid Expr argument to DoMarkVarDeclReferenced"); Var->setReferenced(); + TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + bool MarkODRUsed = true; + // If the context is not potentially evaluated, this is not an odr-use and // does not trigger instantiation. if (!IsPotentiallyEvaluatedContext(SemaRef)) { @@ -12443,25 +12659,29 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // arguments, where local variables can't be used. const bool RefersToEnclosingScope = (SemaRef.CurContext != Var->getDeclContext() && - Var->getDeclContext()->isFunctionOrMethod() && - Var->hasLocalStorage()); - if (!RefersToEnclosingScope) - return; - - if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) { - // If a variable could potentially be odr-used, defer marking it so - // until we finish analyzing the full expression for any lvalue-to-rvalue - // or discarded value conversions that would obviate odr-use. - // Add it to the list of potential captures that will be analyzed - // later (ActOnFinishFullExpr) for eventual capture and odr-use marking - // unless the variable is a reference that was initialized by a constant - // expression (this will never need to be captured or odr-used). - assert(E && "Capture variable should be used in an expression."); - if (!Var->getType()->isReferenceType() || - !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context)) - LSI->addPotentialCapture(E->IgnoreParens()); + Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); + if (RefersToEnclosingScope) { + if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) { + // If a variable could potentially be odr-used, defer marking it so + // until we finish analyzing the full expression for any + // lvalue-to-rvalue + // or discarded value conversions that would obviate odr-use. + // Add it to the list of potential captures that will be analyzed + // later (ActOnFinishFullExpr) for eventual capture and odr-use marking + // unless the variable is a reference that was initialized by a constant + // expression (this will never need to be captured or odr-used). + assert(E && "Capture variable should be used in an expression."); + if (!Var->getType()->isReferenceType() || + !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context)) + LSI->addPotentialCapture(E->IgnoreParens()); + } } - return; + + if (!isTemplateInstantiation(TSK)) + return; + + // Instantiate, but do not mark as odr-used, variable templates. + MarkODRUsed = false; } VarTemplateSpecializationDecl *VarSpec = @@ -12473,7 +12693,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // templates of class templates, and variable template specializations. Delay // instantiations of variable templates, except for those that could be used // in a constant expression. - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); if (isTemplateInstantiation(TSK)) { bool TryInstantiating = TSK == TSK_ImplicitInstantiation; @@ -12513,6 +12732,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, } } + if(!MarkODRUsed) return; + // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies // the requirements for appearing in a constant expression (5.19) and, if // it is an object, the lvalue-to-rvalue conversion (4.1) @@ -12555,6 +12776,10 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ME->getMemberDecl()); if (!MD) return; + // Only attempt to devirtualize if this is truly a virtual call. + bool IsVirtualCall = MD->isVirtual() && !ME->hasQualifier(); + if (!IsVirtualCall) + return; const Expr *Base = ME->getBase(); const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); if (!MostDerivedClassDecl) @@ -12602,14 +12827,14 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { /// normal expression which refers to a variable. void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) { if (OdrUse) { - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (auto *VD = dyn_cast<VarDecl>(D)) { MarkVariableReferenced(Loc, VD); return; } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - MarkFunctionReferenced(Loc, FD); - return; - } + } + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + MarkFunctionReferenced(Loc, FD, OdrUse); + return; } D->setReferenced(); } @@ -12935,6 +13160,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { << T << E->getSourceRange(); return ExprError(); } + CheckBoolLikeConversion(E, Loc); } return E; @@ -13306,6 +13532,39 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { << VD << E->getSourceRange(); return ExprError(); } + if (const FunctionProtoType *FT = Type->getAs<FunctionProtoType>()) { + // We must match the FunctionDecl's type to the hack introduced in + // RebuildUnknownAnyExpr::VisitCallExpr to vararg functions of unknown + // type. See the lengthy commentary in that routine. + QualType FDT = FD->getType(); + const FunctionType *FnType = FDT->castAs<FunctionType>(); + const FunctionProtoType *Proto = dyn_cast_or_null<FunctionProtoType>(FnType); + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); + if (DRE && Proto && Proto->getParamTypes().empty() && Proto->isVariadic()) { + SourceLocation Loc = FD->getLocation(); + FunctionDecl *NewFD = FunctionDecl::Create(FD->getASTContext(), + FD->getDeclContext(), + Loc, Loc, FD->getNameInfo().getName(), + DestType, FD->getTypeSourceInfo(), + SC_None, false/*isInlineSpecified*/, + FD->hasPrototype(), + false/*isConstexprSpecified*/); + + if (FD->getQualifier()) + NewFD->setQualifierInfo(FD->getQualifierLoc()); + + SmallVector<ParmVarDecl*, 16> Params; + for (const auto &AI : FT->param_types()) { + ParmVarDecl *Param = + S.BuildParmVarDeclForTypedef(FD, Loc, AI); + Param->setScopeInfo(0, Params.size()); + Params.push_back(Param); + } + NewFD->setParams(Params); + DRE->setDecl(NewFD); + VD = DRE->getDecl(); + } + } if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) if (MD->isInstance()) { @@ -13431,6 +13690,15 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { /// Check for operands with placeholder types and complain if found. /// Returns true if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E) { + if (!getLangOpts().CPlusPlus) { + // C cannot handle TypoExpr nodes on either side of a binop because it + // doesn't handle dependent types properly, so make sure any TypoExprs have + // been dealt with before checking the operands. + ExprResult Result = CorrectDelayedTyposInExpr(E); + if (!Result.isUsable()) return ExprError(); + E = Result.get(); + } + const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType(); if (!placeholderType) return E; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0dabdca..422398e 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" @@ -67,6 +68,7 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, break; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); @@ -198,6 +200,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { @@ -354,6 +357,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, return true; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: return false; @@ -380,6 +384,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); + if (T->isVariablyModifiedType()) + return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); + return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } @@ -389,6 +396,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { + bool WasEvaluated = false; if (E && !E->isTypeDependent()) { if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); @@ -418,6 +426,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); + WasEvaluated = true; } } @@ -434,6 +443,18 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, } } + if (E->getType()->isVariablyModifiedType()) + return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) + << E->getType()); + else if (ActiveTemplateInstantiations.empty() && + E->HasSideEffects(Context, WasEvaluated)) { + // The expression operand for typeid is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(E->getExprLoc(), WasEvaluated + ? diag::warn_side_effects_typeid + : diag::warn_side_effects_unevaluated_context); + } + return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, SourceRange(TypeidLoc, RParenLoc)); } @@ -580,15 +601,15 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { bool IsThrownVarInScope = false; if (Ex) { // C++0x [class.copymove]p31: - // When certain criteria are met, an implementation is allowed to omit the + // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // - // - in a throw-expression, when the operand is the name of a + // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or catch- - // clause parameter) whose scope does not extend beyond the end of the - // innermost enclosing try-block (if there is one), the copy/move - // operation from the operand to the exception object (15.1) can be - // omitted by constructing the automatic object directly into the + // clause parameter) whose scope does not extend beyond the end of the + // innermost enclosing try-block (if there is one), the copy/move + // operation from the operand to the exception object (15.1) can be + // omitted by constructing the automatic object directly into the // exception object if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens())) if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { @@ -1083,7 +1104,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; if (Expr *NumElts = (Expr *)Array.NumElts) { if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { - if (getLangOpts().CPlusPlus1y) { + if (getLangOpts().CPlusPlus14) { // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator // shall be a converted constant expression (5.19) of type std::size_t // and shall evaluate to a strictly positive value. @@ -1257,7 +1278,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // std::size_t. if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize; - if (getLangOpts().CPlusPlus1y) { + if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), @@ -2072,19 +2093,18 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, if (!getLangOpts().CPlusPlus11) { BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); assert(StdBadAlloc && "Must have std::bad_alloc declared"); - EPI.ExceptionSpecType = EST_Dynamic; - EPI.NumExceptions = 1; - EPI.Exceptions = &BadAllocType; + EPI.ExceptionSpec.Type = EST_Dynamic; + EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } } else { - EPI.ExceptionSpecType = getLangOpts().CPlusPlus11 ? - EST_BasicNoexcept : EST_DynamicNone; + EPI.ExceptionSpec = + getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } QualType Params[] = { Param1, Param2 }; QualType FnType = Context.getFunctionType( - Return, ArrayRef<QualType>(Params, NumParams), EPI); + Return, llvm::makeArrayRef(Params, NumParams), EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, @@ -2102,7 +2122,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, SC_None, nullptr); ParamDecls[I]->setImplicit(); } - Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams)); + Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams)); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); @@ -2622,8 +2642,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the - // initial standard conversion sequence converts the source type to the - // type required by the argument of the constructor + // initial standard conversion sequence converts the source type to + // the type required by the argument of the constructor BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); } } @@ -2739,15 +2759,19 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: - // Nothing to do. + if (const AtomicType *FromAtomic = FromType->getAs<AtomicType>()) { + FromType = FromAtomic->getValueType().getUnqualifiedType(); + From = ImplicitCastExpr::Create(Context, FromType, CK_AtomicToNonAtomic, + From, /*BasePath=*/nullptr, VK_RValue); + } break; case ICK_Lvalue_To_Rvalue: { assert(From->getObjectKind() != OK_ObjCProperty); - FromType = FromType.getUnqualifiedType(); ExprResult FromRes = DefaultLvalueConversion(From); assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!"); From = FromRes.get(); + FromType = From->getType(); break; } @@ -2770,10 +2794,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: - // If both sides are functions (or pointers/references to them), there could - // be incompatible exception declarations. - if (CheckExceptionSpecCompatibility(From, ToType)) - return ExprError(); + // C++ [except.spec]p5: + // [For] assignment to and initialization of pointers to functions, + // pointers to member functions, and references to functions: the + // target entity shall allow at least the exceptions allowed by the + // source value in the assignment or initialization. + switch (Action) { + case AA_Assigning: + case AA_Initializing: + // Note, function argument passing and returning are initialization. + case AA_Passing: + case AA_Returning: + case AA_Sending: + case AA_Passing_CFAudited: + if (CheckExceptionSpecCompatibility(From, ToType)) + return ExprError(); + break; + + case AA_Casting: + case AA_Converting: + // Casts and implicit conversions are not initialization, so are not + // checked for exception specification mismatches. + break; + } // Nothing else to do. break; @@ -2899,6 +2942,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); + + // We may not have been able to figure out what this member pointer resolved + // to up until this exact point. Attempt to lock-in it's inheritance model. + QualType FromType = From->getType(); + if (FromType->isMemberPointerType()) + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) + RequireCompleteType(From->getExprLoc(), FromType, 0); + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; @@ -3642,12 +3693,13 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (T->isObjectType() || T->isFunctionType()) T = S.Context.getRValueReferenceType(T); OpaqueArgExprs.push_back( - OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(), + OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(), T.getNonLValueExprType(S.Context), Expr::getValueKindForType(T))); - ArgExprs.push_back(&OpaqueArgExprs.back()); } - + for (Expr &E : OpaqueArgExprs) + ArgExprs.push_back(&E); + // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); @@ -4549,10 +4601,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { - UsualArithmeticConversions(LHS, RHS); + QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - return LHS.get()->getType(); + + LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); + RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); + + return ResTy; } // -- The second and third operands have pointer type, or one has pointer @@ -4993,9 +5049,8 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { if (!ExprNeedsCleanups) return SubExpr; - ArrayRef<ExprWithCleanups::CleanupObject> Cleanups - = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, - ExprCleanupObjects.size() - FirstCleanup); + auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, + ExprCleanupObjects.size() - FirstCleanup); Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups); DiscardCleanupsInEvaluationContext(); @@ -5231,7 +5286,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, OperatorArrows.push_back(OpCall->getDirectCallee()); BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); - if (!CTypes.insert(CBaseType)) { + if (!CTypes.insert(CBaseType).second) { Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType; noteOperatorArrows(*this, OperatorArrows); return ExprError(); @@ -5581,7 +5636,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), + false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); @@ -5649,6 +5705,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { + if (ActiveTemplateInstantiations.empty() && + Operand->HasSideEffects(Context, false)) { + // The expression operand for noexcept is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); + } + CanThrowResult CanThrow = canThrow(Operand); return new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen); @@ -5905,6 +5968,284 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( CurrentLSI->clearPotentialCaptures(); } +static ExprResult attemptRecovery(Sema &SemaRef, + const TypoCorrectionConsumer &Consumer, + TypoCorrection TC) { + LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), + Consumer.getLookupResult().getLookupKind()); + const CXXScopeSpec *SS = Consumer.getSS(); + CXXScopeSpec NewSS; + + // Use an approprate CXXScopeSpec for building the expr. + if (auto *NNS = TC.getCorrectionSpecifier()) + NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); + else if (SS && !TC.WillReplaceSpecifier()) + NewSS = *SS; + + if (auto *ND = TC.getCorrectionDecl()) { + R.setLookupName(ND->getDeclName()); + R.addDecl(ND); + if (ND->isCXXClassMember()) { + // Figure out the correct naming class to add to the LookupResult. + CXXRecordDecl *Record = nullptr; + if (auto *NNS = TC.getCorrectionSpecifier()) + Record = NNS->getAsType()->getAsCXXRecordDecl(); + if (!Record) + Record = + dyn_cast<CXXRecordDecl>(ND->getDeclContext()->getRedeclContext()); + if (Record) + R.setNamingClass(Record); + + // Detect and handle the case where the decl might be an implicit + // member. + bool MightBeImplicitMember; + if (!Consumer.isAddressOfOperand()) + MightBeImplicitMember = true; + else if (!NewSS.isEmpty()) + MightBeImplicitMember = false; + else if (R.isOverloadedResult()) + MightBeImplicitMember = false; + else if (R.isUnresolvableResult()) + MightBeImplicitMember = true; + else + MightBeImplicitMember = isa<FieldDecl>(ND) || + isa<IndirectFieldDecl>(ND) || + isa<MSPropertyDecl>(ND); + + if (MightBeImplicitMember) + return SemaRef.BuildPossibleImplicitMemberExpr( + NewSS, /*TemplateKWLoc*/ SourceLocation(), R, + /*TemplateArgs*/ nullptr); + } else if (auto *Ivar = dyn_cast<ObjCIvarDecl>(ND)) { + return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), + Ivar->getIdentifier()); + } + } + + return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false, + /*AcceptInvalidDecl*/ true); +} + +namespace { +class FindTypoExprs : public RecursiveASTVisitor<FindTypoExprs> { + llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs; + +public: + explicit FindTypoExprs(llvm::SmallSetVector<TypoExpr *, 2> &TypoExprs) + : TypoExprs(TypoExprs) {} + bool VisitTypoExpr(TypoExpr *TE) { + TypoExprs.insert(TE); + return true; + } +}; + +class TransformTypos : public TreeTransform<TransformTypos> { + typedef TreeTransform<TransformTypos> BaseTransform; + + llvm::function_ref<ExprResult(Expr *)> ExprFilter; + llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs; + llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache; + llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution; + + /// \brief Emit diagnostics for all of the TypoExprs encountered. + /// If the TypoExprs were successfully corrected, then the diagnostics should + /// suggest the corrections. Otherwise the diagnostics will not suggest + /// anything (having been passed an empty TypoCorrection). + void EmitAllDiagnostics() { + for (auto E : TypoExprs) { + TypoExpr *TE = cast<TypoExpr>(E); + auto &State = SemaRef.getTypoExprState(TE); + if (State.DiagHandler) { + TypoCorrection TC = State.Consumer->getCurrentCorrection(); + ExprResult Replacement = TransformCache[TE]; + + // Extract the NamedDecl from the transformed TypoExpr and add it to the + // TypoCorrection, replacing the existing decls. This ensures the right + // NamedDecl is used in diagnostics e.g. in the case where overload + // resolution was used to select one from several possible decls that + // had been stored in the TypoCorrection. + if (auto *ND = getDeclFromExpr( + Replacement.isInvalid() ? nullptr : Replacement.get())) + TC.setCorrectionDecl(ND); + + State.DiagHandler(TC); + } + SemaRef.clearDelayedTypo(TE); + } + } + + /// \brief If corrections for the first TypoExpr have been exhausted for a + /// given combination of the other TypoExprs, retry those corrections against + /// the next combination of substitutions for the other TypoExprs by advancing + /// to the next potential correction of the second TypoExpr. For the second + /// and subsequent TypoExprs, if its stream of corrections has been exhausted, + /// the stream is reset and the next TypoExpr's stream is advanced by one (a + /// TypoExpr's correction stream is advanced by removing the TypoExpr from the + /// TransformCache). Returns true if there is still any untried combinations + /// of corrections. + bool CheckAndAdvanceTypoExprCorrectionStreams() { + for (auto TE : TypoExprs) { + auto &State = SemaRef.getTypoExprState(TE); + TransformCache.erase(TE); + if (!State.Consumer->finished()) + return true; + State.Consumer->resetCorrectionStream(); + } + return false; + } + + NamedDecl *getDeclFromExpr(Expr *E) { + if (auto *OE = dyn_cast_or_null<OverloadExpr>(E)) + E = OverloadResolution[OE]; + + if (!E) + return nullptr; + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + return DRE->getDecl(); + if (auto *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + // FIXME: Add any other expr types that could be be seen by the delayed typo + // correction TreeTransform for which the corresponding TypoCorrection could + // contain multiple decls. + return nullptr; + } + + ExprResult TryTransform(Expr *E) { + Sema::SFINAETrap Trap(SemaRef); + ExprResult Res = TransformExpr(E); + if (Trap.hasErrorOccurred() || Res.isInvalid()) + return ExprError(); + + return ExprFilter(Res.get()); + } + +public: + TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter) + : BaseTransform(SemaRef), ExprFilter(Filter) {} + + ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation RParenLoc, + Expr *ExecConfig = nullptr) { + auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, + RParenLoc, ExecConfig); + if (auto *OE = dyn_cast<OverloadExpr>(Callee)) { + if (Result.isUsable()) { + Expr *ResultCall = Result.get(); + if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall)) + ResultCall = BE->getSubExpr(); + if (auto *CE = dyn_cast<CallExpr>(ResultCall)) + OverloadResolution[OE] = CE->getCallee(); + } + } + return Result; + } + + ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } + + ExprResult TransformOpaqueValueExpr(OpaqueValueExpr *E) { + if (Expr *SE = E->getSourceExpr()) + return TransformExpr(SE); + return BaseTransform::TransformOpaqueValueExpr(E); + } + + ExprResult Transform(Expr *E) { + ExprResult Res; + while (true) { + Res = TryTransform(E); + + // Exit if either the transform was valid or if there were no TypoExprs + // to transform that still have any untried correction candidates.. + if (!Res.isInvalid() || + !CheckAndAdvanceTypoExprCorrectionStreams()) + break; + } + + // Ensure none of the TypoExprs have multiple typo correction candidates + // with the same edit length that pass all the checks and filters. + // TODO: Properly handle various permutations of possible corrections when + // there is more than one potentially ambiguous typo correction. + while (!AmbiguousTypoExprs.empty()) { + auto TE = AmbiguousTypoExprs.back(); + auto Cached = TransformCache[TE]; + AmbiguousTypoExprs.pop_back(); + TransformCache.erase(TE); + if (!TryTransform(E).isInvalid()) { + SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream(); + TransformCache.erase(TE); + Res = ExprError(); + break; + } else + TransformCache[TE] = Cached; + } + + // Ensure that all of the TypoExprs within the current Expr have been found. + if (!Res.isUsable()) + FindTypoExprs(TypoExprs).TraverseStmt(E); + + EmitAllDiagnostics(); + + return Res; + } + + ExprResult TransformTypoExpr(TypoExpr *E) { + // If the TypoExpr hasn't been seen before, record it. Otherwise, return the + // cached transformation result if there is one and the TypoExpr isn't the + // first one that was encountered. + auto &CacheEntry = TransformCache[E]; + if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) { + return CacheEntry; + } + + auto &State = SemaRef.getTypoExprState(E); + assert(State.Consumer && "Cannot transform a cleared TypoExpr"); + + // For the first TypoExpr and an uncached TypoExpr, find the next likely + // typo correction and return it. + while (TypoCorrection TC = State.Consumer->getNextCorrection()) { + ExprResult NE = State.RecoveryHandler ? + State.RecoveryHandler(SemaRef, E, TC) : + attemptRecovery(SemaRef, *State.Consumer, TC); + if (!NE.isInvalid()) { + // Check whether there may be a second viable correction with the same + // edit distance; if so, remember this TypoExpr may have an ambiguous + // correction so it can be more thoroughly vetted later. + TypoCorrection Next; + if ((Next = State.Consumer->peekNextCorrection()) && + Next.getEditDistance(false) == TC.getEditDistance(false)) { + AmbiguousTypoExprs.insert(E); + } else { + AmbiguousTypoExprs.remove(E); + } + assert(!NE.isUnset() && + "Typo was transformed into a valid-but-null ExprResult"); + return CacheEntry = NE; + } + } + return CacheEntry = ExprError(); + } +}; +} + +ExprResult Sema::CorrectDelayedTyposInExpr( + Expr *E, llvm::function_ref<ExprResult(Expr *)> Filter) { + // If the current evaluation context indicates there are uncorrected typos + // and the current expression isn't guaranteed to not have typos, try to + // resolve any TypoExpr nodes that might be in the expression. + if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && + (E->isTypeDependent() || E->isValueDependent() || + E->isInstantiationDependent())) { + auto TyposResolved = DelayedTypos.size(); + auto Result = TransformTypos(*this, Filter).Transform(E); + TyposResolved -= DelayedTypos.size(); + if (Result.isInvalid() || Result.get() != E) { + ExprEvalContexts.back().NumTypos -= TyposResolved; + return Result; + } + assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); + } + return E; +} ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, @@ -5952,6 +6293,10 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, return ExprError(); } + FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); + if (FullExpr.isInvalid()) + return ExprError(); + CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); // At the end of this full expression (which could be a deeply nested diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index ef78982..af1cf90 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -10,7 +10,7 @@ // This file implements semantic analysis member access expressions. // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Overload.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,6 +21,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" using namespace clang; using namespace sema; @@ -89,7 +90,6 @@ enum IMAKind { /// conservatively answer "yes", in which case some errors will simply /// not be caught until template-instantiation. static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, - Scope *CurScope, const LookupResult &R) { assert(!R.empty() && (*R.begin())->isCXXClassMember()); @@ -204,6 +204,9 @@ static void diagnoseInstanceReference(Sema &SemaRef, SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + // Look through using shadow decls and aliases. + Rep = Rep->getUnderlyingDecl(); + DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext(); CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC); CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr; @@ -236,7 +239,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { + switch (ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true); @@ -536,9 +539,17 @@ namespace { // FunctionTemplateDecl and are declared in the current record or, for a C++ // classes, one of its base classes. class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { - public: +public: explicit RecordMemberExprValidatorCCC(const RecordType *RTy) - : Record(RTy->getDecl()) {} + : Record(RTy->getDecl()) { + // Don't add bare keywords to the consumer since they will always fail + // validation by virtue of not being associated with any decls. + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantFunctionLikeCasts = false; + WantRemainingKeywords = false; + } bool ValidateCandidate(const TypoCorrection &candidate) override { NamedDecl *ND = candidate.getCorrectionDecl(); @@ -554,8 +565,8 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) { // Accept candidates that occur in any of the current class' base classes. for (const auto &BS : RD->bases()) { - if (const RecordType *BSTy = dyn_cast_or_null<RecordType>( - BS.getType().getTypePtrOrNull())) { + if (const RecordType *BSTy = + dyn_cast_or_null<RecordType>(BS.getType().getTypePtrOrNull())) { if (BSTy->getDecl()->containsDecl(ND)) return true; } @@ -565,17 +576,19 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback { return false; } - private: +private: const RecordDecl *const Record; }; } -static bool -LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, - SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, CXXScopeSpec &SS, - bool HasTemplateArgs) { +static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + Expr *BaseExpr, + const RecordType *RTy, + SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, bool HasTemplateArgs, + TypoExpr *&TE) { + SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); RecordDecl *RDecl = RTy->getDecl(); if (!SemaRef.isThisOutsideMemberFunctionBody(QualType(RTy, 0)) && SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), @@ -600,7 +613,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, if (SemaRef.RequireCompleteDeclContext(SS, DC)) { SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) - << SS.getRange() << DC; + << SS.getRange() << DC; return true; } @@ -608,47 +621,48 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, if (!isa<TypeDecl>(DC)) { SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) - << DC << SS.getRange(); + << DC << SS.getRange(); return true; } } // The record definition is complete, now look up the member. - SemaRef.LookupQualifiedName(R, DC); + SemaRef.LookupQualifiedName(R, DC, SS); if (!R.empty()) return false; - // We didn't find anything with the given name, so try to correct - // for typos. - DeclarationName Name = R.getLookupName(); - RecordMemberExprValidatorCCC Validator(RTy); - TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(), - R.getLookupKind(), nullptr, - &SS, Validator, - Sema::CTK_ErrorRecovery, DC); - R.clear(); - if (Corrected.isResolved() && !Corrected.isKeyword()) { - R.setLookupName(Corrected.getCorrection()); - for (TypoCorrection::decl_iterator DI = Corrected.begin(), - DIEnd = Corrected.end(); - DI != DIEnd; ++DI) { - R.addDecl(*DI); - } - R.resolveKind(); - - // If we're typo-correcting to an overloaded name, we don't yet have enough - // information to do overload resolution, so we don't know which previous - // declaration to point to. - if (Corrected.isOverloaded()) - Corrected.setCorrectionDecl(nullptr); - bool DroppedSpecifier = - Corrected.WillReplaceSpecifier() && - Name.getAsString() == Corrected.getAsString(SemaRef.getLangOpts()); - SemaRef.diagnoseTypo(Corrected, - SemaRef.PDiag(diag::err_no_member_suggest) - << Name << DC << DroppedSpecifier << SS.getRange()); - } + DeclarationName Typo = R.getLookupName(); + SourceLocation TypoLoc = R.getNameLoc(); + TE = SemaRef.CorrectTypoDelayed( + R.getLookupNameInfo(), R.getLookupKind(), nullptr, &SS, + llvm::make_unique<RecordMemberExprValidatorCCC>(RTy), + [=, &SemaRef](const TypoCorrection &TC) { + if (TC) { + assert(!TC.isKeyword() && + "Got a keyword as a correction for a member!"); + bool DroppedSpecifier = + TC.WillReplaceSpecifier() && + Typo.getAsString() == TC.getAsString(SemaRef.getLangOpts()); + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) + << Typo << DC << DroppedSpecifier + << SS.getRange()); + } else { + SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << DC << BaseRange; + } + }, + [=](Sema &SemaRef, TypoExpr *TE, TypoCorrection TC) mutable { + R.clear(); // Ensure there's no decls lingering in the shared state. + R.suppressDiagnostics(); + R.setLookupName(TC.getCorrection()); + for (NamedDecl *ND : TC) + R.addDecl(ND); + R.resolveKind(); + return SemaRef.BuildMemberReferenceExpr( + BaseExpr, BaseExpr->getType(), OpLoc, IsArrow, SS, SourceLocation(), + nullptr, R, nullptr); + }, + Sema::CTK_ErrorRecovery, DC); return false; } @@ -678,12 +692,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, // Implicit member accesses. if (!Base) { + TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, SourceRange(), - RecordTy->getAs<RecordType>(), - OpLoc, SS, TemplateArgs != nullptr)) + if (LookupMemberExprInRecord(*this, R, nullptr, + RecordTy->getAs<RecordType>(), OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TE)) return ExprError(); + if (TE) + return TE; // Explicit member accesses. } else { @@ -1211,13 +1228,16 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - if (LookupMemberExprInRecord(S, R, BaseExpr.get()->getSourceRange(), - RTy, OpLoc, SS, HasTemplateArgs)) + TypoExpr *TE = nullptr; + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, + OpLoc, IsArrow, SS, HasTemplateArgs, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that - // the lookup result was filled in. - return ExprResult((Expr *)nullptr); + // the lookup result was filled in. If typo correction was attempted and + // failed, the lookup result will have been cleared--that combined with the + // valid-but-null ExprResult will trigger the appropriate diagnostics. + return ExprResult(TE); } // Handle ivar access to Objective-C objects. @@ -1262,11 +1282,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (!IV) { // Attempt to correct for typos in ivar names. - DeclFilterCCC<ObjCIvarDecl> Validator; - Validator.IsObjCIvarLookup = IsArrow; + auto Validator = llvm::make_unique<DeclFilterCCC<ObjCIvarDecl>>(); + Validator->IsObjCIvarLookup = IsArrow; if (TypoCorrection Corrected = S.CorrectTypo( R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr, - Validator, Sema::CTK_ErrorRecovery, IDecl)) { + std::move(Validator), Sema::CTK_ErrorRecovery, IDecl)) { IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>(); S.diagnoseTypo( Corrected, diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 5002332..9c3b51c 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -944,7 +944,11 @@ ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, return ExprError(); std::string Str; - Context.getObjCEncodingForType(EncodedType, Str); + QualType NotEncodedT; + Context.getObjCEncodingForType(EncodedType, Str, nullptr, &NotEncodedT); + if (!NotEncodedT.isNull()) + Diag(AtLoc, diag::warn_incomplete_encoded_type) + << EncodedType << NotEncodedT; // The type of @encode is the same as the type of the corresponding string, // which is an array type. @@ -983,7 +987,7 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, ObjCMethodList *M = &MethList; bool Warned = false; for (M = M->getNext(); M; M=M->getNext()) { - ObjCMethodDecl *MatchingMethodDecl = M->Method; + ObjCMethodDecl *MatchingMethodDecl = M->getMethod(); if (MatchingMethodDecl == Method || isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) || MatchingMethodDecl->getSelector() != Method->getSelector()) @@ -1086,6 +1090,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, case OMF_mutableCopy: case OMF_new: case OMF_self: + case OMF_initialize: case OMF_performSelector: break; } @@ -1105,6 +1110,8 @@ ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; } + if (PDecl->hasDefinition()) + PDecl = PDecl->getDefinition(); QualType Ty = Context.getObjCProtoType(); if (Ty.isNull()) @@ -1222,12 +1229,8 @@ void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) { // 'instancetype'. if (const ObjCMethodDecl *overridden = findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) { - SourceLocation loc; - SourceRange range; - if (TypeSourceInfo *TSI = overridden->getReturnTypeSourceInfo()) { - range = TSI->getTypeLoc().getSourceRange(); - loc = range.getBegin(); - } + SourceRange range = overridden->getReturnTypeSourceRange(); + SourceLocation loc = range.getBegin(); if (loc.isInvalid()) loc = overridden->getLocation(); Diag(loc, diag::note_related_result_type_explicit) @@ -1276,6 +1279,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, + SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK) { SourceLocation SelLoc; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) @@ -1317,9 +1321,12 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, : diag::warn_instance_method_not_found_with_typo; Selector MatchedSel = OMD->getSelector(); SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back()); - Diag(SelLoc, DiagID) - << Sel<< isClassMessage << MatchedSel - << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + if (MatchedSel.isUnarySelector()) + Diag(SelLoc, DiagID) + << Sel<< isClassMessage << MatchedSel + << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString()); + else + Diag(SelLoc, DiagID) << Sel<< isClassMessage << MatchedSel; } else Diag(SelLoc, DiagID) @@ -1327,9 +1334,15 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, SelectorLocs.back()); // Find the class to which we are sending this message. if (ReceiverType->isObjCObjectPointerType()) { - if (ObjCInterfaceDecl *Class = - ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) - Diag(Class->getLocation(), diag::note_receiver_class_declared); + if (ObjCInterfaceDecl *ThisClass = + ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) { + Diag(ThisClass->getLocation(), diag::note_receiver_class_declared); + if (!RecRange.isInvalid()) + if (ThisClass->lookupClassMethod(Sel)) + Diag(RecRange.getBegin(),diag::note_receiver_expr_here) + << FixItHint::CreateReplacement(RecRange, + ThisClass->getNameAsString()); + } } } @@ -1400,7 +1413,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, param); - ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, argExpr); + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr); if (ArgE.isInvalid()) IsError = true; else @@ -1434,7 +1447,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, // Do additional checkings on method. IsError |= CheckObjCMethodCall( - Method, SelLoc, makeArrayRef<const Expr *>(Args.data(), Args.size())); + Method, SelLoc, makeArrayRef(Args.data(), Args.size())); return IsError; } @@ -1651,6 +1664,22 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); + // Special warning if member name used in a property-dot for a setter accessor + // does not use a property with same name; e.g. obj.X = ... for a property with + // name 'x'. + if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() + && !IFace->FindPropertyDeclaration(Member)) { + if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { + // Do not warn if user is using property-dot syntax to make call to + // user named setter. + if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter)) + Diag(MemberLoc, + diag::warn_property_access_suggest) + << MemberName << QualType(OPT, 0) << PDecl->getName() + << FixItHint::CreateReplacement(MemberLoc, PDecl->getName()); + } + } + if (Getter || Setter) { if (Super) return new (Context) @@ -1664,10 +1693,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Attempt to correct for typos in property names. - DeclFilterCCC<ObjCPropertyDecl> Validator; - if (TypoCorrection Corrected = CorrectTypo( - DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, - nullptr, nullptr, Validator, CTK_ErrorRecovery, IFace, false, OPT)) { + if (TypoCorrection Corrected = + CorrectTypo(DeclarationNameInfo(MemberName, MemberLoc), + LookupOrdinaryName, nullptr, nullptr, + llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), + CTK_ErrorRecovery, IFace, false, OPT)) { diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); @@ -1892,11 +1922,10 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } } - ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl()); - if (TypoCorrection Corrected = - CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - nullptr, Validator, CTK_ErrorRecovery, nullptr, false, - nullptr, false)) { + if (TypoCorrection Corrected = CorrectTypo( + Result.getLookupNameInfo(), Result.getLookupKind(), S, nullptr, + llvm::make_unique<ObjCInterfaceOrSuperCCC>(getCurMethodDecl()), + CTK_ErrorRecovery, nullptr, false, nullptr, false)) { if (Corrected.isKeyword()) { // If we've found the keyword "super" (the only keyword that would be // returned by CorrectTypo), this is a send to super. @@ -2034,6 +2063,45 @@ static void checkCocoaAPI(Sema &S, const ObjCMessageExpr *Msg) { edit::rewriteObjCRedundantCallWithLiteral); } +/// \brief Diagnose use of %s directive in an NSString which is being passed +/// as formatting string to formatting method. +static void +DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, + ObjCMethodDecl *Method, + Selector Sel, + Expr **Args, unsigned NumArgs) { + unsigned Idx = 0; + bool Format = false; + ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily(); + if (SFFamily == ObjCStringFormatFamily::SFF_NSString) { + Idx = 0; + Format = true; + } + else if (Method) { + for (const auto *I : Method->specific_attrs<FormatAttr>()) { + if (S.GetFormatNSStringIdx(I, Idx)) { + Format = true; + break; + } + } + } + if (!Format || NumArgs <= Idx) + return; + + Expr *FormatExpr = Args[Idx]; + if (ObjCStringLiteral *OSL = + dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) { + StringLiteral *FormatString = OSL->getString(); + if (S.FormatStringHasSArg(FormatString)) { + S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) + << "%s" << 0 << 0; + if (Method) + S.Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + } + } +} + /// \brief Build an Objective-C class message expression. /// /// This routine takes care of both normal class messages and @@ -2146,7 +2214,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), Sel, SelectorLocs, Method, true, - SuperLoc.isValid(), LBracLoc, RBracLoc, + SuperLoc.isValid(), LBracLoc, RBracLoc, + SourceRange(), ReturnType, VK)) return ExprError(); @@ -2154,7 +2223,32 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, RequireCompleteType(LBracLoc, Method->getReturnType(), diag::err_illegal_message_expr_incomplete_type)) return ExprError(); - + + // Warn about explicit call of +initialize on its own class. But not on 'super'. + if (Method && Method->getMethodFamily() == OMF_initialize) { + if (!SuperLoc.isValid()) { + const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()); + if (ID == Class) { + Diag(Loc, diag::warn_direct_initialize_call); + Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + } + } + else if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + // [super initialize] is allowed only within an +initialize implementation + if (CurMeth->getMethodFamily() != OMF_initialize) { + Diag(Loc, diag::warn_direct_super_initialize_call); + Diag(Method->getLocation(), diag::note_method_declared_at) + << Method->getDeclName(); + Diag(CurMeth->getLocation(), diag::note_method_declared_at) + << CurMeth->getDeclName(); + } + } + } + + DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); + // Construct the appropriate ObjCMessageExpr. ObjCMessageExpr *Result; if (SuperLoc.isValid()) @@ -2354,11 +2448,19 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LBracLoc,RBracLoc), receiverIsId); + if (Method) { + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; + if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod())) + DiagnoseUseOfDecl(Method, SelLoc); + } } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. - // We allow sending a message to a qualified Class ("Class<foo>"), which - // is ok as long as one of the protocols implements the selector (if not, warn). + // We allow sending a message to a qualified Class ("Class<foo>"), which + // is ok as long as one of the protocols implements the selector (if not, + // warn). if (const ObjCObjectPointerType *QClassTy = ReceiverType->getAsObjCQualifiedClassType()) { // Search protocols for class methods. @@ -2405,6 +2507,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Sel << SourceRange(LBracLoc, RBracLoc); } } + if (Method) + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; } } } @@ -2543,7 +2649,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), Sel, SelectorLocs, Method, ClassMessage, SuperLoc.isValid(), - LBracLoc, RBracLoc, ReturnType, VK)) + LBracLoc, RBracLoc, RecRange, ReturnType, VK)) return ExprError(); if (Method && !Method->getReturnType()->isVoidType() && @@ -2568,6 +2674,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_mutableCopy: case OMF_new: case OMF_self: + case OMF_initialize: break; case OMF_dealloc: @@ -2630,6 +2737,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } + DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs); + // Construct the appropriate ObjCMessageExpr instance. ObjCMessageExpr *Result; if (SuperLoc.isValid()) @@ -3296,6 +3405,9 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { HadTheAttribute = true; + if (Parm->isStr("id")) + return true; + NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 06ca9ae..569ef30 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -466,11 +466,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, // members in the aggregate, then each member not explicitly initialized // shall be initialized from its brace-or-equal-initializer [...] if (Field->hasInClassInitializer()) { - Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, Loc, Field); + ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field); + if (DIE.isInvalid()) { + hadError = true; + return; + } if (Init < NumInits) - ILE->setInit(Init, DIE); + ILE->setInit(Init, DIE.get()); else { - ILE->updateInit(SemaRef.Context, Init, DIE); + ILE->updateInit(SemaRef.Context, Init, DIE.get()); RequiresSecondPass = true; } return; @@ -1555,10 +1559,11 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } } - // Value-initialize the first named member of the union. + // Value-initialize the first member of the union that isn't an unnamed + // bitfield. for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { - if (Field->getDeclName()) { + if (!Field->isUnnamedBitfield()) { if (VerifyOnly) CheckEmptyInitializable( InitializedEntity::InitializeMember(*Field, &Entity), @@ -1734,24 +1739,6 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, &Replacements[0] + Replacements.size()); } -/// \brief Given an implicit anonymous field, search the IndirectField that -/// corresponds to FieldName. -static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, - IdentifierInfo *FieldName) { - if (!FieldName) - return nullptr; - - assert(AnonField->isAnonymousStructOrUnion()); - Decl *NextDecl = AnonField->getNextDeclInContext(); - while (IndirectFieldDecl *IF = - dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) { - if (FieldName == IF->getAnonField()->getIdentifier()) - return IF; - NextDecl = NextDecl->getNextDeclInContext(); - } - return nullptr; -} - static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, DesignatedInitExpr *DIE) { unsigned NumIndexExprs = DIE->getNumSubExprs() - 1; @@ -1892,103 +1879,76 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return true; } - // Note: we perform a linear search of the fields here, despite - // the fact that we have a faster lookup method, because we always - // need to compute the field's index. FieldDecl *KnownField = D->getField(); - IdentifierInfo *FieldName = D->getFieldName(); - unsigned FieldIndex = 0; - RecordDecl::field_iterator - Field = RT->getDecl()->field_begin(), - FieldEnd = RT->getDecl()->field_end(); - for (; Field != FieldEnd; ++Field) { - if (Field->isUnnamedBitfield()) - continue; - - // If we find a field representing an anonymous field, look in the - // IndirectFieldDecl that follow for the designated initializer. - if (!KnownField && Field->isAnonymousStructOrUnion()) { - if (IndirectFieldDecl *IF = - FindIndirectFieldDesignator(*Field, FieldName)) { + if (!KnownField) { + IdentifierInfo *FieldName = D->getFieldName(); + DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + for (NamedDecl *ND : Lookup) { + if (auto *FD = dyn_cast<FieldDecl>(ND)) { + KnownField = FD; + break; + } + if (auto *IFD = dyn_cast<IndirectFieldDecl>(ND)) { // In verify mode, don't modify the original. if (VerifyOnly) DIE = CloneDesignatedInitExpr(SemaRef, DIE); - ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IF); + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, IFD); D = DIE->getDesignator(DesigIdx); + KnownField = cast<FieldDecl>(*IFD->chain_begin()); break; } } - if (KnownField && KnownField == *Field) - break; - if (FieldName && FieldName == Field->getIdentifier()) - break; - - ++FieldIndex; - } + if (!KnownField) { + if (VerifyOnly) { + ++Index; + return true; // No typo correction when just trying this out. + } - if (Field == FieldEnd) { - if (VerifyOnly) { - ++Index; - return true; // No typo correction when just trying this out. - } + // Name lookup found something, but it wasn't a field. + if (!Lookup.empty()) { + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) + << FieldName; + SemaRef.Diag(Lookup.front()->getLocation(), + diag::note_field_designator_found); + ++Index; + return true; + } - // 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), - // may find nothing, or may find a member of an anonymous - // struct/union. - DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); - FieldDecl *ReplacementField = nullptr; - if (Lookup.empty()) { - // Name lookup didn't find anything. Determine whether this - // was a typo for another field name. - FieldInitializerValidatorCCC Validator(RT->getDecl()); + // Name lookup didn't find anything. + // Determine whether this was a typo for another field name. if (TypoCorrection Corrected = SemaRef.CorrectTypo( DeclarationNameInfo(FieldName, D->getFieldLoc()), - Sema::LookupMemberName, /*Scope=*/ nullptr, /*SS=*/ nullptr, - Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) { + Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, + llvm::make_unique<FieldInitializerValidatorCCC>(RT->getDecl()), + Sema::CTK_ErrorRecovery, RT->getDecl())) { SemaRef.diagnoseTypo( Corrected, SemaRef.PDiag(diag::err_field_designator_unknown_suggest) - << FieldName << CurrentObjectType); - ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>(); + << FieldName << CurrentObjectType); + KnownField = Corrected.getCorrectionDeclAs<FieldDecl>(); hadError = true; } else { + // Typo correction didn't find anything. SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; ++Index; return true; } } + } - if (!ReplacementField) { - // Name lookup found something, but it wasn't a field. - SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) - << FieldName; - SemaRef.Diag(Lookup.front()->getLocation(), - diag::note_field_designator_found); - ++Index; - return true; - } - - if (!KnownField) { - // The replacement field comes from typo correction; find it - // in the list of fields. - FieldIndex = 0; - Field = RT->getDecl()->field_begin(); - for (; Field != FieldEnd; ++Field) { - if (Field->isUnnamedBitfield()) - continue; - - if (ReplacementField == *Field || - Field->getIdentifier() == ReplacementField->getIdentifier()) - break; - - ++FieldIndex; - } - } + unsigned FieldIndex = 0; + for (auto *FI : RT->getDecl()->fields()) { + if (FI->isUnnamedBitfield()) + continue; + if (KnownField == FI) + break; + ++FieldIndex; } + RecordDecl::field_iterator Field = + RecordDecl::field_iterator(DeclContext::decl_iterator(KnownField)); + // All of the fields of a union are located at the same place in // the initializer list. if (RT->getDecl()->isUnion()) { @@ -5537,18 +5497,18 @@ static void performLifetimeExtension(Expr *Init, static bool performReferenceExtension(Expr *Init, const InitializedEntity *ExtendingEntity) { - if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) { - // This is just redundant braces around an initializer. Step over it. - Init = ILE->getInit(0); - } - } - // Walk past any constructs which we can lifetime-extend across. Expr *Old; do { Old = Init; + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + if (ILE->getNumInits() == 1 && ILE->isGLValue()) { + // This is just redundant braces around an initializer. Step over it. + Init = ILE->getInit(0); + } + } + // Step over any subobject adjustments; we may have a materialized // temporary inside them. SmallVector<const Expr *, 2> CommaLHSs; @@ -6476,12 +6436,45 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, return diagnoseListInit(S, HiddenArray, InitList); } + if (DestType->isReferenceType()) { + // A list-initialization failure for a reference means that we tried to + // create a temporary of the inner type (per [dcl.init.list]p3.6) and the + // inner initialization failed. + QualType T = DestType->getAs<ReferenceType>()->getPointeeType(); + diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList); + SourceLocation Loc = InitList->getLocStart(); + if (auto *D = Entity.getDecl()) + Loc = D->getLocation(); + S.Diag(Loc, diag::note_in_reference_temporary_list_initializer) << T; + return; + } + InitListChecker DiagnoseInitList(S, Entity, InitList, DestType, /*VerifyOnly=*/false); assert(DiagnoseInitList.HadError() && "Inconsistent init list check result."); } +/// Prints a fixit for adding a null initializer for |Entity|. Call this only +/// right after emitting a diagnostic. +static void maybeEmitZeroInitializationFixit(Sema &S, + InitializationSequence &Sequence, + const InitializedEntity &Entity) { + if (Entity.getKind() != InitializedEntity::EK_Variable) + return; + + VarDecl *VD = cast<VarDecl>(Entity.getDecl()); + if (VD->getInit() || VD->getLocEnd().isMacroID()) + return; + + QualType VariableTy = VD->getType().getCanonicalType(); + SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd()); + std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); + + S.Diag(Loc, diag::note_add_initializer) + << VD << FixItHint::CreateInsertion(Loc, Init); +} + bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -6812,7 +6805,8 @@ bool InitializationSequence::Diagnose(Sema &S, << Entity.getName(); } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) - << DestType << (bool)DestType->getAs<RecordType>(); + << DestType << (bool)DestType->getAs<RecordType>(); + maybeEmitZeroInitializationFixit(S, *this, Entity); } break; diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 0cf4ed7..90a81f4 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -617,7 +617,7 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { // If it was ever a placeholder, it had to been deduced to DependentTy. assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType()); - // C++ Core Issue #975, proposed resolution: + // C++ core issue 975: // If a lambda-expression does not include a trailing-return-type, // it is as if the trailing-return-type denotes the following type: // - if there are no return statements in the compound-statement, @@ -631,6 +631,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { // same, that common type; // - otherwise, the program is ill-formed. // + // C++ core issue 1048 additionally removes top-level cv-qualifiers + // from the types of returned expressions to match the C++14 auto + // deduction rules. + // // In addition, in blocks in non-C++ modes, if all of the return // statements are enumerator-like expressions of some type T, where // T has a name for linkage, then we infer the return type of the @@ -679,7 +683,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { const ReturnStmt *RS = *I; const Expr *RetE = RS->getRetValue(); - QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy); + QualType ReturnType = + (RetE ? RetE->getType() : Context.VoidTy).getUnqualifiedType(); if (Context.hasSameType(ReturnType, CSI.ReturnType)) continue; @@ -873,7 +878,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // We don't do this before C++1y, because we don't support deduced return // types there. QualType DefaultTypeForNoTrailingReturn = - getLangOpts().CPlusPlus1y ? Context.getAutoDeductType() + getLangOpts().CPlusPlus14 ? Context.getAutoDeductType() : Context.DependentTy; QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI); @@ -999,7 +1004,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, VarDecl *Var = nullptr; if (C->Init.isUsable()) { - Diag(C->Loc, getLangOpts().CPlusPlus1y + Diag(C->Loc, getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_init_capture : diag::ext_init_capture); @@ -1049,8 +1054,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (R.empty()) { // FIXME: Disable corrections that would add qualification? CXXScopeSpec ScopeSpec; - DeclFilterCCC<VarDecl> Validator; - if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator)) + if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, + llvm::make_unique<DeclFilterCCC<VarDecl>>())) continue; } @@ -1062,7 +1067,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. - if (!CaptureNames.insert(C->Id)) { + if (!CaptureNames.insert(C->Id).second) { if (Var && LSI->isCaptured(Var)) { Diag(C->Loc, diag::err_capture_more_than_once) << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) @@ -1414,6 +1419,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, /*isImplicit=*/true)); continue; } + if (From.isVLATypeCapture()) { + Captures.push_back( + LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType)); + CaptureInits.push_back(nullptr); + continue; + } VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; @@ -1451,7 +1462,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, // different machinery. // FIXME: Refactor and Merge the return type deduction machinery. // FIXME: Assumes current resolution to core issue 975. - if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus1y) { + if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus14) { deduceClosureReturnType(*LSI); // - if there are no return statements in the diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index fe2c816..3445264 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -128,7 +128,7 @@ namespace { // that contexts be visited from the inside out in order to get // the effective DCs right. void visit(DeclContext *DC, DeclContext *EffectiveDC) { - if (!visited.insert(DC)) + if (!visited.insert(DC).second) return; addUsingDirectives(DC, EffectiveDC); @@ -139,7 +139,7 @@ namespace { // were declared in the effective DC. void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { DeclContext *NS = UD->getNominatedNamespace(); - if (!visited.insert(NS)) + if (!visited.insert(NS).second) return; addUsingDirective(UD, EffectiveDC); @@ -154,7 +154,7 @@ namespace { while (true) { for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); - if (visited.insert(NS)) { + if (visited.insert(NS).second) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } @@ -285,7 +285,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, } void LookupResult::configure() { - IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus, + IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation @@ -296,7 +296,7 @@ void LookupResult::configure() { case OO_Delete: case OO_Array_New: case OO_Array_Delete: - SemaRef.DeclareGlobalNewDelete(); + getSema().DeclareGlobalNewDelete(); break; default: @@ -307,7 +307,7 @@ void LookupResult::configure() { // up being declared. if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { if (unsigned BuiltinID = Id->getBuiltinID()) { - if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) AllowHidden = true; } } @@ -400,8 +400,8 @@ void LookupResult::resolveKind() { // canonical type. if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) { if (!TD->getDeclContext()->isRecord()) { - QualType T = SemaRef.Context.getTypeDeclType(TD); - if (!UniqueTypes.insert(SemaRef.Context.getCanonicalType(T))) { + QualType T = getSema().Context.getTypeDeclType(TD); + if (!UniqueTypes.insert(getSema().Context.getCanonicalType(T)).second) { // The type is not unique; pull something off the back and continue // at this index. Decls[I] = Decls[--N]; @@ -410,7 +410,7 @@ void LookupResult::resolveKind() { } } - if (!Unique.insert(D)) { + if (!Unique.insert(D).second) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; @@ -735,8 +735,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // FIXME: Calling convention! FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); - EPI.ExceptionSpecType = EST_None; - EPI.NumExceptions = 0; + EPI.ExceptionSpec = EST_None; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), None, EPI); @@ -1176,21 +1175,8 @@ static Module *getDefiningModule(Decl *Entity) { if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Entity)) { - // If it's a class template specialization, find the template or partial - // specialization from which it was instantiated. - if (ClassTemplateSpecializationDecl *SpecRD = - dyn_cast<ClassTemplateSpecializationDecl>(RD)) { - llvm::PointerUnion<ClassTemplateDecl*, - ClassTemplatePartialSpecializationDecl*> From = - SpecRD->getInstantiatedFrom(); - if (ClassTemplateDecl *FromTemplate = From.dyn_cast<ClassTemplateDecl*>()) - Entity = FromTemplate->getTemplatedDecl(); - else if (From) - Entity = From.get<ClassTemplatePartialSpecializationDecl*>(); - // Otherwise, it's an explicit specialization. - } else if (MemberSpecializationInfo *MSInfo = - RD->getMemberSpecializationInfo()) - Entity = getInstantiatedFrom(RD, MSInfo); + if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern()) + Entity = Pattern; } else if (EnumDecl *ED = dyn_cast<EnumDecl>(Entity)) { if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo()) Entity = getInstantiatedFrom(ED, MSInfo); @@ -1279,7 +1265,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { - return findAcceptableDecl(SemaRef, D); + return findAcceptableDecl(getSema(), D); } /// @brief Perform unqualified name lookup starting from a given @@ -1466,7 +1452,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, // with its using-children. for (auto *I : UsingDirectives) { NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); - if (Visited.insert(ND)) + if (Visited.insert(ND).second) Queue.push_back(ND); } @@ -1514,7 +1500,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, for (auto I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); - if (Visited.insert(Nom)) + if (Visited.insert(Nom).second) Queue.push_back(Nom); } } @@ -1776,6 +1762,31 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, return true; } +/// \brief Performs qualified name lookup or special type of lookup for +/// "__super::" scope specifier. +/// +/// This routine is a convenience overload meant to be called from contexts +/// that need to perform a qualified name lookup with an optional C++ scope +/// specifier that might require special kind of lookup. +/// +/// \param R captures both the lookup criteria and any lookup results found. +/// +/// \param LookupCtx The context in which qualified name lookup will +/// search. +/// +/// \param SS An optional C++ scope-specifier. +/// +/// \returns true if lookup succeeded, false if it failed. +bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + CXXScopeSpec &SS) { + auto *NNS = SS.getScopeRep(); + if (NNS && NNS->getKind() == NestedNameSpecifier::Super) + return LookupInSuper(R, NNS->getAsRecordDecl()); + else + + return LookupQualifiedName(R, LookupCtx); +} + /// @brief Performs name lookup for a name that was parsed in the /// source code, and may contain a C++ scope specifier. /// @@ -1783,7 +1794,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// contexts that receive a name and an optional C++ scope specifier /// (e.g., "N::M::x"). It will then perform either qualified or /// unqualified name lookup (with LookupQualifiedName or LookupName, -/// respectively) on the given name and return those results. +/// respectively) on the given name and return those results. It will +/// perform a special type of lookup for "__super::" scope specifier. /// /// @param S The scope from which unqualified name lookup will /// begin. @@ -1803,6 +1815,10 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, } if (SS && SS->isSet()) { + NestedNameSpecifier *NNS = SS->getScopeRep(); + if (NNS->getKind() == NestedNameSpecifier::Super) + return LookupInSuper(R, NNS->getAsRecordDecl()); + if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. @@ -1825,6 +1841,30 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, return LookupName(R, S, AllowBuiltinCreation); } +/// \brief Perform qualified name lookup into all base classes of the given +/// class. +/// +/// \param R captures both the lookup criteria and any lookup results found. +/// +/// \param Class The context in which qualified name lookup will +/// search. Name lookup will search in all base classes merging the results. +/// +/// @returns True if any decls were found (but possibly ambiguous) +bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { + for (const auto &BaseSpec : Class->bases()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>( + BaseSpec.getType()->castAs<RecordType>()->getDecl()); + LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); + Result.setBaseObjectType(Context.getRecordType(Class)); + LookupQualifiedName(Result, RD); + for (auto *Decl : Result) + R.addDecl(Decl); + } + + R.resolveKind(); + + return !R.empty(); +} /// \brief Produce a diagnostic describing the ambiguity that resulted /// from name lookup. @@ -2024,7 +2064,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // FIXME: That's not correct, we may have added this class only because it // was the enclosing class of another class, and in that case we won't have // added its base classes yet. - if (!Result.Classes.insert(Class)) + if (!Result.Classes.insert(Class).second) return; // -- If T is a template-id, its associated namespaces and classes are @@ -2073,7 +2113,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (Result.Classes.insert(BaseDecl)) { + if (Result.Classes.insert(BaseDecl).second) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); @@ -2875,7 +2915,7 @@ public: /// \brief Determine whether we have already visited this context /// (and, if not, note that we are going to visit that context now). bool visitedContext(DeclContext *Ctx) { - return !VisitedContexts.insert(Ctx); + return !VisitedContexts.insert(Ctx).second; } bool alreadyVisitedContext(DeclContext *Ctx) { @@ -3263,6 +3303,49 @@ static void LookupPotentialTypoResult(Sema &SemaRef, bool isObjCIvarLookup, bool FindHidden); +/// \brief Check whether the declarations found for a typo correction are +/// visible, and if none of them are, convert the correction to an 'import +/// a module' correction. +static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { + if (TC.begin() == TC.end()) + return; + + TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end(); + + for (/**/; DI != DE; ++DI) + if (!LookupResult::isVisible(SemaRef, *DI)) + break; + // Nothing to do if all decls are visible. + if (DI == DE) + return; + + llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI); + bool AnyVisibleDecls = !NewDecls.empty(); + + for (/**/; DI != DE; ++DI) { + NamedDecl *VisibleDecl = *DI; + if (!LookupResult::isVisible(SemaRef, *DI)) + VisibleDecl = findAcceptableDecl(SemaRef, *DI); + + if (VisibleDecl) { + if (!AnyVisibleDecls) { + // Found a visible decl, discard all hidden ones. + AnyVisibleDecls = true; + NewDecls.clear(); + } + NewDecls.push_back(VisibleDecl); + } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate()) + NewDecls.push_back(*DI); + } + + if (NewDecls.empty()) + TC = TypoCorrection(); + else { + TC.setCorrectionDecls(NewDecls); + TC.setRequiresImport(!AnyVisibleDecls); + } +} + // Fill the supplied vector with the IdentifierInfo pointers for each piece of // the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", // fill the vector with the IdentifierInfo pointers for "foo" and "bar"). @@ -3297,6 +3380,7 @@ static void getNestedNameSpecifierIdentifiers( break; case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return; } @@ -3304,157 +3388,6 @@ static void getNestedNameSpecifierIdentifiers( Identifiers.push_back(II); } -namespace { - -static const unsigned MaxTypoDistanceResultSets = 5; - -class TypoCorrectionConsumer : public VisibleDeclConsumer { - typedef SmallVector<TypoCorrection, 1> TypoResultList; - typedef llvm::StringMap<TypoResultList> TypoResultsMap; - typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; - -public: - explicit TypoCorrectionConsumer(Sema &SemaRef, - const DeclarationNameInfo &TypoName, - Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - CorrectionCandidateCallback &CCC, - DeclContext *MemberContext, - bool EnteringContext) - : Typo(TypoName.getName().getAsIdentifierInfo()), SemaRef(SemaRef), S(S), - SS(SS), CorrectionValidator(CCC), MemberContext(MemberContext), - Result(SemaRef, TypoName, LookupKind), - Namespaces(SemaRef.Context, SemaRef.CurContext, SS), - EnteringContext(EnteringContext), SearchNamespaces(false) { - Result.suppressDiagnostics(); - } - - bool includeHiddenDecls() const override { return true; } - - // Methods for adding potential corrections to the consumer. - void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, - bool InBaseClass) override; - void FoundName(StringRef Name); - void addKeywordResult(StringRef Keyword); - void addCorrection(TypoCorrection Correction); - - bool empty() const { return CorrectionResults.empty(); } - - /// \brief Return the list of TypoCorrections for the given identifier from - /// the set of corrections that have the closest edit distance, if any. - TypoResultList &operator[](StringRef Name) { - return CorrectionResults.begin()->second[Name]; - } - - /// \brief Return the edit distance of the corrections that have the - /// closest/best edit distance from the original typop. - unsigned getBestEditDistance(bool Normalized) { - if (CorrectionResults.empty()) - return (std::numeric_limits<unsigned>::max)(); - - unsigned BestED = CorrectionResults.begin()->first; - return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; - } - - /// \brief Set-up method to add to the consumer the set of namespaces to use - /// in performing corrections to nested name specifiers. This method also - /// implicitly adds all of the known classes in the current AST context to the - /// to the consumer for correcting nested name specifiers. - void - addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces); - - /// \brief Return the next typo correction that passes all internal filters - /// and is deemed valid by the consumer's CorrectionCandidateCallback, - /// starting with the corrections that have the closest edit distance. An - /// empty TypoCorrection is returned once no more viable corrections remain - /// in the consumer. - TypoCorrection getNextCorrection(); - -private: - class NamespaceSpecifierSet { - struct SpecifierInfo { - DeclContext* DeclCtx; - NestedNameSpecifier* NameSpecifier; - unsigned EditDistance; - }; - - typedef SmallVector<DeclContext*, 4> DeclContextList; - typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; - - ASTContext &Context; - DeclContextList CurContextChain; - std::string CurNameSpecifier; - SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers; - SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers; - bool isSorted; - - SpecifierInfoList Specifiers; - llvm::SmallSetVector<unsigned, 4> Distances; - llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap; - - /// \brief Helper for building the list of DeclContexts between the current - /// context and the top of the translation unit - static DeclContextList buildContextChain(DeclContext *Start); - - void sortNamespaces(); - - unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, - NestedNameSpecifier *&NNS); - - public: - NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, - CXXScopeSpec *CurScopeSpec); - - /// \brief Add the DeclContext (a namespace or record) to the set, computing - /// the corresponding NestedNameSpecifier and its distance in the process. - void addNameSpecifier(DeclContext *Ctx); - - typedef SpecifierInfoList::iterator iterator; - iterator begin() { - if (!isSorted) sortNamespaces(); - return Specifiers.begin(); - } - iterator end() { return Specifiers.end(); } - }; - - void addName(StringRef Name, NamedDecl *ND, - NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); - - /// \brief Find any visible decls for the given typo correction candidate. - /// If none are found, it to the set of candidates for which qualified lookups - /// will be performed to find possible nested name specifier changes. - bool resolveCorrection(TypoCorrection &Candidate); - - /// \brief Perform qualified lookups on the queued set of typo correction - /// candidates and add the nested name specifier changes to each candidate if - /// a lookup succeeds (at which point the candidate will be returned to the - /// main pool of potential corrections). - void performQualifiedLookups(); - - /// \brief The name written that is a typo in the source. - IdentifierInfo *Typo; - - /// \brief The results found that have the smallest edit distance - /// found (so far) with the typo name. - /// - /// The pointer value being set to the current DeclContext indicates - /// whether there is a keyword with this name. - TypoEditDistanceMap CorrectionResults; - - Sema &SemaRef; - Scope *S; - CXXScopeSpec *SS; - CorrectionCandidateCallback &CorrectionValidator; - DeclContext *MemberContext; - LookupResult Result; - NamespaceSpecifierSet Namespaces; - SmallVector<TypoCorrection, 2> QualifiedResults; - bool EnteringContext; - bool SearchNamespaces; -}; - -} - void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. @@ -3506,9 +3439,12 @@ void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED); if (isKeyword) TC.makeKeyword(); + TC.setCorrectionRange(nullptr, Result.getLookupNameInfo()); addCorrection(TC); } +static const unsigned MaxTypoDistanceResultSets = 5; + void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef TypoStr = Typo->getName(); StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); @@ -3521,9 +3457,11 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { return; // If the correction is resolved but is not viable, ignore it. - if (Correction.isResolved() && - !isCandidateViable(CorrectionValidator, Correction)) - return; + if (Correction.isResolved()) { + checkCorrectionVisibility(SemaRef, Correction); + if (!Correction || !isCandidateViable(*CorrectionValidator, Correction)) + return; + } TypoResultList &CList = CorrectionResults[Correction.getEditDistance(false)][Name]; @@ -3577,7 +3515,11 @@ void TypoCorrectionConsumer::addNamespaces( } } -TypoCorrection TypoCorrectionConsumer::getNextCorrection() { +const TypoCorrection &TypoCorrectionConsumer::getNextCorrection() { + if (++CurrentTCIndex < ValidatedCorrections.size()) + return ValidatedCorrections[CurrentTCIndex]; + + CurrentTCIndex = ValidatedCorrections.size(); while (!CorrectionResults.empty()) { auto DI = CorrectionResults.begin(); if (DI->second.empty()) { @@ -3593,20 +3535,22 @@ TypoCorrection TypoCorrectionConsumer::getNextCorrection() { } TypoCorrection TC = RI->second.pop_back_val(); - if (TC.isResolved() || resolveCorrection(TC)) - return TC; + if (TC.isResolved() || TC.requiresImport() || resolveCorrection(TC)) { + ValidatedCorrections.push_back(TC); + return ValidatedCorrections[CurrentTCIndex]; + } } - return TypoCorrection(); + return ValidatedCorrections[0]; // The empty correction. } bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) { IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo(); DeclContext *TempMemberContext = MemberContext; - CXXScopeSpec *TempSS = SS; + CXXScopeSpec *TempSS = SS.get(); retry_lookup: LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext, EnteringContext, - CorrectionValidator.IsObjCIvarLookup, + CorrectionValidator->IsObjCIvarLookup, Name == Typo && !Candidate.WillReplaceSpecifier()); switch (Result.getResultKind()) { case LookupResult::NotFound: @@ -3620,7 +3564,7 @@ retry_lookup: } if (TempMemberContext) { if (SS && !TempSS) - TempSS = SS; + TempSS = SS.get(); TempMemberContext = nullptr; goto retry_lookup; } @@ -3637,11 +3581,13 @@ retry_lookup: // Store all of the Decls for overloaded symbols for (auto *TRD : Result) Candidate.addCorrectionDecl(TRD); - if (!isCandidateViable(CorrectionValidator, Candidate)) { + checkCorrectionVisibility(SemaRef, Candidate); + if (!isCandidateViable(*CorrectionValidator, Candidate)) { if (SearchNamespaces) QualifiedResults.push_back(Candidate); break; } + Candidate.setCorrectionRange(TempSS, Result.getLookupNameInfo()); return true; } return false; @@ -3707,8 +3653,10 @@ void TypoCorrectionConsumer::performQualifiedLookups() { TRD.getPair()) == Sema::AR_accessible) TC.addCorrectionDecl(*TRD); } - if (TC.isResolved()) + if (TC.isResolved()) { + TC.setCorrectionRange(SS.get(), Result.getLookupNameInfo()); addCorrection(TC); + } break; } case LookupResult::NotFound: @@ -3856,8 +3804,8 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); NumSpecifiers = llvm::ComputeEditDistance( - ArrayRef<const IdentifierInfo *>(CurNameSpecifierIdentifiers), - ArrayRef<const IdentifierInfo *>(NewNameSpecifierIdentifiers)); + llvm::makeArrayRef(CurNameSpecifierIdentifiers), + llvm::makeArrayRef(NewNameSpecifierIdentifiers)); } isSorted = false; @@ -3972,6 +3920,13 @@ static void AddKeywordsToConsumer(Sema &SemaRef, if (SemaRef.getLangOpts().GNUMode) Consumer.addKeywordResult("typeof"); + } else if (CCC.WantFunctionLikeCasts) { + static const char *const CastableTypeSpecs[] = { + "char", "double", "float", "int", "long", "short", + "signed", "unsigned", "void" + }; + for (auto *kw : CastableTypeSpecs) + Consumer.addKeywordResult(kw); } if (CCC.WantCXXNamedCasts && SemaRef.getLangOpts().CPlusPlus) { @@ -4063,212 +4018,96 @@ static void AddKeywordsToConsumer(Sema &SemaRef, } } -/// \brief Check whether the declarations found for a typo correction are -/// visible, and if none of them are, convert the correction to an 'import -/// a module' correction. -static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { - if (TC.begin() == TC.end()) - return; - - TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end(); - - for (/**/; DI != DE; ++DI) - if (!LookupResult::isVisible(SemaRef, *DI)) - break; - // Nothing to do if all decls are visible. - if (DI == DE) - return; - - llvm::SmallVector<NamedDecl*, 4> NewDecls(TC.begin(), DI); - bool AnyVisibleDecls = !NewDecls.empty(); - - for (/**/; DI != DE; ++DI) { - NamedDecl *VisibleDecl = *DI; - if (!LookupResult::isVisible(SemaRef, *DI)) - VisibleDecl = findAcceptableDecl(SemaRef, *DI); - - if (VisibleDecl) { - if (!AnyVisibleDecls) { - // Found a visible decl, discard all hidden ones. - AnyVisibleDecls = true; - NewDecls.clear(); - } - NewDecls.push_back(VisibleDecl); - } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate()) - NewDecls.push_back(*DI); - } - - if (NewDecls.empty()) - TC = TypoCorrection(); - else { - TC.setCorrectionDecls(NewDecls); - TC.setRequiresImport(!AnyVisibleDecls); - } -} - -/// \brief Try to "correct" a typo in the source code by finding -/// visible declarations whose names are similar to the name that was -/// present in the source code. -/// -/// \param TypoName the \c DeclarationNameInfo structure that contains -/// the name that was present in the source code along with its location. -/// -/// \param LookupKind the name-lookup criteria used to search for the name. -/// -/// \param S the scope in which name lookup occurs. -/// -/// \param SS the nested-name-specifier that precedes the name we're -/// looking for, if present. -/// -/// \param CCC A CorrectionCandidateCallback object that provides further -/// validation of typo correction candidates. It also provides flags for -/// determining the set of keywords permitted. -/// -/// \param MemberContext if non-NULL, the context in which to look for -/// a member access expression. -/// -/// \param EnteringContext whether we're entering the context described by -/// the nested-name-specifier SS. -/// -/// \param OPT when non-NULL, the search for visible declarations will -/// also walk the protocols in the qualified interfaces of \p OPT. -/// -/// \returns a \c TypoCorrection containing the corrected name if the typo -/// along with information such as the \c NamedDecl where the corrected name -/// was declared, and any additional \c NestedNameSpecifier needed to access -/// it (C++ only). The \c TypoCorrection is empty if there is no correction. -TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, - Sema::LookupNameKind LookupKind, - Scope *S, CXXScopeSpec *SS, - CorrectionCandidateCallback &CCC, - CorrectTypoKind Mode, - DeclContext *MemberContext, - bool EnteringContext, - const ObjCObjectPointerType *OPT, - bool RecordFailure) { - // Always let the ExternalSource have the first chance at correction, even - // if we would otherwise have given up. - if (ExternalSource) { - if (TypoCorrection Correction = ExternalSource->CorrectTypo( - TypoName, LookupKind, S, SS, CCC, MemberContext, EnteringContext, OPT)) - return Correction; - } +std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( + const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT, bool ErrorRecovery) { if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking || DisableTypoCorrection) - return TypoCorrection(); + return nullptr; // In Microsoft mode, don't perform typo correction in a template member // function dependent context because it interferes with the "lookup into // dependent bases of class templates" feature. if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && isa<CXXMethodDecl>(CurContext)) - return TypoCorrection(); + return nullptr; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) - return TypoCorrection(); + return nullptr; // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) - return TypoCorrection(); + return nullptr; // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) - return TypoCorrection(); + return nullptr; // Don't try to correct 'super'. if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) - return TypoCorrection(); + return nullptr; // Abort if typo correction already failed for this specific typo. IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo); if (locs != TypoCorrectionFailures.end() && locs->second.count(TypoName.getLoc())) - return TypoCorrection(); + return nullptr; // Don't try to correct the identifier "vector" when in AltiVec mode. // TODO: Figure out why typo correction misbehaves in this case, fix it, and // remove this workaround. if (getLangOpts().AltiVec && Typo->isStr("vector")) - return TypoCorrection(); + return nullptr; + + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + unsigned Limit = getDiagnostics().getDiagnosticOptions().SpellCheckingLimit; + if (Limit && TyposCorrected >= Limit) + return nullptr; + ++TyposCorrected; // If we're handling a missing symbol error, using modules, and the // special search all modules option is used, look for a missing import. - if ((Mode == CTK_ErrorRecovery) && getLangOpts().Modules && + if (ErrorRecovery && getLangOpts().Modules && getLangOpts().ModulesSearchAll) { // The following has the side effect of loading the missing module. getModuleLoader().lookupMissingImports(Typo->getName(), TypoName.getLocStart()); } - TypoCorrectionConsumer Consumer(*this, TypoName, LookupKind, S, SS, CCC, - MemberContext, EnteringContext); - - // If a callback object considers an empty typo correction candidate to be - // viable, assume it does not do any actual validation of the candidates. - TypoCorrection EmptyCorrection; - bool ValidatingCallback = !isCandidateViable(CCC, EmptyCorrection); + CorrectionCandidateCallback &CCCRef = *CCC; + auto Consumer = llvm::make_unique<TypoCorrectionConsumer>( + *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, + EnteringContext); // Perform name lookup to find visible, similarly-named entities. bool IsUnqualifiedLookup = false; DeclContext *QualifiedDC = MemberContext; if (MemberContext) { - LookupVisibleDecls(MemberContext, LookupKind, Consumer); + LookupVisibleDecls(MemberContext, LookupKind, *Consumer); // Look in qualified interfaces. if (OPT) { for (auto *I : OPT->quals()) - LookupVisibleDecls(I, LookupKind, Consumer); + LookupVisibleDecls(I, LookupKind, *Consumer); } } else if (SS && SS->isSet()) { QualifiedDC = computeDeclContext(*SS, EnteringContext); if (!QualifiedDC) - return TypoCorrection(); + return nullptr; - // Provide a stop gap for files that are just seriously broken. Trying - // to correct all typos can turn into a HUGE performance penalty, causing - // some files to take minutes to get rejected by the parser. - if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) - return TypoCorrection(); - ++TyposCorrected; - - LookupVisibleDecls(QualifiedDC, LookupKind, Consumer); + LookupVisibleDecls(QualifiedDC, LookupKind, *Consumer); } else { IsUnqualifiedLookup = true; - UnqualifiedTyposCorrectedMap::iterator Cached - = UnqualifiedTyposCorrected.find(Typo); - if (Cached != UnqualifiedTyposCorrected.end()) { - // Add the cached value, unless it's a keyword or fails validation. In the - // keyword case, we'll end up adding the keyword below. - if (Cached->second) { - if (!Cached->second.isKeyword() && - isCandidateViable(CCC, Cached->second)) { - // Do not use correction that is unaccessible in the given scope. - NamedDecl *CorrectionDecl = Cached->second.getCorrectionDecl(); - DeclarationNameInfo NameInfo(CorrectionDecl->getDeclName(), - CorrectionDecl->getLocation()); - LookupResult R(*this, NameInfo, LookupOrdinaryName); - if (LookupName(R, S)) - Consumer.addCorrection(Cached->second); - } - } else { - // Only honor no-correction cache hits when a callback that will validate - // correction candidates is not being used. - if (!ValidatingCallback) - return TypoCorrection(); - } - } - if (Cached == UnqualifiedTyposCorrected.end()) { - // Provide a stop gap for files that are just seriously broken. Trying - // to correct all typos can turn into a HUGE performance penalty, causing - // some files to take minutes to get rejected by the parser. - if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) - return TypoCorrection(); - } } // Determine whether we are going to search in the various namespaces for @@ -4276,17 +4115,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, bool SearchNamespaces = getLangOpts().CPlusPlus && (IsUnqualifiedLookup || (SS && SS->isSet())); - // In a few cases we *only* want to search for corrections based on just - // adding or changing the nested name specifier. - unsigned TypoLen = Typo->getName().size(); - bool AllowOnlyNNSChanges = TypoLen < 3; if (IsUnqualifiedLookup || SearchNamespaces) { // For unqualified lookup, look through all of the names that we have // seen in this translation unit. // FIXME: Re-add the ability to skip very unlikely potential corrections. for (const auto &I : Context.Idents) - Consumer.FoundName(I.getKey()); + Consumer->FoundName(I.getKey()); // Walk through identifiers in external identifier sources. // FIXME: Re-add the ability to skip very unlikely potential corrections. @@ -4298,24 +4133,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (Name.empty()) break; - Consumer.FoundName(Name); + Consumer->FoundName(Name); } while (true); } } - AddKeywordsToConsumer(*this, Consumer, S, CCC, SS && SS->isNotEmpty()); - - // If we haven't found anything, we're done. - if (Consumer.empty()) - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, - IsUnqualifiedLookup); - - // Make sure the best edit distance (prior to adding any namespace qualifiers) - // is not more that about a third of the length of the typo's identifier. - unsigned ED = Consumer.getBestEditDistance(true); - if (ED > 0 && TypoLen / ED < 3) - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, - IsUnqualifiedLookup); + AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty()); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. @@ -4329,22 +4152,99 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, KnownNamespaces[N] = true; } - Consumer.addNamespaces(KnownNamespaces); + Consumer->addNamespaces(KnownNamespaces); } - TypoCorrection BestTC = Consumer.getNextCorrection(); - TypoCorrection SecondBestTC = Consumer.getNextCorrection(); + return Consumer; +} + +/// \brief Try to "correct" a typo in the source code by finding +/// visible declarations whose names are similar to the name that was +/// present in the source code. +/// +/// \param TypoName the \c DeclarationNameInfo structure that contains +/// the name that was present in the source code along with its location. +/// +/// \param LookupKind the name-lookup criteria used to search for the name. +/// +/// \param S the scope in which name lookup occurs. +/// +/// \param SS the nested-name-specifier that precedes the name we're +/// looking for, if present. +/// +/// \param CCC A CorrectionCandidateCallback object that provides further +/// validation of typo correction candidates. It also provides flags for +/// determining the set of keywords permitted. +/// +/// \param MemberContext if non-NULL, the context in which to look for +/// a member access expression. +/// +/// \param EnteringContext whether we're entering the context described by +/// the nested-name-specifier SS. +/// +/// \param OPT when non-NULL, the search for visible declarations will +/// also walk the protocols in the qualified interfaces of \p OPT. +/// +/// \returns a \c TypoCorrection containing the corrected name if the typo +/// along with information such as the \c NamedDecl where the corrected name +/// was declared, and any additional \c NestedNameSpecifier needed to access +/// it (C++ only). The \c TypoCorrection is empty if there is no correction. +TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + CorrectTypoKind Mode, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT, + bool RecordFailure) { + assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback"); + + // Always let the ExternalSource have the first chance at correction, even + // if we would otherwise have given up. + if (ExternalSource) { + if (TypoCorrection Correction = ExternalSource->CorrectTypo( + TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT)) + return Correction; + } + + // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; + // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for + // some instances of CTC_Unknown, while WantRemainingKeywords is true + // for CTC_Unknown but not for CTC_ObjCMessageReceiver. + bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords; + + IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); + auto Consumer = makeTypoCorrectionConsumer( + TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, + EnteringContext, OPT, Mode == CTK_ErrorRecovery); + + if (!Consumer) + return TypoCorrection(); + + // If we haven't found anything, we're done. + if (Consumer->empty()) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); + + // Make sure the best edit distance (prior to adding any namespace qualifiers) + // is not more that about a third of the length of the typo's identifier. + unsigned ED = Consumer->getBestEditDistance(true); + unsigned TypoLen = Typo->getName().size(); + if (ED > 0 && TypoLen / ED < 3) + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); + + TypoCorrection BestTC = Consumer->getNextCorrection(); + TypoCorrection SecondBestTC = Consumer->getNextCorrection(); if (!BestTC) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); ED = BestTC.getEditDistance(); - if (!AllowOnlyNNSChanges && ED > 0 && TypoLen / ED < 3) { + if (TypoLen >= 3 && ED > 0 && TypoLen / ED < 3) { // If this was an unqualified lookup and we believe the callback // object wouldn't have filtered out possible corrections, note // that no correction was found. - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, - IsUnqualifiedLookup && !ValidatingCallback); + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); } // If only a single name remains, return that result. @@ -4357,28 +4257,19 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (ED == 0 && Result.isKeyword()) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); - // Record the correction for unqualified lookup. - if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] = Result; - TypoCorrection TC = Result; TC.setCorrectionRange(SS, TypoName); checkCorrectionVisibility(*this, TC); return TC; - } - // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; - // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for - // some instances of CTC_Unknown, while WantRemainingKeywords is true - // for CTC_Unknown but not for CTC_ObjCMessageReceiver. - else if (SecondBestTC && CCC.WantObjCSuper && !CCC.WantRemainingKeywords) { + } else if (SecondBestTC && ObjCMessageReceiver) { // Prefer 'super' when we're completing in a message-receiver // context. if (BestTC.getCorrection().getAsString() != "super") { if (SecondBestTC.getCorrection().getAsString() == "super") BestTC = SecondBestTC; - else if (Consumer["super"].front().isKeyword()) - BestTC = Consumer["super"].front(); + else if ((*Consumer)["super"].front().isKeyword()) + BestTC = (*Consumer)["super"].front(); } // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. @@ -4386,10 +4277,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, BestTC.getCorrection().getAsString() != "super") return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); - // Record the correction for unqualified lookup. - if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] = BestTC; - BestTC.setCorrectionRange(SS, TypoName); return BestTC; } @@ -4397,8 +4284,75 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // Record the failure's location if needed and return an empty correction. If // this was an unqualified lookup and we believe the callback object did not // filter out possible corrections, also cache the failure for the typo. - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, - IsUnqualifiedLookup && !ValidatingCallback); + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); +} + +/// \brief Try to "correct" a typo in the source code by finding +/// visible declarations whose names are similar to the name that was +/// present in the source code. +/// +/// \param TypoName the \c DeclarationNameInfo structure that contains +/// the name that was present in the source code along with its location. +/// +/// \param LookupKind the name-lookup criteria used to search for the name. +/// +/// \param S the scope in which name lookup occurs. +/// +/// \param SS the nested-name-specifier that precedes the name we're +/// looking for, if present. +/// +/// \param CCC A CorrectionCandidateCallback object that provides further +/// validation of typo correction candidates. It also provides flags for +/// determining the set of keywords permitted. +/// +/// \param TDG A TypoDiagnosticGenerator functor that will be used to print +/// diagnostics when the actual typo correction is attempted. +/// +/// \param TRC A TypoRecoveryCallback functor that will be used to build an +/// Expr from a typo correction candidate. +/// +/// \param MemberContext if non-NULL, the context in which to look for +/// a member access expression. +/// +/// \param EnteringContext whether we're entering the context described by +/// the nested-name-specifier SS. +/// +/// \param OPT when non-NULL, the search for visible declarations will +/// also walk the protocols in the qualified interfaces of \p OPT. +/// +/// \returns a new \c TypoExpr that will later be replaced in the AST with an +/// Expr representing the result of performing typo correction, or nullptr if +/// typo correction is not possible. If nullptr is returned, no diagnostics will +/// be emitted and it is the responsibility of the caller to emit any that are +/// needed. +TypoExpr *Sema::CorrectTypoDelayed( + const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + std::unique_ptr<CorrectionCandidateCallback> CCC, + TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT) { + assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); + + TypoCorrection Empty; + auto Consumer = makeTypoCorrectionConsumer( + TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, + EnteringContext, OPT, + /*SearchModules=*/(Mode == CTK_ErrorRecovery) && getLangOpts().Modules && + getLangOpts().ModulesSearchAll); + + if (!Consumer || Consumer->empty()) + return nullptr; + + // Make sure the best edit distance (prior to adding any namespace qualifiers) + // is not more that about a third of the length of the typo's identifier. + unsigned ED = Consumer->getBestEditDistance(true); + IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); + if (ED > 0 && Typo->getName().size() / ED < 3) + return nullptr; + + ExprEvalContexts.back().NumTypos++; + return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { @@ -4425,7 +4379,8 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { return CorrectionName.getAsString(); } -bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candidate) { +bool CorrectionCandidateCallback::ValidateCandidate( + const TypoCorrection &candidate) { if (!candidate.isResolved()) return true; @@ -4461,7 +4416,8 @@ FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, MemberExpr *ME) : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs), CurContext(SemaRef.CurContext), MemberFn(ME) { - WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus; + WantTypeSpecifiers = false; + WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus && NumArgs == 1; WantRemainingKeywords = false; } @@ -4596,3 +4552,26 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); } + +TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, + TypoDiagnosticGenerator TDG, + TypoRecoveryCallback TRC) { + assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); + auto TE = new (Context) TypoExpr(Context.DependentTy); + auto &State = DelayedTypos[TE]; + State.Consumer = std::move(TCC); + State.DiagHandler = std::move(TDG); + State.RecoveryHandler = std::move(TRC); + return TE; +} + +const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const { + auto Entry = DelayedTypos.find(TE); + assert(Entry != DelayedTypos.end() && + "Failed to get the state for a TypoExpr!"); + return Entry->second; +} + +void Sema::clearDelayedTypo(TypoExpr *TE) { + DelayedTypos.erase(TE); +} diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 8eb806b..72b6020 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -116,9 +116,9 @@ static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) { static void CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, ObjCProtocolDecl *Proto, - llvm::SmallPtrSet<ObjCProtocolDecl *, 16> &Known) { + llvm::SmallPtrSetImpl<ObjCProtocolDecl *> &Known) { // Have we seen this protocol before? - if (!Known.insert(Proto)) + if (!Known.insert(Proto).second) return; // Look for a property with the same name. @@ -1547,36 +1547,22 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, if (IMPDecl->getInstanceMethod(Prop->getSetterName())) continue; } - // If property to be implemented in the super class, ignore. - if (SuperPropMap[Prop->getIdentifier()]) { - ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()]; - if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && - (PropInSuperClass->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_readonly) && - !IMPDecl->getInstanceMethod(Prop->getSetterName()) && - !IDecl->HasUserDeclaredSetterMethod(Prop)) { - Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) - << Prop->getIdentifier(); - Diag(PropInSuperClass->getLocation(), diag::note_property_declare); - } - continue; - } if (ObjCPropertyImplDecl *PID = IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) { - if (PID->getPropertyDecl() != Prop) { - Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property) - << Prop->getIdentifier(); - if (!PID->getLocation().isInvalid()) - Diag(PID->getLocation(), diag::note_property_synthesize); - } + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property) + << Prop->getIdentifier(); + if (!PID->getLocation().isInvalid()) + Diag(PID->getLocation(), diag::note_property_synthesize); continue; } + ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()]; if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) { // We won't auto-synthesize properties declared in protocols. // Suppress the warning if class's superclass implements property's // getter and implements property's setter (if readwrite property). - if (!SuperClassImplementsProperty(IDecl, Prop)) { + // Or, if property is going to be implemented in its super class. + if (!SuperClassImplementsProperty(IDecl, Prop) && !PropInSuperClass) { Diag(IMPDecl->getLocation(), diag::warn_auto_synthesizing_protocol_property) << Prop << Proto; @@ -1584,7 +1570,25 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, } continue; } - + // If property to be implemented in the super class, ignore. + if (PropInSuperClass) { + if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && + (PropInSuperClass->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readonly) && + !IMPDecl->getInstanceMethod(Prop->getSetterName()) && + !IDecl->HasUserDeclaredSetterMethod(Prop)) { + Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) + << Prop->getIdentifier(); + Diag(PropInSuperClass->getLocation(), diag::note_property_declare); + } + else { + Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass) + << Prop->getIdentifier(); + Diag(PropInSuperClass->getLocation(), diag::note_property_declare); + Diag(IMPDecl->getLocation(), diag::note_while_in_implementation); + } + continue; + } // We use invalid SourceLocations for the synthesized ivars since they // aren't really synthesized at a particular location; they just exist. // Saying that they are located at the @implementation isn't really going diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 7f2af68..d72942a 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" @@ -91,15 +92,17 @@ private: DeclarationNameInfo DirectiveName; Scope *CurScope; SourceLocation ConstructLoc; + bool OrderedRegion; + SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc) {} + ConstructLoc(Loc), OrderedRegion(false), InnerTeamsRegionLoc() {} SharingMapTy() : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc() {} + ConstructLoc(), OrderedRegion(false), InnerTeamsRegionLoc() {} }; typedef SmallVector<SharingMapTy, 64> StackTy; @@ -194,13 +197,42 @@ public: return isOpenMPThreadPrivate(DVar.CKind); } + /// \brief Marks current region as ordered (it has an 'ordered' clause). + void setOrderedRegion(bool IsOrdered = true) { + Stack.back().OrderedRegion = IsOrdered; + } + /// \brief Returns true, if parent region is ordered (has associated + /// 'ordered' clause), false - otherwise. + bool isParentOrderedRegion() const { + if (Stack.size() > 2) + return Stack[Stack.size() - 2].OrderedRegion; + return false; + } + + /// \brief Marks current target region as one with closely nested teams + /// region. + void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { + if (Stack.size() > 2) + Stack[Stack.size() - 2].InnerTeamsRegionLoc = TeamsRegionLoc; + } + /// \brief Returns true, if current region has closely nested teams region. + bool hasInnerTeamsRegion() const { + return getInnerTeamsRegionLoc().isValid(); + } + /// \brief Returns location of the nested teams region (if any). + SourceLocation getInnerTeamsRegionLoc() const { + if (Stack.size() > 1) + return Stack.back().InnerTeamsRegionLoc; + return SourceLocation(); + } + Scope *getCurScope() const { return Stack.back().CurScope; } Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || - DKind == OMPD_unknown; + isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown; } } // namespace @@ -213,7 +245,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // File-scope or namespace-scope variables referenced in called routines // in the region are shared unless they appear in a threadprivate // directive. - if (!D->isFunctionOrMethodVarDecl()) + if (!D->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) DVar.CKind = OMPC_shared; // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced @@ -263,7 +295,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // In a parallel construct, if no default clause is present, these // variables are shared. DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; - if (isOpenMPParallelDirective(DVar.DKind)) { + if (isOpenMPParallelDirective(DVar.DKind) || + isOpenMPTeamsDirective(DVar.DKind)) { DVar.CKind = OMPC_shared; return DVar; } @@ -358,7 +391,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if (D->getTLSKind() != VarDecl::TLS_None) { + if (D->getTLSKind() != VarDecl::TLS_None || + D->getStorageClass() == SC_Register) { DVar.CKind = OMPC_threadprivate; return DVar; } @@ -380,8 +414,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { StartI = std::next(StartI); } if (!isParallelOrTaskRegion(Kind)) { - if (isOpenMPLocal(D, StartI) && D->isLocalVarDecl() && - (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) { + if (isOpenMPLocal(D, StartI) && + ((D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto || + D->getStorageClass() == SC_None)) || + isa<ParmVarDecl>(D))) { DVar.CKind = OMPC_private; return DVar; } @@ -516,6 +552,19 @@ void Sema::InitDataSharingAttributesStack() { #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack) +bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + if (DSAStack->getCurrentDirective() != OMPD_unknown) { + auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) + return true; + DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), + /*FromParent=*/false); + return DVarPrivate.CKind != OMPC_unknown; + } + return false; +} + void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -612,10 +661,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, VarDecl *VD; if (!Lookup.isSingleResult()) { - VarDeclFilterCCC Validator(*this); - if (TypoCorrection Corrected = - CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, Validator, - CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = CorrectTypo( + Id, LookupOrdinaryName, CurScope, nullptr, + llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest @@ -794,8 +842,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { } // Check if this is a TLS variable. - if (VD->getTLSKind()) { - Diag(ILoc, diag::err_omp_var_thread_local) << VD; + if (VD->getTLSKind() != VarDecl::TLS_None || + VD->getStorageClass() == SC_Register) { + Diag(ILoc, diag::err_omp_var_thread_local) + << VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), @@ -814,6 +864,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { Vars.push_back(RefExpr); DSAStack->addDSA(VD, DE, OMPC_threadprivate); + VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( + Context, SourceRange(Loc, Loc))); + if (auto *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPThreadPrivate(VD); } OMPThreadPrivateDecl *D = nullptr; if (!Vars.empty()) { @@ -918,7 +972,8 @@ public: DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), [](OpenMPDirectiveKind K) -> bool { return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K); + isOpenMPWorksharingDirective(K) || + isOpenMPTeamsDirective(K); }, false); if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) { @@ -993,6 +1048,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_for_simd: { + Sema::CapturedParamNameType Params[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_sections: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars @@ -1045,6 +1108,18 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_parallel_for_simd: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_parallel_sections: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars @@ -1061,7 +1136,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_taskyield: { + case OMPD_ordered: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -1069,7 +1144,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_barrier: { + case OMPD_atomic: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -1077,7 +1152,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_taskwait: { + case OMPD_target: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -1085,8 +1160,12 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_flush: { + case OMPD_teams: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1094,6 +1173,10 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_threadprivate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_flush: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -1110,6 +1193,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // +------------------+-----------------+------------------------------------+ // | parallel | parallel | * | // | parallel | for | * | + // | parallel | for simd | * | // | parallel | master | * | // | parallel | critical | * | // | parallel | simd | * | @@ -1117,15 +1201,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel | section | + | // | parallel | single | * | // | parallel | parallel for | * | + // | parallel |parallel for simd| * | // | parallel |parallel sections| * | // | parallel | task | * | // | parallel | taskyield | * | // | parallel | barrier | * | // | parallel | taskwait | * | // | parallel | flush | * | + // | parallel | ordered | + | + // | parallel | atomic | * | + // | parallel | target | * | + // | parallel | teams | + | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | + // | for | for simd | + | // | for | master | + | // | for | critical | * | // | for | simd | * | @@ -1133,15 +1223,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | for | section | + | // | for | single | + | // | for | parallel for | * | + // | for |parallel for simd| * | // | for |parallel sections| * | // | for | task | * | // | for | taskyield | * | // | for | barrier | + | // | for | taskwait | * | // | for | flush | * | + // | for | ordered | * (if construct is ordered) | + // | for | atomic | * | + // | for | target | * | + // | for | teams | + | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | + // | master | for simd | + | // | master | master | * | // | master | critical | * | // | master | simd | * | @@ -1149,30 +1245,42 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | master | section | + | // | master | single | + | // | master | parallel for | * | + // | master |parallel for simd| * | // | master |parallel sections| * | // | master | task | * | // | master | taskyield | * | // | master | barrier | + | // | master | taskwait | * | // | master | flush | * | + // | master | ordered | + | + // | master | atomic | * | + // | master | target | * | + // | master | teams | + | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | + // | critical | for simd | + | // | critical | master | * | - // | critical | critical | * (should have dirrerent names) | + // | critical | critical | * (should have different names) | // | critical | simd | * | // | critical | sections | + | // | critical | section | + | // | critical | single | + | // | critical | parallel for | * | + // | critical |parallel for simd| * | // | critical |parallel sections| * | // | critical | task | * | // | critical | taskyield | * | // | critical | barrier | + | // | critical | taskwait | * | + // | critical | ordered | + | + // | critical | atomic | * | + // | critical | target | * | + // | critical | teams | + | // +------------------+-----------------+------------------------------------+ // | simd | parallel | | // | simd | for | | + // | simd | for simd | | // | simd | master | | // | simd | critical | | // | simd | simd | | @@ -1180,15 +1288,65 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | simd | section | | // | simd | single | | // | simd | parallel for | | + // | simd |parallel for simd| | // | simd |parallel sections| | // | simd | task | | // | simd | taskyield | | // | simd | barrier | | // | simd | taskwait | | // | simd | flush | | + // | simd | ordered | | + // | simd | atomic | | + // | simd | target | | + // | simd | teams | | + // +------------------+-----------------+------------------------------------+ + // | for simd | parallel | | + // | for simd | for | | + // | for simd | for simd | | + // | for simd | master | | + // | for simd | critical | | + // | for simd | simd | | + // | for simd | sections | | + // | for simd | section | | + // | for simd | single | | + // | for simd | parallel for | | + // | for simd |parallel for simd| | + // | for simd |parallel sections| | + // | for simd | task | | + // | for simd | taskyield | | + // | for simd | barrier | | + // | for simd | taskwait | | + // | for simd | flush | | + // | for simd | ordered | | + // | for simd | atomic | | + // | for simd | target | | + // | for simd | teams | | + // +------------------+-----------------+------------------------------------+ + // | parallel for simd| parallel | | + // | parallel for simd| for | | + // | parallel for simd| for simd | | + // | parallel for simd| master | | + // | parallel for simd| critical | | + // | parallel for simd| simd | | + // | parallel for simd| sections | | + // | parallel for simd| section | | + // | parallel for simd| single | | + // | parallel for simd| parallel for | | + // | parallel for simd|parallel for simd| | + // | parallel for simd|parallel sections| | + // | parallel for simd| task | | + // | parallel for simd| taskyield | | + // | parallel for simd| barrier | | + // | parallel for simd| taskwait | | + // | parallel for simd| flush | | + // | parallel for simd| ordered | | + // | parallel for simd| atomic | | + // | parallel for simd| target | | + // | parallel for simd| teams | | // +------------------+-----------------+------------------------------------+ // | sections | parallel | * | // | sections | for | + | + // | sections | for simd | + | // | sections | master | + | // | sections | critical | * | // | sections | simd | * | @@ -1196,15 +1354,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | sections | section | * | // | sections | single | + | // | sections | parallel for | * | + // | sections |parallel for simd| * | // | sections |parallel sections| * | // | sections | task | * | // | sections | taskyield | * | // | sections | barrier | + | // | sections | taskwait | * | // | sections | flush | * | + // | sections | ordered | + | + // | sections | atomic | * | + // | sections | target | * | + // | sections | teams | + | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | + // | section | for simd | + | // | section | master | + | // | section | critical | * | // | section | simd | * | @@ -1212,15 +1376,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | section | section | + | // | section | single | + | // | section | parallel for | * | + // | section |parallel for simd| * | // | section |parallel sections| * | // | section | task | * | // | section | taskyield | * | // | section | barrier | + | // | section | taskwait | * | // | section | flush | * | + // | section | ordered | + | + // | section | atomic | * | + // | section | target | * | + // | section | teams | + | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | + // | single | for simd | + | // | single | master | + | // | single | critical | * | // | single | simd | * | @@ -1228,15 +1398,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | single | section | + | // | single | single | + | // | single | parallel for | * | + // | single |parallel for simd| * | // | single |parallel sections| * | // | single | task | * | // | single | taskyield | * | // | single | barrier | + | // | single | taskwait | * | // | single | flush | * | + // | single | ordered | + | + // | single | atomic | * | + // | single | target | * | + // | single | teams | + | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | + // | parallel for | for simd | + | // | parallel for | master | + | // | parallel for | critical | * | // | parallel for | simd | * | @@ -1244,15 +1420,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel for | section | + | // | parallel for | single | + | // | parallel for | parallel for | * | + // | parallel for |parallel for simd| * | // | parallel for |parallel sections| * | // | parallel for | task | * | // | parallel for | taskyield | * | // | parallel for | barrier | + | // | parallel for | taskwait | * | // | parallel for | flush | * | + // | parallel for | ordered | * (if construct is ordered) | + // | parallel for | atomic | * | + // | parallel for | target | * | + // | parallel for | teams | + | // +------------------+-----------------+------------------------------------+ // | parallel sections| parallel | * | // | parallel sections| for | + | + // | parallel sections| for simd | + | // | parallel sections| master | + | // | parallel sections| critical | + | // | parallel sections| simd | * | @@ -1260,15 +1442,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | parallel sections| section | * | // | parallel sections| single | + | // | parallel sections| parallel for | * | + // | parallel sections|parallel for simd| * | // | parallel sections|parallel sections| * | // | parallel sections| task | * | // | parallel sections| taskyield | * | // | parallel sections| barrier | + | // | parallel sections| taskwait | * | // | parallel sections| flush | * | + // | parallel sections| ordered | + | + // | parallel sections| atomic | * | + // | parallel sections| target | * | + // | parallel sections| teams | + | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | + // | task | for simd | + | // | task | master | + | // | task | critical | * | // | task | simd | * | @@ -1276,24 +1464,128 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | task | section | + | // | task | single | + | // | task | parallel for | * | + // | task |parallel for simd| * | // | task |parallel sections| * | // | task | task | * | // | task | taskyield | * | // | task | barrier | + | // | task | taskwait | * | // | task | flush | * | + // | task | ordered | + | + // | task | atomic | * | + // | task | target | * | + // | task | teams | + | + // +------------------+-----------------+------------------------------------+ + // | ordered | parallel | * | + // | ordered | for | + | + // | ordered | for simd | + | + // | ordered | master | * | + // | ordered | critical | * | + // | ordered | simd | * | + // | ordered | sections | + | + // | ordered | section | + | + // | ordered | single | + | + // | ordered | parallel for | * | + // | ordered |parallel for simd| * | + // | ordered |parallel sections| * | + // | ordered | task | * | + // | ordered | taskyield | * | + // | ordered | barrier | + | + // | ordered | taskwait | * | + // | ordered | flush | * | + // | ordered | ordered | + | + // | ordered | atomic | * | + // | ordered | target | * | + // | ordered | teams | + | + // +------------------+-----------------+------------------------------------+ + // | atomic | parallel | | + // | atomic | for | | + // | atomic | for simd | | + // | atomic | master | | + // | atomic | critical | | + // | atomic | simd | | + // | atomic | sections | | + // | atomic | section | | + // | atomic | single | | + // | atomic | parallel for | | + // | atomic |parallel for simd| | + // | atomic |parallel sections| | + // | atomic | task | | + // | atomic | taskyield | | + // | atomic | barrier | | + // | atomic | taskwait | | + // | atomic | flush | | + // | atomic | ordered | | + // | atomic | atomic | | + // | atomic | target | | + // | atomic | teams | | + // +------------------+-----------------+------------------------------------+ + // | target | parallel | * | + // | target | for | * | + // | target | for simd | * | + // | target | master | * | + // | target | critical | * | + // | target | simd | * | + // | target | sections | * | + // | target | section | * | + // | target | single | * | + // | target | parallel for | * | + // | target |parallel for simd| * | + // | target |parallel sections| * | + // | target | task | * | + // | target | taskyield | * | + // | target | barrier | * | + // | target | taskwait | * | + // | target | flush | * | + // | target | ordered | * | + // | target | atomic | * | + // | target | target | * | + // | target | teams | * | + // +------------------+-----------------+------------------------------------+ + // | teams | parallel | * | + // | teams | for | + | + // | teams | for simd | + | + // | teams | master | + | + // | teams | critical | + | + // | teams | simd | + | + // | teams | sections | + | + // | teams | section | + | + // | teams | single | + | + // | teams | parallel for | * | + // | teams |parallel for simd| * | + // | teams |parallel sections| * | + // | teams | task | + | + // | teams | taskyield | + | + // | teams | barrier | + | + // | teams | taskwait | + | + // | teams | flush | + | + // | teams | ordered | + | + // | teams | atomic | + | + // | teams | target | + | + // | teams | teams | + | // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); bool NestingProhibited = false; bool CloseNesting = true; - bool ShouldBeInParallelRegion = false; + enum { + NoRecommend, + ShouldBeInParallelRegion, + ShouldBeInOrderedRegion, + ShouldBeInTargetRegion + } Recommend = NoRecommend; if (isOpenMPSimdDirective(ParentRegion)) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); return true; } + if (ParentRegion == OMPD_atomic) { + // OpenMP [2.16, Nesting of Regions] + // OpenMP constructs may not be nested inside an atomic region. + SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_atomic); + return true; + } if (CurrentRegion == OMPD_section) { // OpenMP [2.7.2, sections Construct, Restrictions] // Orphaned section directives are prohibited. That is, the section @@ -1308,10 +1600,14 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, } return false; } + // Allow some constructs to be orphaned (they could be used in functions, + // called from OpenMP regions with the required preconditions). + if (ParentRegion == OMPD_unknown) + return false; if (CurrentRegion == OMPD_master) { // OpenMP [2.16, Nesting of Regions] // A master region may not be closely nested inside a worksharing, - // atomic (TODO), or explicit task region. + // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || ParentRegion == OMPD_task; } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { @@ -1346,30 +1642,52 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, } else if (CurrentRegion == OMPD_barrier) { // OpenMP [2.16, Nesting of Regions] // A barrier region may not be closely nested inside a worksharing, - // explicit task, critical, ordered(TODO), atomic(TODO), or master - // region. - NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || - ParentRegion == OMPD_master || - ParentRegion == OMPD_critical; + // explicit task, critical, ordered, atomic, or master region. + NestingProhibited = + isOpenMPWorksharingDirective(ParentRegion) || + ParentRegion == OMPD_task || ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && - !isOpenMPParallelDirective(CurrentRegion) && - !isOpenMPSimdDirective(CurrentRegion)) { + !isOpenMPParallelDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // A worksharing region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. - // TODO - NestingProhibited = (isOpenMPWorksharingDirective(ParentRegion) && - !isOpenMPSimdDirective(ParentRegion)) || + NestingProhibited = + isOpenMPWorksharingDirective(ParentRegion) || + ParentRegion == OMPD_task || ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; + Recommend = ShouldBeInParallelRegion; + } else if (CurrentRegion == OMPD_ordered) { + // OpenMP [2.16, Nesting of Regions] + // An ordered region may not be closely nested inside a critical, + // atomic, or explicit task region. + // An ordered region must be closely nested inside a loop region (or + // parallel loop region) with an ordered clause. + NestingProhibited = ParentRegion == OMPD_critical || ParentRegion == OMPD_task || - ParentRegion == OMPD_master || - ParentRegion == OMPD_critical; - ShouldBeInParallelRegion = true; + !Stack->isParentOrderedRegion(); + Recommend = ShouldBeInOrderedRegion; + } else if (isOpenMPTeamsDirective(CurrentRegion)) { + // OpenMP [2.16, Nesting of Regions] + // If specified, a teams construct must be contained within a target + // construct. + NestingProhibited = ParentRegion != OMPD_target; + Recommend = ShouldBeInTargetRegion; + Stack->setParentTeamsRegionLoc(Stack->getConstructLoc()); + } + if (!NestingProhibited && isOpenMPTeamsDirective(ParentRegion)) { + // OpenMP [2.16, Nesting of Regions] + // distribute, parallel, parallel sections, parallel workshare, and the + // parallel loop and parallel loop SIMD constructs are the only OpenMP + // constructs that can be closely nested in the teams region. + // TODO: add distribute directive. + NestingProhibited = !isOpenMPParallelDirective(CurrentRegion); + Recommend = ShouldBeInParallelRegion; } if (NestingProhibited) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) - << CloseNesting << getOpenMPDirectiveName(ParentRegion) - << ShouldBeInParallelRegion << getOpenMPDirectiveName(CurrentRegion); + << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend + << getOpenMPDirectiveName(CurrentRegion); return true; } } @@ -1426,6 +1744,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; + case OMPD_for_simd: + Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); + break; case OMPD_sections: Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); @@ -1453,6 +1775,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; + case OMPD_parallel_for_simd: + Res = ActOnOpenMPParallelForSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + break; case OMPD_parallel_sections: Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); @@ -1487,6 +1813,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, "No associated statement allowed for 'omp flush' directive"); Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); break; + case OMPD_ordered: + assert(ClausesWithImplicit.empty() && + "No clauses are allowed for 'omp ordered' directive"); + Res = ActOnOpenMPOrderedDirective(AStmt, StartLoc, EndLoc); + break; + case OMPD_atomic: + Res = ActOnOpenMPAtomicDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; + case OMPD_teams: + Res = + ActOnOpenMPTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); + break; + case OMPD_target: + Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + break; case OMPD_threadprivate: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: @@ -1535,10 +1878,16 @@ class OpenMPIterationSpaceChecker { SourceLocation DefaultLoc; /// \brief A location for diagnostics (when increment is not compatible). SourceLocation ConditionLoc; + /// \brief A source location for referring to loop init later. + SourceRange InitSrcRange; /// \brief A source location for referring to condition later. SourceRange ConditionSrcRange; + /// \brief A source location for referring to increment later. + SourceRange IncrementSrcRange; /// \brief Loop variable. VarDecl *Var; + /// \brief Reference to loop variable. + DeclRefExpr *VarRef; /// \brief Lower bound (initializer for the var). Expr *LB; /// \brief Upper bound. @@ -1559,9 +1908,10 @@ class OpenMPIterationSpaceChecker { public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), - ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr), - UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false), - SubtractStep(false) {} + InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()), + IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr), + LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false), + TestIsStrictOp(false), SubtractStep(false) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool CheckInit(Stmt *S); @@ -1573,6 +1923,24 @@ public: bool CheckInc(Expr *S); /// \brief Return the loop counter variable. VarDecl *GetLoopVar() const { return Var; } + /// \brief Return the reference expression to loop counter variable. + DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; } + /// \brief Source range of the loop init. + SourceRange GetInitSrcRange() const { return InitSrcRange; } + /// \brief Source range of the loop condition. + SourceRange GetConditionSrcRange() const { return ConditionSrcRange; } + /// \brief Source range of the loop increment. + SourceRange GetIncrementSrcRange() const { return IncrementSrcRange; } + /// \brief True if the step should be subtracted. + bool ShouldSubtractStep() const { return SubtractStep; } + /// \brief Build the expression to calculate the number of iterations. + Expr *BuildNumIterations(Scope *S, const bool LimitedType) const; + /// \brief Build reference expression to the counter be used for codegen. + Expr *BuildCounterVar() const; + /// \brief Build initization of the counter be used for codegen. + Expr *BuildCounterInit() const; + /// \brief Build step of the counter be used for codegen. + Expr *BuildCounterStep() const; /// \brief Return true if any expression is dependent. bool Dependent() const; @@ -1581,7 +1949,7 @@ private: /// expression. bool CheckIncRHS(Expr *RHS); /// \brief Helper to set loop counter variable and its initializer. - bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB); + bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR, const SourceLocation &SL); @@ -1598,13 +1966,16 @@ bool OpenMPIterationSpaceChecker::Dependent() const { (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); } -bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) { +bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, + DeclRefExpr *NewVarRefExpr, + Expr *NewLB) { // State consistency checking to ensure correct usage. - assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr && - !TestIsLessOp && !TestIsStrictOp); + assert(Var == nullptr && LB == nullptr && VarRef == nullptr && + UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewVar || !NewLB) return true; Var = NewVar; + VarRef = NewVarRefExpr; LB = NewLB; return false; } @@ -1655,10 +2026,12 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation(); bool IsConstNeg = IsConstant && Result.isSigned() && (Subtract != Result.isNegative()); + bool IsConstPos = + IsConstant && Result.isSigned() && (Subtract == Result.isNegative()); bool IsConstZero = IsConstant && !Result.getBoolValue(); if (UB && (IsConstZero || (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract)) - : (!IsConstNeg || (IsUnsigned && !Subtract))))) { + : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) << Var << TestIsLessOp << NewStep->getSourceRange(); @@ -1667,6 +2040,11 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { << TestIsLessOp << ConditionSrcRange; return true; } + if (TestIsLessOp == Subtract) { + NewStep = SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, + NewStep).get(); + Subtract = !Subtract; + } } Step = NewStep; @@ -1687,12 +2065,14 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); return true; } + InitSrcRange = S->getSourceRange(); if (Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParens(); if (auto BO = dyn_cast<BinaryOperator>(S)) { if (BO->getOpcode() == BO_Assign) if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS()); + return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, + BO->getRHS()); } else if (auto DS = dyn_cast<DeclStmt>(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { @@ -1702,14 +2082,15 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); - return SetVarAndLB(Var, Var->getInit()); + return SetVarAndLB(Var, nullptr, Var->getInit()); } } } } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) if (CE->getOperator() == OO_Equal) if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0))) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1)); + return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, + CE->getArg(1)); SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) << S->getSourceRange(); @@ -1833,6 +2214,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; return true; } + IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); if (auto UO = dyn_cast<UnaryOperator>(S)) { if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) @@ -1882,6 +2264,115 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { << S->getSourceRange() << Var; return true; } + +/// \brief Build the expression to calculate the number of iterations. +Expr * +OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, + const bool LimitedType) const { + ExprResult Diff; + if (Var->getType()->isIntegerType() || Var->getType()->isPointerType() || + SemaRef.getLangOpts().CPlusPlus) { + // Upper - Lower + Expr *Upper = TestIsLessOp ? UB : LB; + Expr *Lower = TestIsLessOp ? LB : UB; + + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + + if (!Diff.isUsable() && Var->getType()->getAsCXXRecordDecl()) { + // BuildBinOp already emitted error, this one is to point user to upper + // and lower bound, and to tell what is passed to 'operator-'. + SemaRef.Diag(Upper->getLocStart(), diag::err_omp_loop_diff_cxx) + << Upper->getSourceRange() << Lower->getSourceRange(); + return nullptr; + } + } + + if (!Diff.isUsable()) + return nullptr; + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return nullptr; + + // Upper - Lower [- 1] + Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), + Step->IgnoreImplicit()); + if (!Diff.isUsable()) + return nullptr; + + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) + return nullptr; + + // (Upper - Lower [- 1] + Step) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), + Step->IgnoreImplicit()); + if (!Diff.isUsable()) + return nullptr; + + // OpenMP runtime requires 32-bit or 64-bit loop variables. + if (LimitedType) { + auto &C = SemaRef.Context; + QualType Type = Diff.get()->getType(); + unsigned NewSize = (C.getTypeSize(Type) > 32) ? 64 : 32; + if (NewSize != C.getTypeSize(Type)) { + if (NewSize < C.getTypeSize(Type)) { + assert(NewSize == 64 && "incorrect loop var size"); + SemaRef.Diag(DefaultLoc, diag::warn_omp_loop_64_bit_var) + << InitSrcRange << ConditionSrcRange; + } + QualType NewType = C.getIntTypeForBitwidth( + NewSize, Type->hasSignedIntegerRepresentation()); + Diff = SemaRef.PerformImplicitConversion(Diff.get(), NewType, + Sema::AA_Converting, true); + if (!Diff.isUsable()) + return nullptr; + } + } + + return Diff.get(); +} + +/// \brief Build reference expression to the counter be used for codegen. +Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { + return DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), + GetIncrementSrcRange().getBegin(), Var, false, + DefaultLoc, Var->getType(), VK_LValue); +} + +/// \brief Build initization of the counter be used for codegen. +Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } + +/// \brief Build step of the counter be used for codegen. +Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; } + +/// \brief Iteration space of a single for loop. +struct LoopIterationSpace { + /// \brief This expression calculates the number of iterations in the loop. + /// It is always possible to calculate it before starting the loop. + Expr *NumIterations; + /// \brief The loop counter variable. + Expr *CounterVar; + /// \brief This is initializer for the initial value of #CounterVar. + Expr *CounterInit; + /// \brief This is step for the #CounterVar used to generate its update: + /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. + Expr *CounterStep; + /// \brief Should step be subtracted? + bool Subtract; + /// \brief Source range of the loop init. + SourceRange InitSrcRange; + /// \brief Source range of the loop condition. + SourceRange CondSrcRange; + /// \brief Source range of the loop increment. + SourceRange IncSrcRange; +}; + } // namespace /// \brief Called on a for stmt to check and extract its iteration space @@ -1890,7 +2381,8 @@ static bool CheckOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, Expr *NestedLoopCountExpr, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, + LoopIterationSpace &ResultIterSpace) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block auto For = dyn_cast_or_null<ForStmt>(S); @@ -1943,8 +2435,7 @@ static bool CheckOpenMPIterationSpace( // that is the increment of the associated for-loop. // Exclude loop var from the list of variables with implicitly defined data // sharing attributes. - while (VarsWithImplicitDSA.count(Var) > 0) - VarsWithImplicitDSA.erase(Var); + VarsWithImplicitDSA.erase(Var); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in // a Construct, C/C++]. @@ -1954,25 +2445,40 @@ static bool CheckOpenMPIterationSpace( // The loop iteration variable(s) in the associated for-loop(s) of a for or // parallel for construct may be listed in a private or lastprivate clause. DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false); + auto LoopVarRefExpr = ISC.GetLoopVarRefExpr(); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable is + // declared in the loop and it is predetermined as a private. auto PredeterminedCKind = isOpenMPSimdDirective(DKind) ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && DVar.CKind != PredeterminedCKind) || - (isOpenMPWorksharingDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (isOpenMPWorksharingDirective(DKind) && !isOpenMPSimdDirective(DKind) && + DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private && + DVar.CKind != OMPC_lastprivate)) && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(PredeterminedCKind); ReportOriginalDSA(SemaRef, &DSA, Var, DVar, true); HasErrors = true; - } else { + } else if (LoopVarRefExpr != nullptr) { // Make the loop iteration variable private (for worksharing constructs), // linear (for simd directives with the only one associated loop) or // lastprivate (for simd directives with several collapsed loops). - DSA.addDSA(Var, nullptr, PredeterminedCKind); + // FIXME: the next check and error message must be removed once the + // capturing of global variables in loops is fixed. + if (DVar.CKind == OMPC_unknown) + DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), + /*FromParent=*/false); + if (!Var->hasLocalStorage() && DVar.CKind == OMPC_unknown) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_global_loop_var_dsa) + << getOpenMPClauseName(PredeterminedCKind) + << getOpenMPDirectiveName(DKind); + HasErrors = true; + } else + DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); } assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); @@ -1983,35 +2489,97 @@ static bool CheckOpenMPIterationSpace( // Check incr-expr. HasErrors |= ISC.CheckInc(For->getInc()); - if (ISC.Dependent()) + if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; - // FIXME: Build loop's iteration space representation. + // Build the loop's iteration space representation. + ResultIterSpace.NumIterations = ISC.BuildNumIterations( + DSA.getCurScope(), /* LimitedType */ isOpenMPWorksharingDirective(DKind)); + ResultIterSpace.CounterVar = ISC.BuildCounterVar(); + ResultIterSpace.CounterInit = ISC.BuildCounterInit(); + ResultIterSpace.CounterStep = ISC.BuildCounterStep(); + ResultIterSpace.InitSrcRange = ISC.GetInitSrcRange(); + ResultIterSpace.CondSrcRange = ISC.GetConditionSrcRange(); + ResultIterSpace.IncSrcRange = ISC.GetIncrementSrcRange(); + ResultIterSpace.Subtract = ISC.ShouldSubtractStep(); + + HasErrors |= (ResultIterSpace.NumIterations == nullptr || + ResultIterSpace.CounterVar == nullptr || + ResultIterSpace.CounterInit == nullptr || + ResultIterSpace.CounterStep == nullptr); + return HasErrors; } -/// \brief A helper routine to skip no-op (attributed, compound) stmts get the -/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt -/// to get the first for loop. -static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) { - if (IgnoreCaptured) - if (auto CapS = dyn_cast_or_null<CapturedStmt>(S)) - S = CapS->getCapturedStmt(); - // OpenMP [2.8.1, simd construct, Restrictions] - // All loops associated with the construct must be perfectly nested; that is, - // there must be no intervening code nor any OpenMP directive between any two - // loops. - while (true) { - if (auto AS = dyn_cast_or_null<AttributedStmt>(S)) - S = AS->getSubStmt(); - else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) { - if (CS->size() != 1) - break; - S = CS->body_back(); - } else - break; - } - return S; +/// \brief Build a variable declaration for OpenMP loop iteration variable. +static VarDecl *BuildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, + StringRef Name) { + DeclContext *DC = SemaRef.CurContext; + IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = + VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); + Decl->setImplicit(); + return Decl; +} + +/// \brief Build 'VarRef = Start + Iter * Step'. +static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S, + SourceLocation Loc, ExprResult VarRef, + ExprResult Start, ExprResult Iter, + ExprResult Step, bool Subtract) { + // Add parentheses (for debugging purposes only). + Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); + if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() || + !Step.isUsable()) + return ExprError(); + + ExprResult Update = SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), + Step.get()->IgnoreImplicit()); + if (!Update.isUsable()) + return ExprError(); + + // Build 'VarRef = Start + Iter * Step'. + Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add), + Start.get()->IgnoreImplicit(), Update.get()); + if (!Update.isUsable()) + return ExprError(); + + Update = SemaRef.PerformImplicitConversion( + Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); + if (!Update.isUsable()) + return ExprError(); + + Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + return Update; +} + +/// \brief Convert integer expression \a E to make it have at least \a Bits +/// bits. +static ExprResult WidenIterationCount(unsigned Bits, Expr *E, + Sema &SemaRef) { + if (E == nullptr) + return ExprError(); + auto &C = SemaRef.Context; + QualType OldType = E->getType(); + unsigned HasBits = C.getTypeSize(OldType); + if (HasBits >= Bits) + return ExprResult(E); + // OK to convert to signed, because new type has more bits than old. + QualType NewType = C.getIntTypeForBitwidth(Bits, /* Signed */ true); + return SemaRef.PerformImplicitConversion(E, NewType, Sema::AA_Converting, + true); +} + +/// \brief Check if the given expression \a E is a constant integer that fits +/// into \a Bits bits. +static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { + if (E == nullptr) + return false; + llvm::APSInt Result; + if (E->isIntegerConstantExpr(Result, SemaRef.Context)) + return Signed ? Result.isSignedIntN(Bits) : Result.isIntN(Bits); + return false; } /// \brief Called on a for stmt to check itself and nested loops (if any). @@ -2020,7 +2588,8 @@ static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) { static unsigned CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, + OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; if (NestedLoopCountExpr) { // Found 'collapse' clause - calculate collapse number. @@ -2030,18 +2599,336 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). - Stmt *CurStmt = IgnoreContainerStmts(AStmt, true); + SmallVector<LoopIterationSpace, 4> IterSpaces; + IterSpaces.resize(NestedLoopCount); + Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, NestedLoopCountExpr, - VarsWithImplicitDSA)) + VarsWithImplicitDSA, IterSpaces[Cnt])) return 0; // Move on to the next nested for loop, or to the loop body. - CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false); + // OpenMP [2.8.1, simd construct, Restrictions] + // All loops associated with the construct must be perfectly nested; that + // is, there must be no intervening code nor any OpenMP directive between + // any two loops. + CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers(); + } + + Built.clear(/* size */ NestedLoopCount); + + if (SemaRef.CurContext->isDependentContext()) + return NestedLoopCount; + + // An example of what is generated for the following code: + // + // #pragma omp simd collapse(2) + // for (i = 0; i < NI; ++i) + // for (j = J0; j < NJ; j+=2) { + // <loop body> + // } + // + // We generate the code below. + // Note: the loop body may be outlined in CodeGen. + // Note: some counters may be C++ classes, operator- is used to find number of + // iterations and operator+= to calculate counter value. + // Note: decltype(NumIterations) must be integer type (in 'omp for', only i32 + // or i64 is currently supported). + // + // #define NumIterations (NI * ((NJ - J0 - 1 + 2) / 2)) + // for (int[32|64]_t IV = 0; IV < NumIterations; ++IV ) { + // .local.i = IV / ((NJ - J0 - 1 + 2) / 2); + // .local.j = J0 + (IV % ((NJ - J0 - 1 + 2) / 2)) * 2; + // // similar updates for vars in clauses (e.g. 'linear') + // <loop body (using local i and j)> + // } + // i = NI; // assign final values of counters + // j = NJ; + // + + // Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are + // the iteration counts of the collapsed for loops. + auto N0 = IterSpaces[0].NumIterations; + ExprResult LastIteration32 = WidenIterationCount(32 /* Bits */, N0, SemaRef); + ExprResult LastIteration64 = WidenIterationCount(64 /* Bits */, N0, SemaRef); + + if (!LastIteration32.isUsable() || !LastIteration64.isUsable()) + return NestedLoopCount; + + auto &C = SemaRef.Context; + bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32; + + Scope *CurScope = DSA.getCurScope(); + for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) { + auto N = IterSpaces[Cnt].NumIterations; + AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32; + if (LastIteration32.isUsable()) + LastIteration32 = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_Mul, + LastIteration32.get(), N); + if (LastIteration64.isUsable()) + LastIteration64 = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_Mul, + LastIteration64.get(), N); + } + + // Choose either the 32-bit or 64-bit version. + ExprResult LastIteration = LastIteration64; + if (LastIteration32.isUsable() && + C.getTypeSize(LastIteration32.get()->getType()) == 32 && + (AllCountsNeedLessThan32Bits || NestedLoopCount == 1 || + FitsInto( + 32 /* Bits */, + LastIteration32.get()->getType()->hasSignedIntegerRepresentation(), + LastIteration64.get(), SemaRef))) + LastIteration = LastIteration32; + + if (!LastIteration.isUsable()) + return 0; + + // Save the number of iterations. + ExprResult NumIterations = LastIteration; + { + LastIteration = SemaRef.BuildBinOp( + CurScope, SourceLocation(), BO_Sub, LastIteration.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!LastIteration.isUsable()) + return 0; + } + + // Calculate the last iteration number beforehand instead of doing this on + // each iteration. Do not do this if the number of iterations may be kfold-ed. + llvm::APSInt Result; + bool IsConstant = + LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); + ExprResult CalcLastIteration; + if (!IsConstant) { + SourceLocation SaveLoc; + VarDecl *SaveVar = + BuildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), + ".omp.last.iteration"); + ExprResult SaveRef = SemaRef.BuildDeclRefExpr( + SaveVar, LastIteration.get()->getType(), VK_LValue, SaveLoc); + CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign, + SaveRef.get(), LastIteration.get()); + LastIteration = SaveRef; + + // Prepare SaveRef + 1. + NumIterations = SemaRef.BuildBinOp( + CurScope, SaveLoc, BO_Add, SaveRef.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!NumIterations.isUsable()) + return 0; + } + + SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); + + // Precondition tests if there is at least one iteration (LastIteration > 0). + ExprResult PreCond = SemaRef.BuildBinOp( + CurScope, InitLoc, BO_GT, LastIteration.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get()); + + QualType VType = LastIteration.get()->getType(); + // Build variables passed into runtime, nesessary for worksharing directives. + ExprResult LB, UB, IL, ST, EUB; + if (isOpenMPWorksharingDirective(DKind)) { + // Lower bound variable, initialized with zero. + VarDecl *LBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); + LB = SemaRef.BuildDeclRefExpr(LBDecl, VType, VK_LValue, InitLoc); + SemaRef.AddInitializerToDecl( + LBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), + /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + + // Upper bound variable, initialized with last iteration number. + VarDecl *UBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.ub"); + UB = SemaRef.BuildDeclRefExpr(UBDecl, VType, VK_LValue, InitLoc); + SemaRef.AddInitializerToDecl(UBDecl, LastIteration.get(), + /*DirectInit*/ false, + /*TypeMayContainAuto*/ false); + + // A 32-bit variable-flag where runtime returns 1 for the last iteration. + // This will be used to implement clause 'lastprivate'. + QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(32, true); + VarDecl *ILDecl = BuildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last"); + IL = SemaRef.BuildDeclRefExpr(ILDecl, Int32Ty, VK_LValue, InitLoc); + SemaRef.AddInitializerToDecl( + ILDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), + /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + + // Stride variable returned by runtime (we initialize it to 1 by default). + VarDecl *STDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); + ST = SemaRef.BuildDeclRefExpr(STDecl, VType, VK_LValue, InitLoc); + SemaRef.AddInitializerToDecl( + STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(), + /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + + // Build expression: UB = min(UB, LastIteration) + // It is nesessary for CodeGen of directives with static scheduling. + ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT, + UB.get(), LastIteration.get()); + ExprResult CondOp = SemaRef.ActOnConditionalOp( + InitLoc, InitLoc, IsUBGreater.get(), LastIteration.get(), UB.get()); + EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(), + CondOp.get()); + EUB = SemaRef.ActOnFinishFullExpr(EUB.get()); + } + + // Build the iteration variable and its initialization before loop. + ExprResult IV; + ExprResult Init; + { + VarDecl *IVDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); + IV = SemaRef.BuildDeclRefExpr(IVDecl, VType, VK_LValue, InitLoc); + Expr *RHS = isOpenMPWorksharingDirective(DKind) + ? LB.get() + : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); + Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); + Init = SemaRef.ActOnFinishFullExpr(Init.get()); } - // FIXME: Build resulting iteration space for IR generation (collapsing - // iteration spaces when loop count > 1 ('collapse' clause)). + // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. + SourceLocation CondLoc; + ExprResult Cond = + isOpenMPWorksharingDirective(DKind) + ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()) + : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), + NumIterations.get()); + // Loop condition with 1 iteration separated (IV < LastIteration) + ExprResult SeparatedCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, + IV.get(), LastIteration.get()); + + // Loop increment (IV = IV + 1) + SourceLocation IncLoc; + ExprResult Inc = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, IV.get(), + SemaRef.ActOnIntegerConstant(IncLoc, 1).get()); + if (!Inc.isUsable()) + return 0; + Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, IV.get(), Inc.get()); + Inc = SemaRef.ActOnFinishFullExpr(Inc.get()); + if (!Inc.isUsable()) + return 0; + + // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). + // Used for directives with static scheduling. + ExprResult NextLB, NextUB; + if (isOpenMPWorksharingDirective(DKind)) { + // LB + ST + NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get()); + if (!NextLB.isUsable()) + return 0; + // LB = LB + ST + NextLB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get()); + NextLB = SemaRef.ActOnFinishFullExpr(NextLB.get()); + if (!NextLB.isUsable()) + return 0; + // UB + ST + NextUB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, UB.get(), ST.get()); + if (!NextUB.isUsable()) + return 0; + // UB = UB + ST + NextUB = + SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, UB.get(), NextUB.get()); + NextUB = SemaRef.ActOnFinishFullExpr(NextUB.get()); + if (!NextUB.isUsable()) + return 0; + } + + // Build updates and final values of the loop counters. + bool HasErrors = false; + Built.Counters.resize(NestedLoopCount); + Built.Updates.resize(NestedLoopCount); + Built.Finals.resize(NestedLoopCount); + { + ExprResult Div; + // Go from inner nested loop to outer. + for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) { + LoopIterationSpace &IS = IterSpaces[Cnt]; + SourceLocation UpdLoc = IS.IncSrcRange.getBegin(); + // Build: Iter = (IV / Div) % IS.NumIters + // where Div is product of previous iterations' IS.NumIters. + ExprResult Iter; + if (Div.isUsable()) { + Iter = + SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Div, IV.get(), Div.get()); + } else { + Iter = IV; + assert((Cnt == (int)NestedLoopCount - 1) && + "unusable div expected on first iteration only"); + } + + if (Cnt != 0 && Iter.isUsable()) + Iter = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Rem, Iter.get(), + IS.NumIterations); + if (!Iter.isUsable()) { + HasErrors = true; + break; + } + + // Build update: IS.CounterVar = IS.Start + Iter * IS.Step + ExprResult Update = + BuildCounterUpdate(SemaRef, CurScope, UpdLoc, IS.CounterVar, + IS.CounterInit, Iter, IS.CounterStep, IS.Subtract); + if (!Update.isUsable()) { + HasErrors = true; + break; + } + + // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step + ExprResult Final = BuildCounterUpdate( + SemaRef, CurScope, UpdLoc, IS.CounterVar, IS.CounterInit, + IS.NumIterations, IS.CounterStep, IS.Subtract); + if (!Final.isUsable()) { + HasErrors = true; + break; + } + + // Build Div for the next iteration: Div <- Div * IS.NumIters + if (Cnt != 0) { + if (Div.isUnset()) + Div = IS.NumIterations; + else + Div = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Mul, Div.get(), + IS.NumIterations); + + // Add parentheses (for debugging purposes only). + if (Div.isUsable()) + Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get()); + if (!Div.isUsable()) { + HasErrors = true; + break; + } + } + if (!Update.isUsable() || !Final.isUsable()) { + HasErrors = true; + break; + } + // Save results + Built.Counters[Cnt] = IS.CounterVar; + Built.Updates[Cnt] = Update.get(); + Built.Finals[Cnt] = Final.get(); + } + } + + if (HasErrors) + return 0; + + // Save results + Built.IterationVarRef = IV.get(); + Built.LastIteration = LastIteration.get(); + Built.CalcLastIteration = CalcLastIteration.get(); + Built.PreCond = PreCond.get(); + Built.Cond = Cond.get(); + Built.SeparatedCond = SeparatedCond.get(); + Built.Init = Init.get(); + Built.Inc = Inc.get(); + Built.LB = LB.get(); + Built.UB = UB.get(); + Built.IL = IL.get(); + Built.ST = ST.get(); + Built.EUB = EUB.get(); + Built.NLB = NextLB.get(); + Built.NUB = NextUB.get(); + return NestedLoopCount; } @@ -2060,32 +2947,60 @@ StmtResult Sema::ActOnOpenMPSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this, - *DSAStack, VarsWithImplicitDSA); + *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp simd loop exprs were not built"); + getCurFunction()->setHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt); + Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this, - *DSAStack, VarsWithImplicitDSA); + *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + getCurFunction()->setHasBranchProtectedScope(); return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt); + Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse', it will define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_for_simd, GetCollapseNumberExpr(Clauses), AStmt, + *this, *DSAStack, VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for simd loop exprs were not built"); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, + Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, @@ -2178,16 +3093,46 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. unsigned NestedLoopCount = CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt, - *this, *DSAStack, VarsWithImplicitDSA); + *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp parallel for loop exprs were not built"); + getCurFunction()->setHasBranchProtectedScope(); return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt); + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse', it will define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_parallel_for_simd, GetCollapseNumberExpr(Clauses), + AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult @@ -2264,6 +3209,271 @@ StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); } +StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt); +} + +StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + auto CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + // TODO further analysis of associated statements and clauses. + OpenMPClauseKind AtomicKind = OMPC_unknown; + SourceLocation AtomicKindLoc; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || + C->getClauseKind() == OMPC_update || + C->getClauseKind() == OMPC_capture) { + if (AtomicKind != OMPC_unknown) { + Diag(C->getLocStart(), diag::err_omp_atomic_several_clauses) + << SourceRange(C->getLocStart(), C->getLocEnd()); + Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause) + << getOpenMPClauseName(AtomicKind); + } else { + AtomicKind = C->getClauseKind(); + AtomicKindLoc = C->getLocStart(); + } + } + } + + auto Body = CS->getCapturedStmt(); + Expr *X = nullptr; + Expr *V = nullptr; + Expr *E = nullptr; + // OpenMP [2.12.6, atomic Construct] + // In the next expressions: + // * x and v (as applicable) are both l-value expressions with scalar type. + // * During the execution of an atomic region, multiple syntactic + // occurrences of x must designate the same storage location. + // * Neither of v and expr (as applicable) may access the storage location + // designated by x. + // * Neither of x and expr (as applicable) may access the storage location + // designated by v. + // * expr is an expression with scalar type. + // * binop is one of +, *, -, /, &, ^, |, <<, or >>. + // * binop, binop=, ++, and -- are not overloaded operators. + // * The expression x binop expr must be numerically equivalent to x binop + // (expr). This requirement is satisfied if the operators in expr have + // precedence greater than binop, or by using parentheses around expr or + // subexpressions of expr. + // * The expression expr binop x must be numerically equivalent to (expr) + // binop x. This requirement is satisfied if the operators in expr have + // precedence equal to or greater than binop, or by using parentheses around + // expr or subexpressions of expr. + // * For forms that allow multiple occurrences of x, the number of times + // that x is evaluated is unspecified. + enum { + NotAnExpression, + NotAnAssignmentOp, + NotAScalarType, + NotAnLValue, + NoError + } ErrorFound = NoError; + if (AtomicKind == OMPC_read) { + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + // If clause is read: + // v = x; + if (auto AtomicBody = dyn_cast<Expr>(Body)) { + auto AtomicBinOp = + dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); + if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { + X = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); + V = AtomicBinOp->getLHS()->IgnoreParenImpCasts(); + if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && + (V->isInstantiationDependent() || V->getType()->isScalarType())) { + if (!X->isLValue() || !V->isLValue()) { + auto NotLValueExpr = X->isLValue() ? V : X; + ErrorFound = NotAnLValue; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = NotLValueExpr->getExprLoc(); + NoteRange = NotLValueExpr->getSourceRange(); + } + } else if (!X->isInstantiationDependent() || + !V->isInstantiationDependent()) { + auto NotScalarExpr = + (X->isInstantiationDependent() || X->getType()->isScalarType()) + ? V + : X; + ErrorFound = NotAScalarType; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = NotScalarExpr->getExprLoc(); + NoteRange = NotScalarExpr->getSourceRange(); + } + } else { + ErrorFound = NotAnAssignmentOp; + ErrorLoc = AtomicBody->getExprLoc(); + ErrorRange = AtomicBody->getSourceRange(); + NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() + : AtomicBody->getExprLoc(); + NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() + : AtomicBody->getSourceRange(); + } + } else { + ErrorFound = NotAnExpression; + NoteLoc = ErrorLoc = Body->getLocStart(); + NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); + } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_read_not_expression_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound + << NoteRange; + return StmtError(); + } else if (CurContext->isDependentContext()) + V = X = nullptr; + } else if (AtomicKind == OMPC_write) { + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + // If clause is write: + // x = expr; + if (auto AtomicBody = dyn_cast<Expr>(Body)) { + auto AtomicBinOp = + dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); + if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { + X = AtomicBinOp->getLHS()->IgnoreParenImpCasts(); + E = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); + if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && + (E->isInstantiationDependent() || E->getType()->isScalarType())) { + if (!X->isLValue()) { + ErrorFound = NotAnLValue; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = X->getExprLoc(); + NoteRange = X->getSourceRange(); + } + } else if (!X->isInstantiationDependent() || + !E->isInstantiationDependent()) { + auto NotScalarExpr = + (X->isInstantiationDependent() || X->getType()->isScalarType()) + ? E + : X; + ErrorFound = NotAScalarType; + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = NotScalarExpr->getExprLoc(); + NoteRange = NotScalarExpr->getSourceRange(); + } + } else { + ErrorFound = NotAnAssignmentOp; + ErrorLoc = AtomicBody->getExprLoc(); + ErrorRange = AtomicBody->getSourceRange(); + NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() + : AtomicBody->getExprLoc(); + NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() + : AtomicBody->getSourceRange(); + } + } else { + ErrorFound = NotAnExpression; + NoteLoc = ErrorLoc = Body->getLocStart(); + NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); + } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_write_not_expression_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound + << NoteRange; + return StmtError(); + } else if (CurContext->isDependentContext()) + E = X = nullptr; + } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) { + if (!isa<Expr>(Body)) { + Diag(Body->getLocStart(), + diag::err_omp_atomic_update_not_expression_statement) + << (AtomicKind == OMPC_update); + return StmtError(); + } + } else if (AtomicKind == OMPC_capture) { + if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) { + Diag(Body->getLocStart(), + diag::err_omp_atomic_capture_not_expression_statement); + return StmtError(); + } else if (!isa<Expr>(Body) && !isa<CompoundStmt>(Body)) { + Diag(Body->getLocStart(), + diag::err_omp_atomic_capture_not_compound_statement); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + X, V, E); +} + +StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + + // OpenMP [2.16, Nesting of Regions] + // If specified, a teams construct must be contained within a target + // construct. That target construct must contain no statements or directives + // outside of the teams construct. + if (DSAStack->hasInnerTeamsRegion()) { + auto S = AStmt->IgnoreContainers(/*IgnoreCaptured*/ true); + bool OMPTeamsFound = true; + if (auto *CS = dyn_cast<CompoundStmt>(S)) { + auto I = CS->body_begin(); + while (I != CS->body_end()) { + auto OED = dyn_cast<OMPExecutableDirective>(*I); + if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { + OMPTeamsFound = false; + break; + } + ++I; + } + assert(I != CS->body_end() && "Not found statement"); + S = *I; + } + if (!OMPTeamsFound) { + Diag(StartLoc, diag::err_omp_target_contains_not_only_teams); + Diag(DSAStack->getInnerTeamsRegionLoc(), + diag::note_omp_nested_teams_construct_here); + Diag(S->getLocStart(), diag::note_omp_nested_statement_here) + << isa<OMPExecutableDirective>(S); + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); +} + +StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected"); + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -2303,6 +3513,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2345,7 +3560,6 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); } - ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, Expr *Op) { if (!Op) @@ -2396,7 +3610,6 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation EndLoc) { Expr *ValExpr = NumThreads; if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() && - !NumThreads->isInstantiationDependent() && !NumThreads->containsUnexpandedParameterPack()) { SourceLocation NumThreadsLoc = NumThreads->getLocStart(); ExprResult Val = @@ -2437,6 +3650,11 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, << getOpenMPClauseName(CKind) << E->getSourceRange(); return ExprError(); } + if (CKind == OMPC_aligned && !Result.isPowerOf2()) { + Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two) + << E->getSourceRange(); + return ExprError(); + } return ICE; } @@ -2506,6 +3724,11 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2621,6 +3844,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_mergeable: case OMPC_threadprivate: case OMPC_flush: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2700,6 +3928,21 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_mergeable: Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc); break; + case OMPC_read: + Res = ActOnOpenMPReadClause(StartLoc, EndLoc); + break; + case OMPC_write: + Res = ActOnOpenMPWriteClause(StartLoc, EndLoc); + break; + case OMPC_update: + Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc); + break; + case OMPC_capture: + Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc); + break; + case OMPC_seq_cst: + Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -2727,6 +3970,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc) { + DSAStack->setOrderedRegion(); return new (Context) OMPOrderedClause(StartLoc, EndLoc); } @@ -2745,6 +3989,31 @@ OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc, return new (Context) OMPMergeableClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPReadClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPReadClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPWriteClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPUpdateClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPCaptureClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPSeqCstClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, @@ -2798,6 +4067,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_untied: case OMPC_mergeable: case OMPC_threadprivate: + case OMPC_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: case OMPC_unknown: llvm_unreachable("Clause is not allowed."); } @@ -2809,11 +4083,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + PrivateCopies.push_back(nullptr); continue; } @@ -2835,6 +4111,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + PrivateCopies.push_back(nullptr); continue; } @@ -2860,54 +4137,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the // class type. - while (Type.getNonReferenceType()->isArrayType()) { - Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr()) - ->getElementType(); - } - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the private variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); - } + while (Type->isArrayType()) { + Type = cast<ArrayType>(Type.getTypePtr())->getElementType(); } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -2925,14 +4156,59 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, continue; } + // Generate helper private variable and initialize it with the default + // value. The address of the original variable is replaced by the address of + // the new private variable in CodeGen. This new variable is not added to + // IdResolver, so the code in the OpenMP region uses original variable for + // proper diagnostics. + auto VDPrivate = + VarDecl::Create(Context, CurContext, DE->getLocStart(), + DE->getExprLoc(), VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false); + if (VDPrivate->isInvalidDecl()) + continue; + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = + DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDPrivate, + /*RefersToEnclosingVariableOrCapture*/ false, + /*NameLoc*/ SourceLocation(), DE->getType(), + /*VK*/ VK_LValue); + DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); + PrivateCopies.push_back(VDPrivateRefExpr); } if (Vars.empty()) return nullptr; - return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + PrivateCopies); +} + +namespace { +class DiagsUninitializedSeveretyRAII { +private: + DiagnosticsEngine &Diags; + SourceLocation SavedLoc; + bool IsIgnored; + +public: + DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc, + bool IsIgnored) + : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) { + if (!IsIgnored) { + Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init, + /*Map*/ diag::Severity::Ignored, Loc); + } + } + ~DiagsUninitializedSeveretyRAII() { + if (!IsIgnored) + Diags.popMappings(SavedLoc); + } +}; } OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, @@ -2940,6 +4216,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> PrivateCopies; + SmallVector<Expr *, 8> Inits; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); auto ImplicitClauseLoc = DSAStack->getConstructLoc(); @@ -2949,11 +4227,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + PrivateCopies.push_back(nullptr); + Inits.push_back(nullptr); continue; } - SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc - : RefExpr->getExprLoc(); + SourceLocation ELoc = + IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] @@ -2971,6 +4251,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + PrivateCopies.push_back(nullptr); + Inits.push_back(nullptr); continue; } @@ -3004,65 +4286,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // clause requires an accessible, unambiguous copy constructor for the // class type. Type = Context.getBaseElementType(Type); - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the firstprivate variable. - if (RD) { - CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - if (IsImplicitClause) { - Diag(ImplicitClauseLoc, - diag::err_omp_task_predetermined_firstprivate_required_method) - << 0; - Diag(RefExpr->getExprLoc(), diag::note_used_here); - } else { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_firstprivate) << 1; - } - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - if (IsImplicitClause) { - Diag(ImplicitClauseLoc, - diag::err_omp_task_predetermined_firstprivate_required_method) - << 1; - Diag(RefExpr->getExprLoc(), diag::note_used_here); - } else { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_firstprivate) << 4; - } - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); - } - } // If an implicit firstprivate variable found it was checked already. if (!IsImplicitClause) { @@ -3152,15 +4375,75 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, } } + Type = Type.getUnqualifiedType(); + auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(), + ELoc, VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + // Generate helper private variable and initialize it with the value of the + // original variable. The address of the original variable is replaced by + // the address of the new private variable in the CodeGen. This new variable + // is not added to IdResolver, so the code in the OpenMP region uses + // original variable for proper diagnostics and variable capturing. + Expr *VDInitRefExpr = nullptr; + // For arrays generate initializer for single element and replace it by the + // original array element in CodeGen. + if (DE->getType()->isArrayType()) { + auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(), + ELoc, VD->getIdentifier(), Type, + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + CurContext->addHiddenDecl(VDInit); + VDInitRefExpr = DeclRefExpr::Create( + Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDInit, + /*RefersToEnclosingVariableOrCapture*/ true, ELoc, Type, + /*VK*/ VK_LValue); + VDInit->setIsUsed(); + auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); + InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit); + InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc); + + InitializationSequence InitSeq(*this, Entity, Kind, Init); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init); + if (Result.isInvalid()) + VDPrivate->setInvalidDecl(); + else + VDPrivate->setInit(Result.getAs<Expr>()); + } else { + AddInitializerToDecl( + VDPrivate, + DefaultLvalueConversion( + DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), DE->getDecl(), + /*RefersToEnclosingVariableOrCapture=*/true, + DE->getExprLoc(), DE->getType(), + /*VK=*/VK_LValue)).get(), + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); + } + if (VDPrivate->isInvalidDecl()) { + if (IsImplicitClause) { + Diag(DE->getExprLoc(), + diag::note_omp_task_predetermined_firstprivate_here); + } + continue; + } + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = + DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDPrivate, + /*RefersToEnclosingVariableOrCapture*/ false, + DE->getLocStart(), DE->getType(), + /*VK*/ VK_LValue); DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); + PrivateCopies.push_back(VDPrivateRefExpr); + Inits.push_back(VDInitRefExpr); } if (Vars.empty()) return nullptr; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); + Vars, PrivateCopies, Inits); } OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, @@ -4099,4 +5382,3 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } -#undef DSAStack diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 03001d8..9195ee5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -35,7 +35,7 @@ #include <algorithm> #include <cstdlib> -namespace clang { +using namespace clang; using namespace sema; /// A convenience routine for creating a decayed reference to a function. @@ -102,43 +102,9 @@ CompareDerivedToBaseConversions(Sema &S, const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); - - -/// GetConversionCategory - Retrieve the implicit conversion -/// category corresponding to the given implicit conversion kind. -ImplicitConversionCategory -GetConversionCategory(ImplicitConversionKind Kind) { - static const ImplicitConversionCategory - Category[(int)ICK_Num_Conversion_Kinds] = { - ICC_Identity, - ICC_Lvalue_Transformation, - ICC_Lvalue_Transformation, - ICC_Lvalue_Transformation, - ICC_Identity, - ICC_Qualification_Adjustment, - ICC_Promotion, - ICC_Promotion, - ICC_Promotion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion, - ICC_Conversion - }; - return Category[(int)Kind]; -} - /// GetConversionRank - Retrieve the implicit conversion rank /// corresponding to the given implicit conversion kind. -ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { +ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { static const ImplicitConversionRank Rank[(int)ICK_Num_Conversion_Kinds] = { ICR_Exact_Match, @@ -171,7 +137,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { /// GetImplicitConversionName - Return the name of this kind of /// implicit conversion. -const char* GetImplicitConversionName(ImplicitConversionKind Kind) { +static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { static const char* const Name[(int)ICK_Num_Conversion_Kinds] = { "No conversion", "Lvalue-to-rvalue", @@ -195,7 +161,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Vector splat", "Complex-real conversion", "Block Pointer conversion", - "Transparent Union Conversion" + "Transparent Union Conversion", "Writeback conversion" }; return Name[Kind]; @@ -568,9 +534,10 @@ namespace { /// \brief Convert from Sema's representation of template deduction information /// to the form used in overload-candidate information. -DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, - Sema::TemplateDeductionResult TDK, - TemplateDeductionInfo &Info) { +DeductionFailureInfo +clang::MakeDeductionFailureInfo(ASTContext &Context, + Sema::TemplateDeductionResult TDK, + TemplateDeductionInfo &Info) { DeductionFailureInfo Result; Result.Result = static_cast<unsigned>(TDK); Result.HasDiagnostic = false; @@ -1067,7 +1034,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // is a redeclaration of OldMethod. unsigned OldQuals = OldMethod->getTypeQualifiers(); unsigned NewQuals = NewMethod->getTypeQualifiers(); - if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() && + if (!getLangOpts().CPlusPlus14 && NewMethod->isConstexpr() && !isa<CXXConstructorDecl>(NewMethod)) NewQuals |= Qualifiers::Const; @@ -1268,11 +1235,11 @@ Sema::TryImplicitConversion(Expr *From, QualType ToType, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion) { - return clang::TryImplicitConversion(*this, From, ToType, - SuppressUserConversions, AllowExplicit, - InOverloadResolution, CStyle, - AllowObjCWritebackConversion, - /*AllowObjCConversionOnExplicit=*/false); + return ::TryImplicitConversion(*this, From, ToType, + SuppressUserConversions, AllowExplicit, + InOverloadResolution, CStyle, + AllowObjCWritebackConversion, + /*AllowObjCConversionOnExplicit=*/false); } /// PerformImplicitConversion - Perform an implicit conversion of the @@ -1301,13 +1268,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (getLangOpts().ObjC1) CheckObjCBridgeRelatedConversions(From->getLocStart(), ToType, From->getType(), From); - ICS = clang::TryImplicitConversion(*this, From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*InOverloadResolution=*/false, - /*CStyle=*/false, - AllowObjCWritebackConversion, - /*AllowObjCConversionOnExplicit=*/false); + ICS = ::TryImplicitConversion(*this, From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + AllowObjCWritebackConversion, + /*AllowObjCConversionOnExplicit=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -1451,6 +1418,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); + SCS.setFromType(FromType); // we can sometimes resolve &foo<int> regardless of ToType, so check // if the type matches (identity) or we are converting to bool @@ -3656,7 +3624,7 @@ CompareStandardConversionSequences(Sema &S, /// CompareQualificationConversions - Compares two standard conversion /// sequences to determine whether they can be ranked based on their /// qualification conversions (C++ 13.3.3.2p3 bullet 3). -ImplicitConversionSequence::CompareKind +static ImplicitConversionSequence::CompareKind CompareQualificationConversions(Sema &S, const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { @@ -3769,7 +3737,7 @@ CompareQualificationConversions(Sema &S, /// various kinds of derived-to-base conversions (C++ /// [over.ics.rank]p4b3). As part of these checks, we also look at /// conversions between Objective-C interface types. -ImplicitConversionSequence::CompareKind +static ImplicitConversionSequence::CompareKind CompareDerivedToBaseConversions(Sema &S, const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { @@ -4849,9 +4817,8 @@ Sema::PerformObjectArgumentInitialization(Expr *From, // Note that we always use the true parent context when performing // the actual argument initialization. - ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(*this, From->getType(), FromClassification, - Method, Method->getParent()); + ImplicitConversionSequence ICS = TryObjectArgumentInitialization( + *this, From->getType(), FromClassification, Method, Method->getParent()); if (ICS.isBad()) { if (ICS.Bad.Kind == BadConversionSequence::bad_qualifiers) { Qualifiers FromQs = FromRecordType.getQualifiers(); @@ -4927,41 +4894,51 @@ static bool CheckConvertedConstantConversions(Sema &S, // conversions are fine. switch (SCS.Second) { case ICK_Identity: + case ICK_NoReturn_Adjustment: case ICK_Integral_Promotion: - case ICK_Integral_Conversion: - case ICK_Zero_Event_Conversion: + case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere. return true; case ICK_Boolean_Conversion: // Conversion from an integral or unscoped enumeration type to bool is - // classified as ICK_Boolean_Conversion, but it's also an integral - // conversion, so it's permitted in a converted constant expression. + // classified as ICK_Boolean_Conversion, but it's also arguably an integral + // conversion, so we allow it in a converted constant expression. + // + // FIXME: Per core issue 1407, we should not allow this, but that breaks + // a lot of popular code. We should at least add a warning for this + // (non-conforming) extension. return SCS.getFromType()->isIntegralOrUnscopedEnumerationType() && SCS.getToType(2)->isBooleanType(); + case ICK_Pointer_Conversion: + case ICK_Pointer_Member: + // C++1z: null pointer conversions and null member pointer conversions are + // only permitted if the source type is std::nullptr_t. + return SCS.getFromType()->isNullPtrType(); + + case ICK_Floating_Promotion: + case ICK_Complex_Promotion: + case ICK_Floating_Conversion: + case ICK_Complex_Conversion: case ICK_Floating_Integral: + case ICK_Compatible_Conversion: + case ICK_Derived_To_Base: + case ICK_Vector_Conversion: + case ICK_Vector_Splat: case ICK_Complex_Real: + case ICK_Block_Pointer_Conversion: + case ICK_TransparentUnionConversion: + case ICK_Writeback_Conversion: + case ICK_Zero_Event_Conversion: return false; case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: - case ICK_NoReturn_Adjustment: + llvm_unreachable("found a first conversion kind in Second"); + case ICK_Qualification: - case ICK_Compatible_Conversion: - case ICK_Vector_Conversion: - case ICK_Vector_Splat: - case ICK_Derived_To_Base: - case ICK_Pointer_Conversion: - case ICK_Pointer_Member: - case ICK_Block_Pointer_Conversion: - case ICK_Writeback_Conversion: - case ICK_Floating_Promotion: - case ICK_Complex_Promotion: - case ICK_Complex_Conversion: - case ICK_Floating_Conversion: - case ICK_TransparentUnionConversion: - llvm_unreachable("unexpected second conversion kind"); + llvm_unreachable("found a third conversion kind in Second"); case ICK_Num_Conversion_Kinds: break; @@ -4973,67 +4950,71 @@ static bool CheckConvertedConstantConversions(Sema &S, /// CheckConvertedConstantExpression - Check that the expression From is a /// converted constant expression of type T, perform the conversion and produce /// the converted expression, per C++11 [expr.const]p3. -ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, - llvm::APSInt &Value, - CCEKind CCE) { - assert(LangOpts.CPlusPlus11 && "converted constant expression outside C++11"); - assert(T->isIntegralOrEnumerationType() && "unexpected converted const type"); - - if (checkPlaceholderForOverload(*this, From)) +static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, + QualType T, APValue &Value, + Sema::CCEKind CCE, + bool RequireInt) { + assert(S.getLangOpts().CPlusPlus11 && + "converted constant expression outside C++11"); + + if (checkPlaceholderForOverload(S, From)) return ExprError(); - // C++11 [expr.const]p3 with proposed wording fixes: - // A converted constant expression of type T is a core constant expression, - // implicitly converted to a prvalue of type T, where the converted - // expression is a literal constant expression and the implicit conversion - // sequence contains only user-defined conversions, lvalue-to-rvalue - // conversions, integral promotions, and integral conversions other than - // narrowing conversions. + // C++1z [expr.const]p3: + // A converted constant expression of type T is an expression, + // implicitly converted to type T, where the converted + // expression is a constant expression and the implicit conversion + // sequence contains only [... list of conversions ...]. ImplicitConversionSequence ICS = - TryImplicitConversion(From, T, + TryCopyInitialization(S, From, T, /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, /*InOverloadResolution=*/false, - /*CStyle=*/false, - /*AllowObjcWritebackConversion=*/false); + /*AllowObjcWritebackConversion=*/false, + /*AllowExplicit=*/false); StandardConversionSequence *SCS = nullptr; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: - if (!CheckConvertedConstantConversions(*this, ICS.Standard)) - return Diag(From->getLocStart(), - diag::err_typecheck_converted_constant_expression_disallowed) - << From->getType() << From->getSourceRange() << T; SCS = &ICS.Standard; break; case ImplicitConversionSequence::UserDefinedConversion: - // We are converting from class type to an integral or enumeration type, so - // the Before sequence must be trivial. - if (!CheckConvertedConstantConversions(*this, ICS.UserDefined.After)) - return Diag(From->getLocStart(), - diag::err_typecheck_converted_constant_expression_disallowed) - << From->getType() << From->getSourceRange() << T; + // We are converting to a non-class type, so the Before sequence + // must be trivial. SCS = &ICS.UserDefined.After; break; case ImplicitConversionSequence::AmbiguousConversion: case ImplicitConversionSequence::BadConversion: - if (!DiagnoseMultipleUserDefinedConversion(From, T)) - return Diag(From->getLocStart(), - diag::err_typecheck_converted_constant_expression) - << From->getType() << From->getSourceRange() << T; + if (!S.DiagnoseMultipleUserDefinedConversion(From, T)) + return S.Diag(From->getLocStart(), + diag::err_typecheck_converted_constant_expression) + << From->getType() << From->getSourceRange() << T; return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("ellipsis conversion in converted constant expression"); } - ExprResult Result = PerformImplicitConversion(From, T, ICS, AA_Converting); + // Check that we would only use permitted conversions. + if (!CheckConvertedConstantConversions(S, *SCS)) { + return S.Diag(From->getLocStart(), + diag::err_typecheck_converted_constant_expression_disallowed) + << From->getType() << From->getSourceRange() << T; + } + // [...] and where the reference binding (if any) binds directly. + if (SCS->ReferenceBinding && !SCS->DirectBinding) { + return S.Diag(From->getLocStart(), + diag::err_typecheck_converted_constant_expression_indirect) + << From->getType() << From->getSourceRange() << T; + } + + ExprResult Result = + S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting); if (Result.isInvalid()) return Result; // Check for a narrowing implicit conversion. APValue PreNarrowingValue; QualType PreNarrowingType; - switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue, + switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, PreNarrowingType)) { case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant @@ -5042,13 +5023,13 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, break; case NK_Constant_Narrowing: - Diag(From->getLocStart(), diag::ext_cce_narrowing) + S.Diag(From->getLocStart(), diag::ext_cce_narrowing) << CCE << /*Constant*/1 - << PreNarrowingValue.getAsString(Context, PreNarrowingType) << T; + << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T; break; case NK_Type_Narrowing: - Diag(From->getLocStart(), diag::ext_cce_narrowing) + S.Diag(From->getLocStart(), diag::ext_cce_narrowing) << CCE << /*Constant*/0 << From->getType() << T; break; } @@ -5058,12 +5039,15 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, Expr::EvalResult Eval; Eval.Diag = &Notes; - if (!Result.get()->EvaluateAsRValue(Eval, Context) || !Eval.Val.isInt()) { + if ((T->isReferenceType() + ? !Result.get()->EvaluateAsLValue(Eval, S.Context) + : !Result.get()->EvaluateAsRValue(Eval, S.Context)) || + (RequireInt && !Eval.Val.isInt())) { // The expression can't be folded, so we can't keep it at this position in // the AST. Result = ExprError(); } else { - Value = Eval.Val.getInt(); + Value = Eval.Val; if (Notes.empty()) { // It's a constant expression. @@ -5074,16 +5058,34 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, // It's not a constant expression. Produce an appropriate diagnostic. if (Notes.size() == 1 && Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) - Diag(Notes[0].first, diag::err_expr_not_cce) << CCE; + S.Diag(Notes[0].first, diag::err_expr_not_cce) << CCE; else { - Diag(From->getLocStart(), diag::err_expr_not_cce) + S.Diag(From->getLocStart(), diag::err_expr_not_cce) << CCE << From->getSourceRange(); for (unsigned I = 0; I < Notes.size(); ++I) - Diag(Notes[I].first, Notes[I].second); + S.Diag(Notes[I].first, Notes[I].second); } - return Result; + return ExprError(); +} + +ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, + APValue &Value, CCEKind CCE) { + return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false); } +ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, + llvm::APSInt &Value, + CCEKind CCE) { + assert(T->isIntegralOrEnumerationType() && "unexpected converted const type"); + + APValue V; + auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true); + if (!R.isInvalid()) + Value = V.getInt(); + return R; +} + + /// dropPointerConversions - If the given standard conversion sequence /// involves any pointer conversions, remove them. This may change /// the result type of the conversion sequence. @@ -5364,14 +5366,14 @@ ExprResult Sema::PerformContextualImplicitConversion( CXXConversionDecl *Conversion; FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); if (ConvTemplate) { - if (getLangOpts().CPlusPlus1y) + if (getLangOpts().CPlusPlus14) Conversion = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else continue; // C++11 does not consider conversion operator templates(?). } else Conversion = cast<CXXConversionDecl>(D); - assert((!ConvTemplate || getLangOpts().CPlusPlus1y) && + assert((!ConvTemplate || getLangOpts().CPlusPlus14) && "Conversion operator templates are considered potentially " "viable in C++1y"); @@ -5384,7 +5386,7 @@ ExprResult Sema::PerformContextualImplicitConversion( if (!ConvTemplate) ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); } else { - if (!ConvTemplate && getLangOpts().CPlusPlus1y) { + if (!ConvTemplate && getLangOpts().CPlusPlus14) { if (ToType.isNull()) ToType = CurToType.getUnqualifiedType(); else if (HasUniqueTargetType && @@ -5396,7 +5398,7 @@ ExprResult Sema::PerformContextualImplicitConversion( } } - if (getLangOpts().CPlusPlus1y) { + if (getLangOpts().CPlusPlus14) { // C++1y [conv]p6: // ... An expression e of class type E appearing in such a context // is said to be contextually implicitly converted to a specified @@ -5584,6 +5586,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // Overload resolution is always an unevaluated context. EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); + // Add this candidate + OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size()); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = Function; + Candidate.Viable = true; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.ExplicitCallArguments = Args.size(); + if (Constructor) { // C++ [class.copy]p3: // A member function template is never instantiated to perform the copy @@ -5592,19 +5603,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (Args.size() == 1 && Constructor->isSpecializationCopyingObject() && (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) || - IsDerivedFrom(Args[0]->getType(), ClassType))) + IsDerivedFrom(Args[0]->getType(), ClassType))) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_illegal_constructor; return; + } } - // Add this candidate - OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size()); - Candidate.FoundDecl = FoundDecl; - Candidate.Function = Function; - Candidate.Viable = true; - Candidate.IsSurrogate = false; - Candidate.IgnoreObjectArgument = false; - Candidate.ExplicitCallArguments = Args.size(); - unsigned NumParams = Proto->getNumParams(); // (C++ 13.3.2p2): A candidate function having fewer than m @@ -5633,7 +5638,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // (CUDA B.1): Check for invalid calls between targets. if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) - if (CheckCUDATarget(Caller, Function)) { + // Skip the check for callers that are implicit members, because in this + // case we may not yet know what the member's target is; the target is + // inferred for the member automatically, based on the bases and fields of + // the class. + if (!Caller->isImplicit() && CheckCUDATarget(Caller, Function)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_target; return; @@ -5676,6 +5685,93 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, } } +ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, + bool IsInstance) { + SmallVector<ObjCMethodDecl*, 4> Methods; + if (!CollectMultipleMethodsInGlobalPool(Sel, Methods, IsInstance)) + return nullptr; + + for (unsigned b = 0, e = Methods.size(); b < e; b++) { + bool Match = true; + ObjCMethodDecl *Method = Methods[b]; + unsigned NumNamedArgs = Sel.getNumArgs(); + // Method might have more arguments than selector indicates. This is due + // to addition of c-style arguments in method. + if (Method->param_size() > NumNamedArgs) + NumNamedArgs = Method->param_size(); + if (Args.size() < NumNamedArgs) + continue; + + for (unsigned i = 0; i < NumNamedArgs; i++) { + // We can't do any type-checking on a type-dependent argument. + if (Args[i]->isTypeDependent()) { + Match = false; + break; + } + + ParmVarDecl *param = Method->parameters()[i]; + Expr *argExpr = Args[i]; + assert(argExpr && "SelectBestMethod(): missing expression"); + + // Strip the unbridged-cast placeholder expression off unless it's + // a consumed argument. + if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) && + !param->hasAttr<CFConsumedAttr>()) + argExpr = stripARCUnbridgedCast(argExpr); + + // If the parameter is __unknown_anytype, move on to the next method. + if (param->getType() == Context.UnknownAnyTy) { + Match = false; + break; + } + + ImplicitConversionSequence ConversionState + = TryCopyInitialization(*this, argExpr, param->getType(), + /*SuppressUserConversions*/false, + /*InOverloadResolution=*/true, + /*AllowObjCWritebackConversion=*/ + getLangOpts().ObjCAutoRefCount, + /*AllowExplicit*/false); + if (ConversionState.isBad()) { + Match = false; + break; + } + } + // Promote additional arguments to variadic methods. + if (Match && Method->isVariadic()) { + for (unsigned i = NumNamedArgs, e = Args.size(); i < e; ++i) { + if (Args[i]->isTypeDependent()) { + Match = false; + break; + } + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, + nullptr); + if (Arg.isInvalid()) { + Match = false; + break; + } + } + } else { + // Check for extra arguments to non-variadic methods. + if (Args.size() != NumNamedArgs) + Match = false; + else if (Match && NumNamedArgs == 0 && Methods.size() > 1) { + // Special case when selectors have no argument. In this case, select + // one with the most general result type of 'id'. + for (unsigned b = 0, e = Methods.size(); b < e; b++) { + QualType ReturnT = Methods[b]->getReturnType(); + if (ReturnT->isObjCIdType()) + return Methods[b]; + } + } + } + + if (Match) + return Method; + } + return nullptr; +} + static bool IsNotEnableIfAttr(Attr *A) { return !isa<EnableIfAttr>(A); } EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, @@ -5696,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, // Convert the arguments. SmallVector<Expr *, 16> ConvertedArgs; bool InitializationFailed = false; + bool ContainsValueDependentExpr = false; for (unsigned i = 0, e = Args.size(); i != e; ++i) { if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) && !cast<CXXMethodDecl>(Function)->isStatic() && @@ -5708,6 +5805,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, InitializationFailed = true; break; } + ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } else { ExprResult R = @@ -5720,6 +5818,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, InitializationFailed = true; break; } + ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } } @@ -5730,11 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) { APValue Result; EnableIfAttr *EIA = cast<EnableIfAttr>(*I); + if (EIA->getCond()->isValueDependent()) { + // Don't even try now, we'll examine it after instantiation. + continue; + } + if (!EIA->getCond()->EvaluateWithSubstitution( - Result, Context, Function, - ArrayRef<const Expr*>(ConvertedArgs.data(), - ConvertedArgs.size())) || - !Result.isInt() || !Result.getInt().getBoolValue()) { + Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) { + if (!ContainsValueDependentExpr) + return EIA; + } else if (!Result.isInt() || !Result.getInt().getBoolValue()) { return EIA; } } @@ -5891,6 +5995,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, } } + // (CUDA B.1): Check for invalid calls between targets. + if (getLangOpts().CUDA) + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) + if (CheckCUDATarget(Caller, Method)) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_target; + return; + } + // Determine the implicit conversion sequences for each of the // arguments. for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { @@ -6087,7 +6200,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // If the conversion function has an undeduced return type, trigger its // deduction now. - if (getLangOpts().CPlusPlus1y && ConvType->isUndeducedType()) { + if (getLangOpts().CPlusPlus14 && ConvType->isUndeducedType()) { if (DeduceReturnType(Conversion, From->getExprLoc())) return; ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -6226,7 +6339,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, "Can only end up with a standard conversion sequence or failure"); } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) { + if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -6379,7 +6492,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) { + if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -6610,7 +6723,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, const Qualifiers &VisibleQuals) { // Insert this type. - if (!PointerTypes.insert(Ty)) + if (!PointerTypes.insert(Ty).second) return false; QualType PointeeTy; @@ -6678,7 +6791,7 @@ bool BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( QualType Ty) { // Insert this type. - if (!MemberPointerTypes.insert(Ty)) + if (!MemberPointerTypes.insert(Ty).second) return false; const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>(); @@ -7248,7 +7361,7 @@ public: MemPtr != MemPtrEnd; ++MemPtr) { // Don't add the same builtin candidate twice. - if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second) continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; @@ -7323,7 +7436,7 @@ public: PtrEnd = CandidateTypes[ArgIdx].pointer_end(); Ptr != PtrEnd; ++Ptr) { // Don't add the same builtin candidate twice. - if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second) continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; @@ -7337,7 +7450,7 @@ public: // Don't add the same builtin candidate twice, or if a user defined // candidate exists. - if (!AddedTypes.insert(CanonType) || + if (!AddedTypes.insert(CanonType).second || UserDefinedBinaryOperators.count(std::make_pair(CanonType, CanonType))) continue; @@ -7348,7 +7461,7 @@ public: if (CandidateTypes[ArgIdx].hasNullPtrType()) { CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); - if (AddedTypes.insert(NullPtrTy) && + if (AddedTypes.insert(NullPtrTy).second && !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, NullPtrTy))) { QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; @@ -7401,7 +7514,7 @@ public: } if (Op == OO_Minus) { // ptrdiff_t operator-(T, T); - if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second) continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; @@ -7530,7 +7643,7 @@ public: Enum = CandidateTypes[ArgIdx].enumeration_begin(), EnumEnd = CandidateTypes[ArgIdx].enumeration_end(); Enum != EnumEnd; ++Enum) { - if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second) continue; AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, CandidateSet); @@ -7540,7 +7653,7 @@ public: MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); MemPtr != MemPtrEnd; ++MemPtr) { - if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second) continue; AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, CandidateSet); @@ -7623,7 +7736,7 @@ public: PtrEnd = CandidateTypes[1].pointer_end(); Ptr != PtrEnd; ++Ptr) { // Make sure we don't add the same candidate twice. - if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second) continue; QualType ParamTypes[2] = { @@ -7904,7 +8017,7 @@ public: Ptr = CandidateTypes[ArgIdx].pointer_begin(), PtrEnd = CandidateTypes[ArgIdx].pointer_end(); Ptr != PtrEnd; ++Ptr) { - if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Ptr)).second) continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; @@ -7915,7 +8028,7 @@ public: MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); MemPtr != MemPtrEnd; ++MemPtr) { - if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr)).second) continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; @@ -7930,7 +8043,7 @@ public: if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped()) continue; - if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) + if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second) continue; QualType ParamTypes[2] = { *Enum, *Enum }; @@ -8184,12 +8297,10 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). -bool -isBetterOverloadCandidate(Sema &S, - const OverloadCandidate &Cand1, - const OverloadCandidate &Cand2, - SourceLocation Loc, - bool UserDefinedConversion) { +bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2, + SourceLocation Loc, + bool UserDefinedConversion) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -8521,9 +8632,8 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion( S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I); } -namespace { - -void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { +static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, + unsigned I) { const ImplicitConversionSequence &Conv = Cand->Conversions[I]; assert(Conv.isBad()); assert(Cand->Function && "for now, candidate must be a function"); @@ -8741,8 +8851,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { /// Additional arity mismatch diagnosis specific to a function overload /// candidates. This is not covered by the more general DiagnoseArityMismatch() /// over a candidate in any candidate set. -bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { +static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; unsigned MinParams = Fn->getMinRequiredArguments(); @@ -8769,7 +8879,7 @@ bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, } /// General arity mismatch diagnosis over a candidate in a candidate set. -void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { +static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { assert(isa<FunctionDecl>(D) && "The templated declaration should at least be a function" " when diagnosing bad template argument deduction due to too many" @@ -8813,13 +8923,13 @@ void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { } /// Arity mismatch diagnosis specific to a function overload candidate. -void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, - unsigned NumFormalArgs) { +static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumFormalArgs) { if (!CheckArityMismatch(S, Cand, NumFormalArgs)) DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs); } -TemplateDecl *getDescribedTemplate(Decl *Templated) { +static TemplateDecl *getDescribedTemplate(Decl *Templated) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated)) return FD->getDescribedFunctionTemplate(); else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated)) @@ -8830,9 +8940,9 @@ TemplateDecl *getDescribedTemplate(Decl *Templated) { } /// Diagnose a failed template-argument deduction. -void DiagnoseBadDeduction(Sema &S, Decl *Templated, - DeductionFailureInfo &DeductionFailure, - unsigned NumArgs) { +static void DiagnoseBadDeduction(Sema &S, Decl *Templated, + DeductionFailureInfo &DeductionFailure, + unsigned NumArgs) { TemplateParameter Param = DeductionFailure.getTemplateParameter(); NamedDecl *ParamD; (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || @@ -9019,7 +9129,8 @@ void DiagnoseBadDeduction(Sema &S, Decl *Templated, } /// Diagnose a failed template-argument deduction, for function calls. -void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) { +static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, + unsigned NumArgs) { unsigned TDK = Cand->DeductionFailure.Result; if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) { if (CheckArityMismatch(S, Cand, NumArgs)) @@ -9030,7 +9141,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs) { } /// CUDA: diagnose an invalid call across targets. -void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { +static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext); FunctionDecl *Callee = Cand->Function; @@ -9041,10 +9152,50 @@ void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) - << (unsigned) FnKind << CalleeTarget << CallerTarget; + << (unsigned)FnKind << CalleeTarget << CallerTarget; + + // This could be an implicit constructor for which we could not infer the + // target due to a collsion. Diagnose that case. + CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Callee); + if (Meth != nullptr && Meth->isImplicit()) { + CXXRecordDecl *ParentClass = Meth->getParent(); + Sema::CXXSpecialMember CSM; + + switch (FnKind) { + default: + return; + case oc_implicit_default_constructor: + CSM = Sema::CXXDefaultConstructor; + break; + case oc_implicit_copy_constructor: + CSM = Sema::CXXCopyConstructor; + break; + case oc_implicit_move_constructor: + CSM = Sema::CXXMoveConstructor; + break; + case oc_implicit_copy_assignment: + CSM = Sema::CXXCopyAssignment; + break; + case oc_implicit_move_assignment: + CSM = Sema::CXXMoveAssignment; + break; + }; + + bool ConstRHS = false; + if (Meth->getNumParams()) { + if (const ReferenceType *RT = + Meth->getParamDecl(0)->getType()->getAs<ReferenceType>()) { + ConstRHS = RT->getPointeeType().isConstQualified(); + } + } + + S.inferCUDATargetForImplicitSpecialMember(ParentClass, CSM, Meth, + /* ConstRHS */ ConstRHS, + /* Diagnose */ true); + } } -void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { +static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Callee = Cand->Function; EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data); @@ -9066,8 +9217,8 @@ void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { /// It would be great to be able to express per-candidate problems /// more richly for those diagnostic clients that cared, but we'd /// still have to be just as careful with the default diagnostics. -void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { +static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, + unsigned NumArgs) { FunctionDecl *Fn = Cand->Function; // Note deleted candidates, but only if they're viable. @@ -9097,6 +9248,13 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_bad_deduction: return DiagnoseBadDeduction(S, Cand, NumArgs); + case ovl_fail_illegal_constructor: { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor) + << (Fn->getPrimaryTemplate() ? 1 : 0); + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: case ovl_fail_final_conversion_not_exact: @@ -9122,7 +9280,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, } } -void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { +static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { // Desugar the type of the surrogate down to a function type, // retaining as many typedefs as possible while still showing // the function type (and, therefore, its parameter types). @@ -9155,10 +9313,9 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { MaybeEmitInheritedConstructorNote(S, Cand->Surrogate); } -void NoteBuiltinOperatorCandidate(Sema &S, - StringRef Opc, - SourceLocation OpLoc, - OverloadCandidate *Cand) { +static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc, + SourceLocation OpLoc, + OverloadCandidate *Cand) { assert(Cand->NumConversions <= 2 && "builtin operator is not binary"); std::string TypeStr("operator"); TypeStr += Opc; @@ -9175,8 +9332,8 @@ void NoteBuiltinOperatorCandidate(Sema &S, } } -void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, - OverloadCandidate *Cand) { +static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, + OverloadCandidate *Cand) { unsigned NoOperands = Cand->NumConversions; for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; @@ -9228,6 +9385,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { llvm_unreachable("Unhandled deduction result"); } +namespace { struct CompareOverloadCandidatesForDisplay { Sema &S; size_t NumArgs; @@ -9351,11 +9509,12 @@ struct CompareOverloadCandidatesForDisplay { return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); } }; +} /// CompleteNonViableCandidate - Normally, overload resolution only /// computes up to the first. Produces the FixIt set if possible. -void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, - ArrayRef<Expr *> Args) { +static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, + ArrayRef<Expr *> Args) { assert(!Cand->Viable); // Don't do anything on failures other than bad conversion. @@ -9435,8 +9594,6 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, } } -} // end anonymous namespace - /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate /// set. @@ -9513,6 +9670,7 @@ GetLocationForCandidate(const TemplateSpecCandidate *Cand) { : SourceLocation(); } +namespace { struct CompareTemplateSpecCandidatesForDisplay { Sema &S; CompareTemplateSpecCandidatesForDisplay(Sema &S) : S(S) {} @@ -9543,6 +9701,7 @@ struct CompareTemplateSpecCandidatesForDisplay { return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); } }; +} /// Diagnose a template argument deduction failure. /// We are treating these failures as overload failures due to bad @@ -9631,10 +9790,10 @@ QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) { return Ret; } +namespace { // A helper class to help with address of function resolution // - allows us to avoid passing around all those ugly parameters -class AddressOfFunctionResolver -{ +class AddressOfFunctionResolver { Sema& S; Expr* SourceExpr; const QualType& TargetType; @@ -9782,12 +9941,12 @@ private: if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { if (S.getLangOpts().CUDA) if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) - if (S.CheckCUDATarget(Caller, FunDecl)) + if (!Caller->isImplicit() && S.CheckCUDATarget(Caller, FunDecl)) return false; // If any candidate has a placeholder return type, trigger its deduction // now. - if (S.getLangOpts().CPlusPlus1y && + if (S.getLangOpts().CPlusPlus14 && FunDecl->getReturnType()->isUndeducedType() && S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain)) return false; @@ -9960,7 +10119,8 @@ public: return &Matches[0].first; } }; - +} + /// ResolveAddressOfOverloadedFunction - Try to resolve the address of /// an overloaded function (C++ [over.over]), where @p From is an /// expression with overloaded function type and @p ToType is the type @@ -10092,7 +10252,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, if (FoundResult) *FoundResult = I.getPair(); } - if (Matched && getLangOpts().CPlusPlus1y && + if (Matched && getLangOpts().CPlusPlus14 && Matched->getReturnType()->isUndeducedType() && DeduceReturnType(Matched, ovl->getExprLoc(), Complain)) return nullptr; @@ -10422,6 +10582,15 @@ public: } +static std::unique_ptr<CorrectionCandidateCallback> +MakeValidator(Sema &SemaRef, MemberExpr *ME, size_t NumArgs, + bool HasTemplateArgs, bool AllowTypoCorrection) { + if (!AllowTypoCorrection) + return llvm::make_unique<NoTypoCorrectionCCC>(); + return llvm::make_unique<FunctionCallFilterCCC>(SemaRef, NumArgs, + HasTemplateArgs, ME); +} + /// Attempts to recover from a call where no functions were found. /// /// Returns true if new candidates were found. @@ -10455,19 +10624,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - FunctionCallFilterCCC Validator(SemaRef, Args.size(), - ExplicitTemplateArgs != nullptr, - dyn_cast<MemberExpr>(Fn)); - NoTypoCorrectionCCC RejectAll; - CorrectionCandidateCallback *CCC = AllowTypoCorrection ? - (CorrectionCandidateCallback*)&Validator : - (CorrectionCandidateCallback*)&RejectAll; if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R, OverloadCandidateSet::CSK_Normal, ExplicitTemplateArgs, Args) && (!EmptyLookup || - SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC, - ExplicitTemplateArgs, Args))) + SemaRef.DiagnoseEmptyLookup( + S, SS, R, + MakeValidator(SemaRef, dyn_cast<MemberExpr>(Fn), Args.size(), + ExplicitTemplateArgs != nullptr, AllowTypoCorrection), + ExplicitTemplateArgs, Args))) return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); @@ -10945,10 +11110,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); - // Add candidates from ADL. - AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, - /*ExplicitTemplateArgs*/ nullptr, - CandidateSet); + // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not + // performed for an assignment operator (nor for operator[] nor operator->, + // which don't get here). + if (Opc != BO_Assign) + AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, + /*ExplicitTemplateArgs*/ nullptr, + CandidateSet); // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); @@ -11031,7 +11199,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Cut off the implicit 'this'. if (isa<CXXMethodDecl>(FnDecl)) ArgsArray = ArgsArray.slice(1); - checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc, + + // Check for a self move. + if (Op == OO_Equal) + DiagnoseSelfMove(Args[0], Args[1], OpLoc); + + checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(), VariadicDoesNotApply); return MaybeBindToTemporary(TheCall); @@ -11352,6 +11525,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << (qualsString.find(' ') == std::string::npos ? 1 : 2); } + if (resultType->isMemberPointerType()) + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) + RequireCompleteType(LParenLoc, resultType, 0); + CXXMemberCallExpr *call = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, resultType, valueKind, RParenLoc); @@ -11505,6 +11682,18 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, ResultType, VK, RParenLoc); + // (CUDA B.1): Check for invalid calls between targets. + if (getLangOpts().CUDA) { + if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) { + if (CheckCUDATarget(Caller, Method)) { + Diag(MemExpr->getMemberLoc(), diag::err_ref_bad_target) + << IdentifyCUDATarget(Method) << Method->getIdentifier() + << IdentifyCUDATarget(Caller); + return ExprError(); + } + } + } + // Check for a valid return type. if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(), TheCall, Method)) @@ -11568,7 +11757,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) return ExprError(); - assert(Object.get()->getType()->isRecordType() && "Requires object type argument"); + assert(Object.get()->getType()->isRecordType() && + "Requires object type argument"); const RecordType *Record = Object.get()->getType()->getAs<RecordType>(); // C++ [over.call.object]p1: @@ -12272,5 +12462,3 @@ ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, FunctionDecl *Fn) { return FixOverloadedFunctionReference(E.get(), Found, Fn); } - -} // end namespace clang diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index aa3e89e..5e92d5d 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -406,6 +406,10 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, BinaryOperatorKind opcode, Expr *LHS, Expr *RHS) { assert(BinaryOperator::isAssignmentOp(opcode)); + + // Recover from user error + if (isa<UnresolvedLookupExpr>(RHS)) + return ExprError(); Expr *syntacticLHS = rebuildAndCaptureObject(LHS); OpaqueValueExpr *capturedRHS = capture(RHS); @@ -615,7 +619,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { if (setter->isPropertyAccessor() && warn) if (const ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) { - const StringRef thisPropertyName(prop->getName()); + StringRef thisPropertyName = prop->getName(); // Try flipping the case of the first character. char front = thisPropertyName.front(); front = isLowercase(front) ? toUppercase(front) : toLowercase(front); @@ -1022,7 +1026,8 @@ Sema::ObjCSubscriptKind // If we don't have a class type in C++, there's no way we can get an // expression of integral or enumeration type. const RecordType *RecordTy = T->getAs<RecordType>(); - if (!RecordTy && T->isObjCObjectPointerType()) + if (!RecordTy && + (T->isObjCObjectPointerType() || T->isVoidPointerType())) // All other scalar cases are assumed to be dictionary indexing which // caller handles, with diagnostics if needed. return OS_Dictionary; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 278e6d6..22ed930 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" @@ -184,6 +185,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { const Expr *E = dyn_cast_or_null<Expr>(S); if (!E) return; + + // If we are in an unevaluated expression context, then there can be no unused + // results because the results aren't expected to be used in the first place. + if (isUnevaluatedContext()) + return; + SourceLocation ExprLoc = E->IgnoreParens()->getExprLoc(); // In most cases, we don't want to warn if the expression is written in a // macro body, or if the macro comes from a system header. If the offending @@ -364,6 +371,23 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, return StmtError(); } + ExprResult LHS = + CorrectDelayedTyposInExpr(LHSVal, [this](class Expr *E) { + if (!getLangOpts().CPlusPlus11) + return VerifyIntegerConstantExpression(E); + if (Expr *CondExpr = + getCurFunction()->SwitchStack.back()->getCond()) { + QualType CondType = CondExpr->getType(); + llvm::APSInt TempVal; + return CheckConvertedConstantExpression(E, CondType, TempVal, + CCEK_CaseValue); + } + return ExprError(); + }); + if (LHS.isInvalid()) + return StmtError(); + LHSVal = LHS.get(); + if (!getLangOpts().CPlusPlus11) { // C99 6.8.4.2p3: The expression shall be an integer constant. // However, GCC allows any evaluatable integer expression. @@ -381,14 +405,19 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, } } - LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, - getLangOpts().CPlusPlus11).get(); - if (RHSVal) - RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false, - getLangOpts().CPlusPlus11).get(); + LHS = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, + getLangOpts().CPlusPlus11); + if (LHS.isInvalid()) + return StmtError(); + + auto RHS = RHSVal ? ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false, + getLangOpts().CPlusPlus11) + : ExprResult(); + if (RHS.isInvalid()) + return StmtError(); - CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, - ColonLoc); + CaseStmt *CS = new (Context) + CaseStmt(LHS.get(), RHS.get(), CaseLoc, DotDotDotLoc, ColonLoc); getCurFunction()->SwitchStack.back()->addSwitchCase(CS); return CS; } @@ -431,7 +460,11 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, TheDecl->setStmt(LS); if (!TheDecl->isGnuLocal()) { TheDecl->setLocStart(IdentLoc); - TheDecl->setLocation(IdentLoc); + if (!TheDecl->isMSAsmLabel()) { + // Don't update the location of MS ASM labels. These will result in + // a diagnostic, and changing the location here will mess that up. + TheDecl->setLocation(IdentLoc); + } } return LS; } @@ -481,47 +514,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, thenStmt, ElseLoc, elseStmt); } -/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have -/// the specified width and sign. If an overflow occurs, detect it and emit -/// the specified diagnostic. -void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, - unsigned NewWidth, bool NewSign, - SourceLocation Loc, - unsigned DiagID) { - // Perform a conversion to the promoted condition type if needed. - if (NewWidth > Val.getBitWidth()) { - // If this is an extension, just do it. - Val = Val.extend(NewWidth); - Val.setIsSigned(NewSign); - - // If the input was signed and negative and the output is - // unsigned, don't bother to warn: this is implementation-defined - // behavior. - // FIXME: Introduce a second, default-ignored warning for this case? - } else if (NewWidth < Val.getBitWidth()) { - // If this is a truncation, check for overflow. - llvm::APSInt ConvVal(Val); - ConvVal = ConvVal.trunc(NewWidth); - ConvVal.setIsSigned(NewSign); - ConvVal = ConvVal.extend(Val.getBitWidth()); - ConvVal.setIsSigned(Val.isSigned()); - if (ConvVal != Val) - Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10); - - // Regardless of whether a diagnostic was emitted, really do the - // truncation. - Val = Val.trunc(NewWidth); - Val.setIsSigned(NewSign); - } else if (NewSign != Val.isSigned()) { - // Convert the sign to match the sign of the condition. This can cause - // overflow as well: unsigned(INTMIN) - // We don't diagnose this overflow, because it is implementation-defined - // behavior. - // FIXME: Introduce a second, default-ignored warning for this case? - Val.setIsSigned(NewSign); - } -} - namespace { struct CaseCompareFunctor { bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS, @@ -671,33 +663,63 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, } static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) { - if (Val.getBitWidth() < BitWidth) - Val = Val.extend(BitWidth); - else if (Val.getBitWidth() > BitWidth) - Val = Val.trunc(BitWidth); + Val = Val.extOrTrunc(BitWidth); Val.setIsSigned(IsSigned); } +/// Check the specified case value is in range for the given unpromoted switch +/// type. +static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val, + unsigned UnpromotedWidth, bool UnpromotedSign) { + // If the case value was signed and negative and the switch expression is + // unsigned, don't bother to warn: this is implementation-defined behavior. + // FIXME: Introduce a second, default-ignored warning for this case? + if (UnpromotedWidth < Val.getBitWidth()) { + llvm::APSInt ConvVal(Val); + AdjustAPSInt(ConvVal, UnpromotedWidth, UnpromotedSign); + AdjustAPSInt(ConvVal, Val.getBitWidth(), Val.isSigned()); + // FIXME: Use different diagnostics for overflow in conversion to promoted + // type versus "switch expression cannot have this value". Use proper + // IntRange checking rather than just looking at the unpromoted type here. + if (ConvVal != Val) + S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10) + << ConvVal.toString(10); + } +} + +typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; + /// Returns true if we should emit a diagnostic about this case expression not /// being a part of the enum used in the switch controlling expression. -static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx, +static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S, const EnumDecl *ED, - const Expr *CaseExpr) { - // Don't warn if the 'case' expression refers to a static const variable of - // the enum type. - CaseExpr = CaseExpr->IgnoreParenImpCasts(); - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseExpr)) { + const Expr *CaseExpr, + EnumValsTy::iterator &EI, + EnumValsTy::iterator &EIEnd, + const llvm::APSInt &Val) { + bool FlagType = ED->hasAttr<FlagEnumAttr>(); + + if (const DeclRefExpr *DRE = + dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) { if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - if (!VD->hasGlobalStorage()) - return true; QualType VarType = VD->getType(); - if (!VarType.isConstQualified()) - return true; - QualType EnumType = Ctx.getTypeDeclType(ED); - if (Ctx.hasSameUnqualifiedType(EnumType, VarType)) + QualType EnumType = S.Context.getTypeDeclType(ED); + if (VD->hasGlobalStorage() && VarType.isConstQualified() && + S.Context.hasSameUnqualifiedType(EnumType, VarType)) return false; } } + + if (FlagType) { + return !S.IsValueInFlagEnum(ED, Val, false); + } else { + while (EI != EIEnd && EI->first < Val) + EI++; + + if (EI != EIEnd && EI->first == Val) + return false; + } + return true; } @@ -708,9 +730,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, assert(SS == getCurFunction()->SwitchStack.back() && "switch stack missing push/pop!"); + getCurFunction()->SwitchStack.pop_back(); + if (!BodyStmt) return StmtError(); SS->setBody(BodyStmt, SwitchLoc); - getCurFunction()->SwitchStack.pop_back(); Expr *CondExpr = SS->getCond(); if (!CondExpr) return StmtError(); @@ -744,13 +767,20 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } } - // Get the bitwidth of the switched-on value before promotions. We must + // Get the bitwidth of the switched-on value after promotions. We must // convert the integer case values to this width before comparison. bool HasDependentValue = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); - unsigned CondWidth + unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondType); + bool CondIsSigned = CondType->isSignedIntegerOrEnumerationType(); + + // Get the width and signedness that the condition might actually have, for + // warning purposes. + // FIXME: Grab an IntRange for the condition rather than using the unpromoted + // type. + unsigned CondWidthBeforePromotion = HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion); - bool CondIsSigned + bool CondIsSignedBeforePromotion = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType(); // Accumulate all of the case values in a vector so that we can sort them @@ -816,15 +846,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get(); } - // Convert the value to the same width/sign as the condition had prior to - // integral promotions. - // - // FIXME: This causes us to reject valid code: - // switch ((char)c) { case 256: case 0: return 0; } - // Here we claim there is a duplicated condition value, but there is not. - ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, - Lo->getLocStart(), - diag::warn_case_value_overflow); + // Check the unconverted value is within the range of possible values of + // the switch expression. + checkCaseValue(*this, Lo->getLocStart(), LoVal, + CondWidthBeforePromotion, CondIsSignedBeforePromotion); + + // Convert the value to the same width/sign as the condition. + AdjustAPSInt(LoVal, CondWidth, CondIsSigned); CS->setLHS(Lo); @@ -847,9 +875,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, llvm::APSInt ConstantCondValue; bool HasConstantCond = false; if (!HasDependentValue && !TheDefaultStmt) { - HasConstantCond - = CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context, - Expr::SE_AllowSideEffects); + HasConstantCond = CondExpr->EvaluateAsInt(ConstantCondValue, Context, + Expr::SE_AllowSideEffects); assert(!HasConstantCond || (ConstantCondValue.getBitWidth() == CondWidth && ConstantCondValue.isSigned() == CondIsSigned)); @@ -935,10 +962,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get(); } + // Check the unconverted value is within the range of possible values of + // the switch expression. + checkCaseValue(*this, Hi->getLocStart(), HiVal, + CondWidthBeforePromotion, CondIsSignedBeforePromotion); + // Convert the value to the same width/sign as the condition. - ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, - Hi->getLocStart(), - diag::warn_case_value_overflow); + AdjustAPSInt(HiVal, CondWidth, CondIsSigned); CR->setRHS(Hi); @@ -1029,8 +1059,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); - typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> - EnumValsTy; EnumValsTy EnumVals; // Gather all enum values, set their type and sort them, @@ -1041,57 +1069,48 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, EnumVals.push_back(std::make_pair(Val, EDI)); } std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); - EnumValsTy::iterator EIend = + auto EI = EnumVals.begin(), EIEnd = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); // See which case values aren't in enum. - EnumValsTy::const_iterator EI = EnumVals.begin(); for (CaseValsTy::const_iterator CI = CaseVals.begin(); - CI != CaseVals.end(); CI++) { - while (EI != EIend && EI->first < CI->first) - EI++; - if (EI == EIend || EI->first > CI->first) { - Expr *CaseExpr = CI->second->getLHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) - Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) - << CondTypeBeforePromotion; - } + CI != CaseVals.end(); CI++) { + Expr *CaseExpr = CI->second->getLHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, + CI->first)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; } + // See which of case ranges aren't in enum EI = EnumVals.begin(); for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); - RI != CaseRanges.end() && EI != EIend; RI++) { - while (EI != EIend && EI->first < RI->first) - EI++; - - if (EI == EIend || EI->first != RI->first) { - Expr *CaseExpr = RI->second->getLHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) - Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) - << CondTypeBeforePromotion; - } + RI != CaseRanges.end(); RI++) { + Expr *CaseExpr = RI->second->getLHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, + RI->first)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; llvm::APSInt Hi = RI->second->getRHS()->EvaluateKnownConstInt(Context); AdjustAPSInt(Hi, CondWidth, CondIsSigned); - while (EI != EIend && EI->first < Hi) - EI++; - if (EI == EIend || EI->first != Hi) { - Expr *CaseExpr = RI->second->getRHS(); - if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) - Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) - << CondTypeBeforePromotion; - } + + CaseExpr = RI->second->getRHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd, + Hi)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; } // Check which enum vals aren't in switch - CaseValsTy::const_iterator CI = CaseVals.begin(); - CaseRangesTy::const_iterator RI = CaseRanges.begin(); + auto CI = CaseVals.begin(); + auto RI = CaseRanges.begin(); bool hasCasesNotInSwitch = false; SmallVector<DeclarationName,8> UnhandledNames; - for (EI = EnumVals.begin(); EI != EIend; EI++){ + for (EI = EnumVals.begin(); EI != EIEnd; EI++){ // Drop unneeded case values while (CI != CaseVals.end() && CI->first < EI->first) CI++; @@ -1178,30 +1197,37 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context); AdjustAPSInt(RhsVal, DstWidth, DstIsSigned); const EnumDecl *ED = ET->getDecl(); - typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64> - EnumValsTy; - EnumValsTy EnumVals; - - // Gather all enum values, set their type and sort them, - // allowing easier comparison with rhs constant. - for (auto *EDI : ED->enumerators()) { - llvm::APSInt Val = EDI->getInitVal(); - AdjustAPSInt(Val, DstWidth, DstIsSigned); - EnumVals.push_back(std::make_pair(Val, EDI)); - } - if (EnumVals.empty()) - return; - std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); - EnumValsTy::iterator EIend = - std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); - - // See which values aren't in the enum. - EnumValsTy::const_iterator EI = EnumVals.begin(); - while (EI != EIend && EI->first < RhsVal) - EI++; - if (EI == EIend || EI->first != RhsVal) { - Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment) + + if (ED->hasAttr<FlagEnumAttr>()) { + if (!IsValueInFlagEnum(ED, RhsVal, true)) + Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment) << DstType.getUnqualifiedType(); + } else { + typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64> + EnumValsTy; + EnumValsTy EnumVals; + + // Gather all enum values, set their type and sort them, + // allowing easier comparison with rhs constant. + for (auto *EDI : ED->enumerators()) { + llvm::APSInt Val = EDI->getInitVal(); + AdjustAPSInt(Val, DstWidth, DstIsSigned); + EnumVals.push_back(std::make_pair(Val, EDI)); + } + if (EnumVals.empty()) + return; + std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); + EnumValsTy::iterator EIend = + std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); + + // See which values aren't in the enum. + EnumValsTy::const_iterator EI = EnumVals.begin(); + while (EI != EIend && EI->first < RhsVal) + EI++; + if (EI == EIend || EI->first != RhsVal) { + Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment) + << DstType.getUnqualifiedType(); + } } } } @@ -1260,13 +1286,13 @@ namespace { // the evaluated decls into a vector. Simple is set to true if none // of the excluded constructs are used. class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> { - llvm::SmallPtrSet<VarDecl*, 8> &Decls; + llvm::SmallPtrSetImpl<VarDecl*> &Decls; SmallVectorImpl<SourceRange> &Ranges; bool Simple; public: typedef EvaluatedExprVisitor<DeclExtractor> Inherited; - DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, + DeclExtractor(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls, SmallVectorImpl<SourceRange> &Ranges) : Inherited(S.Context), Decls(Decls), @@ -1338,13 +1364,13 @@ namespace { // DeclMatcher checks to see if the decls are used in a non-evauluated // context. class DeclMatcher : public EvaluatedExprVisitor<DeclMatcher> { - llvm::SmallPtrSet<VarDecl*, 8> &Decls; + llvm::SmallPtrSetImpl<VarDecl*> &Decls; bool FoundDecl; public: typedef EvaluatedExprVisitor<DeclMatcher> Inherited; - DeclMatcher(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls, + DeclMatcher(Sema &S, llvm::SmallPtrSetImpl<VarDecl*> &Decls, Stmt *Statement) : Inherited(S.Context), Decls(Decls), FoundDecl(false) { if (!Statement) return; @@ -1427,8 +1453,8 @@ namespace { if (Decls.size() == 0) return; // Don't warn on volatile, static, or global variables. - for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(), - E = Decls.end(); + for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(), + E = Decls.end(); I != E; ++I) if ((*I)->getType().isVolatileQualified() || (*I)->hasGlobalStorage()) return; @@ -1443,8 +1469,8 @@ namespace { PDiag << 0; else { PDiag << Decls.size(); - for (llvm::SmallPtrSet<VarDecl*, 8>::iterator I = Decls.begin(), - E = Decls.end(); + for (llvm::SmallPtrSetImpl<VarDecl*>::iterator I = Decls.begin(), + E = Decls.end(); I != E; ++I) PDiag << (*I)->getDeclName(); } @@ -1660,11 +1686,16 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { if (!collection) return ExprError(); + ExprResult result = CorrectDelayedTyposInExpr(collection); + if (!result.isUsable()) + return ExprError(); + collection = result.get(); + // Bail out early if we've got a type-dependent expression. if (collection->isTypeDependent()) return collection; // Perform normal l-value conversion. - ExprResult result = DefaultFunctionArrayLvalueConversion(collection); + result = DefaultFunctionArrayLvalueConversion(collection); if (result.isInvalid()) return ExprError(); collection = result.get(); @@ -2453,7 +2484,7 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, // - in a return statement in a function [where] ... // ... the expression is the name of a non-volatile automatic object ... DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()); - if (!DR || DR->refersToEnclosingLocal()) + if (!DR || DR->refersToEnclosingVariableOrCapture()) return nullptr; VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) @@ -2621,8 +2652,12 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return StmtError(); RetValExp = Result.get(); + // DR1048: even prior to C++14, we should use the 'auto' deduction rules + // when deducing a return type for a lambda-expression (or by extension + // for a block). These rules differ from the stated C++11 rules only in + // that they remove top-level cv-qualifiers. if (!CurContext->isDependentContext()) - FnRetType = RetValExp->getType(); + FnRetType = RetValExp->getType().getUnqualifiedType(); else FnRetType = CurCap->ReturnType = Context.DependentTy; } else { @@ -2727,14 +2762,54 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Result; } +namespace { +/// \brief Marks all typedefs in all local classes in a type referenced. +/// +/// In a function like +/// auto f() { +/// struct S { typedef int a; }; +/// return S(); +/// } +/// +/// the local type escapes and could be referenced in some TUs but not in +/// others. Pretend that all local typedefs are always referenced, to not warn +/// on this. This isn't necessary if f has internal linkage, or the typedef +/// is private. +class LocalTypedefNameReferencer + : public RecursiveASTVisitor<LocalTypedefNameReferencer> { +public: + LocalTypedefNameReferencer(Sema &S) : S(S) {} + bool VisitRecordType(const RecordType *RT); +private: + Sema &S; +}; +bool LocalTypedefNameReferencer::VisitRecordType(const RecordType *RT) { + auto *R = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!R || !R->isLocalClass() || !R->isLocalClass()->isExternallyVisible() || + R->isDependentType()) + return true; + for (auto *TmpD : R->decls()) + if (auto *T = dyn_cast<TypedefNameDecl>(TmpD)) + if (T->getAccess() != AS_private || R->hasFriends()) + S.MarkAnyDeclReferenced(T->getLocation(), T, /*OdrUse=*/false); + return true; +} +} + +TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const { + TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens(); + while (auto ATL = TL.getAs<AttributedTypeLoc>()) + TL = ATL.getModifiedLoc().IgnoreParens(); + return TL.castAs<FunctionProtoTypeLoc>().getReturnLoc(); +} + /// Deduce the return type for a function from a returned expression, per /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT) { - TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc(). - IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc(); + TypeLoc OrigResultType = getReturnTypeLoc(FD); QualType Deduced; if (RetExpr && isa<InitListExpr>(RetExpr)) { @@ -2772,6 +2847,11 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, if (DAR != DAR_Succeeded) return true; + + // If a local type is part of the returned type, mark its fields as + // referenced. + LocalTypedefNameReferencer Referencer(*this); + Referencer.TraverseType(RetExpr->getType()); } else { // In the case of a return with no operand, the initializer is considered // to be void(). @@ -2872,7 +2952,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. - if (getLangOpts().CPlusPlus1y) { + if (getLangOpts().CPlusPlus14) { if (AutoType *AT = FnRetType->getContainedAutoType()) { FunctionDecl *FD = cast<FunctionDecl>(CurContext); if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { @@ -2964,14 +3044,26 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr); } else if (!RetValExp && !HasDependentReturnType) { - unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 - // C99 6.8.6.4p1 (ext_ since GCC warns) - if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr; + FunctionDecl *FD = getCurFunctionDecl(); - if (FunctionDecl *FD = getCurFunctionDecl()) + unsigned DiagID; + if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) { + // C++11 [stmt.return]p2 + DiagID = diag::err_constexpr_return_missing_expr; + FD->setInvalidDecl(); + } else if (getLangOpts().C99) { + // C99 6.8.6.4p1 (ext_ since GCC warns) + DiagID = diag::ext_return_missing_expr; + } else { + // C90 6.6.6.4p4 + DiagID = diag::warn_return_missing_expr; + } + + if (FD) Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/; else Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; + Result = new (Context) ReturnStmt(ReturnLoc); } else { assert(RetValExp || HasDependentReturnType); @@ -3119,9 +3211,24 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) { 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(); + if (!pointerType || !pointerType->getPointeeType()->isVoidType()) { + if (getLangOpts().CPlusPlus) { + if (RequireCompleteType(atLoc, type, + diag::err_incomplete_receiver_type)) + return Diag(atLoc, diag::error_objc_synchronized_expects_object) + << type << operand->getSourceRange(); + + ExprResult result = PerformContextuallyConvertToObjCPointer(operand); + if (!result.isUsable()) + return Diag(atLoc, diag::error_objc_synchronized_expects_object) + << type << operand->getSourceRange(); + + operand = result.get(); + } else { + return Diag(atLoc, diag::error_objc_synchronized_expects_object) + << type << operand->getSourceRange(); + } + } } // The operand to @synchronized is a full-expression. @@ -3249,15 +3356,16 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers); } -StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, - Stmt *TryBlock, Stmt *Handler, - int HandlerIndex, int HandlerParentIndex) { +StmtResult +Sema::ActOnSEHTryBlock(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) { assert(TryBlock && Handler); getCurFunction()->setHasBranchProtectedScope(); - return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler, - HandlerIndex, HandlerParentIndex); + return SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler); } StmtResult @@ -3330,6 +3438,7 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, else RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/nullptr); + RD->setCapturedRecord(); DC->addDecl(RD); RD->setImplicit(); RD->startDefinition(); @@ -3353,6 +3462,11 @@ static void buildCapturedStmtCaptureList( CapturedStmt::VCK_This)); CaptureInits.push_back(Cap->getInitExpr()); continue; + } else if (Cap->isVLATypeCapture()) { + Captures.push_back( + CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_VLAType)); + CaptureInits.push_back(nullptr); + continue; } assert(Cap->isReferenceCapture() && diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 5d076ca..286c761 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -15,6 +15,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -74,6 +75,32 @@ static bool isOperandMentioned(unsigned OpNo, return false; } +static bool CheckNakedParmReference(Expr *E, Sema &S) { + FunctionDecl *Func = dyn_cast<FunctionDecl>(S.CurContext); + if (!Func) + return false; + if (!Func->hasAttr<NakedAttr>()) + return false; + + SmallVector<Expr*, 4> WorkList; + WorkList.push_back(E); + while (WorkList.size()) { + Expr *E = WorkList.pop_back_val(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (isa<ParmVarDecl>(DRE->getDecl())) { + S.Diag(DRE->getLocStart(), diag::err_asm_naked_parm_ref); + S.Diag(Func->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); + return true; + } + } + for (Stmt *Child : E->children()) { + if (Expr *E = dyn_cast_or_null<Expr>(Child)) + WorkList.push_back(E); + } + } + return false; +} + StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -89,15 +116,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; // The parser verifies that there is a string literal here. - if (!AsmString->isAscii()) - return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) - << AsmString->getSourceRange()); + assert(AsmString->isAscii()); for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); + assert(Literal->isAscii()); StringRef OutputName; if (Names[i]) @@ -109,27 +132,69 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, diag::err_asm_invalid_output_constraint) << Info.getConstraintStr()); + ExprResult ER = CheckPlaceholderExpr(Exprs[i]); + if (ER.isInvalid()) + return StmtError(); + Exprs[i] = ER.get(); + // Check that the output exprs are valid lvalues. Expr *OutputExpr = Exprs[i]; - if (CheckAsmLValue(OutputExpr, *this)) - return StmtError(Diag(OutputExpr->getLocStart(), - diag::err_asm_invalid_lvalue_in_output) - << OutputExpr->getSourceRange()); - if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), - diag::err_dereference_incomplete_type)) + // Referring to parameters is not allowed in naked functions. + if (CheckNakedParmReference(OutputExpr, *this)) return StmtError(); OutputConstraintInfos.push_back(Info); + + // If this is dependent, just continue. + if (OutputExpr->isTypeDependent()) + continue; + + Expr::isModifiableLvalueResult IsLV = + OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr); + switch (IsLV) { + case Expr::MLV_Valid: + // Cool, this is an lvalue. + break; + case Expr::MLV_ArrayType: + // This is OK too. + break; + case Expr::MLV_LValueCast: { + const Expr *LVal = OutputExpr->IgnoreParenNoopCasts(Context); + if (!getLangOpts().HeinousExtensions) { + Diag(LVal->getLocStart(), diag::err_invalid_asm_cast_lvalue) + << OutputExpr->getSourceRange(); + } else { + Diag(LVal->getLocStart(), diag::warn_invalid_asm_cast_lvalue) + << OutputExpr->getSourceRange(); + } + // Accept, even if we emitted an error diagnostic. + break; + } + case Expr::MLV_IncompleteType: + case Expr::MLV_IncompleteVoidType: + if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(), + diag::err_dereference_incomplete_type)) + return StmtError(); + default: + return StmtError(Diag(OutputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_output) + << OutputExpr->getSourceRange()); + } + + unsigned Size = Context.getTypeSize(OutputExpr->getType()); + if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), + Size)) + return StmtError(Diag(OutputExpr->getLocStart(), + diag::err_asm_invalid_output_size) + << Info.getConstraintStr()); } SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { StringLiteral *Literal = Constraints[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); + assert(Literal->isAscii()); StringRef InputName; if (Names[i]) @@ -143,8 +208,17 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, << Info.getConstraintStr()); } + ExprResult ER = CheckPlaceholderExpr(Exprs[i]); + if (ER.isInvalid()) + return StmtError(); + Exprs[i] = ER.get(); + Expr *InputExpr = Exprs[i]; + // Referring to parameters is not allowed in naked functions. + if (CheckNakedParmReference(InputExpr, *this)) + return StmtError(); + // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { if (CheckAsmLValue(InputExpr, *this)) @@ -152,6 +226,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); + } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { + llvm::APSInt Result; + if (!InputExpr->EvaluateAsInt(Result, Context)) + return StmtError( + Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) + << InputExpr->getType() << Info.getConstraintStr() + << InputExpr->getSourceRange()); + if (Result.slt(Info.getImmConstantMin()) || + Result.sgt(Info.getImmConstantMax())) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_invalid_asm_value_for_constraint) + << Result.toString(10) << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) @@ -191,9 +279,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { StringLiteral *Literal = Clobbers[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); + assert(Literal->isAscii()); StringRef Clobber = Literal->getString(); @@ -257,16 +343,47 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, continue; unsigned Size = Context.getTypeSize(Ty); - if (!Context.getTargetInfo() - .validateConstraintModifier(Literal->getString(), Piece.getModifier(), - Size)) + std::string SuggestedModifier; + if (!Context.getTargetInfo().validateConstraintModifier( + Literal->getString(), Piece.getModifier(), Size, + SuggestedModifier)) { Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); + + if (!SuggestedModifier.empty()) { + auto B = Diag(Piece.getRange().getBegin(), + diag::note_asm_missing_constraint_modifier) + << SuggestedModifier; + SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); + B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(), + SuggestedModifier)); + } + } } // Validate tied input operands for type mismatches. + unsigned NumAlternatives = ~0U; + for (unsigned i = 0, e = OutputConstraintInfos.size(); i != e; ++i) { + TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; + StringRef ConstraintStr = Info.getConstraintStr(); + unsigned AltCount = ConstraintStr.count(',') + 1; + if (NumAlternatives == ~0U) + NumAlternatives = AltCount; + else if (NumAlternatives != AltCount) + return StmtError(Diag(NS->getOutputExpr(i)->getLocStart(), + diag::err_asm_unexpected_constraint_alternatives) + << NumAlternatives << AltCount); + } for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + StringRef ConstraintStr = Info.getConstraintStr(); + unsigned AltCount = ConstraintStr.count(',') + 1; + if (NumAlternatives == ~0U) + NumAlternatives = AltCount; + else if (NumAlternatives != AltCount) + return StmtError(Diag(NS->getInputExpr(i)->getLocStart(), + diag::err_asm_unexpected_constraint_alternatives) + << NumAlternatives << AltCount); // If this is a tied constraint, verify that the output and input have // either exactly the same type, or that they are int/ptr operands with the @@ -394,6 +511,10 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; + // Referring to parameters is not allowed in naked functions. + if (CheckNakedParmReference(Result.get(), *this)) + return ExprError(); + QualType T = Result.get()->getType(); // For now, reject dependent types. @@ -443,9 +564,10 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, NamedDecl *FoundDecl = BaseResult.getFoundDecl(); if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) RT = VD->getType()->getAs<RecordType>(); - else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) + else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) { + MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); RT = TD->getUnderlyingType()->getAs<RecordType>(); - else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl)) + } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl)) RT = TD->getTypeForDecl()->getAs<RecordType>(); if (!RT) return true; @@ -481,6 +603,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef<Expr*> Exprs, SourceLocation EndLoc) { bool IsSimple = (NumOutputs != 0 || NumInputs != 0); + getCurFunction()->setHasBranchProtectedScope(); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, @@ -488,3 +611,34 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, Clobbers, EndLoc); return NS; } + +LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate) { + LabelDecl* Label = LookupOrCreateLabel(PP.getIdentifierInfo(ExternalLabelName), + Location); + + if (Label->isMSAsmLabel()) { + // If we have previously created this label implicitly, mark it as used. + Label->markUsed(Context); + } else { + // Otherwise, insert it, but only resolve it if we have seen the label itself. + std::string InternalName; + llvm::raw_string_ostream OS(InternalName); + // Create an internal name for the label. The name should not be a valid mangled + // name, and should be unique. We use a dot to make the name an invalid mangled + // name. + OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__" << ExternalLabelName; + Label->setMSAsmLabel(OS.str()); + } + if (AlwaysCreate) { + // The label might have been created implicitly from a previously encountered + // goto statement. So, for both newly created and looked up labels, we mark + // them as resolved. + Label->setMSAsmLabelResolved(); + } + // Adjust their location for being able to generate accurate diagnostics. + Label->setLocation(Location); + + return Label; +} diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index a32e0fb..19e2c8e 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -47,30 +47,36 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange) { IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); IdentifierLoc *OptionLoc = A.getArgAsIdent(1); - IdentifierInfo *OptionInfo = OptionLoc->Ident; - IdentifierLoc *ValueLoc = A.getArgAsIdent(2); - IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr; + IdentifierLoc *StateLoc = A.getArgAsIdent(2); Expr *ValueExpr = A.getArgAsExpr(3); - assert(OptionInfo && "Attribute must have valid option info."); - + bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll"; + bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll"; if (St->getStmtClass() != Stmt::DoStmtClass && St->getStmtClass() != Stmt::ForStmtClass && St->getStmtClass() != Stmt::CXXForRangeStmtClass && St->getStmtClass() != Stmt::WhileStmtClass) { - const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll" - ? "#pragma unroll" - : "#pragma clang loop"; + const char *Pragma = + llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName()) + .Case("unroll", "#pragma unroll") + .Case("nounroll", "#pragma nounroll") + .Default("#pragma clang loop"); S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma; return nullptr; } LoopHintAttr::OptionType Option; LoopHintAttr::Spelling Spelling; - if (PragmaNameLoc->Ident->getName() == "unroll") { - Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll; + if (PragmaUnroll) { + Option = ValueExpr ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll; Spelling = LoopHintAttr::Pragma_unroll; + } else if (PragmaNoUnroll) { + Option = LoopHintAttr::Unroll; + Spelling = LoopHintAttr::Pragma_nounroll; } else { + assert(OptionLoc && OptionLoc->Ident && + "Attribute must have valid option info."); + IdentifierInfo *OptionInfo = OptionLoc->Ident; Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName()) .Case("vectorize", LoopHintAttr::Vectorize) .Case("vectorize_width", LoopHintAttr::VectorizeWidth) @@ -82,53 +88,45 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, Spelling = LoopHintAttr::Pragma_clang_loop; } - int ValueInt; - if (Option == LoopHintAttr::Unroll && - Spelling == LoopHintAttr::Pragma_unroll) { - ValueInt = 1; - } else if (Option == LoopHintAttr::Vectorize || - Option == LoopHintAttr::Interleave || - Option == LoopHintAttr::Unroll) { - if (!ValueInfo) { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword); - return nullptr; - } - if (ValueInfo->isStr("disable")) - ValueInt = 0; - else if (ValueInfo->isStr("enable")) - ValueInt = 1; - else { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword); - return nullptr; - } + LoopHintAttr::LoopHintState State = LoopHintAttr::Default; + if (PragmaNoUnroll) { + State = LoopHintAttr::Disable; } else if (Option == LoopHintAttr::VectorizeWidth || Option == LoopHintAttr::InterleaveCount || Option == LoopHintAttr::UnrollCount) { - // FIXME: We should support template parameters for the loop hint value. - // See bug report #19610. - llvm::APSInt ValueAPS; - if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) || - (ValueInt = ValueAPS.getSExtValue()) < 1) { - S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value); + assert(ValueExpr && "Attribute must have a valid value expression."); + if (S.CheckLoopHintExpr(ValueExpr, St->getLocStart())) return nullptr; + } else if (Option == LoopHintAttr::Vectorize || + Option == LoopHintAttr::Interleave || + Option == LoopHintAttr::Unroll) { + // Default state is assumed if StateLoc is not specified, such as with + // '#pragma unroll'. + if (StateLoc && StateLoc->Ident) { + if (StateLoc->Ident->isStr("disable")) + State = LoopHintAttr::Disable; + else + State = LoopHintAttr::Enable; } - } else - llvm_unreachable("Unknown loop hint option"); + } - return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt, - A.getRange()); + return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State, + ValueExpr, A.getRange()); } -static void CheckForIncompatibleAttributes( - Sema &S, const SmallVectorImpl<const Attr *> &Attrs) { - // There are 3 categories of loop hints: vectorize, interleave, and - // unroll. Each comes in two variants: an enable/disable form and a - // form which takes a numeric argument. For example: - // unroll(enable|disable) and unroll_count(N). The following array - // accumulate the hints encountered while iterating through the - // attributes to check for compatibility. +static void +CheckForIncompatibleAttributes(Sema &S, + const SmallVectorImpl<const Attr *> &Attrs) { + // There are 3 categories of loop hints attributes: vectorize, interleave, + // and unroll. Each comes in two variants: a state form and a numeric form. + // The state form selectively defaults/enables/disables the transformation + // for the loop (for unroll, default indicates full unrolling rather than + // enabling the transformation). The numeric form form provides an integer + // hint (for example, unroll count) to the transformer. The following array + // accumulates the hints encountered while iterating through the attributes + // to check for compatibility. struct { - const LoopHintAttr *EnableAttr; + const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; @@ -141,49 +139,53 @@ static void CheckForIncompatibleAttributes( int Option = LH->getOption(); int Category; + enum { Vectorize, Interleave, Unroll }; switch (Option) { case LoopHintAttr::Vectorize: case LoopHintAttr::VectorizeWidth: - Category = 0; + Category = Vectorize; break; case LoopHintAttr::Interleave: case LoopHintAttr::InterleaveCount: - Category = 1; + Category = Interleave; break; case LoopHintAttr::Unroll: case LoopHintAttr::UnrollCount: - Category = 2; + Category = Unroll; break; }; auto &CategoryState = HintAttrs[Category]; - SourceLocation OptionLoc = LH->getRange().getBegin(); const LoopHintAttr *PrevAttr; if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { // Enable|disable hint. For example, vectorize(enable). - PrevAttr = CategoryState.EnableAttr; - CategoryState.EnableAttr = LH; + PrevAttr = CategoryState.StateAttr; + CategoryState.StateAttr = LH; } else { // Numeric hint. For example, vectorize_width(8). PrevAttr = CategoryState.NumericAttr; CategoryState.NumericAttr = LH; } + PrintingPolicy Policy(S.Context.getLangOpts()); + SourceLocation OptionLoc = LH->getRange().getBegin(); if (PrevAttr) // Cannot specify same type of attribute twice. S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) - << /*Duplicate=*/true << PrevAttr->getDiagnosticName() - << LH->getDiagnosticName(); - - if (CategoryState.EnableAttr && !CategoryState.EnableAttr->getValue() && - CategoryState.NumericAttr) { - // Disable hints are not compatible with numeric hints of the - // same category. + << /*Duplicate=*/true << PrevAttr->getDiagnosticName(Policy) + << LH->getDiagnosticName(Policy); + + if (CategoryState.StateAttr && CategoryState.NumericAttr && + (Category == Unroll || + CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) { + // Disable hints are not compatible with numeric hints of the same + // category. As a special case, numeric unroll hints are also not + // compatible with "enable" form of the unroll pragma, unroll(full). S.Diag(OptionLoc, diag::err_pragma_loop_compatibility) << /*Duplicate=*/false - << CategoryState.EnableAttr->getDiagnosticName() - << CategoryState.NumericAttr->getDiagnosticName(); + << CategoryState.StateAttr->getDiagnosticName(Policy) + << CategoryState.NumericAttr->getDiagnosticName(Policy); } } } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7e8f0b7..67c36a5 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -107,7 +107,7 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R, // template itself and not a specialization thereof, and is not // ambiguous. if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) - if (!ClassTemplates.insert(ClassTmpl)) { + if (!ClassTemplates.insert(ClassTmpl).second) { filter.erase(); continue; } @@ -318,15 +318,14 @@ void Sema::LookupTemplateName(LookupResult &Found, DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast - CorrectionCandidateCallback FilterCCC; - FilterCCC.WantTypeSpecifiers = false; - FilterCCC.WantExpressionKeywords = false; - FilterCCC.WantRemainingKeywords = false; - FilterCCC.WantCXXNamedCasts = true; - if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(), - Found.getLookupKind(), S, &SS, - FilterCCC, CTK_ErrorRecovery, - LookupCtx)) { + auto FilterCCC = llvm::make_unique<CorrectionCandidateCallback>(); + FilterCCC->WantTypeSpecifiers = false; + FilterCCC->WantExpressionKeywords = false; + FilterCCC->WantRemainingKeywords = false; + FilterCCC->WantCXXNamedCasts = true; + if (TypoCorrection Corrected = CorrectTypo( + Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, + std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) { Found.setLookupName(Corrected.getCorrection()); if (Corrected.getCorrectionDecl()) Found.addDecl(Corrected.getCorrectionDecl()); @@ -652,12 +651,8 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // A non-type template-parameter of type "array of T" or // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. - else if (T->isArrayType()) - // FIXME: Keep the type prior to promotion? - return Context.getArrayDecayedType(T); - else if (T->isFunctionType()) - // FIXME: Keep the type prior to promotion? - return Context.getPointerType(T); + else if (T->isArrayType() || T->isFunctionType()) + return Context.getDecayedType(T); Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -720,7 +715,8 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, return Param; TemplateArgument Converted; - ExprResult DefaultRes = CheckTemplateArgument(Param, Param->getType(), Default, Converted); + ExprResult DefaultRes = + CheckTemplateArgument(Param, Param->getType(), Default, Converted); if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; @@ -1105,9 +1101,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, AddPushedVisibilityAttribute(NewClass); - if (TUK != TUK_Friend) - PushOnScopeChains(NewTemplate, S); - else { + if (TUK != TUK_Friend) { + // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. + Scope *Outer = S; + while ((Outer->getFlags() & Scope::TemplateParamScope) != 0) + Outer = Outer->getParent(); + PushOnScopeChains(NewTemplate, Outer); + } else { if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) { NewTemplate->setAccess(PrevClassTemplate->getAccess()); NewClass->setAccess(PrevClassTemplate->getAccess()); @@ -2396,7 +2396,7 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, - TemplateParameterList *TemplateParams, VarDecl::StorageClass SC, + TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization) { // D must be variable template id. assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId && @@ -4106,6 +4106,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: return false; case NestedNameSpecifier::TypeSpec: @@ -4595,8 +4596,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; // Create the template argument. - Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), - ParamType->isReferenceType()); + Converted = + TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), ParamType); S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity, false); return false; } @@ -4691,7 +4692,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, Converted = TemplateArgument(Arg); } else { VD = cast<ValueDecl>(VD->getCanonicalDecl()); - Converted = TemplateArgument(VD, /*isReferenceParam*/false); + Converted = TemplateArgument(VD, ParamType); } return Invalid; } @@ -4720,7 +4721,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, Converted = TemplateArgument(Arg); } else { ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl()); - Converted = TemplateArgument(D, /*isReferenceParam*/false); + Converted = TemplateArgument(D, ParamType); } return Invalid; } @@ -4738,30 +4739,152 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, /// /// This routine implements the semantics of C++ [temp.arg.nontype]. /// If an error occurred, it returns ExprError(); otherwise, it -/// returns the converted template argument. \p -/// InstantiatedParamType is the type of the non-type template -/// parameter after it has been instantiated. +/// returns the converted template argument. \p ParamType is the +/// type of the non-type template parameter after it has been instantiated. ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - QualType InstantiatedParamType, Expr *Arg, + QualType ParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getLocStart(); // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. - if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { + if (ParamType->isDependentType() || Arg->isTypeDependent()) { // FIXME: Produce a cloned, canonical expression? Converted = TemplateArgument(Arg); return Arg; } + // We should have already dropped all cv-qualifiers by now. + assert(!ParamType.hasQualifiers() && + "non-type template parameter type cannot be qualified"); + + if (CTAK == CTAK_Deduced && + !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) { + // C++ [temp.deduct.type]p17: + // If, in the declaration of a function template with a non-type + // template-parameter, the non-type template-parameter is used + // in an expression in the function parameter-list and, if the + // corresponding template-argument is deduced, the + // template-argument type shall match the type of the + // template-parameter exactly, except that a template-argument + // deduced from an array bound may be of any integral type. + Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) + << Arg->getType().getUnqualifiedType() + << ParamType.getUnqualifiedType(); + Diag(Param->getLocation(), diag::note_template_param_here); + return ExprError(); + } + + if (getLangOpts().CPlusPlus1z) { + // FIXME: We can do some limited checking for a value-dependent but not + // type-dependent argument. + if (Arg->isValueDependent()) { + Converted = TemplateArgument(Arg); + return Arg; + } + + // C++1z [temp.arg.nontype]p1: + // A template-argument for a non-type template parameter shall be + // a converted constant expression of the type of the template-parameter. + APValue Value; + ExprResult ArgResult = CheckConvertedConstantExpression( + Arg, ParamType, Value, CCEK_TemplateArg); + if (ArgResult.isInvalid()) + return ExprError(); + + QualType CanonParamType = Context.getCanonicalType(ParamType); + + // Convert the APValue to a TemplateArgument. + switch (Value.getKind()) { + case APValue::Uninitialized: + assert(ParamType->isNullPtrType()); + Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true); + break; + case APValue::Int: + assert(ParamType->isIntegralOrEnumerationType()); + Converted = TemplateArgument(Context, Value.getInt(), CanonParamType); + break; + case APValue::MemberPointer: { + assert(ParamType->isMemberPointerType()); + + // FIXME: We need TemplateArgument representation and mangling for these. + if (!Value.getMemberPointerPath().empty()) { + Diag(Arg->getLocStart(), + diag::err_template_arg_member_ptr_base_derived_not_supported) + << Value.getMemberPointerDecl() << ParamType + << Arg->getSourceRange(); + return ExprError(); + } + + auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl()); + Converted = VD ? TemplateArgument(VD, CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr*/true); + break; + } + case APValue::LValue: { + // For a non-type template-parameter of pointer or reference type, + // the value of the constant expression shall not refer to + assert(ParamType->isPointerType() || ParamType->isReferenceType() || + ParamType->isNullPtrType()); + // -- a temporary object + // -- a string literal + // -- the result of a typeid expression, or + // -- a predefind __func__ variable + if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { + if (isa<CXXUuidofExpr>(E)) { + Converted = TemplateArgument(const_cast<Expr*>(E)); + break; + } + Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + return ExprError(); + } + auto *VD = const_cast<ValueDecl *>( + Value.getLValueBase().dyn_cast<const ValueDecl *>()); + // -- a subobject + if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 && + VD && VD->getType()->isArrayType() && + Value.getLValuePath()[0].ArrayIndex == 0 && + !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) { + // Per defect report (no number yet): + // ... other than a pointer to the first element of a complete array + // object. + } else if (!Value.hasLValuePath() || Value.getLValuePath().size() || + Value.isLValueOnePastTheEnd()) { + Diag(StartLoc, diag::err_non_type_template_arg_subobject) + << Value.getAsString(Context, ParamType); + return ExprError(); + } + assert((VD || !ParamType->isReferenceType()) && + "null reference should not be a constant expression"); + assert((!VD || !ParamType->isNullPtrType()) && + "non-null value of type nullptr_t?"); + Converted = VD ? TemplateArgument(VD, CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr*/true); + break; + } + case APValue::AddrLabelDiff: + return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); + case APValue::Float: + case APValue::ComplexInt: + case APValue::ComplexFloat: + case APValue::Vector: + case APValue::Array: + case APValue::Struct: + case APValue::Union: + llvm_unreachable("invalid kind for template argument"); + } + + return ArgResult.get(); + } + // C++ [temp.arg.nontype]p5: // The following conversions are performed on each expression used // as a non-type template-argument. If a non-type // template-argument cannot be converted to the type of the // corresponding template-parameter then the program is // ill-formed. - QualType ParamType = InstantiatedParamType; if (ParamType->isIntegralOrEnumerationType()) { // C++11: // -- for a non-type template-parameter of integral or @@ -4773,23 +4896,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // enumeration type, integral promotions (4.5) and integral // conversions (4.7) are applied. - if (CTAK == CTAK_Deduced && - !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) { - // C++ [temp.deduct.type]p17: - // If, in the declaration of a function template with a non-type - // template-parameter, the non-type template-parameter is used - // in an expression in the function parameter-list and, if the - // corresponding template-argument is deduced, the - // template-argument type shall match the type of the - // template-parameter exactly, except that a template-argument - // deduced from an array bound may be of any integral type. - Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) - << Arg->getType().getUnqualifiedType() - << ParamType.getUnqualifiedType(); - Diag(Param->getLocation(), diag::note_template_param_here); - return ExprError(); - } - if (getLangOpts().CPlusPlus11) { // We can't check arbitrary value-dependent arguments. // FIXME: If there's no viable conversion to the template parameter type, @@ -4867,9 +4973,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return ExprError(); } - // From here on out, all we care about are the unqualified forms - // of the parameter and argument types. - ParamType = ParamType.getUnqualifiedType(); + // From here on out, all we care about is the unqualified form + // of the argument type. ArgType = ArgType.getUnqualifiedType(); // Try to convert the argument to the parameter's type. @@ -4886,7 +4991,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't perform this conversion. Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) - << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); + << Arg->getType() << ParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); } @@ -6329,14 +6434,11 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { - D->dropAttrs(); + D->dropAttr<DLLImportAttr>(); + D->dropAttr<DLLExportAttr>(); - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) FD->setInlineSpecified(false); - - for (auto I : FD->params()) - I->dropAttrs(); - } } /// \brief Compute the diagnostic location for an explicit instantiation @@ -7606,6 +7708,29 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Ignore access control bits, we don't need them for redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + // C++11 [except.spec]p4 + // In an explicit instantiation an exception-specification may be specified, + // but is not required. + // If an exception-specification is specified in an explicit instantiation + // directive, it shall be compatible with the exception-specifications of + // other declarations of that function. + if (auto *FPT = R->getAs<FunctionProtoType>()) + if (FPT->hasExceptionSpec()) { + unsigned DiagID = + diag::err_mismatched_exception_spec_explicit_instantiation; + if (getLangOpts().MicrosoftExt) + DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation; + bool Result = CheckEquivalentExceptionSpec( + PDiag(DiagID) << Specialization->getType(), + PDiag(diag::note_explicit_instantiation_here), + Specialization->getType()->getAs<FunctionProtoType>(), + Specialization->getLocation(), FPT, D.getLocStart()); + // In Microsoft mode, mismatching exception specifications just cause a + // warning. + if (!getLangOpts().MicrosoftExt && Result) + return true; + } + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) @@ -7879,7 +8004,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx); + LookupQualifiedName(Result, Ctx, SS); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { @@ -7924,6 +8049,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); return Context.getElaboratedType(ETK_Typename, QualifierLoc.getNestedNameSpecifier(), Context.getTypeDeclType(Type)); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 53a75d2..dd2a4d2 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -262,8 +262,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced two declarations, make sure they they refer to the // same declaration. if (Y.getKind() == TemplateArgument::Declaration && - isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) && - X.isDeclForReferenceParam() == Y.isDeclForReferenceParam()) + isSameDeclaration(X.getAsDecl(), Y.getAsDecl())) return X; // All other combinations are incompatible. @@ -384,7 +383,7 @@ DeduceNonTypeTemplateArgument(Sema &S, "Cannot deduce non-type template argument with depth > 0"); D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr; - TemplateArgument New(D, NTTP->getType()->isReferenceType()); + TemplateArgument New(D, NTTP->getType()); DeducedTemplateArgument NewDeduced(New); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[NTTP->getIndex()], @@ -1302,7 +1301,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T & case Type::LValueReference: { - const LValueReferenceType *ReferenceArg = Arg->getAs<LValueReferenceType>(); + const LValueReferenceType *ReferenceArg = + Arg->getAs<LValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; @@ -1313,7 +1313,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T && [C++0x] case Type::RValueReference: { - const RValueReferenceType *ReferenceArg = Arg->getAs<RValueReferenceType>(); + const RValueReferenceType *ReferenceArg = + Arg->getAs<RValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; @@ -1492,7 +1493,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, const RecordType *NextT = ToVisit.pop_back_val(); // If we have already seen this type, skip it. - if (!Visited.insert(NextT)) + if (!Visited.insert(NextT).second) continue; // If this is a base class, try to perform template argument @@ -1726,8 +1727,7 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Declaration: if (Arg.getKind() == TemplateArgument::Declaration && - isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()) && - Param.isDeclForReferenceParam() == Arg.isDeclForReferenceParam()) + isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -1962,8 +1962,7 @@ static bool isSameTemplateArg(ASTContext &Context, Context.getCanonicalType(Y.getAsType()); case TemplateArgument::Declaration: - return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) && - X.isDeclForReferenceParam() == Y.isDeclForReferenceParam(); + return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()); case TemplateArgument::NullPtr: return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()); @@ -2056,7 +2055,8 @@ getTrivialTemplateArgumentLoc(Sema &S, TemplateName Template = Arg.getAsTemplate(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc); - else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + else if (QualifiedTemplateName *QTN = + Template.getAsQualifiedTemplateName()) Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc); if (Arg.getKind() == TemplateArgument::Template) @@ -2588,6 +2588,9 @@ Sema::SubstituteExplicitTemplateArguments( = Function->getType()->getAs<FunctionProtoType>(); assert(Proto && "Function template does not have a prototype?"); + // Isolate our substituted parameters from our caller. + LocalInstantiationScope InstScope(*this, /*MergeWithOuterScope*/true); + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute @@ -3000,7 +3003,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, FunctionDecl *Fn) { // We may need to deduce the return type of the function now. - if (S.getLangOpts().CPlusPlus1y && Fn->getReturnType()->isUndeducedType() && + if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() && S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false)) return QualType(); @@ -3229,9 +3232,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, return false; } -static bool hasDeducibleTemplateParameters(Sema &S, - FunctionTemplateDecl *FunctionTemplate, - QualType T); +static bool +hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate, + QualType T); /// \brief Perform template argument deduction by matching a parameter type /// against a single expression, where the expression is an element of @@ -3488,8 +3491,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, - NumExplicitlySpecified, - Specialization, Info, &OriginalCallArgs); + NumExplicitlySpecified, Specialization, + Info, &OriginalCallArgs); } QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, @@ -3579,7 +3582,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // If the function has a deduced return type, substitute it for a dependent // type so that we treat it as a non-deduced context in what follows. bool HasDeducedReturnType = false; - if (getLangOpts().CPlusPlus1y && InOverloadResolution && + if (getLangOpts().CPlusPlus14 && InOverloadResolution && Function->getReturnType()->getContainedAutoType()) { FunctionType = SubstAutoType(FunctionType, Context.DependentTy); HasDeducedReturnType = true; @@ -3788,7 +3791,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // C++0x [temp.deduct.conv]p4: // If A is a cv-qualified type, the top level cv-qualifiers of A's - // type are ignored for type deduction. If A is a reference type, the type + // type are ignored for type deduction. If A is a reference type, the type // referred to by A is used for type deduction. A = A.getUnqualifiedType(); } @@ -3842,8 +3845,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized); // If the conversion operator is being invoked on a lambda closure to convert - // to a ptr-to-function, use the deduced arguments from the conversion function - // to specialize the corresponding call operator. + // to a ptr-to-function, use the deduced arguments from the conversion + // function to specialize the corresponding call operator. // e.g., int (*fp)(int) = [](auto a) { return a; }; if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) { @@ -3907,9 +3910,10 @@ namespace { public TreeTransform<SubstituteAutoTransform> { QualType Replacement; public: - SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) : - TreeTransform<SubstituteAutoTransform>(SemaRef), Replacement(Replacement) { - } + SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) + : TreeTransform<SubstituteAutoTransform>(SemaRef), + Replacement(Replacement) {} + QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { // If we're building the type pattern to deduce against, don't wrap the // substituted type in an AutoType. Certain template deduction rules @@ -3988,7 +3992,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { return DAR_FailedAlreadyDiagnosed; } - QualType Deduced = BuildDecltypeType(Init, Init->getLocStart()); + QualType Deduced = BuildDecltypeType(Init, Init->getLocStart(), false); // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); Result = SubstituteAutoTransform(*this, Deduced).Apply(Type); @@ -4885,8 +4889,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, Depth, 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 + // 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 // non-deduced context. if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) @@ -5069,10 +5073,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, /// \brief Marks all of the template parameters that will be deduced by a /// call to the given function template. -void -Sema::MarkDeducedTemplateParameters(ASTContext &Ctx, - const FunctionTemplateDecl *FunctionTemplate, - llvm::SmallBitVector &Deduced) { +void Sema::MarkDeducedTemplateParameters( + ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 14c6405..6ac7175 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -448,6 +448,10 @@ void Sema::PrintInstantiationStack() { diag::note_template_enum_def_here) << ED << Active->InstantiationRange; + } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_nsdmi_here) + << FD << Active->InstantiationRange; } else { Diags.Report(Active->PointOfInstantiation, diag::note_template_type_alias_instantiation_here) @@ -767,6 +771,8 @@ namespace { QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr); + const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); + ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -789,11 +795,17 @@ namespace { ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL); + FunctionProtoTypeLoc TL) { + // Call the base version; it will forward to our overridden version below. + return inherited::TransformFunctionProtoType(TLB, TL); + } + + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals); + unsigned ThisTypeQuals, + Fn TransformExceptionSpec); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1023,7 +1035,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope) { if (TemplateTemplateParmDecl *TTP @@ -1127,6 +1139,24 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg); } +const LoopHintAttr * +TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { + Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get(); + + if (TransformedExpr == LH->getValue()) + return LH; + + // Generate error if there is a problem with the value. + if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation())) + return LH; + + // Create new LoopHintValueAttr with integral expression in place of the + // non-type template parameter. + return LoopHintAttr::CreateImplicit( + getSema().Context, LH->getSemanticSpelling(), LH->getOption(), + LH->getState(), TransformedExpr, LH->getRange()); +} + ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( NonTypeTemplateParmDecl *parm, SourceLocation loc, @@ -1255,8 +1285,8 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, Decl *TransformedDecl; if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) { - // If this is a reference to a function parameter pack which we can substitute - // but can't yet expand, build a FunctionParmPackExpr for it. + // If this is a reference to a function parameter pack which we can + // substitute but can't yet expand, build a FunctionParmPackExpr for it. if (getSema().ArgumentPackSubstitutionIndex == -1) { QualType T = TransformType(E->getType()); if (T.isNull()) @@ -1307,21 +1337,16 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( E->getParam()); } -QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL) { - // We need a local instantiation scope for this function prototype. - LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType(TLB, TL); -} - +template<typename Fn> QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals) { + unsigned ThisTypeQuals, + Fn TransformExceptionSpec) { // We need a local instantiation scope for this function prototype. LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, - ThisTypeQuals); + return inherited::TransformFunctionProtoType( + TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec); } ParmVarDecl * @@ -1556,7 +1581,8 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { /// A form of SubstType intended specifically for instantiating the /// type of a FunctionDecl. Its purpose is solely to force the -/// instantiation of default-argument expressions. +/// instantiation of default-argument expressions and to avoid +/// instantiating an exception-specification. TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, @@ -1579,9 +1605,17 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, QualType Result; - if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { - Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext, - ThisTypeQuals); + if (FunctionProtoTypeLoc Proto = + TL.IgnoreParens().getAs<FunctionProtoTypeLoc>()) { + // Instantiate the type, other than its exception specification. The + // exception specification is instantiated in InitFunctionInstantiation + // once we've built the FunctionDecl. + // FIXME: Set the exception specification to EST_Uninstantiated here, + // instead of rebuilding the function type again later. + Result = Instantiator.TransformFunctionProtoType( + TLB, Proto, ThisContext, ThisTypeQuals, + [](FunctionProtoType::ExceptionSpecInfo &ESI, + bool &Changed) { return false; }); } else { Result = Instantiator.TransformType(TLB, TL); } @@ -1591,6 +1625,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return TLB.getTypeSourceInfo(Context, Result); } +void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &Args) { + FunctionProtoType::ExceptionSpecInfo ESI = + Proto->getExtProtoInfo().ExceptionSpec; + assert(ESI.Type != EST_Uninstantiated); + + TemplateInstantiator Instantiator(*this, Args, New->getLocation(), + New->getDeclName()); + + SmallVector<QualType, 4> ExceptionStorage; + bool Changed = false; + if (Instantiator.TransformExceptionSpec( + New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI, + ExceptionStorage, Changed)) + // On error, recover by dropping the exception specification. + ESI.Type = EST_None; + + UpdateExceptionSpec(New, ESI); +} + ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -1947,8 +2001,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); SmallVector<Decl*, 4> Fields; - SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> - FieldsWithMemberInitializers; // Delay instantiation of late parsed attributes. LateInstantiatedAttrVec LateAttrs; Instantiator.enableLateAttributeInstantiation(&LateAttrs); @@ -1975,10 +2027,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (NewMember) { if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) { Fields.push_back(Field); - FieldDecl *OldField = cast<FieldDecl>(Member); - if (OldField->getInClassInitializer()) - FieldsWithMemberInitializers.push_back(std::make_pair(OldField, - Field)); } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) { // C++11 [temp.inst]p1: The implicit instantiation of a class template // specialization causes the implicit instantiation of the definitions @@ -2015,31 +2063,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, SourceLocation(), SourceLocation(), nullptr); CheckCompletedCXXClass(Instantiation); - // Attach any in-class member initializers now the class is complete. - // FIXME: We are supposed to defer instantiating these until they are needed. - if (!FieldsWithMemberInitializers.empty()) { - // C++11 [expr.prim.general]p4: - // Otherwise, if a member-declarator declares a non-static data member - // (9.2) of a class X, the expression this is a prvalue of type "pointer - // to X" within the optional brace-or-equal-initializer. It shall not - // appear elsewhere in the member-declarator. - CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0); - - for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { - FieldDecl *OldField = FieldsWithMemberInitializers[I].first; - FieldDecl *NewField = FieldsWithMemberInitializers[I].second; - Expr *OldInit = OldField->getInClassInitializer(); - - ActOnStartCXXInClassMemberInitializer(); - ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, - /*CXXDirectInit=*/false); - Expr *Init = NewInit.get(); - assert((!Init || !isa<ParenListExpr>(Init)) && - "call-style init in class"); - ActOnFinishCXXInClassMemberInitializer(NewField, - Init ? Init->getLocStart() : SourceLocation(), Init); - } - } // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), @@ -2180,6 +2203,80 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, return Instantiation->isInvalidDecl(); } + +/// \brief Instantiate the definition of a field from the given pattern. +/// +/// \param PointOfInstantiation The point of instantiation within the +/// source code. +/// \param Instantiation is the declaration whose definition is being +/// instantiated. This will be a class of a class temploid +/// specialization, or a local enumeration within a function temploid +/// specialization. +/// \param Pattern The templated declaration from which the instantiation +/// occurs. +/// \param TemplateArgs The template arguments to be substituted into +/// the pattern. +/// +/// \return \c true if an error occurred, \c false otherwise. +bool Sema::InstantiateInClassInitializer( + SourceLocation PointOfInstantiation, FieldDecl *Instantiation, + FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { + // If there is no initializer, we don't need to do anything. + if (!Pattern->hasInClassInitializer()) + return false; + + assert(Instantiation->getInClassInitStyle() == + Pattern->getInClassInitStyle() && + "pattern and instantiation disagree about init style"); + + // Error out if we haven't parsed the initializer of the pattern yet because + // we are waiting for the closing brace of the outer class. + Expr *OldInit = Pattern->getInClassInitializer(); + if (!OldInit) { + RecordDecl *PatternRD = Pattern->getParent(); + RecordDecl *OutermostClass = PatternRD->getOuterLexicalRecordContext(); + if (OutermostClass == PatternRD) { + Diag(Pattern->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) + << PatternRD << Pattern; + } else { + Diag(Pattern->getLocEnd(), + diag::err_in_class_initializer_not_yet_parsed_outer_class) + << PatternRD << OutermostClass << Pattern; + } + Instantiation->setInvalidDecl(); + return true; + } + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); + if (Inst.isInvalid()) + return true; + + // Enter the scope of this instantiation. We don't use PushDeclContext because + // we don't have a scope. + ContextRAII SavedContext(*this, Instantiation->getParent()); + EnterExpressionEvaluationContext EvalContext(*this, + Sema::PotentiallyEvaluated); + + LocalInstantiationScope Scope(*this); + + // Instantiate the initializer. + ActOnStartCXXInClassMemberInitializer(); + CXXThisScopeRAII ThisScope(*this, Instantiation->getParent(), /*TypeQuals=*/0); + + ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, + /*CXXDirectInit=*/false); + Expr *Init = NewInit.get(); + assert((!Init || !isa<ParenListExpr>(Init)) && "call-style init in class"); + ActOnFinishCXXInClassMemberInitializer( + Instantiation, Init ? Init->getLocStart() : SourceLocation(), Init); + + // Exit the scope of this instantiation. + SavedContext.pop(); + + // Return true if the in-class initializer is still missing. + return !Instantiation->getInClassInitializer(); +} + namespace { /// \brief A partial specialization whose template arguments have matched /// a given template-id. @@ -2458,7 +2555,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // Always skip the injected-class-name, along with any // redeclarations of nested classes, since both would cause us // to try to instantiate the members of a class twice. - if (Record->isInjectedClassName() || Record->getPreviousDecl()) + // Skip closure types; they'll get instantiated when we instantiate + // the corresponding lambda-expression. + if (Record->isInjectedClassName() || Record->getPreviousDecl() || + Record->isLambda()) continue; MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); @@ -2541,6 +2641,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); } + } else if (auto *Field = dyn_cast<FieldDecl>(D)) { + // No need to instantiate in-class initializers during explicit + // instantiation. + if (Field->hasInClassInitializer() && TSK == TSK_ImplicitInstantiation) { + CXXRecordDecl *ClassPattern = + Instantiation->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + assert(Lookup.size() == 1); + FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern, + TemplateArgs); + } } } } @@ -2649,8 +2762,7 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); } - -static const Decl* getCanonicalParmVarDecl(const Decl *D) { +static const Decl *getCanonicalParmVarDecl(const Decl *D) { // When storing ParmVarDecls in the local instantiation scope, we always // want to use the ParmVarDecl from the canonical function declaration, // since the map is then valid for any redeclaration or definition of that @@ -2658,7 +2770,10 @@ static const Decl* getCanonicalParmVarDecl(const Decl *D) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { unsigned i = PV->getFunctionScopeIndex(); - return FD->getCanonicalDecl()->getParamDecl(i); + // This parameter might be from a freestanding function type within the + // function and isn't necessarily referring to one of FD's parameters. + if (FD->getParamDecl(i) == PV) + return FD->getCanonicalDecl()->getParamDecl(i); } } return D; @@ -2707,12 +2822,22 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; - if (Stored.isNull()) + if (Stored.isNull()) { +#ifndef NDEBUG + // It should not be present in any surrounding scope either. + LocalInstantiationScope *Current = this; + while (Current->CombineWithOuterScope && Current->Outer) { + Current = Current->Outer; + assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() && + "Instantiated local in inner and outer scopes"); + } +#endif Stored = Inst; - else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) + } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) { Pack->push_back(Inst); - else + } else { assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); + } } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, @@ -2723,9 +2848,16 @@ void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, } void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { +#ifndef NDEBUG + // This should be the first time we've been told about this decl. + for (LocalInstantiationScope *Current = this; + Current && Current->CombineWithOuterScope; Current = Current->Outer) + assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() && + "Creating local pack after instantiation of local"); +#endif + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; - assert(Stored.isNull() && "Already instantiated this local"); DeclArgumentPack *Pack = new DeclArgumentPack; Stored = Pack; ArgumentPacks.push_back(Pack); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index accec95..40e8617 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -36,14 +36,24 @@ static bool isDeclWithinFunction(const Decl *D) { return false; } -bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, - DeclaratorDecl *NewDecl) { +template<typename DeclT> +static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl, + const MultiLevelTemplateArgumentList &TemplateArgs) { if (!OldDecl->getQualifierLoc()) return false; + assert((NewDecl->getFriendObjectKind() || + !OldDecl->getLexicalDeclContext()->isDependentContext()) && + "non-friend with qualified name defined in dependent context"); + Sema::ContextRAII SavedContext( + SemaRef, + const_cast<DeclContext *>(NewDecl->getFriendObjectKind() + ? NewDecl->getLexicalDeclContext() + : OldDecl->getLexicalDeclContext())); + NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), - TemplateArgs); + = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), + TemplateArgs); if (!NewQualifierLoc) return true; @@ -52,20 +62,14 @@ bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, return false; } +bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl) { + return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs); +} + bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl) { - if (!OldDecl->getQualifierLoc()) - return false; - - NestedNameSpecifierLoc NewQualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(), - TemplateArgs); - - if (!NewQualifierLoc) - return true; - - NewDecl->setQualifierInfo(NewQualifierLoc); - return false; + return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs); } // Include attribute instantiation code. @@ -129,6 +133,40 @@ static void instantiateDependentAlignedAttr( } } +static void instantiateDependentAssumeAlignedAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AssumeAlignedAttr *Aligned, Decl *New) { + // The alignment expression is a constant expression. + EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated); + + Expr *E, *OE = nullptr; + ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs); + if (Result.isInvalid()) + return; + E = Result.getAs<Expr>(); + + if (Aligned->getOffset()) { + Result = S.SubstExpr(Aligned->getOffset(), TemplateArgs); + if (Result.isInvalid()) + return; + OE = Result.getAs<Expr>(); + } + + S.AddAssumeAlignedAttr(Aligned->getLocation(), New, E, OE, + Aligned->getSpellingListIndex()); +} + +static void instantiateDependentAlignValueAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const AlignValueAttr *Aligned, Decl *New) { + // The alignment expression is a constant expression. + EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated); + ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs); + if (!Result.isInvalid()) + S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(), + Aligned->getSpellingListIndex()); +} + static void instantiateDependentEnableIfAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const EnableIfAttr *A, const Decl *Tmpl, Decl *New) { @@ -176,6 +214,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + const AssumeAlignedAttr *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr); + if (AssumeAligned) { + instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New); + continue; + } + + const AlignValueAttr *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr); + if (AlignValue) { + instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New); + continue; + } + const EnableIfAttr *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr); if (EnableIf && EnableIf->getCond()->isValueDependent()) { instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl, @@ -183,6 +233,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + // Existing DLL attribute on the instantiation takes precedence. + if (TmplAttr->getKind() == attr::DLLExport || + TmplAttr->getKind() == attr::DLLImport) { + if (New->hasAttr<DLLExportAttr>() || New->hasAttr<DLLImportAttr>()) { + continue; + } + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -207,6 +265,24 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } +/// Get the previous declaration of a declaration for the purposes of template +/// instantiation. If this finds a previous declaration, then the previous +/// declaration of the instantiation of D should be an instantiation of the +/// result of this function. +template<typename DeclT> +static DeclT *getPreviousDeclForInstantiation(DeclT *D) { + DeclT *Result = D->getPreviousDecl(); + + // If the declaration is within a class, and the previous declaration was + // merged from a different definition of that class, then we don't have a + // previous declaration for the purpose of template instantiation. + if (Result && isa<CXXRecordDecl>(D->getDeclContext()) && + D->getLexicalDeclContext() != Result->getLexicalDeclContext()) + return nullptr; + + return Result; +} + Decl * TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { llvm_unreachable("Translation units cannot be instantiated"); @@ -293,7 +369,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, } } - if (TypedefNameDecl *Prev = D->getPreviousDecl()) { + if (TypedefNameDecl *Prev = getPreviousDeclForInstantiation(D)) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); if (!InstPrev) @@ -316,13 +392,15 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false); - Owner->addDecl(Typedef); + if (Typedef) + Owner->addDecl(Typedef); return Typedef; } Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) { Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true); - Owner->addDecl(Typedef); + if (Typedef) + Owner->addDecl(Typedef); return Typedef; } @@ -340,7 +418,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { TypeAliasDecl *Pattern = D->getTemplatedDecl(); TypeAliasTemplateDecl *PrevAliasTemplate = nullptr; - if (Pattern->getPreviousDecl()) { + if (getPreviousDeclForInstantiation<TypedefNameDecl>(Pattern)) { DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); if (!Found.empty()) { PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Found.front()); @@ -355,6 +433,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { TypeAliasTemplateDecl *Inst = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getDeclName(), InstParams, AliasInst); + AliasInst->setDescribedAliasTemplate(Inst); if (PrevAliasTemplate) Inst->setPreviousDecl(PrevAliasTemplate); @@ -578,11 +657,12 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { } QualType T = cast<FieldDecl>(NamedChain[i-1])->getType(); - IndirectFieldDecl* IndirectField - = IndirectFieldDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T, - NamedChain, D->getChainingSize()); + IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( + SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, + NamedChain, D->getChainingSize()); + for (const auto *Attr : D->attrs()) + IndirectField->addAttr(Attr->clone(SemaRef.Context)); IndirectField->setImplicit(D->isImplicit()); IndirectField->setAccess(D->getAccess()); @@ -659,9 +739,9 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { EnumDecl *PrevDecl = nullptr; - if (D->getPreviousDecl()) { + if (EnumDecl *PatternPrev = getPreviousDeclForInstantiation(D)) { NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(), - D->getPreviousDecl(), + PatternPrev, TemplateArgs); if (!Prev) return nullptr; PrevDecl = cast<EnumDecl>(Prev); @@ -823,7 +903,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl *PrevDecl = nullptr; ClassTemplateDecl *PrevClassTemplate = nullptr; - if (!isFriend && Pattern->getPreviousDecl()) { + if (!isFriend && getPreviousDeclForInstantiation(Pattern)) { DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); if (!Found.empty()) { PrevClassTemplate = dyn_cast<ClassTemplateDecl>(Found.front()); @@ -1017,7 +1097,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { VarDecl *Pattern = D->getTemplatedDecl(); VarTemplateDecl *PrevVarTemplate = nullptr; - if (Pattern->getPreviousDecl()) { + if (getPreviousDeclForInstantiation(Pattern)) { DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); if (!Found.empty()) PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); @@ -1127,7 +1207,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!isFriend) { Owner->addDecl(InstTemplate); } else if (InstTemplate->getDeclContext()->isRecord() && - !D->getPreviousDecl()) { + !getPreviousDeclForInstantiation(D)) { SemaRef.CheckFriendAccess(InstTemplate); } @@ -1138,9 +1218,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = nullptr; if (D->isInjectedClassName()) PrevDecl = cast<CXXRecordDecl>(Owner); - else if (D->getPreviousDecl()) { + else if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) { NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(), - D->getPreviousDecl(), + PatternPrev, TemplateArgs); if (!Prev) return nullptr; PrevDecl = cast<CXXRecordDecl>(Prev); @@ -1191,6 +1271,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs, TSK_ImplicitInstantiation); } + + SemaRef.DiagnoseUnusedNestedTypedefs(Record); + return Record; } @@ -2201,7 +2284,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (CheckRedeclaration) { if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl)) continue; - } else if (UsingShadowDecl *OldPrev = Shadow->getPreviousDecl()) { + } else if (UsingShadowDecl *OldPrev = + getPreviousDeclForInstantiation(Shadow)) { PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl( Shadow->getLocation(), OldPrev, TemplateArgs)); } @@ -2276,8 +2360,10 @@ Decl * TemplateDeclInstantiator Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { CXXMethodDecl *OldFD = Decl->getSpecialization(); - CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, - nullptr, true)); + CXXMethodDecl *NewFD = + cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true)); + if (!NewFD) + return nullptr; LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); @@ -2976,7 +3062,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. -static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, +static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -2987,15 +3073,22 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, // Simple case: not a parameter pack. assert(FParamIdx < Function->getNumParams()); ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); // If the parameter's type is not dependent, update it to match the type // in the pattern. They can differ in top-level cv-qualifiers, and we want // the pattern's type here. If the type is dependent, they can't differ, - // per core issue 1668. + // per core issue 1668. Substitute into the type from the pattern, in case + // it's instantiation-dependent. // FIXME: Updating the type to work around this is at best fragile. - if (!PatternDecl->getType()->isDependentType()) - FunctionParam->setType(PatternParam->getType()); + if (!PatternDecl->getType()->isDependentType()) { + QualType T = S.SubstType(PatternParam->getType(), TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); + if (T.isNull()) + return true; + FunctionParam->setType(T); + } - FunctionParam->setDeclName(PatternParam->getDeclName()); Scope.InstantiatedLocal(PatternParam, FunctionParam); ++FParamIdx; continue; @@ -3007,137 +3100,27 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); assert(NumArgumentsInExpansion && "should only be called when all template arguments are known"); + QualType PatternType = + PatternParam->getType()->castAs<PackExpansionType>()->getPattern(); for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - if (!PatternDecl->getType()->isDependentType()) - FunctionParam->setType(PatternParam->getType()); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; - } - } -} - -static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New, - const FunctionProtoType *Proto, - const MultiLevelTemplateArgumentList &TemplateArgs) { - assert(Proto->getExceptionSpecType() != EST_Uninstantiated); - - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - CXXRecordDecl *ThisContext = nullptr; - unsigned ThisTypeQuals = 0; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) { - ThisContext = Method->getParent(); - ThisTypeQuals = Method->getTypeQualifiers(); - } - Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals, - SemaRef.getLangOpts().CPlusPlus11); - - // The function has an exception specification or a "noreturn" - // attribute. Substitute into each of the exception types. - 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. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && - "Pack expansion without parameter packs?"); - - bool Expand = false; - bool RetainExpansion = false; - Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), - SourceRange(), - Unexpanded, - TemplateArgs, - 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 - // type. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); + if (!PatternDecl->getType()->isDependentType()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); + QualType T = S.SubstType(PatternType, TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); if (T.isNull()) - break; - - T = SemaRef.Context.getPackExpansionType(T, NumExpansions); - Exceptions.push_back(T); - continue; - } - - // Substitute into the pack expansion pattern for each template - bool Invalid = false; - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) { - Invalid = true; - break; - } - - Exceptions.push_back(T); + return true; + FunctionParam->setType(T); } - if (Invalid) - break; - - continue; - } - - QualType T - = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull() || - SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) - continue; - - Exceptions.push_back(T); - } - Expr *NoexceptExpr = nullptr; - if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Sema::ConstantEvaluated); - ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); - if (E.isUsable()) - E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); - - if (E.isUsable()) { - NoexceptExpr = E.get(); - if (!NoexceptExpr->isTypeDependent() && - !NoexceptExpr->isValueDependent()) - NoexceptExpr - = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, - nullptr, diag::err_noexcept_needs_constant_expression, - /*AllowFold*/ false).get(); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; } } - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = Proto->getExceptionSpecType(); - EPI.NumExceptions = Exceptions.size(); - EPI.Exceptions = Exceptions.data(); - EPI.NoexceptExpr = NoexceptExpr; - - SemaRef.UpdateExceptionSpec(New, EPI); + return false; } void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, @@ -3151,9 +3134,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, if (Inst.isInvalid()) { // We hit the instantiation depth limit. Clear the exception specification // so that our callers don't have to cope with EST_Uninstantiated. - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExceptionSpecType = EST_None; - UpdateExceptionSpec(Decl, EPI); + UpdateExceptionSpec(Decl, EST_None); return; } @@ -3166,11 +3147,14 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); FunctionDecl *Template = Proto->getExceptionSpecTemplate(); - addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs); + if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, + TemplateArgs)) { + UpdateExceptionSpec(Decl, EST_None); + return; + } - ::InstantiateExceptionSpec(*this, Decl, - Template->getType()->castAs<FunctionProtoType>(), - TemplateArgs); + SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(), + TemplateArgs); } /// \brief Initializes the common fields of an instantiation function @@ -3218,14 +3202,14 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, // DR1330: In C++11, defer instantiation of a non-trivial // exception specification. if (SemaRef.getLangOpts().CPlusPlus11 && - EPI.ExceptionSpecType != EST_None && - EPI.ExceptionSpecType != EST_DynamicNone && - EPI.ExceptionSpecType != EST_BasicNoexcept) { + EPI.ExceptionSpec.Type != EST_None && + EPI.ExceptionSpec.Type != EST_DynamicNone && + EPI.ExceptionSpec.Type != EST_BasicNoexcept) { FunctionDecl *ExceptionSpecTemplate = Tmpl; - if (EPI.ExceptionSpecType == EST_Uninstantiated) - ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; + if (EPI.ExceptionSpec.Type == EST_Uninstantiated) + ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; ExceptionSpecificationType NewEST = EST_Uninstantiated; - if (EPI.ExceptionSpecType == EST_Unevaluated) + if (EPI.ExceptionSpec.Type == EST_Unevaluated) NewEST = EST_Unevaluated; // Mark the function has having an uninstantiated exception specification. @@ -3233,13 +3217,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, = New->getType()->getAs<FunctionProtoType>(); assert(NewProto && "Template instantiation without function prototype?"); EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = NewEST; - EPI.ExceptionSpecDecl = New; - EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; + EPI.ExceptionSpec.Type = NewEST; + EPI.ExceptionSpec.SourceDecl = New; + EPI.ExceptionSpec.SourceTemplate = ExceptionSpecTemplate; New->setType(SemaRef.Context.getFunctionType( NewProto->getReturnType(), NewProto->getParamTypes(), EPI)); } else { - ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs); + SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs); } } @@ -3322,6 +3306,20 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, 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. + // This has to happen before LateTemplateParser below is called, so that + // it marks vtables used in late parsed templates as used. + SavePendingLocalImplicitInstantiationsRAII + SavedPendingLocalImplicitInstantiations(*this); + std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII> + SavePendingInstantiationsAndVTableUses; + if (Recursive) { + SavePendingInstantiationsAndVTableUses.reset( + new SavePendingInstantiationsAndVTableUsesRAII(*this)); + } + // Call the LateTemplateParser callback if there is a need to late parse // a templated function definition. if (!Pattern && PatternDecl->isLateTemplateParsed() && @@ -3353,6 +3351,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Function->setInvalidDecl(); } else if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition) { + assert(!Recursive); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); } @@ -3389,18 +3388,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); - // 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. - SmallVector<VTableUse, 16> SavedVTableUses; - std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; - SavePendingLocalImplicitInstantiationsRAII - SavedPendingLocalImplicitInstantiations(*this); - if (Recursive) { - VTableUses.swap(SavedVTableUses); - PendingInstantiations.swap(SavedPendingInstantiations); - } - EnterExpressionEvaluationContext EvalContext(*this, Sema::PotentiallyEvaluated); @@ -3417,17 +3404,24 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl->isDefaulted()) SetDeclDefaulted(Function, PatternDecl->getLocation()); else { + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); + + // Substitute into the qualifier; we can get a substitution failure here + // through evil use of alias templates. + // FIXME: Is CurContext correct for this? Should we go to the (instantiation + // of the) lexical context of the pattern? + SubstQualifier(*this, PatternDecl, Function, TemplateArgs); + ActOnStartOfFunctionDef(nullptr, Function); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Function); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); - - addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, - TemplateArgs); + if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs)) + return; // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = @@ -3469,15 +3463,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // instantiation of this template. PerformPendingInstantiations(); - // Restore the set of pending vtables. - assert(VTableUses.empty() && - "VTableUses should be empty before it is discarded."); - VTableUses.swap(SavedVTableUses); - - // Restore the set of pending implicit instantiations. - assert(PendingInstantiations.empty() && - "PendingInstantiations should be empty before it is discarded."); - PendingInstantiations.swap(SavedPendingInstantiations); + // Restore PendingInstantiations and VTableUses. + SavePendingInstantiationsAndVTableUses.reset(); } } @@ -3651,7 +3638,7 @@ void Sema::BuildVariableInstantiation( // Diagnose unused local variables with dependent types, where the diagnostic // will have been deferred. if (!NewVar->isInvalidDecl() && - NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() && + NewVar->getDeclContext()->isFunctionOrMethod() && OldVar->getType()->isDependentType()) DiagnoseUnusedDecl(NewVar); } @@ -3793,11 +3780,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // 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. - SmallVector<VTableUse, 16> SavedVTableUses; - std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; + std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII> + SavePendingInstantiationsAndVTableUses; if (Recursive) { - VTableUses.swap(SavedVTableUses); - PendingInstantiations.swap(SavedPendingInstantiations); + SavePendingInstantiationsAndVTableUses.reset( + new SavePendingInstantiationsAndVTableUsesRAII(*this)); } LocalInstantiationScope Local(*this); @@ -3825,15 +3812,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // instantiation of this template. PerformPendingInstantiations(); - // Restore the set of pending vtables. - assert(VTableUses.empty() && - "VTableUses should be empty before it is discarded."); - VTableUses.swap(SavedVTableUses); - - // Restore the set of pending implicit instantiations. - assert(PendingInstantiations.empty() && - "PendingInstantiations should be empty before it is discarded."); - PendingInstantiations.swap(SavedPendingInstantiations); + // Restore PendingInstantiations and VTableUses. + SavePendingInstantiationsAndVTableUses.reset(); } } @@ -3917,13 +3897,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // 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. - SmallVector<VTableUse, 16> SavedVTableUses; - std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; SavePendingLocalImplicitInstantiationsRAII SavedPendingLocalImplicitInstantiations(*this); + std::unique_ptr<SavePendingInstantiationsAndVTableUsesRAII> + SavePendingInstantiationsAndVTableUses; if (Recursive) { - VTableUses.swap(SavedVTableUses); - PendingInstantiations.swap(SavedPendingInstantiations); + SavePendingInstantiationsAndVTableUses.reset( + new SavePendingInstantiationsAndVTableUsesRAII(*this)); } // Enter the scope of this instantiation. We don't use @@ -3990,15 +3970,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // instantiation of this template. PerformPendingInstantiations(); - // Restore the set of pending vtables. - assert(VTableUses.empty() && - "VTableUses should be empty before it is discarded."); - VTableUses.swap(SavedVTableUses); - - // Restore the set of pending implicit instantiations. - assert(PendingInstantiations.empty() && - "PendingInstantiations should be empty before it is discarded."); - PendingInstantiations.swap(SavedPendingInstantiations); + // Restore PendingInstantiations and VTableUses. + SavePendingInstantiationsAndVTableUses.reset(); } } @@ -4235,25 +4208,26 @@ static bool isInstantiationOf(EnumDecl *Pattern, static bool isInstantiationOf(UsingShadowDecl *Pattern, UsingShadowDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern; + return declaresSameEntity(C.getInstantiatedFromUsingShadowDecl(Instance), + Pattern); } static bool isInstantiationOf(UsingDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUsingDecl(Instance) == Pattern; + return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); } static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUsingDecl(Instance) == Pattern; + return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); } static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUsingDecl(Instance) == Pattern; + return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -4319,8 +4293,8 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) { if (!Field->getDeclName()) { // This is an unnamed field. - return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) == - cast<FieldDecl>(D); + return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field), + cast<FieldDecl>(D)); } } @@ -4412,17 +4386,17 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. - 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); - - int PackIdx = ArgumentPackSubstitutionIndex; - assert(PackIdx != -1 && "found declaration pack but not pack expanding"); - return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); + if (CurrentInstantiationScope) { + if (auto Found = CurrentInstantiationScope->findInstantiationOf(D)) { + if (Decl *FD = Found->dyn_cast<Decl *>()) + return cast<NamedDecl>(FD); + + int PackIdx = ArgumentPackSubstitutionIndex; + assert(PackIdx != -1 && + "found declaration pack but not pack expanding"); + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); + } } // If we're performing a partial substitution during template argument diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 8e4ce0d..e4fab71 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -197,6 +197,20 @@ namespace { }; } +/// \brief Determine whether it's possible for an unexpanded parameter pack to +/// be valid in this location. This only happens when we're in a declaration +/// that is nested within an expression that could be expanded, such as a +/// lambda-expression within a function call. +/// +/// This is conservatively correct, but may claim that some unexpanded packs are +/// permitted when they are not. +bool Sema::isUnexpandedParameterPackPermitted() { + for (auto *SI : FunctionScopes) + if (isa<sema::LambdaScopeInfo>(SI)) + return true; + return false; +} + /// \brief Diagnose all of the unexpanded parameter packs in the given /// vector. bool @@ -230,7 +244,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, else Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); - if (Name && NamesKnown.insert(Name)) + if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); if (Unexpanded[I].second.isValid()) @@ -733,24 +747,48 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_error: break; } - + for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { const DeclaratorChunk &Chunk = D.getTypeObject(I); switch (Chunk.Kind) { case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Paren: + case DeclaratorChunk::BlockPointer: // These declarator chunks cannot contain any parameter packs. break; case DeclaratorChunk::Array: + if (Chunk.Arr.NumElts && + Chunk.Arr.NumElts->containsUnexpandedParameterPack()) + return true; + break; case DeclaratorChunk::Function: - case DeclaratorChunk::BlockPointer: - // Syntactically, these kinds of declarator chunks all come after the - // declarator-id (conceptually), so the parser should not invoke this - // routine at this time. - llvm_unreachable("Could not have seen this kind of declarator chunk"); - + for (unsigned i = 0, e = Chunk.Fun.NumParams; i != e; ++i) { + ParmVarDecl *Param = cast<ParmVarDecl>(Chunk.Fun.Params[i].Param); + QualType ParamTy = Param->getType(); + assert(!ParamTy.isNull() && "Couldn't parse type?"); + if (ParamTy->containsUnexpandedParameterPack()) return true; + } + + if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) { + for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) { + if (Chunk.Fun.Exceptions[i] + .Ty.get() + ->containsUnexpandedParameterPack()) + return true; + } + } else if (Chunk.Fun.getExceptionSpecType() == EST_ComputedNoexcept && + Chunk.Fun.NoexceptExpr->containsUnexpandedParameterPack()) + return true; + + if (Chunk.Fun.hasTrailingReturnType()) { + QualType T = Chunk.Fun.getTrailingReturnType().get(); + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return true; + } + break; + case DeclaratorChunk::MemberPointer: if (Chunk.Mem.Scope().getScopeRep() && Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack()) @@ -800,7 +838,6 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, LookupName(R, S); NamedDecl *ParameterPack = nullptr; - ParameterPackValidatorCCC Validator; switch (R.getResultKind()) { case LookupResult::Found: ParameterPack = R.getFoundDecl(); @@ -808,9 +845,10 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: - if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(), - R.getLookupKind(), S, nullptr, - Validator, CTK_ErrorRecovery)) { + if (TypoCorrection Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr, + llvm::make_unique<ParameterPackValidatorCCC>(), + CTK_ErrorRecovery)) { diagnoseTypo(Corrected, PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name, PDiag(diag::note_parameter_pack_here)); @@ -897,3 +935,108 @@ Sema::getTemplateArgumentPackExpansionPattern( llvm_unreachable("Invalid TemplateArgument Kind!"); } + +static void CheckFoldOperand(Sema &S, Expr *E) { + if (!E) + return; + + E = E->IgnoreImpCasts(); + if (isa<BinaryOperator>(E) || isa<AbstractConditionalOperator>(E)) { + S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand) + << E->getSourceRange() + << FixItHint::CreateInsertion(E->getLocStart(), "(") + << FixItHint::CreateInsertion(E->getLocEnd(), ")"); + } +} + +ExprResult Sema::ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + tok::TokenKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc) { + // LHS and RHS must be cast-expressions. We allow an arbitrary expression + // in the parser and reduce down to just cast-expressions here. + CheckFoldOperand(*this, LHS); + CheckFoldOperand(*this, RHS); + + // [expr.prim.fold]p3: + // In a binary fold, op1 and op2 shall be the same fold-operator, and + // either e1 shall contain an unexpanded parameter pack or e2 shall contain + // an unexpanded parameter pack, but not both. + if (LHS && RHS && + LHS->containsUnexpandedParameterPack() == + RHS->containsUnexpandedParameterPack()) { + return Diag(EllipsisLoc, + LHS->containsUnexpandedParameterPack() + ? diag::err_fold_expression_packs_both_sides + : diag::err_pack_expansion_without_parameter_packs) + << LHS->getSourceRange() << RHS->getSourceRange(); + } + + // [expr.prim.fold]p2: + // In a unary fold, the cast-expression shall contain an unexpanded + // parameter pack. + if (!LHS || !RHS) { + Expr *Pack = LHS ? LHS : RHS; + assert(Pack && "fold expression with neither LHS nor RHS"); + if (!Pack->containsUnexpandedParameterPack()) + return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << Pack->getSourceRange(); + } + + BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator); + return BuildCXXFoldExpr(LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc); +} + +ExprResult Sema::BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc) { + return new (Context) CXXFoldExpr(Context.DependentTy, LParenLoc, LHS, + Operator, EllipsisLoc, RHS, RParenLoc); +} + +ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, + BinaryOperatorKind Operator) { + // [temp.variadic]p9: + // If N is zero for a unary fold-expression, the value of the expression is + // * -> 1 + // + -> int() + // & -> -1 + // | -> int() + // && -> true + // || -> false + // , -> void() + // if the operator is not listed [above], the instantiation is ill-formed. + // + // Note that we need to use something like int() here, not merely 0, to + // prevent the result from being a null pointer constant. + QualType ScalarType; + switch (Operator) { + case BO_Add: + ScalarType = Context.IntTy; + break; + case BO_Mul: + return ActOnIntegerConstant(EllipsisLoc, 1); + case BO_Or: + ScalarType = Context.IntTy; + break; + case BO_And: + return CreateBuiltinUnaryOp(EllipsisLoc, UO_Minus, + ActOnIntegerConstant(EllipsisLoc, 1).get()); + case BO_LOr: + return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false); + case BO_LAnd: + return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_true); + case BO_Comma: + ScalarType = Context.VoidTy; + break; + + default: + return Diag(EllipsisLoc, diag::err_fold_expression_empty) + << BinaryOperator::getOpcodeStr(Operator); + } + + return new (Context) CXXScalarValueInitExpr( + ScalarType, Context.getTrivialTypeSourceInfo(ScalarType, EllipsisLoc), + EllipsisLoc); +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index be1191c..0f96a1c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -107,6 +107,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_StdCall: \ case AttributeList::AT_ThisCall: \ case AttributeList::AT_Pascal: \ + case AttributeList::AT_VectorCall: \ case AttributeList::AT_MSABI: \ case AttributeList::AT_SysVABI: \ case AttributeList::AT_Regparm: \ @@ -660,26 +661,27 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, // ...and *prepend* it to the declarator. SourceLocation NoLoc; declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( - /*HasProto=*/true, - /*IsAmbiguous=*/false, - /*LParenLoc=*/NoLoc, - /*ArgInfo=*/nullptr, - /*NumArgs=*/0, - /*EllipsisLoc=*/NoLoc, - /*RParenLoc=*/NoLoc, - /*TypeQuals=*/0, - /*RefQualifierIsLvalueRef=*/true, - /*RefQualifierLoc=*/NoLoc, - /*ConstQualifierLoc=*/NoLoc, - /*VolatileQualifierLoc=*/NoLoc, - /*MutableLoc=*/NoLoc, - EST_None, - /*ESpecLoc=*/NoLoc, - /*Exceptions=*/nullptr, - /*ExceptionRanges=*/nullptr, - /*NumExceptions=*/0, - /*NoexceptExpr=*/nullptr, - loc, loc, declarator)); + /*HasProto=*/true, + /*IsAmbiguous=*/false, + /*LParenLoc=*/NoLoc, + /*ArgInfo=*/nullptr, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*RestrictQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/nullptr, + /*ExceptionRanges=*/nullptr, + /*NumExceptions=*/0, + /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, + loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. @@ -763,7 +765,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // is inferred from the return statements inside the block. // The declspec is always missing in a lambda expr context; it is either // specified with a trailing return type or inferred. - if (S.getLangOpts().CPlusPlus1y && + if (S.getLangOpts().CPlusPlus14 && declarator.getContext() == Declarator::LambdaExprContext) { // In C++1y, a lambda's implicit return type is 'auto'. Result = Context.getAutoDeductType(); @@ -1005,16 +1007,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size(); const bool IsParameterPack = declarator.hasEllipsis(); - - // Create a name for the invented template parameter type. - std::string InventedTemplateParamName = "$auto-"; - llvm::raw_string_ostream ss(InventedTemplateParamName); - ss << TemplateParameterDepth; - ss << "-" << AutoParameterPosition; - ss.flush(); - - IdentifierInfo& TemplateParamII = Context.Idents.get( - InventedTemplateParamName.c_str()); + // Turns out we must create the TemplateTypeParmDecl here to // retrieve the corresponding template parameter type. TemplateTypeParmDecl *CorrespondingTemplateParam = @@ -1029,11 +1022,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { /*NameLoc*/ declarator.getLocStart(), TemplateParameterDepth, AutoParameterPosition, // our template param index - /* Identifier*/ &TemplateParamII, false, IsParameterPack); + /* Identifier*/ nullptr, false, IsParameterPack); LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam); // Replace the 'auto' in the function parameter with this invented // template type parameter. - Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0); + Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0); } else { Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false); } @@ -1107,8 +1100,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); else if (TypeQuals & DeclSpec::TQ_volatile) - S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers) - << Result << DS.getSourceRange(); + S.Diag(DS.getVolatileSpecLoc(), + diag::warn_typecheck_function_qualifiers) + << Result << DS.getSourceRange(); else { assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) && "Has CVRA quals but not C, V, R, or A?"); @@ -1174,6 +1168,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Qualified; } + assert(!Result.isNull() && "This function should not return a null type"); return Result; } @@ -1186,6 +1181,9 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) { QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS) { + if (T.isNull()) + return QualType(); + // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { @@ -1224,6 +1222,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS) { + if (T.isNull()) + return QualType(); + // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic. unsigned CVR = CVRA & ~DeclSpec::TQ_atomic; @@ -1746,7 +1747,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { } // Functions cannot return half FP. - if (T->isHalfType()) { + if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) { Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(Loc, "*"); return true; @@ -1776,7 +1777,7 @@ QualType Sema::BuildFunctionType(QualType T, if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; - } else if (ParamType->isHalfType()) { + } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) { // Disallow half FP arguments. Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Loc, "*"); @@ -2175,7 +2176,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 0; break; case Declarator::LambdaExprParameterContext: - if (!(SemaRef.getLangOpts().CPlusPlus1y + if (!(SemaRef.getLangOpts().CPlusPlus14 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) Error = 14; break; @@ -2208,11 +2209,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 10; // Type alias break; case Declarator::TrailingReturnContext: - if (!SemaRef.getLangOpts().CPlusPlus1y) + if (!SemaRef.getLangOpts().CPlusPlus14) Error = 11; // Function return type break; case Declarator::ConversionIdContext: - if (!SemaRef.getLangOpts().CPlusPlus1y) + if (!SemaRef.getLangOpts().CPlusPlus14) Error = 12; // conversion-type-id break; case Declarator::TypeNameContext: @@ -2332,6 +2333,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } } + assert(!T.isNull() && "This function should not return a null type"); return T; } @@ -2481,7 +2483,8 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { - + // The TypeSourceInfo that this function returns will not be a null type. + // If there is an error, this function will fill in a dummy type as fallback. QualType T = declSpecType; Declarator &D = state.getDeclarator(); Sema &S = state.getSema(); @@ -2697,7 +2700,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // and not, for instance, a pointer to a function. if (D.getDeclSpec().containsPlaceholderType() && !FTI.hasTrailingReturnType() && chunkIndex == 0 && - !S.getLangOpts().CPlusPlus1y) { + !S.getLangOpts().CPlusPlus14) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto ? diag::err_auto_missing_trailing_return @@ -2751,7 +2754,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T; D.setInvalidType(true); } - } else { + } else if (!S.getLangOpts().HalfArgsAndReturns) { S.Diag(D.getIdentifierLoc(), diag::err_parameters_retval_cannot_have_fp16_type) << 1; D.setInvalidType(true); @@ -2941,7 +2944,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(); Param->setInvalidDecl(); } - } else { + } else if (!S.getLangOpts().HalfArgsAndReturns) { S.Diag(Param->getLocation(), diag::err_parameters_retval_cannot_have_fp16_type) << 0; D.setInvalidType(); @@ -2989,12 +2992,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, NoexceptExpr = FTI.NoexceptExpr; } - S.checkExceptionSpecification(FTI.getExceptionSpecType(), + S.checkExceptionSpecification(D.isFunctionDeclarationContext(), + FTI.getExceptionSpecType(), DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, Exceptions, - EPI); + EPI.ExceptionSpec); T = Context.getFunctionType(T, ParamTys, EPI); } @@ -3021,6 +3025,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: llvm_unreachable("Nested-name-specifier must name a type"); case NestedNameSpecifier::TypeSpec: @@ -3044,7 +3049,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } if (!ClsType.isNull()) - T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); + T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, + D.getIdentifier()); if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); @@ -3064,6 +3070,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, processTypeAttrs(state, T, TAL_DeclChunk, attrs); } + assert(!T.isNull() && "T must not be null after this point"); + if (LangOpts.CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); @@ -3120,9 +3128,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc()); if (Chunk.Fun.TypeQuals & Qualifiers::Volatile) RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc()); - // FIXME: We do not track the location of the __restrict qualifier. - //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) - // RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); + if (Chunk.Fun.TypeQuals & Qualifiers::Restrict) + RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc()); if (!RemovalLocs.empty()) { std::sort(RemovalLocs.begin(), RemovalLocs.end(), BeforeThanCompare<SourceLocation>(S.getSourceManager())); @@ -3153,12 +3160,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Apply any undistributed attributes from the declarator. - if (!T.isNull()) - if (AttributeList *attrs = D.getAttributes()) - processTypeAttrs(state, T, TAL_DeclName, attrs); + if (AttributeList *attrs = D.getAttributes()) + processTypeAttrs(state, T, TAL_DeclName, attrs); // Diagnose any ignored type attributes. - if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T); + state.diagnoseIgnoredTypeAttrs(T); // C++0x [dcl.constexpr]p9: // A constexpr specifier used in an object declaration declares the object @@ -3169,7 +3175,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If there was an ellipsis in the declarator, the declaration declares a // parameter pack whose type may be a pack expansion type. - if (D.hasEllipsis() && !T.isNull()) { + if (D.hasEllipsis()) { // C++0x [dcl.fct]p13: // A declarator-id or abstract-declarator containing an ellipsis shall // only be used in a parameter-declaration. Such a parameter-declaration @@ -3234,15 +3240,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. - S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); + S.Diag(D.getEllipsisLoc(), + diag::err_ellipsis_in_declarator_not_parameter); D.setEllipsisLoc(SourceLocation()); break; } } - if (T.isNull()) - return Context.getNullTypeSourceInfo(); - else if (D.isInvalidType()) + assert(!T.isNull() && "T must not be null at the end of this function"); + if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); @@ -3261,8 +3267,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { TypeSourceInfo *ReturnTypeInfo = nullptr; QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); - if (T.isNull()) - return Context.getNullTypeSourceInfo(); if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount) inferARCWriteback(state, T); @@ -3376,8 +3380,6 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { TypeSourceInfo *ReturnTypeInfo = nullptr; QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); - if (declSpecTy.isNull()) - return Context.getNullTypeSourceInfo(); if (getLangOpts().ObjCAutoRefCount) { Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy); @@ -3417,6 +3419,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_ThisCall; case AttributedType::attr_pascal: return AttributeList::AT_Pascal; + case AttributedType::attr_vectorcall: + return AttributeList::AT_VectorCall; case AttributedType::attr_pcs: case AttributedType::attr_pcs_vfp: return AttributeList::AT_Pcs; @@ -3717,6 +3721,7 @@ namespace { case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: llvm_unreachable("Nested-name-specifier must name a type"); } @@ -3975,6 +3980,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, ASIdx = LangAS::opencl_local; break; case AttributeList::AT_OpenCLConstantAddressSpace: ASIdx = LangAS::opencl_constant; break; + case AttributeList::AT_OpenCLGenericAddressSpace: + ASIdx = LangAS::opencl_generic; break; default: assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace); ASIdx = 0; break; @@ -4432,6 +4439,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { return AttributedType::attr_thiscall; case AttributeList::AT_Pascal: return AttributedType::attr_pascal; + case AttributeList::AT_VectorCall: + return AttributedType::attr_vectorcall; case AttributeList::AT_Pcs: { // The attribute may have had a fixit applied where we treated an // identifier as a string literal. The contents of the string are valid, @@ -4549,7 +4558,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, } // Diagnose use of callee-cleanup calling convention on variadic functions. - if (isCalleeCleanup(CC)) { + if (!supportsVariadicCall(CC)) { const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn); if (FnP && FnP->isVariadic()) { unsigned DiagID = diag::err_cconv_varargs; @@ -4564,23 +4573,12 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, } } - // Diagnose the use of X86 fastcall on unprototyped functions. - if (CC == CC_X86FastCall) { - if (isa<FunctionNoProtoType>(fn)) { - S.Diag(attr.getLoc(), diag::err_cconv_knr) - << FunctionType::getNameForCallConv(CC); - attr.setInvalid(); - return true; - } - - // Also diagnose fastcall with regparm. - if (fn->getHasRegParm()) { - S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << "regparm" - << FunctionType::getNameForCallConv(CC); - attr.setInvalid(); - return true; - } + // Also diagnose fastcall with regparm. + if (CC == CC_X86FastCall && fn->getHasRegParm()) { + S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) + << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall); + attr.setInvalid(); + return true; } // Modify the CC from the wrapped function type, wrap it all back, and then @@ -4739,9 +4737,7 @@ static bool isPermittedNeonBaseType(QualType &Ty, // Signed poly is mathematically wrong, but has been baked into some ABIs by // now. bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 || - Triple.getArch() == llvm::Triple::aarch64_be || - Triple.getArch() == llvm::Triple::arm64 || - Triple.getArch() == llvm::Triple::arm64_be; + Triple.getArch() == llvm::Triple::aarch64_be; if (VecKind == VectorType::NeonPolyVector) { if (IsPolyUnsigned) { // AArch64 polynomial vectors are unsigned and support poly64. @@ -4759,9 +4755,7 @@ static bool isPermittedNeonBaseType(QualType &Ty, // Non-polynomial vector types: the usual suspects are allowed, as well as // float64_t on AArch64. bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 || - Triple.getArch() == llvm::Triple::aarch64_be || - Triple.getArch() == llvm::Triple::arm64 || - Triple.getArch() == llvm::Triple::arm64_be; + Triple.getArch() == llvm::Triple::aarch64_be; if (Is64Bit && BTy->getKind() == BuiltinType::Double) return true; @@ -4899,6 +4893,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_OpenCLGlobalAddressSpace: case AttributeList::AT_OpenCLLocalAddressSpace: case AttributeList::AT_OpenCLConstantAddressSpace: + case AttributeList::AT_OpenCLGenericAddressSpace: case AttributeList::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); @@ -5098,31 +5093,9 @@ static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) { // If this definition was instantiated from a template, map back to the // pattern from which it was instantiated. - // - // FIXME: There must be a better place for this to live. if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { - if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { - auto From = TD->getInstantiatedFrom(); - if (auto *CTD = From.dyn_cast<ClassTemplateDecl*>()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { - if (NewCTD->isMemberSpecialization()) - break; - CTD = NewCTD; - } - RD = CTD->getTemplatedDecl(); - } else if (auto *CTPSD = From.dyn_cast< - ClassTemplatePartialSpecializationDecl *>()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { - if (NewCTPSD->isMemberSpecialization()) - break; - CTPSD = NewCTPSD; - } - RD = CTPSD; - } - } else if (isTemplateInstantiation(RD->getTemplateSpecializationKind())) { - while (auto *NewRD = RD->getInstantiatedFromMemberClass()) - RD = NewRD; - } + if (auto *Pattern = RD->getTemplateInstantiationPattern()) + RD = Pattern; D = RD->getDefinition(); } else if (auto *ED = dyn_cast<EnumDecl>(D)) { while (auto *NewED = ED->getInstantiatedFromMemberEnum()) @@ -5178,14 +5151,6 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { ? S.ImplicitMSInheritanceAttrLoc : RD->getSourceRange())); } - - if (RD->hasDefinition()) { - // Assign inheritance models to all of the base classes, because now we can - // form pointers to members of base classes without calling - // RequireCompleteType on the pointer to member of the base class type. - for (const CXXBaseSpecifier &BS : RD->bases()) - assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl()); - } } /// \brief The implementation of RequireCompleteType @@ -5510,6 +5475,8 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); + } else if (auto *PE = dyn_cast<PredefinedExpr>(E)) { + return PE->getType(); } // C++11 [expr.lambda.prim]p18: @@ -5550,11 +5517,19 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { return T; } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { +QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated) { ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.get(); + if (AsUnevaluated && ActiveTemplateInstantiations.empty() && + E->HasSideEffects(Context, false)) { + // The expression operand for decltype is in an unevaluated expression + // context, so side effects could result in unintended consequences. + Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); + } + return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 312811d..36abbb6 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H -#define LLVM_CLANG_SEMA_TREETRANSFORM_H +#ifndef LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H +#define LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H #include "TypeLocBuilder.h" #include "clang/AST/Decl.h" @@ -327,6 +327,27 @@ public: /// \returns the transformed OpenMP clause. OMPClause *TransformOMPClause(OMPClause *S); + /// \brief Transform the given attribute. + /// + /// By default, this routine transforms a statement by delegating to the + /// appropriate TransformXXXAttr function to transform a specific kind + /// of attribute. Subclasses may override this function to transform + /// attributed statements using some other mechanism. + /// + /// \returns the transformed attribute + const Attr *TransformAttr(const Attr *S); + +/// \brief Transform the specified attribute. +/// +/// Subclasses should override the transformation of attributes with a pragma +/// spelling to transform expressions stored within the attribute. +/// +/// \returns the transformed attribute. +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) \ + const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; } +#include "clang/Basic/AttrList.inc" + /// \brief Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the @@ -542,10 +563,17 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals); + unsigned ThisTypeQuals, + Fn TransformExceptionSpec); + + bool TransformExceptionSpec(SourceLocation Loc, + FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &Exceptions, + bool &Changed); StmtResult TransformSEHHandler(Stmt *Handler); @@ -560,10 +588,9 @@ public: TemplateName Template, CXXScopeSpec &SS); - QualType - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, - NestedNameSpecifierLoc QualifierLoc); + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifierLoc QualifierLoc); /// \brief Transforms the parameters of a function type into the /// given vectors. @@ -1665,10 +1692,8 @@ public: } StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, - Stmt *TryBlock, Stmt *Handler, int HandlerIndex, - int HandlerParentIndex) { - return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler, - HandlerIndex, HandlerParentIndex); + Stmt *TryBlock, Stmt *Handler) { + return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler); } StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, @@ -1680,6 +1705,15 @@ public: return getSema().ActOnSEHFinallyBlock(Loc, Block); } + /// \brief Build a new predefined expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildPredefinedExpr(SourceLocation Loc, + PredefinedExpr::IdentType IT) { + return getSema().BuildPredefinedExpr(Loc, IT); + } + /// \brief Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. @@ -2757,6 +2791,27 @@ public: return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } + /// \brief Build a new C++1z fold-expression. + /// + /// By default, performs semantic analysis in order to build a new fold + /// expression. + ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc) { + return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc, + RHS, RParenLoc); + } + + /// \brief Build an empty C++1z fold-expression with the given operator. + /// + /// By default, produces the fallback value for the fold-expression, or + /// produce an error if there is no fallback value. + ExprResult RebuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, + BinaryOperatorKind Operator) { + return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); + } + /// \brief Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3103,6 +3158,14 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; + case NestedNameSpecifier::Super: { + CXXRecordDecl *RD = + cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + SourceLocation(), QNNS->getAsRecordDecl())); + SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); + break; + } + case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, @@ -4515,15 +4578,20 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { - return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0); -} - -template<typename Derived> -QualType -TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals) { + SmallVector<QualType, 4> ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + return getDerived().TransformFunctionProtoType( + TLB, TL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(TL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); +} + +template<typename Derived> template<typename Fn> +QualType TreeTransform<Derived>::TransformFunctionProtoType( + TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals, Fn TransformExceptionSpec) { // Transform the parameters and return type. // // We are required to instantiate the params and return type in source order. @@ -4568,15 +4636,21 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, return QualType(); } - // FIXME: Need to transform the exception-specification too. + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + + bool EPIChanged = false; + if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged)) + return QualType(); + + // FIXME: Need to transform ConsumedParameters for variadic template + // expansion. QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || T->getNumParams() != ParamTypes.size() || !std::equal(T->param_type_begin(), T->param_type_end(), - ParamTypes.begin())) { - Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, - T->getExtProtoInfo()); + ParamTypes.begin()) || EPIChanged) { + Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI); if (Result.isNull()) return QualType(); } @@ -4593,6 +4667,107 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, } template<typename Derived> +bool TreeTransform<Derived>::TransformExceptionSpec( + SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &Exceptions, bool &Changed) { + assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated); + + // Instantiate a dynamic noexcept expression, if any. + if (ESI.Type == EST_ComputedNoexcept) { + EnterExpressionEvaluationContext Unevaluated(getSema(), + Sema::ConstantEvaluated); + ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); + if (NoexceptExpr.isInvalid()) + return true; + + NoexceptExpr = getSema().CheckBooleanCondition( + NoexceptExpr.get(), NoexceptExpr.get()->getLocStart()); + if (NoexceptExpr.isInvalid()) + return true; + + if (!NoexceptExpr.get()->isValueDependent()) { + NoexceptExpr = getSema().VerifyIntegerConstantExpression( + NoexceptExpr.get(), nullptr, + diag::err_noexcept_needs_constant_expression, + /*AllowFold*/false); + if (NoexceptExpr.isInvalid()) + return true; + } + + if (ESI.NoexceptExpr != NoexceptExpr.get()) + Changed = true; + ESI.NoexceptExpr = NoexceptExpr.get(); + } + + if (ESI.Type != EST_Dynamic) + return false; + + // Instantiate a dynamic exception specification's type. + for (QualType T : ESI.Exceptions) { + if (const PackExpansionType *PackExpansion = + T->getAs<PackExpansionType>()) { + Changed = true; + + // We have a pack expansion. Instantiate it. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and + // should + // be expanded. + bool Expand = false; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + // FIXME: Track the location of the ellipsis (and track source location + // information for the types in the exception specification in general). + if (getDerived().TryExpandParameterPacks( + Loc, SourceRange(), Unexpanded, Expand, + RetainExpansion, NumExpansions)) + return true; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + QualType U = getDerived().TransformType(PackExpansion->getPattern()); + if (U.isNull()) + return true; + + U = SemaRef.Context.getPackExpansionType(U, NumExpansions); + Exceptions.push_back(U); + continue; + } + + // Substitute into the pack expansion pattern for each slice of the + // pack. + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); + + QualType U = getDerived().TransformType(PackExpansion->getPattern()); + if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) + return true; + + Exceptions.push_back(U); + } + } else { + QualType U = getDerived().TransformType(T); + if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) + return true; + if (T != U) + Changed = true; + + Exceptions.push_back(U); + } + } + + ESI.Exceptions = Exceptions; + return false; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( TypeLocBuilder &TLB, FunctionNoProtoTypeLoc TL) { @@ -5147,8 +5322,8 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (const TemplateSpecializationType *TST = NamedT->getAs<TemplateSpecializationType>()) { TemplateName Template = TST->getTemplateName(); - if (TypeAliasTemplateDecl *TAT = - dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + if (TypeAliasTemplateDecl *TAT = dyn_cast_or_null<TypeAliasTemplateDecl>( + Template.getAsTemplateDecl())) { SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), diag::err_tag_reference_non_tag) << 4; SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); @@ -5529,19 +5704,43 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { SubStmt.get()); } -template<typename Derived> -StmtResult -TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { +template <typename Derived> +const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) { + if (!R) + return R; + + switch (R->getKind()) { +// Transform attributes with a pragma spelling by calling TransformXXXAttr. +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) \ + case attr::X: \ + return getDerived().Transform##X##Attr(cast<X##Attr>(R)); +#include "clang/Basic/AttrList.inc" + default: + return R; + } +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { + bool AttrsChanged = false; + SmallVector<const Attr *, 1> Attrs; + + // Visit attributes and keep track if any are transformed. + for (const auto *I : S->getAttrs()) { + const Attr *R = getDerived().TransformAttr(I); + AttrsChanged |= (I != R); + Attrs.push_back(R); + } + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); - // TODO: transform attributes - if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */) + if (SubStmt.get() == S->getSubStmt() && !AttrsChanged) return S; - return getDerived().RebuildAttributedStmt(S->getAttrLoc(), - S->getAttrs(), + return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs, SubStmt.get()); } @@ -5824,7 +6023,8 @@ TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) { - ExprResult Result = getDerived().TransformExpr(S->getRetValue()); + ExprResult Result = getDerived().TransformInitializer(S->getRetValue(), + /*NotCopyInit*/false); if (Result.isInvalid()) return StmtError(); @@ -6380,9 +6580,8 @@ StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) { Handler.get() == S->getHandler()) return S; - return getDerived().RebuildSEHTryStmt( - S->getIsCXXTry(), S->getTryLoc(), TryBlock.get(), Handler.get(), - S->getHandlerIndex(), S->getHandlerParentIndex()); + return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(), + TryBlock.get(), Handler.get()); } template <typename Derived> @@ -6504,6 +6703,17 @@ TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) { template <typename Derived> StmtResult +TreeTransform<Derived>::TransformOMPForSimdDirective(OMPForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_for_simd, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPSectionsDirective(OMPSectionsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr, @@ -6568,6 +6778,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForDirective( } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective( + OMPParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for_simd, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { DeclarationNameInfo DirName; @@ -6633,6 +6854,50 @@ TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) { return Res; } +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPAtomicDirective(OMPAtomicDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPTargetDirective(OMPTargetDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPTeamsDirective(OMPTeamsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_teams, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -6740,6 +7005,39 @@ TreeTransform<Derived>::TransformOMPMergeableClause(OMPMergeableClause *C) { } template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPReadClause(OMPReadClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPWriteClause(OMPWriteClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPUpdateClause(OMPUpdateClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPCaptureClause(OMPCaptureClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector<Expr *, 16> Vars; @@ -6912,7 +7210,11 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { - return E; + if (!E->isTypeDependent()) + return E; + + return getDerived().RebuildPredefinedExpr(E->getLocation(), + E->getIdentType()); } template<typename Derived> @@ -7161,6 +7463,12 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) { + return E; +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) { // Rebuild the syntactic form. The original syntactic form has // opaque-value expressions in it, so strip those away and rebuild @@ -7873,15 +8181,11 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) return E; - return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), - E->getStmtClass(), - E->getAngleBrackets().getBegin(), - Type, - E->getAngleBrackets().getEnd(), - // FIXME. this should be '(' location - E->getAngleBrackets().getEnd(), - SubExpr.get(), - E->getRParenLoc()); + return getDerived().RebuildCXXNamedCastExpr( + E->getOperatorLoc(), E->getStmtClass(), E->getAngleBrackets().getBegin(), + Type, E->getAngleBrackets().getEnd(), + // FIXME. this should be '(' location + E->getAngleBrackets().getEnd(), SubExpr.get(), E->getRParenLoc()); } template<typename Derived> @@ -8786,113 +9090,68 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { - - // Transform any init-capture expressions before entering the scope of the + // Transform any init-capture expressions before entering the scope of the // lambda body, because they are not semantically within that scope. SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes; InitCaptureExprsAndTypes.resize(E->explicit_capture_end() - E->explicit_capture_begin()); - for (LambdaExpr::capture_iterator C = E->capture_begin(), - CEnd = E->capture_end(); - C != CEnd; ++C) { + CEnd = E->capture_end(); + C != CEnd; ++C) { if (!C->isInitCapture()) continue; - EnterExpressionEvaluationContext EEEC(getSema(), - Sema::PotentiallyEvaluated); + EnterExpressionEvaluationContext EEEC(getSema(), + Sema::PotentiallyEvaluated); ExprResult NewExprInitResult = getDerived().TransformInitializer( C->getCapturedVar()->getInit(), C->getCapturedVar()->getInitStyle() == VarDecl::CallInit); - + if (NewExprInitResult.isInvalid()) return ExprError(); Expr *NewExprInit = NewExprInitResult.get(); - + VarDecl *OldVD = C->getCapturedVar(); - QualType NewInitCaptureType = - getSema().performLambdaInitCaptureInitialization(C->getLocation(), - OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), + QualType NewInitCaptureType = + getSema().performLambdaInitCaptureInitialization(C->getLocation(), + OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), NewExprInit); NewExprInitResult = NewExprInit; InitCaptureExprsAndTypes[C - E->capture_begin()] = std::make_pair(NewExprInitResult, NewInitCaptureType); - } LambdaScopeInfo *LSI = getSema().PushLambdaScope(); + Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); + // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); - // Check to see if the TypeSourceInfo of the call operator needs to - // be transformed, and if so do the transformation in the - // CurrentInstantiationScope. - - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - FunctionProtoTypeLoc OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + // Transform the type of the original lambda's call operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. TypeSourceInfo *NewCallOpTSI = nullptr; - - const bool CallOpWasAlreadyTransformed = - getDerived().AlreadyTransformed(OldCallOpTSI->getType()); - - // Use the Old Call Operator's TypeSourceInfo if it is already transformed. - if (CallOpWasAlreadyTransformed) - NewCallOpTSI = OldCallOpTSI; - else { - // Transform the TypeSourceInfo of the Original Lambda's Call Operator. - // The transformation MUST be done in the CurrentInstantiationScope since - // it introduces a mapping of the original to the newly created - // transformed parameters. + { + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + FunctionProtoTypeLoc OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); TypeLocBuilder NewCallOpTLBuilder; - QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, - OldCallOpFPTL, - nullptr, 0); + SmallVector<QualType, 4> ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + if (NewCallOpType.isNull()) + return ExprError(); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } - // Extract the ParmVarDecls from the NewCallOpTSI and add them to - // the vector below - this will be used to synthesize the - // NewCallOperator. Additionally, add the parameters of the untransformed - // lambda call operator to the CurrentInstantiationScope. - SmallVector<ParmVarDecl *, 4> Params; - { - FunctionProtoTypeLoc NewCallOpFPTL = - NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>(); - ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray(); - const unsigned NewNumArgs = NewCallOpFPTL.getNumParams(); - - for (unsigned I = 0; I < NewNumArgs; ++I) { - // If this call operator's type does not require transformation, - // the parameters do not get added to the current instantiation scope, - // - so ADD them! This allows the following to compile when the enclosing - // template is specialized and the entire lambda expression has to be - // transformed. - // template<class T> void foo(T t) { - // auto L = [](auto a) { - // auto M = [](char b) { <-- note: non-generic lambda - // auto N = [](auto c) { - // int x = sizeof(a); - // x = sizeof(b); <-- specifically this line - // x = sizeof(c); - // }; - // }; - // }; - // } - // foo('a') - if (CallOpWasAlreadyTransformed) - getDerived().transformedLocalDecl(NewParamDeclArray[I], - NewParamDeclArray[I]); - // Add to Params array, so these parameters can be used to create - // the newly transformed call operator. - Params.push_back(NewParamDeclArray[I]); - } - } - - if (!NewCallOpTSI) - return ExprError(); // Create the local class that will describe the lambda. CXXRecordDecl *Class @@ -8900,19 +9159,21 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpTSI, /*KnownDependent=*/false, E->getCaptureDefault()); - getDerived().transformedLocalDecl(E->getLambdaClass(), Class); // Build the call operator. - CXXMethodDecl *NewCallOperator - = getSema().startLambdaDefinition(Class, E->getIntroducerRange(), - NewCallOpTSI, - E->getCallOperator()->getLocEnd(), - Params); + CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( + Class, E->getIntroducerRange(), NewCallOpTSI, + E->getCallOperator()->getLocEnd(), + NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams()); LSI->CallOperator = NewCallOperator; getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); + // TransformLambdaScope will manage the function scope, so we can disable the + // cleanup. + FuncScopeCleanup.disable(); + return getDerived().TransformLambdaScope(E, NewCallOperator, InitCaptureExprsAndTypes); } @@ -8954,6 +9215,10 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit()); continue; } + // Captured expression will be recaptured during captured variables + // rebuilding. + if (C->capturesVLAType()) + continue; // Rebuild init-captures, including the implied field declaration. if (C->isInitCapture()) { @@ -9033,7 +9298,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, VarDecl *CapturedVar = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); - if (!CapturedVar) { + if (!CapturedVar || CapturedVar->isInvalidDecl()) { Invalid = true; continue; } @@ -9398,6 +9663,128 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { + Expr *Pattern = E->getPattern(); + + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions; + if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(), + Pattern->getSourceRange(), + Unexpanded, + Expand, RetainExpansion, + NumExpansions)) + return true; + + if (!Expand) { + // Do not expand any packs here, just transform and rebuild a fold + // expression. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + + ExprResult LHS = + E->getLHS() ? getDerived().TransformExpr(E->getLHS()) : ExprResult(); + if (LHS.isInvalid()) + return true; + + ExprResult RHS = + E->getRHS() ? getDerived().TransformExpr(E->getRHS()) : ExprResult(); + if (RHS.isInvalid()) + return true; + + if (!getDerived().AlwaysRebuild() && + LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) + return E; + + return getDerived().RebuildCXXFoldExpr( + E->getLocStart(), LHS.get(), E->getOperator(), E->getEllipsisLoc(), + RHS.get(), E->getLocEnd()); + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + ExprResult Result = getDerived().TransformExpr(E->getInit()); + if (Result.isInvalid()) + return true; + bool LeftFold = E->isLeftFold(); + + // If we're retaining an expansion for a right fold, it is the innermost + // component and takes the init (if any). + if (!LeftFold && RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), Out.get(), E->getOperator(), E->getEllipsisLoc(), + Result.get(), E->getLocEnd()); + if (Result.isInvalid()) + return true; + } + + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex( + getSema(), LeftFold ? I : *NumExpansions - I - 1); + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + if (Out.get()->containsUnexpandedParameterPack()) { + // We still have a pack; retain a pack expansion for this slice. + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), + LeftFold ? Result.get() : Out.get(), + E->getOperator(), E->getEllipsisLoc(), + LeftFold ? Out.get() : Result.get(), + E->getLocEnd()); + } else if (Result.isUsable()) { + // We've got down to a single element; build a binary operator. + Result = getDerived().RebuildBinaryOperator( + E->getEllipsisLoc(), E->getOperator(), + LeftFold ? Result.get() : Out.get(), + LeftFold ? Out.get() : Result.get()); + } else + Result = Out; + + if (Result.isInvalid()) + return true; + } + + // If we're retaining an expansion for a left fold, it is the outermost + // component and takes the complete expansion so far as its init (if any). + if (LeftFold && RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), Result.get(), + E->getOperator(), E->getEllipsisLoc(), + Out.get(), E->getLocEnd()); + if (Result.isInvalid()) + return true; + } + + // If we had no init and an empty pack, and we're not retaining an expansion, + // then produce a fallback value or error. + if (Result.isUnset()) + return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(), + E->getOperator()); + + return Result; +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXStdInitializerListExpr( CXXStdInitializerListExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); @@ -10292,7 +10679,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation RBrace; if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) { - DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo(); + DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo(); LBrace = SourceLocation::getFromRawEncoding( NameLoc.CXXOperatorName.BeginOpNameLoc); RBrace = SourceLocation::getFromRawEncoding( @@ -10348,9 +10735,16 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, // The scope type is now known to be a valid nested name specifier // component. Tack it on to the end of the nested name specifier. - if (ScopeType) - SS.Extend(SemaRef.Context, SourceLocation(), - ScopeType->getTypeLoc(), CCLoc); + if (ScopeType) { + if (!ScopeType->getType()->getAs<TagType>()) { + getSema().Diag(ScopeType->getTypeLoc().getBeginLoc(), + diag::err_expected_class_or_namespace) + << ScopeType->getType() << getSema().getLangOpts().CPlusPlus; + return ExprError(); + } + SS.Extend(SemaRef.Context, SourceLocation(), ScopeType->getTypeLoc(), + CCLoc); + } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. return getSema().BuildMemberReferenceExpr(Base, BaseType, @@ -10397,4 +10791,4 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) { } // end namespace clang -#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H +#endif diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index c3f874e..82844b3 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H -#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H +#ifndef LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H +#define LLVM_CLANG_LIB_SEMA_TYPELOCBUILDER_H #include "clang/AST/ASTContext.h" #include "clang/AST/TypeLoc.h" |