diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-31 17:06:31 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-31 17:06:31 +0000 |
commit | 735bee93f1285c5c55c64d80fdc2ede4c0f23341 (patch) | |
tree | e1209c2a0b4880eee15e0ce705016372f7c88724 /contrib/llvm/tools/clang/lib/Sema | |
parent | 51315c45ff5643a27f9c84b816db54ee870ba29b (diff) | |
parent | 486754660bb926339aefcf012a3f848592babb8b (diff) |
Merge clang trunk r338150, and resolve conflicts.
Notes
Notes:
svn path=/projects/clang700-import/; revision=336979
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema')
46 files changed, 15592 insertions, 10431 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 0033edf326ac..82d9df25d934 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -122,7 +122,7 @@ static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { } namespace { -/// \brief Warn on logical operator errors in CFGBuilder +/// Warn on logical operator errors in CFGBuilder class LogicalErrorHandler : public CFGCallback { Sema &S; @@ -200,60 +200,41 @@ static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { return false; } -// All blocks are in one of three states. States are ordered so that blocks -// can only move to higher states. -enum RecursiveState { - FoundNoPath, - FoundPath, - FoundPathWithNoRecursiveCall -}; - -// Returns true if there exists a path to the exit block and every path -// to the exit block passes through a call to FD. +// Returns true if every path from the entry block passes through a call to FD. static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { + llvm::SmallPtrSet<CFGBlock *, 16> Visited; + llvm::SmallVector<CFGBlock *, 16> WorkList; + // Keep track of whether we found at least one recursive path. + bool foundRecursion = false; const unsigned ExitID = cfg->getExit().getBlockID(); - // Mark all nodes as FoundNoPath, then set the status of the entry block. - SmallVector<RecursiveState, 16> States(cfg->getNumBlockIDs(), FoundNoPath); - States[cfg->getEntry().getBlockID()] = FoundPathWithNoRecursiveCall; - - // Make the processing stack and seed it with the entry block. - SmallVector<CFGBlock *, 16> Stack; - Stack.push_back(&cfg->getEntry()); - - while (!Stack.empty()) { - CFGBlock *CurBlock = Stack.back(); - Stack.pop_back(); + // Seed the work list with the entry block. + WorkList.push_back(&cfg->getEntry()); - unsigned ID = CurBlock->getBlockID(); - RecursiveState CurState = States[ID]; + while (!WorkList.empty()) { + CFGBlock *Block = WorkList.pop_back_val(); - if (CurState == FoundPathWithNoRecursiveCall) { - // Found a path to the exit node without a recursive call. - if (ExitID == ID) - return false; + for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { + if (CFGBlock *SuccBlock = *I) { + if (!Visited.insert(SuccBlock).second) + continue; - // Only change state if the block has a recursive call. - if (hasRecursiveCallInPath(FD, *CurBlock)) - CurState = FoundPath; - } + // Found a path to the exit node without a recursive call. + if (ExitID == SuccBlock->getBlockID()) + return false; - // Loop over successor blocks and add them to the Stack if their state - // changes. - for (auto I = CurBlock->succ_begin(), E = CurBlock->succ_end(); I != E; ++I) - if (*I) { - unsigned next_ID = (*I)->getBlockID(); - if (States[next_ID] < CurState) { - States[next_ID] = CurState; - Stack.push_back(*I); + // If the successor block contains a recursive call, end analysis there. + if (hasRecursiveCallInPath(FD, *SuccBlock)) { + foundRecursion = true; + continue; } + + WorkList.push_back(SuccBlock); } + } } - - // Return true if the exit node is reachable, and only reachable through - // a recursive call. - return States[ExitID] == FoundPath; + return foundRecursion; } static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, @@ -269,10 +250,6 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, CFG *cfg = AC.getCFG(); if (!cfg) return; - // If the exit block is unreachable, skip processing the function. - if (cfg->getExit().pred_empty()) - return; - // Emit diagnostic if a recursive function call is detected for all paths. if (checkForRecursiveFunctionCall(FD, cfg)) S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function); @@ -281,114 +258,62 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, //===----------------------------------------------------------------------===// // Check for throw in a non-throwing function. //===----------------------------------------------------------------------===// -enum ThrowState { - FoundNoPathForThrow, - FoundPathForThrow, - FoundPathWithNoThrowOutFunction, -}; -static bool isThrowCaught(const CXXThrowExpr *Throw, - const CXXCatchStmt *Catch) { - const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); - if (!CaughtType) - return true; - const Type *ThrowType = nullptr; - if (Throw->getSubExpr()) - ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull(); - if (!ThrowType) - return false; - if (ThrowType->isReferenceType()) - ThrowType = ThrowType->castAs<ReferenceType>() - ->getPointeeType() - ->getUnqualifiedDesugaredType(); - if (CaughtType->isReferenceType()) - CaughtType = CaughtType->castAs<ReferenceType>() - ->getPointeeType() - ->getUnqualifiedDesugaredType(); - if (ThrowType->isPointerType() && CaughtType->isPointerType()) { - ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType(); - CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType(); - } - if (CaughtType == ThrowType) - return true; - const CXXRecordDecl *CaughtAsRecordType = - CaughtType->getAsCXXRecordDecl(); - const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl(); - if (CaughtAsRecordType && ThrowTypeAsRecordType) - return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType); - return false; -} +/// Determine whether an exception thrown by E, unwinding from ThrowBlock, +/// can reach ExitBlock. +static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, + CFG *Body) { + SmallVector<CFGBlock *, 16> Stack; + llvm::BitVector Queued(Body->getNumBlockIDs()); -static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE, - const CXXTryStmt *TryStmt) { - for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) { - if (isThrowCaught(CE, TryStmt->getHandler(H))) - return true; - } - return false; -} + Stack.push_back(&ThrowBlock); + Queued[ThrowBlock.getBlockID()] = true; -static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) { - for (const auto &B : Block) { - if (B.getKind() != CFGElement::Statement) - continue; - const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt()); - if (!CE) - continue; + while (!Stack.empty()) { + CFGBlock &UnwindBlock = *Stack.back(); + Stack.pop_back(); - OpLoc = CE->getThrowLoc(); - for (const auto &I : Block.succs()) { - if (!I.isReachable()) + for (auto &Succ : UnwindBlock.succs()) { + if (!Succ.isReachable() || Queued[Succ->getBlockID()]) continue; - if (const auto *Terminator = - dyn_cast_or_null<CXXTryStmt>(I->getTerminator())) - if (isThrowCaughtByHandlers(CE, Terminator)) - return false; + + if (Succ->getBlockID() == Body->getExit().getBlockID()) + return true; + + if (auto *Catch = + dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) { + QualType Caught = Catch->getCaughtType(); + if (Caught.isNull() || // catch (...) catches everything + !E->getSubExpr() || // throw; is considered cuaght by any handler + S.handlerCanCatch(Caught, E->getSubExpr()->getType())) + // Exception doesn't escape via this path. + break; + } else { + Stack.push_back(Succ); + Queued[Succ->getBlockID()] = true; + } } - return true; } + return false; } -static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { - - unsigned ExitID = BodyCFG->getExit().getBlockID(); - - SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(), - FoundNoPathForThrow); - States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction; - - SmallVector<CFGBlock *, 16> Stack; - Stack.push_back(&BodyCFG->getEntry()); - while (!Stack.empty()) { - CFGBlock *CurBlock = Stack.pop_back_val(); - - unsigned ID = CurBlock->getBlockID(); - ThrowState CurState = States[ID]; - if (CurState == FoundPathWithNoThrowOutFunction) { - if (ExitID == ID) +static void visitReachableThrows( + CFG *BodyCFG, + llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) { + llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); + clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); + for (CFGBlock *B : *BodyCFG) { + if (!Reachable[B->getBlockID()]) + continue; + for (CFGElement &E : *B) { + Optional<CFGStmt> S = E.getAs<CFGStmt>(); + if (!S) continue; - - if (doesThrowEscapePath(*CurBlock, OpLoc)) - CurState = FoundPathForThrow; + if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) + Visit(Throw, *B); } - - // Loop over successor blocks and add them to the Stack if their state - // changes. - for (const auto &I : CurBlock->succs()) - if (I.isReachable()) { - unsigned NextID = I->getBlockID(); - if (NextID == ExitID && CurState == FoundPathForThrow) { - States[NextID] = CurState; - } else if (States[NextID] < CurState) { - States[NextID] = CurState; - Stack.push_back(I); - } - } } - // Return true if the exit node is reachable, and only reachable through - // a throw expression. - return States[ExitID] == FoundPathForThrow; } static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, @@ -418,14 +343,15 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, return; if (BodyCFG->getExit().pred_empty()) return; - SourceLocation OpLoc; - if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG)) - EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD); + visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { + if (throwEscapes(S, Throw, Block, BodyCFG)) + EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); + }); } static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (FPT->isNothrow(FD->getASTContext()) || FD->hasAttr<NoThrowAttr>()) + if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()) return true; return false; } @@ -491,9 +417,10 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { CFGBlock::FilterOptions FO; FO.IgnoreDefaultsWithCoveredEnums = 1; - for (CFGBlock::filtered_pred_iterator - I = cfg->getExit().filtered_pred_start_end(FO); I.hasMore(); ++I) { - const CFGBlock& B = **I; + for (CFGBlock::filtered_pred_iterator I = + cfg->getExit().filtered_pred_start_end(FO); + I.hasMore(); ++I) { + const CFGBlock &B = **I; if (!live[B.getBlockID()]) continue; @@ -683,18 +610,19 @@ struct CheckFallThroughDiagnostics { } // anonymous namespace -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// CheckFallThroughForBody - Check that we don't fall off the end of a /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked /// noreturn will return. static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, const BlockExpr *blkExpr, - const CheckFallThroughDiagnostics& CD, - AnalysisDeclContext &AC) { + const CheckFallThroughDiagnostics &CD, + AnalysisDeclContext &AC, + sema::FunctionScopeInfo *FSI) { bool ReturnsVoid = false; bool HasNoReturn = false; - bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine(); + bool IsCoroutine = FSI->isCoroutine(); if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) @@ -726,10 +654,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { if (IsCoroutine) - S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType(); + S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); else S.Diag(Loc, DiagID); }; + + // cpu_dispatch functions permit empty function bodies for ICC compatibility. + if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion()) + return; + // Either in a function body compound statement, or a function-try-block. switch (CheckFallThrough(AC)) { case UnknownFallThrough: @@ -1461,8 +1394,8 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, // Sort by first use so that we emit the warnings in a deterministic order. SourceManager &SM = S.getSourceManager(); - std::sort(UsesByStmt.begin(), UsesByStmt.end(), - [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { + llvm::sort(UsesByStmt.begin(), UsesByStmt.end(), + [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(), RHS.first->getLocStart()); }); @@ -1600,8 +1533,8 @@ public: // Sort the uses by their SourceLocations. While not strictly // guaranteed to produce them in line/column order, this will provide // a stable ordering. - std::sort(vec->begin(), vec->end(), - [](const UninitUse &a, const UninitUse &b) { + llvm::sort(vec->begin(), vec->end(), + [](const UninitUse &a, const UninitUse &b) { // Prefer a more confident report over a less confident one. if (a.getKind() != b.getKind()) return a.getKind() > b.getKind(); @@ -1674,7 +1607,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); return OptionalNotes(1, FNote); } return OptionalNotes(); @@ -1685,7 +1618,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); ONS.push_back(std::move(FNote)); } return ONS; @@ -1699,7 +1632,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); ONS.push_back(std::move(FNote)); } return ONS; @@ -1723,7 +1656,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void setVerbose(bool b) { Verbose = b; } - /// \brief Emit all buffered diagnostics in order of sourcelocation. + /// Emit all buffered diagnostics in order of sourcelocation. /// We need to output diagnostics produced while iterating through /// the lockset in deterministic order, so this function orders diagnostics /// and outputs them. @@ -1815,7 +1748,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { diag::warn_variable_requires_any_lock: diag::warn_var_deref_requires_any_lock; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) - << D->getNameAsString() << getLockKindFromAccessKind(AK)); + << D << getLockKindFromAccessKind(AK)); Warnings.emplace_back(std::move(Warning), getNotes()); } @@ -1843,7 +1776,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D->getNameAsString() + << D << LockName << LK); PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) << *PossibleMatch); @@ -1873,12 +1806,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D->getNameAsString() + << D << LockName << LK); if (Verbose && POK == POK_VarAccess) { PartialDiagnosticAt Note(D->getLocation(), - S.PDiag(diag::note_guarded_by_declared_here) - << D->getNameAsString()); + S.PDiag(diag::note_guarded_by_declared_here)); Warnings.emplace_back(std::move(Warning), getNotes(Note)); } else Warnings.emplace_back(std::move(Warning), getNotes()); @@ -2194,7 +2126,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, : (fscope->isCoroutine() ? CheckFallThroughDiagnostics::MakeForCoroutine(D) : CheckFallThroughDiagnostics::MakeForFunction(D))); - CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); + CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC, fscope); } // Warning: check for unreachable code diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index 3431ddcf70a2..9c4d315a692f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -1,4 +1,4 @@ -//===--- CodeCompleteConsumer.cpp - Code Completion Interface ---*- C++ -*-===// +//===- CodeCompleteConsumer.cpp - Code Completion Interface ---------------===// // // The LLVM Compiler Infrastructure // @@ -10,21 +10,30 @@ // This file implements the CodeCompleteConsumer class. // //===----------------------------------------------------------------------===// + #include "clang/Sema/CodeCompleteConsumer.h" #include "clang-c/Index.h" -#include "clang/AST/DeclCXX.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" -#include "clang/Sema/Scope.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Sema/Sema.h" #include "clang/Lex/Preprocessor.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> -#include <cstring> -#include <functional> +#include <cassert> +#include <cstdint> +#include <string> using namespace clang; @@ -33,7 +42,7 @@ using namespace clang; //===----------------------------------------------------------------------===// bool CodeCompletionContext::wantConstructorResults() const { - switch (Kind) { + switch (CCKind) { case CCC_Recovery: case CCC_Statement: case CCC_Expression: @@ -76,12 +85,87 @@ bool CodeCompletionContext::wantConstructorResults() const { llvm_unreachable("Invalid CodeCompletionContext::Kind!"); } +StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) { + using CCKind = CodeCompletionContext::Kind; + switch (Kind) { + case CCKind::CCC_Other: + return "Other"; + case CCKind::CCC_OtherWithMacros: + return "OtherWithMacros"; + case CCKind::CCC_TopLevel: + return "TopLevel"; + case CCKind::CCC_ObjCInterface: + return "ObjCInterface"; + case CCKind::CCC_ObjCImplementation: + return "ObjCImplementation"; + case CCKind::CCC_ObjCIvarList: + return "ObjCIvarList"; + case CCKind::CCC_ClassStructUnion: + return "ClassStructUnion"; + case CCKind::CCC_Statement: + return "Statement"; + case CCKind::CCC_Expression: + return "Expression"; + case CCKind::CCC_ObjCMessageReceiver: + return "ObjCMessageReceiver"; + case CCKind::CCC_DotMemberAccess: + return "DotMemberAccess"; + case CCKind::CCC_ArrowMemberAccess: + return "ArrowMemberAccess"; + case CCKind::CCC_ObjCPropertyAccess: + return "ObjCPropertyAccess"; + case CCKind::CCC_EnumTag: + return "EnumTag"; + case CCKind::CCC_UnionTag: + return "UnionTag"; + case CCKind::CCC_ClassOrStructTag: + return "ClassOrStructTag"; + case CCKind::CCC_ObjCProtocolName: + return "ObjCProtocolName"; + case CCKind::CCC_Namespace: + return "Namespace"; + case CCKind::CCC_Type: + return "Type"; + case CCKind::CCC_Name: + return "Name"; + case CCKind::CCC_PotentiallyQualifiedName: + return "PotentiallyQualifiedName"; + case CCKind::CCC_MacroName: + return "MacroName"; + case CCKind::CCC_MacroNameUse: + return "MacroNameUse"; + case CCKind::CCC_PreprocessorExpression: + return "PreprocessorExpression"; + case CCKind::CCC_PreprocessorDirective: + return "PreprocessorDirective"; + case CCKind::CCC_NaturalLanguage: + return "NaturalLanguage"; + case CCKind::CCC_SelectorName: + return "SelectorName"; + case CCKind::CCC_TypeQualifiers: + return "TypeQualifiers"; + case CCKind::CCC_ParenthesizedExpression: + return "ParenthesizedExpression"; + case CCKind::CCC_ObjCInstanceMessage: + return "ObjCInstanceMessage"; + case CCKind::CCC_ObjCClassMessage: + return "ObjCClassMessage"; + case CCKind::CCC_ObjCInterfaceName: + return "ObjCInterfaceName"; + case CCKind::CCC_ObjCCategoryName: + return "ObjCCategoryName"; + case CCKind::CCC_Recovery: + return "Recovery"; + } + llvm_unreachable("Invalid CodeCompletionContext::Kind!"); +} + //===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// + CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) - : Kind(Kind), Text("") -{ + : Kind(Kind), Text("") { switch (Kind) { case CK_TypedText: case CK_Text: @@ -195,10 +279,9 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks, unsigned NumAnnotations, StringRef ParentName, const char *BriefComment) - : NumChunks(NumChunks), NumAnnotations(NumAnnotations), - Priority(Priority), Availability(Availability), - ParentName(ParentName), BriefComment(BriefComment) -{ + : NumChunks(NumChunks), NumAnnotations(NumAnnotations), + Priority(Priority), Availability(Availability), + ParentName(ParentName), BriefComment(BriefComment) { assert(NumChunks <= 0xffff); assert(NumAnnotations <= 0xffff); @@ -222,7 +305,6 @@ const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const { return nullptr; } - std::string CodeCompletionString::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); @@ -267,7 +349,7 @@ const char *CodeCompletionAllocator::CopyString(const Twine &String) { StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { const NamedDecl *ND = dyn_cast<NamedDecl>(DC); if (!ND) - return StringRef(); + return {}; // Check whether we've already cached the parent name. StringRef &CachedParentName = ParentNames[DC]; @@ -277,7 +359,7 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { // If we already processed this DeclContext and assigned empty to it, the // data pointer will be non-null. if (CachedParentName.data() != nullptr) - return StringRef(); + return {}; // Find the interesting names. SmallVector<const DeclContext *, 2> Contexts; @@ -311,7 +393,7 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { // Assign an empty StringRef but with non-null data to distinguish // between empty because we didn't process the DeclContext yet. CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0); - return StringRef(); + return {}; } OS << Interface->getName() << '(' << Cat->getName() << ')'; @@ -375,9 +457,8 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK, } void CodeCompletionBuilder::addParentContext(const DeclContext *DC) { - if (DC->isTranslationUnit()) { + if (DC->isTranslationUnit()) return; - } if (DC->isFunctionOrMethod()) return; @@ -427,25 +508,21 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { // Code completion consumer implementation //===----------------------------------------------------------------------===// -CodeCompleteConsumer::~CodeCompleteConsumer() { } +CodeCompleteConsumer::~CodeCompleteConsumer() = default; bool PrintingCodeCompleteConsumer::isResultFilteredOut(StringRef Filter, CodeCompletionResult Result) { switch (Result.Kind) { - case CodeCompletionResult::RK_Declaration: { + case CodeCompletionResult::RK_Declaration: return !(Result.Declaration->getIdentifier() && Result.Declaration->getIdentifier()->getName().startswith(Filter)); - } - case CodeCompletionResult::RK_Keyword: { + case CodeCompletionResult::RK_Keyword: return !StringRef(Result.Keyword).startswith(Filter); - } - case CodeCompletionResult::RK_Macro: { + case CodeCompletionResult::RK_Macro: return !Result.Macro->getName().startswith(Filter); - } - case CodeCompletionResult::RK_Pattern: { + case CodeCompletionResult::RK_Pattern: return !StringRef(Result.Pattern->getAsString()).startswith(Filter); } - } llvm_unreachable("Unknown code completion result Kind."); } @@ -477,7 +554,24 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, if (const char *BriefComment = CCS->getBriefComment()) OS << " : " << BriefComment; } - + for (const FixItHint &FixIt : Results[I].FixIts) { + const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); + const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); + + SourceManager &SM = SemaRef.SourceMgr; + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); + // Adjust for token ranges. + if (FixIt.RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts); + + OS << " (requires fix-it:" + << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << SM.getColumnNumber(EInfo.first, EInfo.second) << "}" + << " to \"" << FixIt.CodeToInsert << "\")"; + } OS << '\n'; break; @@ -485,7 +579,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << Results[I].Keyword << '\n'; break; - case CodeCompletionResult::RK_Macro: { + case CodeCompletionResult::RK_Macro: OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef, Context, @@ -496,14 +590,12 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } OS << '\n'; break; - } - case CodeCompletionResult::RK_Pattern: { + case CodeCompletionResult::RK_Pattern: OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; break; } - } } } @@ -547,7 +639,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } -/// \brief Retrieve the effective availability of the given declaration. +/// Retrieve the effective availability of the given declaration. static AvailabilityResult getDeclAvailability(const Decl *D) { AvailabilityResult AR = D->getAvailability(); if (isa<EnumConstantDecl>(D)) @@ -609,7 +701,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { Availability = CXAvailability_NotAccessible; } -/// \brief Retrieve the name that should be used to order a result. +/// Retrieve the name that should be used to order a result. /// /// If the name needs to be constructed as a string, that string will be /// saved into Saved and the returned StringRef will refer to it. diff --git a/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h b/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h index 33a368d92ff4..d15cf0b756e7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h +++ b/contrib/llvm/tools/clang/lib/Sema/CoroutineStmtBuilder.h @@ -33,16 +33,16 @@ class CoroutineStmtBuilder : public CoroutineBodyStmt::CtorArgs { CXXRecordDecl *PromiseRecordDecl = nullptr; public: - /// \brief Construct a CoroutineStmtBuilder and initialize the promise + /// Construct a CoroutineStmtBuilder and initialize the promise /// statement and initial/final suspends from the FunctionScopeInfo. CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, sema::FunctionScopeInfo &Fn, Stmt *Body); - /// \brief Build the coroutine body statements, including the + /// Build the coroutine body statements, including the /// "promise dependent" statements when the promise type is not dependent. bool buildStatements(); - /// \brief Build the coroutine body statements that require a non-dependent + /// Build the coroutine body statements that require a non-dependent /// promise type in order to construct. /// /// For example different new/delete overloads are selected depending on @@ -51,9 +51,6 @@ public: /// name lookup. bool buildDependentStatements(); - /// \brief Build just parameter moves. To use for rebuilding in TreeTransform. - bool buildParameterMoves(); - bool isInvalid() const { return !this->IsValid; } private: @@ -65,7 +62,6 @@ private: bool makeReturnObject(); bool makeGroDeclAndReturnStmt(); bool makeReturnOnAllocFailure(); - bool makeParamMoves(); }; } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index 2fad5a18ba6b..ccca5d37ea39 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -186,7 +186,6 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Kind = Function; I.Loc = LocalRangeBegin; I.EndLoc = LocalRangeEnd; - I.Fun.AttrList = nullptr; I.Fun.hasPrototype = hasProto; I.Fun.isVariadic = EllipsisLoc.isValid(); I.Fun.isAmbiguous = isAmbiguous; @@ -251,7 +250,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, } break; - case EST_ComputedNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: I.Fun.NoexceptExpr = NoexceptExpr; break; @@ -329,6 +330,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_auto_type: case TST_bool: case TST_char: + case TST_char8: case TST_char16: case TST_char32: case TST_class: @@ -336,6 +338,8 @@ bool Declarator::isDeclarationOfFunction() const { case TST_decimal32: case TST_decimal64: case TST_double: + case TST_Accum: + case TST_Fract: case TST_Float16: case TST_float128: case TST_enum: @@ -499,6 +503,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_void: return "void"; case DeclSpec::TST_char: return "char"; case DeclSpec::TST_wchar: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; + case DeclSpec::TST_char8: return "char8_t"; case DeclSpec::TST_char16: return "char16_t"; case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; @@ -506,6 +511,8 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_accum: return "_Accum"; + case DeclSpec::TST_fract: return "_Fract"; case DeclSpec::TST_float16: return "_Float16"; case DeclSpec::TST_float128: return "__float128"; case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool"; @@ -761,6 +768,19 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, return false; } +bool DeclSpec::SetTypeSpecSat(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // Cannot set twice + if (TypeSpecSat) { + DiagID = diag::warn_duplicate_declspec; + PrevSpec = "_Sat"; + return true; + } + TypeSpecSat = true; + TSSatLoc = Loc; + return false; +} + bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy) { @@ -974,15 +994,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { writtenBS.Width = getTypeSpecWidth(); writtenBS.Type = getTypeSpecType(); // Search the list of attributes for the presence of a mode attribute. - writtenBS.ModeAttr = false; - AttributeList* attrs = getAttributes().getList(); - while (attrs) { - if (attrs->getKind() == AttributeList::AT_Mode) { - writtenBS.ModeAttr = true; - break; - } - attrs = attrs->getNext(); - } + writtenBS.ModeAttr = getAttributes().hasAttribute(ParsedAttr::AT_Mode); } /// Finish - This does final analysis of the declspec, rejecting things like @@ -1096,12 +1108,16 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { } } - // signed/unsigned are only valid with int/char/wchar_t. + bool IsFixedPointType = + TypeSpecType == TST_accum || TypeSpecType == TST_fract; + + // signed/unsigned are only valid with int/char/wchar_t/_Accum. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. - else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && - TypeSpecType != TST_char && TypeSpecType != TST_wchar) { + else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && + TypeSpecType != TST_char && TypeSpecType != TST_wchar && + !IsFixedPointType) { S.Diag(TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType, Policy); // signed double -> double. @@ -1116,20 +1132,24 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. - else if (TypeSpecType != TST_int) { + else if (!(TypeSpecType == TST_int || + (IsFixedPointType && TypeSpecWidth != TSW_longlong))) { S.Diag(TSWRange.getBegin(), diag::err_invalid_width_spec) << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; + TypeSpecSat = false; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. - else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { + else if (TypeSpecType != TST_int && TypeSpecType != TST_double && + !IsFixedPointType) { S.Diag(TSWRange.getBegin(), diag::err_invalid_width_spec) << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; + TypeSpecSat = false; TypeSpecOwned = false; } break; @@ -1202,7 +1222,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { StorageClassSpec == SCS_auto) S.Diag(StorageClassSpecLoc, diag::warn_auto_storage_class) << FixItHint::CreateRemoval(StorageClassSpecLoc); - if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) + if (TypeSpecType == TST_char8) + S.Diag(TSTLoc, diag::warn_cxx17_compat_unicode_type); + else if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) S.Diag(TSTLoc, diag::warn_cxx98_compat_unicode_type) << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (Constexpr_specified) diff --git a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp index 3d321d561e60..122b477d5522 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp @@ -1,4 +1,4 @@ -//===--- DelayedDiagnostic.cpp - Delayed declarator diagnostics -*- C++ -*-===// +//===- DelayedDiagnostic.cpp - Delayed declarator diagnostics -------------===// // // The LLVM Compiler Infrastructure // @@ -14,36 +14,44 @@ // This file also defines AccessedEntity. // //===----------------------------------------------------------------------===// + #include "clang/Sema/DelayedDiagnostic.h" -#include <string.h> +#include <cstring> + using namespace clang; using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeAvailability(AvailabilityResult AR, - SourceLocation Loc, + ArrayRef<SourceLocation> Locs, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, bool ObjCPropertyAccess) { + assert(!Locs.empty()); DelayedDiagnostic DD; DD.Kind = Availability; DD.Triggered = false; - DD.Loc = Loc; + DD.Loc = Locs.front(); DD.AvailabilityData.ReferringDecl = ReferringDecl; DD.AvailabilityData.OffendingDecl = OffendingDecl; DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; - if (Msg.size()) { + if (!Msg.empty()) { MessageData = new char [Msg.size()]; memcpy(MessageData, Msg.data(), Msg.size()); } - DD.AvailabilityData.Message = MessageData; DD.AvailabilityData.MessageLen = Msg.size(); + + DD.AvailabilityData.SelectorLocs = new SourceLocation[Locs.size()]; + memcpy(DD.AvailabilityData.SelectorLocs, Locs.data(), + sizeof(SourceLocation) * Locs.size()); + DD.AvailabilityData.NumSelectorLocs = Locs.size(); + DD.AvailabilityData.AR = AR; DD.AvailabilityData.ObjCPropertyAccess = ObjCPropertyAccess; return DD; @@ -57,6 +65,7 @@ void DelayedDiagnostic::Destroy() { case Availability: delete[] AvailabilityData.Message; + delete[] AvailabilityData.SelectorLocs; break; case ForbiddenType: diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp index 0bdb19490bc5..dbd52dee1eea 100644 --- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp @@ -1,4 +1,4 @@ -//===- IdentifierResolver.cpp - Lexical Scope Name lookup -------*- C++ -*-===// +//===- IdentifierResolver.cpp - Lexical Scope Name lookup -----------------===// // // The LLVM Compiler Infrastructure // @@ -14,10 +14,16 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Scope.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstdint> using namespace clang; @@ -35,17 +41,17 @@ class IdentifierResolver::IdDeclInfoMap { /// impossible to add something to a pre-C++0x STL container without /// a completely unnecessary copy. struct IdDeclInfoPool { - IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {} - IdDeclInfoPool *Next; IdDeclInfo Pool[POOL_SIZE]; + + IdDeclInfoPool(IdDeclInfoPool *Next) : Next(Next) {} }; - IdDeclInfoPool *CurPool; - unsigned int CurIndex; + IdDeclInfoPool *CurPool = nullptr; + unsigned int CurIndex = POOL_SIZE; public: - IdDeclInfoMap() : CurPool(nullptr), CurIndex(POOL_SIZE) {} + IdDeclInfoMap() = default; ~IdDeclInfoMap() { IdDeclInfoPool *Cur = CurPool; @@ -60,7 +66,6 @@ public: IdDeclInfo &operator[](DeclarationName Name); }; - //===----------------------------------------------------------------------===// // IdDeclInfo Implementation //===----------------------------------------------------------------------===// @@ -83,9 +88,7 @@ void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { //===----------------------------------------------------------------------===// IdentifierResolver::IdentifierResolver(Preprocessor &PP) - : LangOpt(PP.getLangOpts()), PP(PP), - IdDeclInfos(new IdDeclInfoMap) { -} + : LangOpt(PP.getLangOpts()), PP(PP), IdDeclInfos(new IdDeclInfoMap) {} IdentifierResolver::~IdentifierResolver() { delete IdDeclInfos; @@ -245,14 +248,16 @@ IdentifierResolver::begin(DeclarationName Name) { } namespace { - enum DeclMatchKind { - DMK_Different, - DMK_Replace, - DMK_Ignore - }; -} -/// \brief Compare two declarations to see whether they are different or, +enum DeclMatchKind { + DMK_Different, + DMK_Replace, + DMK_Ignore +}; + +} // namespace + +/// Compare two declarations to see whether they are different or, /// if they are the same, whether the new declaration should replace the /// existing declaration. static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) { diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index 64fa2c34b238..58a7862370cc 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -154,6 +154,10 @@ static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { return ScopePair(diag::note_protected_by_objc_weak_init, diag::note_exits_objc_weak); + case QualType::DK_nontrivial_c_struct: + return ScopePair(diag::note_protected_by_non_trivial_c_struct_init, + diag::note_exits_dtor); + case QualType::DK_cxx_destructor: OutDiag = diag::note_exits_dtor; break; @@ -212,7 +216,7 @@ static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) { return ScopePair(0U, 0U); } -/// \brief Build scope information for a declaration that is part of a DeclStmt. +/// Build scope information for a declaration that is part of a DeclStmt. void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { // If this decl causes a new scope, push and switch to it. std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D); @@ -229,7 +233,7 @@ void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) { BuildScopeInformation(Init, ParentScope); } -/// \brief Build scope information for a captured block literal variables. +/// Build scope information for a captured block literal variables. void JumpScopeChecker::BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, unsigned &ParentScope) { @@ -254,6 +258,10 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D, Diags = ScopePair(diag::note_enters_block_captures_weak, diag::note_exits_block_captures_weak); break; + case QualType::DK_nontrivial_c_struct: + Diags = ScopePair(diag::note_enters_block_captures_non_trivial_c_struct, + diag::note_exits_block_captures_non_trivial_c_struct); + break; case QualType::DK_none: llvm_unreachable("non-lifetime captured variable"); } diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 77ace0cfa579..7e61ccbb1068 100644 --- a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -16,7 +16,7 @@ using namespace clang; -///\brief Constructs a new multiplexing external sema source and appends the +///Constructs a new multiplexing external sema source and appends the /// given element to it. /// MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1, @@ -28,7 +28,7 @@ MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1, // pin the vtable here. MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {} -///\brief Appends new source to the source list. +///Appends new source to the source list. /// ///\param[in] source - An ExternalSemaSource. /// @@ -164,6 +164,20 @@ void MultiplexExternalSemaSource::PrintStats() { Sources[i]->PrintStats(); } +Module *MultiplexExternalSemaSource::getModule(unsigned ID) { + for (size_t i = 0; i < Sources.size(); ++i) + if (auto M = Sources[i]->getModule(ID)) + return M; + return nullptr; +} + +bool MultiplexExternalSemaSource::DeclIsFromPCHWithObjectFile(const Decl *D) { + for (auto *S : Sources) + if (S->DeclIsFromPCHWithObjectFile(D)) + return true; + return false; +} + bool MultiplexExternalSemaSource::layoutRecordType(const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/ParsedAttr.cpp index 14d334746f1f..6509df9985ef 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/ParsedAttr.cpp @@ -1,4 +1,4 @@ -//===--- AttributeList.cpp --------------------------------------*- C++ -*-===// +//======- ParsedAttr.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,20 +7,23 @@ // //===----------------------------------------------------------------------===// // -// This file defines the AttributeList class implementation +// This file defines the ParsedAttr class implementation // //===----------------------------------------------------------------------===// -#include "clang/Sema/AttributeList.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" #include "clang/Basic/AttrSubjectMatchRules.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <cstddef> +#include <utility> + using namespace clang; IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, @@ -31,91 +34,79 @@ IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, return Result; } -size_t AttributeList::allocated_size() const { +size_t ParsedAttr::allocated_size() const { if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; else if (IsTypeTagForDatatype) return AttributeFactory::TypeTagForDatatypeAllocSize; else if (IsProperty) return AttributeFactory::PropertyAllocSize; - return (sizeof(AttributeList) + NumArgs * sizeof(ArgsUnion)); + else if (HasParsedType) + return sizeof(ParsedAttr) + sizeof(void *); + return (sizeof(ParsedAttr) + NumArgs * sizeof(ArgsUnion)); } AttributeFactory::AttributeFactory() { // Go ahead and configure all the inline capacity. This is just a memset. FreeLists.resize(InlineFreeListsCapacity); } -AttributeFactory::~AttributeFactory() {} +AttributeFactory::~AttributeFactory() = default; static size_t getFreeListIndexForSize(size_t size) { - assert(size >= sizeof(AttributeList)); + assert(size >= sizeof(ParsedAttr)); assert((size % sizeof(void*)) == 0); - return ((size - sizeof(AttributeList)) / sizeof(void*)); + return ((size - sizeof(ParsedAttr)) / sizeof(void *)); } void *AttributeFactory::allocate(size_t size) { // Check for a previously reclaimed attribute. size_t index = getFreeListIndexForSize(size); - if (index < FreeLists.size()) { - if (AttributeList *attr = FreeLists[index]) { - FreeLists[index] = attr->NextInPool; - return attr; - } + if (index < FreeLists.size() && !FreeLists[index].empty()) { + ParsedAttr *attr = FreeLists[index].back(); + FreeLists[index].pop_back(); + return attr; } // Otherwise, allocate something new. return Alloc.Allocate(size, alignof(AttributeFactory)); } -void AttributeFactory::reclaimPool(AttributeList *cur) { - assert(cur && "reclaiming empty pool!"); - do { - // Read this here, because we're going to overwrite NextInPool - // when we toss 'cur' into the appropriate queue. - AttributeList *next = cur->NextInPool; +void AttributeFactory::deallocate(ParsedAttr *Attr) { + size_t size = Attr->allocated_size(); + size_t freeListIndex = getFreeListIndexForSize(size); - size_t size = cur->allocated_size(); - size_t freeListIndex = getFreeListIndexForSize(size); + // Expand FreeLists to the appropriate size, if required. + if (freeListIndex >= FreeLists.size()) + FreeLists.resize(freeListIndex + 1); - // Expand FreeLists to the appropriate size, if required. - if (freeListIndex >= FreeLists.size()) - FreeLists.resize(freeListIndex+1); +#if !NDEBUG + // In debug mode, zero out the attribute to help find memory overwriting. + memset(Attr, 0, size); +#endif - // Add 'cur' to the appropriate free-list. - cur->NextInPool = FreeLists[freeListIndex]; - FreeLists[freeListIndex] = cur; - - cur = next; - } while (cur); + // Add 'Attr' to the appropriate free-list. + FreeLists[freeListIndex].push_back(Attr); } -void AttributePool::takePool(AttributeList *pool) { - assert(pool); - - // Fast path: this pool is empty. - if (!Head) { - Head = pool; - return; - } +void AttributeFactory::reclaimPool(AttributePool &cur) { + for (ParsedAttr *AL : cur.Attrs) + deallocate(AL); +} - // Reverse the pool onto the current head. This optimizes for the - // pattern of pulling a lot of pools into a single pool. - do { - AttributeList *next = pool->NextInPool; - pool->NextInPool = Head; - Head = pool; - pool = next; - } while (pool); +void AttributePool::takePool(AttributePool &pool) { + Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); + pool.Attrs.clear(); } #include "clang/Sema/AttrParsedAttrKinds.inc" static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName, - AttributeList::Syntax SyntaxUsed) { + ParsedAttr::Syntax SyntaxUsed) { // Normalize the attribute name, __foo__ becomes foo. This is only allowable // for GNU attributes. - bool IsGNU = SyntaxUsed == AttributeList::AS_GNU || - ((SyntaxUsed == AttributeList::AS_CXX11 || - SyntaxUsed == AttributeList::AS_C2x) && ScopeName == "gnu"); + bool IsGNU = SyntaxUsed == ParsedAttr::AS_GNU || + ((SyntaxUsed == ParsedAttr::AS_CXX11 || + SyntaxUsed == ParsedAttr::AS_C2x) && + ScopeName == "gnu"); if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") && AttrName.endswith("__")) AttrName = AttrName.slice(2, AttrName.size() - 2); @@ -123,9 +114,9 @@ static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName, return AttrName; } -AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, - const IdentifierInfo *ScopeName, - Syntax SyntaxUsed) { +ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name, + const IdentifierInfo *ScopeName, + Syntax SyntaxUsed) { StringRef AttrName = Name->getName(); SmallString<64> FullName; @@ -143,12 +134,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name, return ::getAttrKind(FullName, SyntaxUsed); } -unsigned AttributeList::getAttributeSpellingListIndex() const { +unsigned ParsedAttr::getAttributeSpellingListIndex() const { // Both variables will be used in tablegen generated // attribute spell list index matching code. StringRef Scope = ScopeName ? ScopeName->getName() : ""; StringRef Name = normalizeAttrName(AttrName->getName(), Scope, - (AttributeList::Syntax)SyntaxUsed); + (ParsedAttr::Syntax)SyntaxUsed); #include "clang/Sema/AttrSpellingListIndex.inc" @@ -164,85 +155,78 @@ struct ParsedAttrInfo { unsigned IsKnownToGCC : 1; unsigned IsSupportedByPragmaAttribute : 1; - bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, - const Decl *); - bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); + bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *); + bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr); bool (*ExistsInTarget)(const TargetInfo &Target); - unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr); + unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr); void (*GetPragmaAttributeMatchRules)( llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules, const LangOptions &LangOpts); }; namespace { - #include "clang/Sema/AttrParsedAttrImpl.inc" -} -static const ParsedAttrInfo &getInfo(const AttributeList &A) { +#include "clang/Sema/AttrParsedAttrImpl.inc" + +} // namespace + +static const ParsedAttrInfo &getInfo(const ParsedAttr &A) { return AttrInfoMap[A.getKind()]; } -unsigned AttributeList::getMinArgs() const { - return getInfo(*this).NumArgs; -} +unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; } -unsigned AttributeList::getMaxArgs() const { +unsigned ParsedAttr::getMaxArgs() const { return getMinArgs() + getInfo(*this).OptArgs; } -bool AttributeList::hasCustomParsing() const { +bool ParsedAttr::hasCustomParsing() const { return getInfo(*this).HasCustomParsing; } -bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { +bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { return getInfo(*this).DiagAppertainsToDecl(S, *this, D); } -bool AttributeList::appliesToDecl(const Decl *D, - attr::SubjectMatchRule MatchRule) const { +bool ParsedAttr::appliesToDecl(const Decl *D, + attr::SubjectMatchRule MatchRule) const { return checkAttributeMatchRuleAppliesTo(D, MatchRule); } -void AttributeList::getMatchRules( +void ParsedAttr::getMatchRules( const LangOptions &LangOpts, SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) const { return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts); } -bool AttributeList::diagnoseLangOpts(Sema &S) const { +bool ParsedAttr::diagnoseLangOpts(Sema &S) const { return getInfo(*this).DiagLangOpts(S, *this); } -bool AttributeList::isTargetSpecificAttr() const { +bool ParsedAttr::isTargetSpecificAttr() const { return getInfo(*this).IsTargetSpecific; } -bool AttributeList::isTypeAttr() const { - return getInfo(*this).IsType; -} +bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; } -bool AttributeList::isStmtAttr() const { - return getInfo(*this).IsStmt; -} +bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; } -bool AttributeList::existsInTarget(const TargetInfo &Target) const { +bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { return getInfo(*this).ExistsInTarget(Target); } -bool AttributeList::isKnownToGCC() const { - return getInfo(*this).IsKnownToGCC; -} +bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; } -bool AttributeList::isSupportedByPragmaAttribute() const { +bool ParsedAttr::isSupportedByPragmaAttribute() const { return getInfo(*this).IsSupportedByPragmaAttribute; } -unsigned AttributeList::getSemanticSpelling() const { +unsigned ParsedAttr::getSemanticSpelling() const { return getInfo(*this).SpellingIndexToSemanticSpelling(*this); } -bool AttributeList::hasVariadicArg() const { +bool ParsedAttr::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 diff --git a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp index b309a36a30a3..62a83ccb70aa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp @@ -43,6 +43,7 @@ void FunctionScopeInfo::Clear() { // Coroutine state FirstCoroutineStmtLoc = SourceLocation(); CoroutinePromise = nullptr; + CoroutineParameterMoves.clear(); NeedsCoroutineSuspends = true; CoroutineSuspends.first = nullptr; CoroutineSuspends.second = nullptr; diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index 4e57e5ef81c6..d57473c5616f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" @@ -31,12 +32,12 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" -#include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" using namespace clang; @@ -51,8 +52,8 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); - // Our printing policy is copied over the ASTContext printing policy whenever - // a diagnostic is emitted, so recompute it. + // In diagnostics, we print _Bool as bool if the latter is defined as the + // former. Policy.Bool = Context.getLangOpts().Bool; if (!Policy.Bool) { if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) { @@ -130,16 +131,19 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), - CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), - NSValueDecl(nullptr), NSStringDecl(nullptr), - StringWithUTF8StringMethod(nullptr), + StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr), + MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr), + NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false), - TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false), - InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), - ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), - DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), + TUKind(TUKind), NumSFINAEErrors(0), + FullyCheckedComparisonCategories( + static_cast<unsigned>(ComparisonCategoryType::Last) + 1), + AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), + NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), + CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), + TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; @@ -159,9 +163,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExprEvalContexts.emplace_back( ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{}, - nullptr, false); + nullptr, ExpressionEvaluationContextRecord::EK_Other); - FunctionScopes.push_back(new FunctionScopeInfo(Diags)); + PreallocatedFunctionScope.reset(new FunctionScopeInfo(Diags)); // Initilization of data sharing attributes stack for OpenMP InitDataSharingAttributesStack(); @@ -331,11 +335,11 @@ void Sema::Initialize() { Sema::~Sema() { if (VisContext) FreeVisContext(); + // Kill all the active scopes. - for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) - delete FunctionScopes[I]; - if (FunctionScopes.size() == 1) - delete FunctionScopes[0]; + for (sema::FunctionScopeInfo *FSI : FunctionScopes) + if (FSI != PreallocatedFunctionScope.get()) + delete FSI; // Tell the SemaConsumer to forget about us; we're going out of scope. if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer)) @@ -391,7 +395,7 @@ ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } -///\brief Registers an external source. If an external source already exists, +///Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. @@ -412,7 +416,7 @@ void Sema::addExternalSource(ExternalSemaSource *E) { } } -/// \brief Print out statistics about the semantic analysis. +/// Print out statistics about the semantic analysis. void Sema::PrintStats() const { llvm::errs() << "\n*** Semantic Analysis Stats:\n"; llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n"; @@ -477,6 +481,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_ToVoid: + case CK_NonAtomicToAtomic: break; } } @@ -532,7 +537,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { llvm_unreachable("unknown scalar type kind"); } -/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. +/// Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; @@ -641,6 +646,8 @@ void Sema::getUndefinedButUsed( !isExternalWithNoLinkageType(FD) && !FD->getMostRecentDecl()->isInlined()) continue; + if (FD->getBuiltinID()) + continue; } else { auto *VD = cast<VarDecl>(ND); if (VD->hasDefinition() != VarDecl::DeclarationOnly) @@ -649,6 +656,11 @@ void Sema::getUndefinedButUsed( !isExternalWithNoLinkageType(VD) && !VD->getMostRecentDecl()->isInline()) continue; + + // Skip VarDecls that lack formal definitions but which we know are in + // fact defined somewhere. + if (VD->isKnownToBeDefined()) + continue; } Undefined.push_back(std::make_pair(ND, UndefinedUse.second)); @@ -720,7 +732,7 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() { typedef llvm::DenseMap<const CXXRecordDecl*, bool> RecordCompleteMap; -/// \brief Returns true, if all methods and nested classes of the given +/// Returns true, if all methods and nested classes of the given /// CXXRecordDecl are defined in this translation unit. /// /// Should only be called from ActOnEndOfTranslationUnit so that all @@ -760,7 +772,7 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, return Complete; } -/// \brief Returns true, if the given CXXRecordDecl is fully defined in this +/// Returns true, if the given CXXRecordDecl is fully defined in this /// translation unit, i.e. all methods are defined or pure virtual and all /// friends, friend functions and nested classes are fully defined in this /// translation unit. @@ -849,6 +861,20 @@ void Sema::ActOnEndOfTranslationUnit() { if (PP.isCodeCompletionEnabled()) return; + // Transfer late parsed template instantiations over to the pending template + // instantiation list. During normal compliation, the late template parser + // will be installed and instantiating these templates will succeed. + // + // If we are building a TU prefix for serialization, it is also safe to + // transfer these over, even though they are not parsed. The end of the TU + // should be outside of any eager template instantiation scope, so when this + // AST is deserialized, these templates will not be parsed until the end of + // the combined TU. + PendingInstantiations.insert(PendingInstantiations.end(), + LateParsedInstantiations.begin(), + LateParsedInstantiations.end()); + LateParsedInstantiations.clear(); + // Complete translation units and modules define vtables and perform implicit // instantiations. PCH files do not. if (TUKind != TU_Prefix) { @@ -878,8 +904,13 @@ void Sema::ActOnEndOfTranslationUnit() { PendingInstantiations.insert(PendingInstantiations.begin(), Pending.begin(), Pending.end()); } + PerformPendingInstantiations(); + assert(LateParsedInstantiations.empty() && + "end of TU template instantiation should not create more " + "late-parsed templates"); + if (LateTemplateParserCleanup) LateTemplateParserCleanup(OpaqueParser); @@ -980,11 +1011,6 @@ 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. - if (!PP.isIncrementalProcessingEnabled()) - TUScope = nullptr; - return; } // C99 6.9.2p2: @@ -1002,8 +1028,7 @@ void Sema::ActOnEndOfTranslationUnit() { for (TentativeDefinitionsType::iterator T = TentativeDefinitions.begin(ExternalSource), TEnd = TentativeDefinitions.end(); - T != TEnd; ++T) - { + T != TEnd; ++T) { VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns @@ -1030,12 +1055,13 @@ void Sema::ActOnEndOfTranslationUnit() { // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); - } // If there were errors, disable 'unused' warnings since they will mostly be - // noise. - if (!Diags.hasErrorOccurred()) { + // noise. Don't warn for a use from a module: either we should warn on all + // file-scope declarations in modules or not at all, but whether the + // declaration is used is immaterial. + if (!Diags.hasErrorOccurred() && TUKind != TU_Module) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource), @@ -1103,6 +1129,8 @@ void Sema::ActOnEndOfTranslationUnit() { } if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) { + // FIXME: Load additional unused private field candidates from the external + // source. RecordCompleteMap RecordsComplete; RecordCompleteMap MNCComplete; for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(), @@ -1264,7 +1292,8 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { } } - // Set up the context's printing policy based on our current state. + // Copy the diagnostic printing policy over the ASTContext printing policy. + // TODO: Stop doing that. See: https://reviews.llvm.org/D45093#1090292 Context.setPrintingPolicy(getPrintingPolicy()); // Emit the diagnostic. @@ -1287,7 +1316,7 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } -/// \brief Looks through the macro-expansion chain for the given +/// Looks through the macro-expansion chain for the given /// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that /// expansion loc. @@ -1308,7 +1337,7 @@ bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) { return false; } -/// \brief Determines the active Scope associated with the given declaration +/// Determines the active Scope associated with the given declaration /// context. /// /// This routine maps a declaration context to the active Scope object that @@ -1337,19 +1366,15 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) { return nullptr; } -/// \brief Enter a new function scope +/// Enter a new function scope void Sema::PushFunctionScope() { - if (FunctionScopes.size() == 1) { - // Use the "top" function scope rather than having to allocate - // memory for a new scope. - FunctionScopes.back()->Clear(); - FunctionScopes.push_back(FunctionScopes.back()); - if (LangOpts.OpenMP) - pushOpenMPFunctionRegion(); - return; + if (FunctionScopes.empty()) { + // Use PreallocatedFunctionScope to avoid allocating memory when possible. + PreallocatedFunctionScope->Clear(); + FunctionScopes.push_back(PreallocatedFunctionScope.get()); + } else { + FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics())); } - - FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics())); if (LangOpts.OpenMP) pushOpenMPFunctionRegion(); } @@ -1369,15 +1394,15 @@ void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) { if (LambdaScopeInfo *const LSI = getCurLambda()) { LSI->AutoTemplateParameterDepth = Depth; return; - } - llvm_unreachable( + } + llvm_unreachable( "Remove assertion if intentionally called in a non-lambda context."); } void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, const Decl *D, const BlockExpr *blkExpr) { - FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); assert(!FunctionScopes.empty() && "mismatched push/pop!"); + FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); if (LangOpts.OpenMP) popOpenMPFunctionRegion(Scope); @@ -1389,12 +1414,13 @@ void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, for (const auto &PUD : Scope->PossiblyUnreachableDiags) Diag(PUD.Loc, PUD.PD); - if (FunctionScopes.back() != Scope) + // Delete the scope unless its our preallocated scope. + if (Scope != PreallocatedFunctionScope.get()) delete Scope; } -void Sema::PushCompoundScope() { - getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo()); +void Sema::PushCompoundScope(bool IsStmtExpr) { + getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo(IsStmtExpr)); } void Sema::PopCompoundScope() { @@ -1404,12 +1430,27 @@ void Sema::PopCompoundScope() { CurFunction->CompoundScopes.pop_back(); } -/// \brief Determine whether any errors occurred within this function/method/ +/// Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const { return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred(); } +void Sema::setFunctionHasBranchIntoScope() { + if (!FunctionScopes.empty()) + FunctionScopes.back()->setHasBranchIntoScope(); +} + +void Sema::setFunctionHasBranchProtectedScope() { + if (!FunctionScopes.empty()) + FunctionScopes.back()->setHasBranchProtectedScope(); +} + +void Sema::setFunctionHasIndirectGoto() { + if (!FunctionScopes.empty()) + FunctionScopes.back()->setHasIndirectGoto(); +} + BlockScopeInfo *Sema::getCurBlock() { if (FunctionScopes.empty()) return nullptr; @@ -1425,6 +1466,18 @@ BlockScopeInfo *Sema::getCurBlock() { return CurBSI; } +FunctionScopeInfo *Sema::getEnclosingFunction() const { + if (FunctionScopes.empty()) + return nullptr; + + for (int e = FunctionScopes.size() - 1; e >= 0; --e) { + if (isa<sema::BlockScopeInfo>(FunctionScopes[e])) + continue; + return FunctionScopes[e]; + } + return nullptr; +} + LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { if (FunctionScopes.empty()) return nullptr; @@ -1462,8 +1515,7 @@ void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; - RawComment RC(SourceMgr, Comment, false, - LangOpts.CommentOpts.ParseAllComments); + RawComment RC(SourceMgr, Comment, LangOpts.CommentOpts, false); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); @@ -1501,25 +1553,7 @@ void ExternalSemaSource::ReadUndefinedButUsed( void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &) {} -void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { - SourceLocation Loc = this->Loc; - if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); - if (Loc.isValid()) { - Loc.print(OS, S.getSourceManager()); - OS << ": "; - } - OS << Message; - - if (auto *ND = dyn_cast_or_null<NamedDecl>(TheDecl)) { - OS << " '"; - ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), true); - OS << "'"; - } - - OS << '\n'; -} - -/// \brief Figure out if an expression could be turned into a call. +/// Figure out if an expression could be turned into a call. /// /// Use this when trying to recover from an error where the programmer may have /// written just the name of a function instead of actually calling it. @@ -1551,6 +1585,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, } bool Ambiguous = false; + bool IsMV = false; if (Overloads) { for (OverloadExpr::decls_iterator it = Overloads->decls_begin(), @@ -1564,11 +1599,16 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl())) { if (OverloadDecl->getMinRequiredArguments() == 0) { - if (!ZeroArgCallReturnTy.isNull() && !Ambiguous) { + if (!ZeroArgCallReturnTy.isNull() && !Ambiguous && + (!IsMV || !(OverloadDecl->isCPUDispatchMultiVersion() || + OverloadDecl->isCPUSpecificMultiVersion()))) { ZeroArgCallReturnTy = QualType(); Ambiguous = true; - } else + } else { ZeroArgCallReturnTy = OverloadDecl->getReturnType(); + IsMV = OverloadDecl->isCPUDispatchMultiVersion() || + OverloadDecl->isCPUSpecificMultiVersion(); + } } } } @@ -1621,7 +1661,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, return false; } -/// \brief Give notes for a set of overloads. +/// Give notes for a set of overloads. /// /// A companion to tryExprAsCall. In cases when the name that the programmer /// wrote was an overloaded function, we may be able to make some guesses about @@ -1647,6 +1687,12 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, } NamedDecl *Fn = (*It)->getUnderlyingDecl(); + // Don't print overloads for non-default multiversioned functions. + if (const auto *FD = Fn->getAsFunction()) { + if (FD->isMultiVersion() && FD->hasAttr<TargetAttr>() && + !FD->getAttr<TargetAttr>()->isDefaultVersion()) + continue; + } S.Diag(Fn->getLocation(), diag::note_possible_target_of_call); ++ShownOverloads; } @@ -1685,6 +1731,21 @@ static bool IsCallableWithAppend(Expr *E) { !isa<CXXOperatorCallExpr>(E)); } +static bool IsCPUDispatchCPUSpecificMultiVersion(const Expr *E) { + if (const auto *UO = dyn_cast<UnaryOperator>(E)) + E = UO->getSubExpr(); + + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + if (ULE->getNumDecls() == 0) + return false; + + const NamedDecl *ND = *ULE->decls_begin(); + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion(); + } + return false; +} + bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { @@ -1701,12 +1762,13 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // so we can emit a fixit and carry on pretending that E was // actually a CallExpr. SourceLocation ParenInsertionLoc = getLocForEndOfToken(Range.getEnd()); - Diag(Loc, PD) - << /*zero-arg*/ 1 << Range - << (IsCallableWithAppend(E.get()) - ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") - : FixItHint()); - notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + bool IsMV = IsCPUDispatchCPUSpecificMultiVersion(E.get()); + Diag(Loc, PD) << /*zero-arg*/ 1 << IsMV << Range + << (IsCallableWithAppend(E.get()) + ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") + : FixItHint()); + if (!IsMV) + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. @@ -1717,8 +1779,10 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, if (!ForceComplain) return false; - Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; - notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); + bool IsMV = IsCPUDispatchCPUSpecificMultiVersion(E.get()); + Diag(Loc, PD) << /*not zero-arg*/ 0 << IsMV << Range; + if (!IsMV) + notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); E = ExprError(); return true; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index 98a918bd7d63..9fbae2ca297f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Specifiers.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -1712,7 +1713,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } -/// \brief Checks access to a member. +/// Checks access to a member. Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, CXXRecordDecl *NamingClass, DeclAccessPair Found) { @@ -1856,29 +1857,31 @@ void Sema::CheckLookupAccess(const LookupResult &R) { } } -/// Checks access to Decl from the given class. The check will take access +/// Checks access to Target from the given class. The check will take access /// specifiers into account, but no member access expressions and such. /// -/// \param Decl the declaration to check if it can be accessed +/// \param Target the declaration to check if it can be accessed /// \param Ctx the class/context from which to start the search -/// \return true if the Decl is accessible from the Class, false otherwise. -bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { +/// \return true if the Target is accessible from the Class, false otherwise. +bool Sema::IsSimplyAccessible(NamedDecl *Target, DeclContext *Ctx) { if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { - if (!Decl->isCXXClassMember()) + if (!Target->isCXXClassMember()) return true; + if (Target->getAccess() == AS_public) + return true; QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal(); + // The unprivileged access is AS_none as we don't know how the member was + // accessed, which is described by the access in DeclAccessPair. + // `IsAccessible` will examine the actual access of Target (i.e. + // Decl->getAccess()) when calculating the access. AccessTarget Entity(Context, AccessedEntity::Member, Class, - DeclAccessPair::make(Decl, Decl->getAccess()), - qType); - if (Entity.getAccess() == AS_public) - return true; - + DeclAccessPair::make(Target, AS_none), qType); EffectiveContext EC(CurContext); return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; } - - if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) { + + if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) { // @public and @package ivars are always accessible. if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 4ba2a317e1f9..4f3cf4633c80 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -205,7 +205,7 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, // "#pragma pack(pop, identifier, n) is undefined" if (Action & Sema::PSK_Pop) { if (Alignment && !SlotLabel.empty()) - Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); + Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifier_and_alignment); if (PackStack.Stack.empty()) Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty"; } @@ -330,7 +330,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, Stack.erase(std::prev(I.base()), Stack.end()); } } else if (!Stack.empty()) { - // We don't have a label, just pop the last entry. + // We do not have a label, just pop the last entry. CurrentValue = Stack.back().Value; CurrentPragmaLocation = Stack.back().PragmaLocation; Stack.pop_back(); @@ -389,7 +389,7 @@ bool Sema::UnifySection(StringRef SectionName, return false; } -/// \brief Called on well formed \#pragma bss_seg(). +/// Called on well formed \#pragma bss_seg(). void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, @@ -410,7 +410,7 @@ void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation, Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName); } -/// \brief Called on well formed \#pragma bss_seg(). +/// Called on well formed \#pragma bss_seg(). void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName) { UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation); @@ -520,7 +520,7 @@ attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) { } // end anonymous namespace -void Sema::ActOnPragmaAttributePush(AttributeList &Attribute, +void Sema::ActOnPragmaAttributePush(ParsedAttr &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules) { SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules; @@ -645,7 +645,7 @@ void Sema::AddPragmaAttributes(Scope *S, Decl *D) { if (PragmaAttributeStack.empty()) return; for (auto &Entry : PragmaAttributeStack) { - const AttributeList *Attribute = Entry.Attribute; + ParsedAttr *Attribute = Entry.Attribute; assert(Attribute && "Expected an attribute"); // Ensure that the attribute can be applied to the given declaration. @@ -659,9 +659,10 @@ void Sema::AddPragmaAttributes(Scope *S, Decl *D) { if (!Applies) continue; Entry.IsUsed = true; - assert(!Attribute->getNext() && "Expected just one attribute"); PragmaAttributeCurrentTargetDecl = D; - ProcessDeclAttributeList(S, D, Attribute); + ParsedAttributesView Attrs; + Attrs.addAtStart(Attribute); + ProcessDeclAttributeList(S, D, Attrs); PragmaAttributeCurrentTargetDecl = nullptr; } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp index cac5f682275e..13dd8d936fd2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements semantic analysis for CUDA constructs. +/// This file implements semantic analysis for CUDA constructs. /// //===----------------------------------------------------------------------===// @@ -42,8 +42,9 @@ ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, SourceLocation GGGLoc) { FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); if (!ConfigDecl) - return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) - << "cudaConfigureCall"); + return ExprError( + Diag(LLLLoc, diag::err_undeclared_var_use) + << (getLangOpts().HIP ? "hipConfigureCall" : "cudaConfigureCall")); QualType ConfigQTy = ConfigDecl->getType(); DeclRefExpr *ConfigDR = new (Context) @@ -54,30 +55,31 @@ ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, /*IsExecConfig=*/true); } -Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const AttributeList *Attr) { +Sema::CUDAFunctionTarget +Sema::IdentifyCUDATarget(const ParsedAttributesView &Attrs) { bool HasHostAttr = false; bool HasDeviceAttr = false; bool HasGlobalAttr = false; bool HasInvalidTargetAttr = false; - while (Attr) { - switch(Attr->getKind()){ - case AttributeList::AT_CUDAGlobal: + for (const ParsedAttr &AL : Attrs) { + switch (AL.getKind()) { + case ParsedAttr::AT_CUDAGlobal: HasGlobalAttr = true; break; - case AttributeList::AT_CUDAHost: + case ParsedAttr::AT_CUDAHost: HasHostAttr = true; break; - case AttributeList::AT_CUDADevice: + case ParsedAttr::AT_CUDADevice: HasDeviceAttr = true; break; - case AttributeList::AT_CUDAInvalidTarget: + case ParsedAttr::AT_CUDAInvalidTarget: HasInvalidTargetAttr = true; break; default: break; } - Attr = Attr->getNext(); } + if (HasInvalidTargetAttr) return CFT_InvalidTarget; @@ -471,6 +473,59 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { return true; } +void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { + if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage()) + return; + const Expr *Init = VD->getInit(); + if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || + VD->hasAttr<CUDASharedAttr>()) { + assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()); + bool AllowedInit = false; + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) + AllowedInit = + isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); + // We'll allow constant initializers even if it's a non-empty + // constructor according to CUDA rules. This deviates from NVCC, + // but allows us to handle things like constexpr constructors. + if (!AllowedInit && + (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) + AllowedInit = VD->getInit()->isConstantInitializer( + Context, VD->getType()->isReferenceType()); + + // Also make sure that destructor, if there is one, is empty. + if (AllowedInit) + if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl()) + AllowedInit = + isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); + + if (!AllowedInit) { + Diag(VD->getLocation(), VD->hasAttr<CUDASharedAttr>() + ? diag::err_shared_var_init + : diag::err_dynamic_var_init) + << Init->getSourceRange(); + VD->setInvalidDecl(); + } + } else { + // This is a host-side global variable. Check that the initializer is + // callable from the host side. + const FunctionDecl *InitFn = nullptr; + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) { + InitFn = CE->getConstructor(); + } else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) { + InitFn = CE->getDirectCallee(); + } + if (InitFn) { + CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn); + if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) { + Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) + << InitFnTarget << InitFn; + Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; + VD->setInvalidDecl(); + } + } + } +} + // With -fcuda-host-device-constexpr, an unattributed constexpr function is // treated as implicitly __host__ __device__, unless: // * it is a variadic function (device-side variadic functions are not @@ -521,7 +576,7 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, if (!getSourceManager().isInSystemHeader(Match->getLocation())) { Diag(NewD->getLocation(), diag::err_cuda_unattributed_constexpr_cannot_overload_device) - << NewD->getName(); + << NewD; Diag(Match->getLocation(), diag::note_cuda_conflicting_device_function_declared_here); } @@ -790,9 +845,12 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // If the caller is known-emitted, mark the callee as known-emitted. // Otherwise, mark the call in our call graph so we can traverse it later. bool CallerKnownEmitted = IsKnownEmitted(*this, Caller); - if (CallerKnownEmitted) - MarkKnownEmitted(*this, Caller, Callee, Loc); - else { + if (CallerKnownEmitted) { + // Host-side references to a __global__ function refer to the stub, so the + // function itself is never emitted and therefore should not be marked. + if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) + MarkKnownEmitted(*this, Caller, Callee, Loc); + } else { // If we have // host fn calls kernel fn calls host+device, // the HD function does not get instantiated on the host. We model this by diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index 6da4d2a26191..f2fad825c3e7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -24,7 +24,7 @@ #include "llvm/ADT/STLExtras.h" using namespace clang; -/// \brief Find the current instantiation that associated with the given type. +/// Find the current instantiation that associated with the given type. static CXXRecordDecl *getCurrentInstantiationOf(QualType T, DeclContext *CurContext) { if (T.isNull()) @@ -44,7 +44,7 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T, return nullptr; } -/// \brief Compute the DeclContext that is associated with the given type. +/// Compute the DeclContext that is associated with the given type. /// /// \param T the type for which we are attempting to find a DeclContext. /// @@ -59,7 +59,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { return ::getCurrentInstantiationOf(T, CurContext); } -/// \brief Compute the DeclContext that is associated with the given +/// Compute the DeclContext that is associated with the given /// scope specifier. /// /// \param SS the C++ scope specifier as it appears in the source @@ -172,7 +172,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { return SS.getScopeRep()->isDependent(); } -/// \brief If the given nested name specifier refers to the current +/// If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). /// @@ -188,7 +188,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return ::getCurrentInstantiationOf(T, CurContext); } -/// \brief Require that the context specified by SS be complete. +/// Require that the context specified by SS be complete. /// /// If SS refers to a type, this routine checks whether the type is /// complete enough (or can be made complete enough) for name lookup @@ -305,7 +305,7 @@ bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, return false; } -/// \brief Determines whether the given declaration is an valid acceptable +/// Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. /// \param SD Declaration checked for nested-name-specifier. /// \param IsExtension If not null and the declaration is accepted as an @@ -350,7 +350,7 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD, return false; } -/// \brief If the given nested-name-specifier begins with a bare identifier +/// If the given nested-name-specifier begins with a bare identifier /// (e.g., Base::), perform name lookup for that identifier as a /// nested-name-specifier within the given scope, and return the result of that /// name lookup. @@ -443,7 +443,7 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { } -/// \brief Build a new nested-name-specifier for "identifier::", as described +/// Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// /// \param S Scope in which the nested-name-specifier occurs. @@ -846,6 +846,9 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + if (T.isNull()) + return true; + if (!T->isDependentType() && !T->getAs<TagType>()) { Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace) << T << getLangOpts().CPlusPlus; @@ -967,7 +970,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, } namespace { - /// \brief A structure that stores a nested-name-specifier annotation, + /// A structure that stores a nested-name-specifier annotation, /// including both the nested-name-specifier struct NestedNameSpecifierAnnotation { NestedNameSpecifier *NNS; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index ad6348685b64..b7f4629fbab7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp @@ -33,10 +33,16 @@ using namespace clang; enum TryCastResult { TC_NotApplicable, ///< The cast method is not applicable. TC_Success, ///< The cast method is appropriate and successful. + TC_Extension, ///< The cast method is appropriate and accepted as a + ///< language extension. TC_Failed ///< The cast method is appropriate, but failed. A ///< diagnostic has been emitted. }; +static bool isValidCast(TryCastResult TCR) { + return TCR == TC_Success || TCR == TC_Extension; +} + enum CastType { CT_Const, ///< const_cast CT_Static, ///< static_cast @@ -83,6 +89,14 @@ namespace { void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); + void updatePartOfExplicitCastFlags(CastExpr *CE) { + // Walk down from the CE to the OrigSrcExpr, and mark all immediate + // ImplicitCastExpr's as being part of ExplicitCastExpr. The original CE + // (which is a ExplicitCastExpr), and the OrigSrcExpr are not touched. + for (; auto *ICE = dyn_cast<ImplicitCastExpr>(CE->getSubExpr()); CE = ICE) + ICE->setIsPartOfExplicitCast(true); + } + /// Complete an apparently-successful cast operation that yields /// the given expression. ExprResult complete(CastExpr *castExpr) { @@ -94,6 +108,7 @@ namespace { CK_Dependent, castExpr, nullptr, castExpr->getValueKind()); } + updatePartOfExplicitCastFlags(castExpr); return castExpr; } @@ -267,6 +282,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, AngleBrackets)); case tok::kw_dynamic_cast: { + // OpenCL C++ 1.0 s2.9: dynamic_cast is not supported. + if (getLangOpts().OpenCLCPlusPlus) { + return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) + << "dynamic_cast"); + } + if (!TypeDependent) { Op.CheckDynamicCast(); if (Op.SrcExpr.isInvalid()) @@ -425,95 +446,114 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, } } -/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes, -/// this removes one level of indirection from both types, provided that they're -/// the same kind of pointer (plain or to-member). Unlike the Sema function, -/// this one doesn't care if the two pointers-to-member don't point into the -/// same class. This is because CastsAwayConstness doesn't care. -/// And additionally, it handles C++ references. If both the types are -/// references, then their pointee types are returned, -/// else if only one of them is reference, it's pointee type is returned, -/// and the other type is returned as-is. -static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { - const PointerType *T1PtrType = T1->getAs<PointerType>(), - *T2PtrType = T2->getAs<PointerType>(); - if (T1PtrType && T2PtrType) { - T1 = T1PtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - const ObjCObjectPointerType *T1ObjCPtrType = - T1->getAs<ObjCObjectPointerType>(), - *T2ObjCPtrType = - T2->getAs<ObjCObjectPointerType>(); - if (T1ObjCPtrType) { - if (T2ObjCPtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2ObjCPtrType->getPointeeType(); - return true; - } - else if (T2PtrType) { - T1 = T1ObjCPtrType->getPointeeType(); - T2 = T2PtrType->getPointeeType(); - return true; - } - } - else if (T2ObjCPtrType) { - if (T1PtrType) { - T2 = T2ObjCPtrType->getPointeeType(); - T1 = T1PtrType->getPointeeType(); - return true; - } - } - - const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), - *T2MPType = T2->getAs<MemberPointerType>(); - if (T1MPType && T2MPType) { - T1 = T1MPType->getPointeeType(); - T2 = T2MPType->getPointeeType(); - return true; - } - - const BlockPointerType *T1BPType = T1->getAs<BlockPointerType>(), - *T2BPType = T2->getAs<BlockPointerType>(); - if (T1BPType && T2BPType) { - T1 = T1BPType->getPointeeType(); - T2 = T2BPType->getPointeeType(); - return true; - } - - const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(), - *T2RefType = T2->getAs<LValueReferenceType>(); - if (T1RefType && T2RefType) { - T1 = T1RefType->getPointeeType(); - T2 = T2RefType->getPointeeType(); - return true; - } +namespace { +/// The kind of unwrapping we did when determining whether a conversion casts +/// away constness. +enum CastAwayConstnessKind { + /// The conversion does not cast away constness. + CACK_None = 0, + /// We unwrapped similar types. + CACK_Similar = 1, + /// We unwrapped dissimilar types with similar representations (eg, a pointer + /// versus an Objective-C object pointer). + CACK_SimilarKind = 2, + /// We unwrapped representationally-unrelated types, such as a pointer versus + /// a pointer-to-member. + CACK_Incoherent = 3, +}; +} - if (T1RefType) { - T1 = T1RefType->getPointeeType(); - // T2 = T2; - return true; +/// Unwrap one level of types for CastsAwayConstness. +/// +/// Like Sema::UnwrapSimilarTypes, this removes one level of indirection from +/// both types, provided that they're both pointer-like or array-like. Unlike +/// the Sema function, doesn't care if the unwrapped pieces are related. +/// +/// This function may remove additional levels as necessary for correctness: +/// the resulting T1 is unwrapped sufficiently that it is never an array type, +/// so that its qualifiers can be directly compared to those of T2 (which will +/// have the combined set of qualifiers from all indermediate levels of T2), +/// as (effectively) required by [expr.const.cast]p7 replacing T1's qualifiers +/// with those from T2. +static CastAwayConstnessKind +unwrapCastAwayConstnessLevel(ASTContext &Context, QualType &T1, QualType &T2) { + enum { None, Ptr, MemPtr, BlockPtr, Array }; + auto Classify = [](QualType T) { + if (T->isAnyPointerType()) return Ptr; + if (T->isMemberPointerType()) return MemPtr; + if (T->isBlockPointerType()) return BlockPtr; + // We somewhat-arbitrarily don't look through VLA types here. This is at + // least consistent with the behavior of UnwrapSimilarTypes. + if (T->isConstantArrayType() || T->isIncompleteArrayType()) return Array; + return None; + }; + + auto Unwrap = [&](QualType T) { + if (auto *AT = Context.getAsArrayType(T)) + return AT->getElementType(); + return T->getPointeeType(); + }; + + CastAwayConstnessKind Kind; + + if (T2->isReferenceType()) { + // Special case: if the destination type is a reference type, unwrap it as + // the first level. (The source will have been an lvalue expression in this + // case, so there is no corresponding "reference to" in T1 to remove.) This + // simulates removing a "pointer to" from both sides. + T2 = T2->getPointeeType(); + Kind = CastAwayConstnessKind::CACK_Similar; + } else if (Context.UnwrapSimilarTypes(T1, T2)) { + Kind = CastAwayConstnessKind::CACK_Similar; + } else { + // Try unwrapping mismatching levels. + int T1Class = Classify(T1); + if (T1Class == None) + return CastAwayConstnessKind::CACK_None; + + int T2Class = Classify(T2); + if (T2Class == None) + return CastAwayConstnessKind::CACK_None; + + T1 = Unwrap(T1); + T2 = Unwrap(T2); + Kind = T1Class == T2Class ? CastAwayConstnessKind::CACK_SimilarKind + : CastAwayConstnessKind::CACK_Incoherent; } - if (T2RefType) { - // T1 = T1; - T2 = T2RefType->getPointeeType(); - return true; + // We've unwrapped at least one level. If the resulting T1 is a (possibly + // multidimensional) array type, any qualifier on any matching layer of + // T2 is considered to correspond to T1. Decompose down to the element + // type of T1 so that we can compare properly. + while (true) { + Context.UnwrapSimilarArrayTypes(T1, T2); + + if (Classify(T1) != Array) + break; + + auto T2Class = Classify(T2); + if (T2Class == None) + break; + + if (T2Class != Array) + Kind = CastAwayConstnessKind::CACK_Incoherent; + else if (Kind != CastAwayConstnessKind::CACK_Incoherent) + Kind = CastAwayConstnessKind::CACK_SimilarKind; + + T1 = Unwrap(T1); + T2 = Unwrap(T2).withCVRQualifiers(T2.getCVRQualifiers()); } - return false; + return Kind; } -/// CastsAwayConstness - Check if the pointer conversion from SrcType to -/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by -/// the cast checkers. Both arguments must denote pointer (possibly to member) -/// types. +/// Check if the pointer conversion from SrcType to DestType casts away +/// constness as defined in C++ [expr.const.cast]. This is used by the cast +/// checkers. Both arguments must denote pointer (possibly to member) types. /// /// \param CheckCVR Whether to check for const/volatile/restrict qualifiers. -/// /// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers. -static bool +static CastAwayConstnessKind CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, bool CheckCVR, bool CheckObjCLifetime, QualType *TheOffendingSrcType = nullptr, @@ -521,33 +561,35 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, Qualifiers *CastAwayQualifiers = nullptr) { // If the only checking we care about is for Objective-C lifetime qualifiers, // and we're not in ObjC mode, there's nothing to check. - if (!CheckCVR && CheckObjCLifetime && - !Self.Context.getLangOpts().ObjC1) - return false; - - // Casting away constness is defined in C++ 5.2.11p8 with reference to - // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since - // the rules are non-trivial. So first we construct Tcv *...cv* as described - // in C++ 5.2.11p8. - assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || - SrcType->isBlockPointerType() || - DestType->isLValueReferenceType()) && - "Source type is not pointer or pointer to member."); - assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || - DestType->isBlockPointerType() || - DestType->isLValueReferenceType()) && - "Destination type is not pointer or pointer to member, or reference."); + if (!CheckCVR && CheckObjCLifetime && !Self.Context.getLangOpts().ObjC1) + return CastAwayConstnessKind::CACK_None; + + if (!DestType->isReferenceType()) { + assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || + SrcType->isBlockPointerType()) && + "Source type is not pointer or pointer to member."); + assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || + DestType->isBlockPointerType()) && + "Destination type is not pointer or pointer to member."); + } QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); - SmallVector<Qualifiers, 8> cv1, cv2; // Find the qualifiers. We only care about cvr-qualifiers for the // purpose of this check, because other qualifiers (address spaces, // Objective-C GC, etc.) are part of the type's identity. QualType PrevUnwrappedSrcType = UnwrappedSrcType; QualType PrevUnwrappedDestType = UnwrappedDestType; - while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { + auto WorstKind = CastAwayConstnessKind::CACK_Similar; + bool AllConstSoFar = true; + while (auto Kind = unwrapCastAwayConstnessLevel( + Self.Context, UnwrappedSrcType, UnwrappedDestType)) { + // Track the worst kind of unwrap we needed to do before we found a + // problem. + if (Kind > WorstKind) + WorstKind = Kind; + // Determine the relevant qualifiers at this level. Qualifiers SrcQuals, DestQuals; Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals); @@ -560,51 +602,71 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, UnwrappedDestType->isObjCObjectType()) SrcQuals.removeConst(); - Qualifiers RetainedSrcQuals, RetainedDestQuals; if (CheckCVR) { - RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers()); - RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers()); + Qualifiers SrcCvrQuals = + Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()); + Qualifiers DestCvrQuals = + Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()); + + if (SrcCvrQuals != DestCvrQuals) { + if (CastAwayQualifiers) + *CastAwayQualifiers = SrcCvrQuals - DestCvrQuals; + + // If we removed a cvr-qualifier, this is casting away 'constness'. + if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) { + if (TheOffendingSrcType) + *TheOffendingSrcType = PrevUnwrappedSrcType; + if (TheOffendingDestType) + *TheOffendingDestType = PrevUnwrappedDestType; + return WorstKind; + } - if (RetainedSrcQuals != RetainedDestQuals && TheOffendingSrcType && - TheOffendingDestType && CastAwayQualifiers) { - *TheOffendingSrcType = PrevUnwrappedSrcType; - *TheOffendingDestType = PrevUnwrappedDestType; - *CastAwayQualifiers = RetainedSrcQuals - RetainedDestQuals; + // If any prior level was not 'const', this is also casting away + // 'constness'. We noted the outermost type missing a 'const' already. + if (!AllConstSoFar) + return WorstKind; } } - + if (CheckObjCLifetime && !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals)) - return true; - - cv1.push_back(RetainedSrcQuals); - cv2.push_back(RetainedDestQuals); + return WorstKind; + + // If we found our first non-const-qualified type, this may be the place + // where things start to go wrong. + if (AllConstSoFar && !DestQuals.hasConst()) { + AllConstSoFar = false; + if (TheOffendingSrcType) + *TheOffendingSrcType = PrevUnwrappedSrcType; + if (TheOffendingDestType) + *TheOffendingDestType = PrevUnwrappedDestType; + } PrevUnwrappedSrcType = UnwrappedSrcType; PrevUnwrappedDestType = UnwrappedDestType; } - if (cv1.empty()) - return false; - // Construct void pointers with those qualifiers (in reverse order of - // unwrapping, of course). - QualType SrcConstruct = Self.Context.VoidTy; - QualType DestConstruct = Self.Context.VoidTy; - ASTContext &Context = Self.Context; - for (SmallVectorImpl<Qualifiers>::reverse_iterator i1 = cv1.rbegin(), - i2 = cv2.rbegin(); - i1 != cv1.rend(); ++i1, ++i2) { - SrcConstruct - = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); - DestConstruct - = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2)); - } - - // Test if they're compatible. - bool ObjCLifetimeConversion; - return SrcConstruct != DestConstruct && - !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false, - ObjCLifetimeConversion); + return CastAwayConstnessKind::CACK_None; +} + +static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK, + unsigned &DiagID) { + switch (CACK) { + case CastAwayConstnessKind::CACK_None: + llvm_unreachable("did not cast away constness"); + + case CastAwayConstnessKind::CACK_Similar: + // FIXME: Accept these as an extension too? + case CastAwayConstnessKind::CACK_SimilarKind: + DiagID = diag::err_bad_cxx_cast_qualifiers_away; + return TC_Failed; + + case CastAwayConstnessKind::CACK_Incoherent: + DiagID = diag::ext_bad_cxx_cast_qualifiers_away_incoherent; + return TC_Extension; + } + + llvm_unreachable("unexpected cast away constness kind"); } /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. @@ -772,12 +834,13 @@ void CastOperation::CheckConstCast() { return; unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success - && msg != 0) { + auto TCR = TryConstCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg); + if (TCR != TC_Success && msg != 0) { Self.Diag(OpRange.getBegin(), msg) << CT_Const << SrcExpr.get()->getType() << DestType << OpRange; - SrcExpr = ExprError(); } + if (!isValidCast(TCR)) + SrcExpr = ExprError(); } /// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast @@ -890,8 +953,7 @@ void CastOperation::CheckReinterpretCast() { TryCastResult tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, Kind); - if (tcr != TC_Success && msg != 0) - { + if (tcr != TC_Success && msg != 0) { if (SrcExpr.isInvalid()) // if conversion failed, don't report another error return; if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { @@ -905,11 +967,14 @@ void CastOperation::CheckReinterpretCast() { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } - SrcExpr = ExprError(); - } else if (tcr == TC_Success) { + } + + if (isValidCast(tcr)) { if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) checkObjCConversion(Sema::CCK_OtherCast); DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); + } else { + SrcExpr = ExprError(); } } @@ -967,14 +1032,15 @@ void CastOperation::CheckStaticCast() { diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType, /*listInitialization=*/false); } - SrcExpr = ExprError(); - } else if (tcr == TC_Success) { + } + + if (isValidCast(tcr)) { if (Kind == CK_BitCast) checkCastAlign(); if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) checkObjCConversion(Sema::CCK_OtherCast); - } else if (Kind == CK_BitCast) { - checkCastAlign(); + } else { + SrcExpr = ExprError(); } } @@ -1145,7 +1211,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, } } } - // Allow arbitray objective-c pointer conversion with static casts. + // Allow arbitrary objective-c pointer conversion with static casts. if (SrcType->isObjCObjectPointerType() && DestType->isObjCObjectPointerType()) { Kind = CK_BitCast; @@ -1663,29 +1729,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, msg = diag::err_bad_const_cast_dest; return TC_NotApplicable; } - SrcType = Self.Context.getCanonicalType(SrcType); - - // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are - // completely equal. - // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers - // in multi-level pointers may change, but the level count must be the same, - // as must be the final pointee type. - while (SrcType != DestType && - Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) { - Qualifiers SrcQuals, DestQuals; - SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals); - DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals); - - // const_cast is permitted to strip cvr-qualifiers, only. Make sure that - // the other qualifiers (e.g., address spaces) are identical. - SrcQuals.removeCVRQualifiers(); - DestQuals.removeCVRQualifiers(); - if (SrcQuals != DestQuals) - return TC_NotApplicable; - } - // Since we're dealing in canonical types, the remainder must be the same. - if (SrcType != DestType) + // C++ [expr.const.cast]p3: + // "For two similar types T1 and T2, [...]" + // + // We only allow a const_cast to change cvr-qualifiers, not other kinds of + // type qualifiers. (Likewise, we ignore other changes when determining + // whether a cast casts away constness.) + if (!Self.Context.hasCvrSimilarType(SrcType, DestType)) return TC_NotApplicable; if (NeedToMaterializeTemporary) @@ -1913,6 +1964,12 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, return Result.isUsable(); } +static bool IsAddressSpaceConversion(QualType SrcType, QualType DestType) { + return SrcType->isPointerType() && DestType->isPointerType() && + SrcType->getAs<PointerType>()->getPointeeType().getAddressSpace() != + DestType->getAs<PointerType>()->getPointeeType().getAddressSpace(); +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, SourceRange OpRange, @@ -1994,16 +2051,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, SrcMemPtr->isMemberFunctionPointer()) return TC_NotApplicable; - // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away - // constness. - // A reinterpret_cast followed by a const_cast can, though, so in C-style, - // we accept it. - if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, - /*CheckObjCLifetime=*/CStyle)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; - } - if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // We need to determine the inheritance model that the class will use if // haven't yet. @@ -2018,6 +2065,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Failed; } + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away + // constness. + // A reinterpret_cast followed by a const_cast can, though, so in C-style, + // we accept it. + if (auto CACK = + CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) + return getCastAwayConstnessCastKind(CACK, msg); + // A valid member pointer cast. assert(!IsLValueCast); Kind = CK_ReinterpretMemberPointer; @@ -2134,19 +2190,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; } - // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. - // The C-style cast operator can. - if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, - /*CheckObjCLifetime=*/CStyle)) { - msg = diag::err_bad_cxx_cast_qualifiers_away; - return TC_Failed; - } - // Cannot convert between block pointers and Objective-C object pointers. if ((SrcType->isBlockPointerType() && DestType->isObjCObjectPointerType()) || (DestType->isBlockPointerType() && SrcType->isObjCObjectPointerType())) return TC_NotApplicable; + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. + // The C-style cast operator can. + TryCastResult SuccessResult = TC_Success; + if (auto CACK = + CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle, + /*CheckObjCLifetime=*/CStyle)) + SuccessResult = getCastAwayConstnessCastKind(CACK, msg); + if (IsLValueCast) { Kind = CK_LValueBitCast; } else if (DestType->isObjCObjectPointerType()) { @@ -2157,6 +2213,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } else { Kind = CK_BitCast; } + } else if (IsAddressSpaceConversion(SrcType, DestType)) { + Kind = CK_AddressSpaceConversion; } else { Kind = CK_BitCast; } @@ -2164,7 +2222,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - return TC_Success; + return SuccessResult; } if (CStyle) DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); @@ -2178,7 +2236,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (DestType->isFunctionPointerType()) { // C++ 5.2.10p6: A pointer to a function can be explicitly converted to // a pointer to a function of a different type. - return TC_Success; + return SuccessResult; } // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to @@ -2191,7 +2249,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, Self.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) << OpRange; - return TC_Success; + return SuccessResult; } if (DestType->isFunctionPointerType()) { @@ -2200,7 +2258,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, Self.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) << OpRange; - return TC_Success; + return SuccessResult; } // C++ 5.2.10p7: A pointer to an object can be explicitly converted to @@ -2208,8 +2266,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // Void pointers are not specified, but supported by every compiler out there. // So we finish by allowing everything that remains - it's got to be two // object pointers. - return TC_Success; -} + return SuccessResult; +} void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { @@ -2289,7 +2347,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, /*CStyle*/true, msg); if (SrcExpr.isInvalid()) return; - if (tcr == TC_Success) + if (isValidCast(tcr)) Kind = CK_NoOp; Sema::CheckedConversionKind CCK @@ -2312,7 +2370,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && - tcr == TC_Success) + isValidCast(tcr)) checkObjCConversion(CCK); if (tcr != TC_Success && msg != 0) { @@ -2336,13 +2394,14 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle), OpRange, SrcExpr.get(), DestType, ListInitialization); } - } else if (Kind == CK_BitCast) { - checkCastAlign(); } - // Clear out SrcExpr if there was a fatal error. - if (tcr != TC_Success) + if (isValidCast(tcr)) { + if (Kind == CK_BitCast) + checkCastAlign(); + } else { SrcExpr = ExprError(); + } } /// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a @@ -2627,11 +2686,13 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, QualType TheOffendingSrcType, TheOffendingDestType; Qualifiers CastAwayQualifiers; - if (!CastsAwayConstness(Self, SrcType, DestType, true, false, - &TheOffendingSrcType, &TheOffendingDestType, - &CastAwayQualifiers)) + if (CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers) != + CastAwayConstnessKind::CACK_Similar) return; + // FIXME: 'restrict' is not properly handled here. int qualifiers = -1; if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { qualifiers = 0; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 57af6b86bf80..8d953b6ef341 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -28,6 +28,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/NSAPI.h" +#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" @@ -196,35 +197,47 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { // First two arguments should be integers. for (unsigned I = 0; I < 2; ++I) { - Expr *Arg = TheCall->getArg(I); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(I); + QualType Ty = Arg.get()->getType(); if (!Ty->isIntegerType()) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), diag::err_overflow_builtin_must_be_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(I, Arg.get()); } // Third argument should be a pointer to a non-const integer. // IRGen correctly handles volatile, restrict, and address spaces, and // the other qualifiers aren't possible. { - Expr *Arg = TheCall->getArg(2); - QualType Ty = Arg->getType(); + ExprResult Arg = TheCall->getArg(2); + QualType Ty = Arg.get()->getType(); const auto *PtrTy = Ty->getAs<PointerType>(); if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && !PtrTy->getPointeeType().isConstQualified())) { - S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_ptr_int) - << Ty << Arg->getSourceRange(); + S.Diag(Arg.get()->getLocStart(), + diag::err_overflow_builtin_must_be_ptr_int) + << Ty << Arg.get()->getSourceRange(); return true; } + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.getASTContext(), Ty, /*consume*/ false); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(2, Arg.get()); } - return false; } static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, - CallExpr *TheCall, unsigned SizeIdx, + CallExpr *TheCall, unsigned SizeIdx, unsigned DstSizeIdx) { if (TheCall->getNumArgs() <= SizeIdx || TheCall->getNumArgs() <= DstSizeIdx) @@ -683,7 +696,7 @@ static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { return false; } -// \brief Performs semantic analysis for the read/write_pipe call. +// Performs semantic analysis for the read/write_pipe call. // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. @@ -737,7 +750,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// Performs a semantic analysis on the {work_group_/sub_group_ // /_}reserve_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -766,7 +779,7 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on {work_group_/sub_group_ +// Performs a semantic analysis on {work_group_/sub_group_ // /_}commit_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -789,7 +802,7 @@ static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { return false; } -// \brief Performs a semantic analysis on the call to built-in Pipe +// Performs a semantic analysis on the call to built-in Pipe // Query Functions. // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. @@ -807,8 +820,8 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { return false; } -// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. -// \brief Performs semantic analysis for the to_global/local/private call. +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. @@ -850,6 +863,20 @@ static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, return false; } +// Emit an error and return true if the current architecture is not in the list +// of supported architectures. +static bool +CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, + ArrayRef<llvm::Triple::ArchType> SupportedArchs) { + llvm::Triple::ArchType CurArch = + S.getASTContext().getTargetInfo().getTriple().getArch(); + if (llvm::is_contained(SupportedArchs, CurArch)) + return false; + S.Diag(TheCall->getLocStart(), diag::err_builtin_target_unsupported) + << TheCall->getSourceRange(); + return true; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -900,6 +927,33 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + + // The acquire, release, and no fence variants are ARM and AArch64 only. + case Builtin::BI_interlockedbittestandset_acq: + case Builtin::BI_interlockedbittestandset_rel: + case Builtin::BI_interlockedbittestandset_nf: + case Builtin::BI_interlockedbittestandreset_acq: + case Builtin::BI_interlockedbittestandreset_rel: + case Builtin::BI_interlockedbittestandreset_nf: + if (CheckBuiltinTargetSupport( + *this, BuiltinID, TheCall, + {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + + // The 64-bit bittest variants are x64, ARM, and AArch64 only. + case Builtin::BI_bittest64: + case Builtin::BI_bittestandcomplement64: + case Builtin::BI_bittestandreset64: + case Builtin::BI_bittestandset64: + case Builtin::BI_interlockedbittestandreset64: + case Builtin::BI_interlockedbittestandset64: + if (CheckBuiltinTargetSupport(*this, BuiltinID, TheCall, + {llvm::Triple::x86_64, llvm::Triple::arm, + llvm::Triple::thumb, llvm::Triple::aarch64})) + return ExprError(); + break; + case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: @@ -918,6 +972,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; @@ -1097,19 +1154,70 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_operator_new: - case Builtin::BI__builtin_operator_delete: - if (!getLangOpts().CPlusPlus) { - Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) - << (BuiltinID == Builtin::BI__builtin_operator_new - ? "__builtin_operator_new" - : "__builtin_operator_delete") - << "C++"; + case Builtin::BI__builtin_operator_delete: { + bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; + ExprResult Res = + SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + if (Res.isInvalid()) + CorrectDelayedTyposInExpr(TheCallResult.get()); + return Res; + } + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType() || + !PtrArgType->getPointeeType()->isRecordType()) { + Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType + << "structure pointer"; + return ExprError(); + } + + // Ensure that the second argument is of type 'FunctionType' + const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); + const QualType FnPtrArgType = FnPtrArg->getType(); + if (!FnPtrArgType->isPointerType()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; return ExprError(); } - // CodeGen assumes it can find the global new and delete to call, - // so ensure that they are declared. - DeclareGlobalNewDelete(); + + const auto *FuncType = + FnPtrArgType->getPointeeType()->getAs<FunctionType>(); + + if (!FuncType) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + + if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) { + if (!FT->getNumParams()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + QualType PT = FT->getParamType(0); + if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy || + !PT->isPointerType() || !PT->getPointeeType()->isCharType() || + !PT->getPointeeType().isConstQualified()) { + Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 + << 2 << FnPtrArgType << "'int (*)(const char *, ...)'"; + return ExprError(); + } + } + + TheCall->setType(Context.IntTy); break; + } // check secure string manipulation functions where overflows // are detectable at compile time @@ -1215,7 +1323,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; - break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) @@ -1244,6 +1351,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::hexagon: + if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1353,6 +1464,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { #define GET_NEON_OVERLOAD_CHECK #include "clang/Basic/arm_neon.inc" +#include "clang/Basic/arm_fp16.inc" #undef GET_NEON_OVERLOAD_CHECK } @@ -1402,9 +1514,10 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; -#define GET_NEON_IMMEDIATE_CHECK -#include "clang/Basic/arm_neon.inc" -#undef GET_NEON_IMMEDIATE_CHECK + #define GET_NEON_IMMEDIATE_CHECK + #include "clang/Basic/arm_neon.inc" + #include "clang/Basic/arm_fp16.inc" + #undef GET_NEON_IMMEDIATE_CHECK } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); @@ -1618,6 +1731,1015 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { + static const std::map<unsigned, std::vector<StringRef>> ValidCPU = { + { Hexagon::BI__builtin_HEXAGON_A6_vcmpbeq_notany, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_A6_vminub_RdP, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vsplatrbp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunehb_ppp, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_S6_vtrunohb_ppp, {"v62", "v65"} }, + }; + + static const std::map<unsigned, std::vector<StringRef>> ValidHVX = { + { Hexagon::BI__builtin_HEXAGON_V6_extractw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_extractw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_hi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lo_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplath_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_not_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_pred_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vand_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvqv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vaslwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vasrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassign_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vassignp_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0h_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcl0w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vcombine_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vd0_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdd0_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlut4_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmaxw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vminw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vmux_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnavgw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vnot_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrdelta_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B, {"v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vror_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundhub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsathub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsatwh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vshufoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv_128B, {"v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vswap_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackob_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackub_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vxor_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzb_128B, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh, {"v60", "v62", "v65"} }, + { Hexagon::BI__builtin_HEXAGON_V6_vzh_128B, {"v60", "v62", "v65"} }, + }; + + const TargetInfo &TI = Context.getTargetInfo(); + + auto FC = ValidCPU.find(BuiltinID); + if (FC != ValidCPU.end()) { + const TargetOptions &Opts = TI.getTargetOpts(); + StringRef CPU = Opts.CPU; + if (!CPU.empty()) { + assert(CPU.startswith("hexagon") && "Unexpected CPU name"); + CPU.consume_front("hexagon"); + if (llvm::none_of(FC->second, [CPU](StringRef S) { return S == CPU; })) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_cpu); + } + } + + auto FH = ValidHVX.find(BuiltinID); + if (FH != ValidHVX.end()) { + if (!TI.hasFeature("hvx")) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_requires_hvx); + + bool IsValid = llvm::any_of(FH->second, + [&TI] (StringRef V) { + std::string F = "hvx" + V.str(); + return TI.hasFeature(F); + }); + if (!IsValid) + return Diag(TheCall->getLocStart(), + diag::err_hexagon_builtin_unsupported_hvx); + } + + return false; +} + +bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { + struct ArgInfo { + ArgInfo(unsigned O, bool S, unsigned W, unsigned A) + : OpNum(O), IsSigned(S), BitWidth(W), Align(A) {} + unsigned OpNum = 0; + bool IsSigned = false; + unsigned BitWidth = 0; + unsigned Align = 0; + }; + + static const std::map<unsigned, std::vector<ArgInfo>> Infos = { + { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, + { Hexagon::BI__builtin_circ_stw, {{ 3, true, 4, 2 }} }, + { Hexagon::BI__builtin_circ_sth, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_sthhi, {{ 3, true, 4, 1 }} }, + { Hexagon::BI__builtin_circ_stb, {{ 3, true, 4, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci, {{ 1, true, 4, 3 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerb_pci, {{ 1, true, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerh_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerf_pci, {{ 1, true, 4, 1 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storeri_pci, {{ 1, true, 4, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_storerd_pci, {{ 1, true, 4, 3 }} }, + + { Hexagon::BI__builtin_HEXAGON_A2_combineii, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrih, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfril, {{ 1, false, 16, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A2_tfrpi, {{ 0, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_bitspliti, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_cround_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_round_ri_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbeqi, {{ 1, false, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpbgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpheqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmphgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpweqi, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgti, {{ 1, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_A4_vcmpwgtui, {{ 1, false, 7, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_bitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C2_muxii, {{ 2, true, 8, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_C4_nbitsclri, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_dfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfclass, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_n, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_F2_sfimm_p, {{ 0, false, 10, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addi, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_M4_mpyri_addr_u2, {{ 1, false, 6, 2 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_addasl_rrri, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_sat, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asl_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax, + {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_p_rnd, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, + {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_r_rnd, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_svw_trun, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_asr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_clrbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractu, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_extractup, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insert, {{ 2, false, 5, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_insertp, {{ 2, false, 6, 0 }, + { 3, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vh, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_lsr_i_vw, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_setbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxb_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxd_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxh_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tableidxw_goodsyntax, + {{ 2, false, 4, 0 }, + { 3, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_togglebit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_tstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_valignib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S2_vspliceib, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_addi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_andi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbaddi, {{ 1, true , 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_clbpaddi, {{ 1, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extract, {{ 1, false, 5, 0 }, + { 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_extractp, {{ 1, false, 6, 0 }, + { 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_lsli, {{ 0, true, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ntstbit_i, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_ori_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_asl_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_subi_lsr_ri, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate_acc, {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S4_vrcrotate, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_asrhub_sat, {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S5_vasrhrnd_goodsyntax, + {{ 1, false, 4, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, {{ 1, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, {{ 2, false, 6, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, {{ 1, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, {{ 2, false, 5, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, + {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, {{ 2, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, + {{ 3, false, 1, 0 }} }, + }; + + auto F = Infos.find(BuiltinID); + if (F == Infos.end()) + return false; + + bool Error = false; + + for (const ArgInfo &A : F->second) { + int32_t Min = A.IsSigned ? -(1 << (A.BitWidth-1)) : 0; + int32_t Max = (1 << (A.IsSigned ? A.BitWidth-1 : A.BitWidth)) - 1; + if (!A.Align) { + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + } else { + unsigned M = 1 << A.Align; + Min *= M; + Max *= M; + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max) | + SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + } + } + return Error; +} + +bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + return CheckHexagonBuiltinCpu(BuiltinID, TheCall) || + CheckHexagonBuiltinArgument(BuiltinID, TheCall); +} + + // CheckMipsBuiltinFunctionCall - Checks the constant value passed to the // intrinsic is correct. The switch statement is ordered by DSP, MSA. The // ordering for DSP is unspecified. MSA is ordered by the data format used @@ -1666,7 +2788,7 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; case Mips::BI__builtin_msa_binsli_h: case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; - // These intrinsics take an unsigned 5 bit immedate. + // These intrinsics take an unsigned 5 bit immediate. // The first block of intrinsics actually have an unsigned 5 bit field, // not a df/n field. case Mips::BI__builtin_msa_clei_u_b: @@ -1966,6 +3088,12 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvttss2usi64: ArgNum = 1; break; + case X86::BI__builtin_ia32_maxpd512: + case X86::BI__builtin_ia32_maxps512: + case X86::BI__builtin_ia32_minpd512: + case X86::BI__builtin_ia32_minps512: + ArgNum = 2; + break; case X86::BI__builtin_ia32_cvtps2pd512_mask: case X86::BI__builtin_ia32_cvttpd2dq512_mask: case X86::BI__builtin_ia32_cvttpd2qq512_mask: @@ -1995,12 +3123,8 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtss2sd_round_mask: case X86::BI__builtin_ia32_getexpsd128_round_mask: case X86::BI__builtin_ia32_getexpss128_round_mask: - case X86::BI__builtin_ia32_maxpd512_mask: - case X86::BI__builtin_ia32_maxps512_mask: case X86::BI__builtin_ia32_maxsd_round_mask: case X86::BI__builtin_ia32_maxss_round_mask: - case X86::BI__builtin_ia32_minpd512_mask: - case X86::BI__builtin_ia32_minps512_mask: case X86::BI__builtin_ia32_minsd_round_mask: case X86::BI__builtin_ia32_minss_round_mask: case X86::BI__builtin_ia32_rcp28sd_round_mask: @@ -2039,9 +3163,19 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvtss2si64: case X86::BI__builtin_ia32_vcvtss2usi32: case X86::BI__builtin_ia32_vcvtss2usi64: + case X86::BI__builtin_ia32_sqrtpd512: + case X86::BI__builtin_ia32_sqrtps512: ArgNum = 1; HasRC = true; break; + case X86::BI__builtin_ia32_addpd512: + case X86::BI__builtin_ia32_addps512: + case X86::BI__builtin_ia32_divpd512: + case X86::BI__builtin_ia32_divps512: + case X86::BI__builtin_ia32_mulpd512: + case X86::BI__builtin_ia32_mulps512: + case X86::BI__builtin_ia32_subpd512: + case X86::BI__builtin_ia32_subps512: case X86::BI__builtin_ia32_cvtsi2sd64: case X86::BI__builtin_ia32_cvtsi2ss32: case X86::BI__builtin_ia32_cvtsi2ss64: @@ -2062,19 +3196,9 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtqq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2pd512_mask: case X86::BI__builtin_ia32_cvtuqq2ps512_mask: - case X86::BI__builtin_ia32_sqrtpd512_mask: - case X86::BI__builtin_ia32_sqrtps512_mask: ArgNum = 3; HasRC = true; break; - case X86::BI__builtin_ia32_addpd512_mask: - case X86::BI__builtin_ia32_addps512_mask: - case X86::BI__builtin_ia32_divpd512_mask: - case X86::BI__builtin_ia32_divps512_mask: - case X86::BI__builtin_ia32_mulpd512_mask: - case X86::BI__builtin_ia32_mulps512_mask: - case X86::BI__builtin_ia32_subpd512_mask: - case X86::BI__builtin_ia32_subps512_mask: case X86::BI__builtin_ia32_addss_round_mask: case X86::BI__builtin_ia32_addsd_round_mask: case X86::BI__builtin_ia32_divss_round_mask: @@ -2092,34 +3216,28 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtsd2ss_round_mask: case X86::BI__builtin_ia32_sqrtsd_round_mask: case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: case X86::BI__builtin_ia32_vfmaddpd512_mask: - case X86::BI__builtin_ia32_vfmaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddps512_mask: - case X86::BI__builtin_ia32_vfmaddps512_mask3: case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_mask: - case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_mask: - case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_maskz: - case X86::BI__builtin_ia32_vfmsubpd512_mask3: - case X86::BI__builtin_ia32_vfmsubps512_mask3: - case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmsubaddps512_mask3: - case X86::BI__builtin_ia32_vfnmaddpd512_mask: - case X86::BI__builtin_ia32_vfnmaddps512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask: - case X86::BI__builtin_ia32_vfnmsubpd512_mask3: - case X86::BI__builtin_ia32_vfnmsubps512_mask: - case X86::BI__builtin_ia32_vfnmsubps512_mask3: - case X86::BI__builtin_ia32_vfmaddsd3_mask: - case X86::BI__builtin_ia32_vfmaddsd3_maskz: - case X86::BI__builtin_ia32_vfmaddsd3_mask3: - case X86::BI__builtin_ia32_vfmaddss3_mask: - case X86::BI__builtin_ia32_vfmaddss3_maskz: - case X86::BI__builtin_ia32_vfmaddss3_mask3: ArgNum = 4; HasRC = true; break; @@ -2256,6 +3374,17 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, << Arg->getSourceRange(); } +static bool isX86_32Builtin(unsigned BuiltinID) { + // These builtins only work on x86-32 targets. + switch (BuiltinID) { + case X86::BI__builtin_ia32_readeflags_u32: + case X86::BI__builtin_ia32_writeeflags_u32: + return true; + } + + return false; +} + bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); @@ -2263,6 +3392,12 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_is) return SemaBuiltinCpuIs(*this, TheCall); + // Check for 32-bit only builtins on a 64-bit target. + const llvm::Triple &TT = Context.getTargetInfo().getTriple(); + if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) + return Diag(TheCall->getCallee()->getLocStart(), + diag::err_32_bit_builtin_64_bit_tgt); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -2277,14 +3412,67 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { default: return false; + case X86::BI__builtin_ia32_vec_ext_v2si: + case X86::BI__builtin_ia32_vec_ext_v2di: + case X86::BI__builtin_ia32_vextractf128_pd256: + case X86::BI__builtin_ia32_vextractf128_ps256: + case X86::BI__builtin_ia32_vextractf128_si256: + case X86::BI__builtin_ia32_extract128i256: + case X86::BI__builtin_ia32_extractf64x4_mask: + case X86::BI__builtin_ia32_extracti64x4_mask: + case X86::BI__builtin_ia32_extractf32x8_mask: + case X86::BI__builtin_ia32_extracti32x8_mask: + case X86::BI__builtin_ia32_extractf64x2_256_mask: + case X86::BI__builtin_ia32_extracti64x2_256_mask: + case X86::BI__builtin_ia32_extractf32x4_256_mask: + case X86::BI__builtin_ia32_extracti32x4_256_mask: + i = 1; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vec_set_v2di: + case X86::BI__builtin_ia32_vinsertf128_pd256: + case X86::BI__builtin_ia32_vinsertf128_ps256: + case X86::BI__builtin_ia32_vinsertf128_si256: + case X86::BI__builtin_ia32_insert128i256: + case X86::BI__builtin_ia32_insertf32x8: + case X86::BI__builtin_ia32_inserti32x8: + case X86::BI__builtin_ia32_insertf64x4: + case X86::BI__builtin_ia32_inserti64x4: + case X86::BI__builtin_ia32_insertf64x2_256: + case X86::BI__builtin_ia32_inserti64x2_256: + case X86::BI__builtin_ia32_insertf32x4_256: + case X86::BI__builtin_ia32_inserti32x4_256: + i = 2; l = 0; u = 1; + break; + case X86::BI__builtin_ia32_vpermilpd: + case X86::BI__builtin_ia32_vec_ext_v4hi: + case X86::BI__builtin_ia32_vec_ext_v4si: + case X86::BI__builtin_ia32_vec_ext_v4sf: + case X86::BI__builtin_ia32_vec_ext_v4di: + case X86::BI__builtin_ia32_extractf32x4_mask: + case X86::BI__builtin_ia32_extracti32x4_mask: + case X86::BI__builtin_ia32_extractf64x2_512_mask: + case X86::BI__builtin_ia32_extracti64x2_512_mask: + i = 1; l = 0; u = 3; + break; case X86::BI_mm_prefetch: + case X86::BI__builtin_ia32_vec_ext_v8hi: + case X86::BI__builtin_ia32_vec_ext_v8si: i = 1; l = 0; u = 7; break; case X86::BI__builtin_ia32_sha1rnds4: - case X86::BI__builtin_ia32_shuf_f32x4_256_mask: - case X86::BI__builtin_ia32_shuf_f64x2_256_mask: - case X86::BI__builtin_ia32_shuf_i32x4_256_mask: - case X86::BI__builtin_ia32_shuf_i64x2_256_mask: + case X86::BI__builtin_ia32_blendpd: + case X86::BI__builtin_ia32_shufpd: + case X86::BI__builtin_ia32_vec_set_v4hi: + case X86::BI__builtin_ia32_vec_set_v4si: + case X86::BI__builtin_ia32_vec_set_v4di: + case X86::BI__builtin_ia32_shuf_f32x4_256: + case X86::BI__builtin_ia32_shuf_f64x2_256: + case X86::BI__builtin_ia32_shuf_i32x4_256: + case X86::BI__builtin_ia32_shuf_i64x2_256: + case X86::BI__builtin_ia32_insertf64x2_512: + case X86::BI__builtin_ia32_inserti64x2_512: + case X86::BI__builtin_ia32_insertf32x4: + case X86::BI__builtin_ia32_inserti32x4: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -2325,14 +3513,29 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vpcomw: case X86::BI__builtin_ia32_vpcomd: case X86::BI__builtin_ia32_vpcomq: + case X86::BI__builtin_ia32_vec_set_v8hi: + case X86::BI__builtin_ia32_vec_set_v8si: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_vpermilpd256: case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: case X86::BI__builtin_ia32_roundpd256: + case X86::BI__builtin_ia32_getmantpd128_mask: + case X86::BI__builtin_ia32_getmantpd256_mask: + case X86::BI__builtin_ia32_getmantps128_mask: + case X86::BI__builtin_ia32_getmantps256_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_vec_ext_v16qi: + case X86::BI__builtin_ia32_vec_ext_v16hi: i = 1; l = 0; u = 15; break; + case X86::BI__builtin_ia32_pblendd128: + case X86::BI__builtin_ia32_blendps: + case X86::BI__builtin_ia32_blendpd256: + case X86::BI__builtin_ia32_shufpd256: case X86::BI__builtin_ia32_roundss: case X86::BI__builtin_ia32_roundsd: case X86::BI__builtin_ia32_rangepd128_mask: @@ -2343,8 +3546,13 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_vec_set_v16qi: + case X86::BI__builtin_ia32_vec_set_v16hi: i = 2; l = 0; u = 15; break; + case X86::BI__builtin_ia32_vec_ext_v32qi: + i = 1; l = 0; u = 31; + break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: @@ -2359,15 +3567,26 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cmppd512_mask: case X86::BI__builtin_ia32_cmpsd_mask: case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_vec_set_v32qi: i = 2; l = 0; u = 31; break; - case X86::BI__builtin_ia32_xabort: - i = 0; l = -128; u = 255; - break; - case X86::BI__builtin_ia32_pshufw: - case X86::BI__builtin_ia32_aeskeygenassist128: - i = 1; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_permdf256: + case X86::BI__builtin_ia32_permdi256: + case X86::BI__builtin_ia32_permdf512: + case X86::BI__builtin_ia32_permdi512: + case X86::BI__builtin_ia32_vpermilps: + case X86::BI__builtin_ia32_vpermilps256: + case X86::BI__builtin_ia32_vpermilpd512: + case X86::BI__builtin_ia32_vpermilps512: + case X86::BI__builtin_ia32_pshufd: + case X86::BI__builtin_ia32_pshufd256: + case X86::BI__builtin_ia32_pshufd512: + case X86::BI__builtin_ia32_pshufhw: + case X86::BI__builtin_ia32_pshufhw256: + case X86::BI__builtin_ia32_pshufhw512: + case X86::BI__builtin_ia32_pshuflw: + case X86::BI__builtin_ia32_pshuflw256: + case X86::BI__builtin_ia32_pshuflw512: case X86::BI__builtin_ia32_vcvtps2ph: case X86::BI__builtin_ia32_vcvtps2ph_mask: case X86::BI__builtin_ia32_vcvtps2ph256: @@ -2385,16 +3604,18 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_reduceps128_mask: case X86::BI__builtin_ia32_reduceps256_mask: case X86::BI__builtin_ia32_reduceps512_mask: - case X86::BI__builtin_ia32_prold512_mask: - case X86::BI__builtin_ia32_prolq512_mask: - case X86::BI__builtin_ia32_prold128_mask: - case X86::BI__builtin_ia32_prold256_mask: - case X86::BI__builtin_ia32_prolq128_mask: - case X86::BI__builtin_ia32_prolq256_mask: - case X86::BI__builtin_ia32_prord128_mask: - case X86::BI__builtin_ia32_prord256_mask: - case X86::BI__builtin_ia32_prorq128_mask: - case X86::BI__builtin_ia32_prorq256_mask: + case X86::BI__builtin_ia32_prold512: + case X86::BI__builtin_ia32_prolq512: + case X86::BI__builtin_ia32_prold128: + case X86::BI__builtin_ia32_prold256: + case X86::BI__builtin_ia32_prolq128: + case X86::BI__builtin_ia32_prolq256: + case X86::BI__builtin_ia32_prord512: + case X86::BI__builtin_ia32_prorq512: + case X86::BI__builtin_ia32_prord128: + case X86::BI__builtin_ia32_prord256: + case X86::BI__builtin_ia32_prorq128: + case X86::BI__builtin_ia32_prorq256: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: @@ -2403,41 +3624,62 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_fpclasspd512_mask: case X86::BI__builtin_ia32_fpclasssd_mask: case X86::BI__builtin_ia32_fpclassss_mask: + case X86::BI__builtin_ia32_pslldqi128_byteshift: + case X86::BI__builtin_ia32_pslldqi256_byteshift: + case X86::BI__builtin_ia32_pslldqi512_byteshift: + case X86::BI__builtin_ia32_psrldqi128_byteshift: + case X86::BI__builtin_ia32_psrldqi256_byteshift: + case X86::BI__builtin_ia32_psrldqi512_byteshift: i = 1; l = 0; u = 255; break; - case X86::BI__builtin_ia32_palignr: - case X86::BI__builtin_ia32_insertps128: - case X86::BI__builtin_ia32_dpps: - case X86::BI__builtin_ia32_dppd: - case X86::BI__builtin_ia32_dpps256: - case X86::BI__builtin_ia32_mpsadbw128: - case X86::BI__builtin_ia32_mpsadbw256: - case X86::BI__builtin_ia32_pcmpistrm128: - case X86::BI__builtin_ia32_pcmpistri128: - case X86::BI__builtin_ia32_pcmpistria128: - case X86::BI__builtin_ia32_pcmpistric128: - case X86::BI__builtin_ia32_pcmpistrio128: - case X86::BI__builtin_ia32_pcmpistris128: - case X86::BI__builtin_ia32_pcmpistriz128: - case X86::BI__builtin_ia32_pclmulqdq128: case X86::BI__builtin_ia32_vperm2f128_pd256: case X86::BI__builtin_ia32_vperm2f128_ps256: case X86::BI__builtin_ia32_vperm2f128_si256: case X86::BI__builtin_ia32_permti256: - i = 2; l = -128; u = 255; - break; + case X86::BI__builtin_ia32_pblendw128: + case X86::BI__builtin_ia32_pblendw256: + case X86::BI__builtin_ia32_blendps256: + case X86::BI__builtin_ia32_pblendd256: case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr512_mask: + case X86::BI__builtin_ia32_palignr512: + case X86::BI__builtin_ia32_alignq512: + case X86::BI__builtin_ia32_alignd512: + case X86::BI__builtin_ia32_alignd128: + case X86::BI__builtin_ia32_alignd256: + case X86::BI__builtin_ia32_alignq128: + case X86::BI__builtin_ia32_alignq256: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: - case X86::BI__builtin_ia32_shuf_f32x4_mask: - case X86::BI__builtin_ia32_shuf_f64x2_mask: - case X86::BI__builtin_ia32_shuf_i32x4_mask: - case X86::BI__builtin_ia32_shuf_i64x2_mask: - case X86::BI__builtin_ia32_dbpsadbw128_mask: - case X86::BI__builtin_ia32_dbpsadbw256_mask: - case X86::BI__builtin_ia32_dbpsadbw512_mask: + case X86::BI__builtin_ia32_shuf_f32x4: + case X86::BI__builtin_ia32_shuf_f64x2: + case X86::BI__builtin_ia32_shuf_i32x4: + case X86::BI__builtin_ia32_shuf_i64x2: + case X86::BI__builtin_ia32_shufpd512: + case X86::BI__builtin_ia32_shufps: + case X86::BI__builtin_ia32_shufps256: + case X86::BI__builtin_ia32_shufps512: + case X86::BI__builtin_ia32_dbpsadbw128: + case X86::BI__builtin_ia32_dbpsadbw256: + case X86::BI__builtin_ia32_dbpsadbw512: + case X86::BI__builtin_ia32_vpshldd128: + case X86::BI__builtin_ia32_vpshldd256: + case X86::BI__builtin_ia32_vpshldd512: + case X86::BI__builtin_ia32_vpshldq128: + case X86::BI__builtin_ia32_vpshldq256: + case X86::BI__builtin_ia32_vpshldq512: + case X86::BI__builtin_ia32_vpshldw128: + case X86::BI__builtin_ia32_vpshldw256: + case X86::BI__builtin_ia32_vpshldw512: + case X86::BI__builtin_ia32_vpshrdd128: + case X86::BI__builtin_ia32_vpshrdd256: + case X86::BI__builtin_ia32_vpshrdd512: + case X86::BI__builtin_ia32_vpshrdq128: + case X86::BI__builtin_ia32_vpshrdq256: + case X86::BI__builtin_ia32_vpshrdq512: + case X86::BI__builtin_ia32_vpshrdw128: + case X86::BI__builtin_ia32_vpshrdw256: + case X86::BI__builtin_ia32_vpshrdw512: i = 2; l = 0; u = 255; break; case X86::BI__builtin_ia32_fixupimmpd512_mask: @@ -2480,21 +3722,17 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_scatterpfqps: i = 4; l = 2; u = 3; break; - case X86::BI__builtin_ia32_pcmpestrm128: - case X86::BI__builtin_ia32_pcmpestri128: - case X86::BI__builtin_ia32_pcmpestria128: - case X86::BI__builtin_ia32_pcmpestric128: - case X86::BI__builtin_ia32_pcmpestrio128: - case X86::BI__builtin_ia32_pcmpestris128: - case X86::BI__builtin_ia32_pcmpestriz128: - i = 4; l = -128; u = 255; - break; case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: i = 4; l = 0; u = 255; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + + // Note that we don't force a hard error on the range check here, allowing + // template-generated or macro-generated dead code to potentially have out-of- + // range values. These need to code generate, but don't need to necessarily + // make any sense. We use a warning that defaults to an error. + return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -2522,7 +3760,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// Checks if a the given expression evaluates to null. /// -/// \brief Returns true if the value evaluates to null. +/// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability @@ -2566,7 +3804,7 @@ bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { return false; } -/// \brief Diagnose use of %s directive in an NSString which is being passed +/// Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, @@ -2636,12 +3874,13 @@ static void CheckNonNullArguments(Sema &S, return; } - for (unsigned Val : NonNull->args()) { - if (Val >= Args.size()) + for (const ParamIdx &Idx : NonNull->args()) { + unsigned IdxAST = Idx.getASTIndex(); + if (IdxAST >= Args.size()) continue; if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); - NonNullArgs.set(Val); + NonNullArgs.set(IdxAST); } } } @@ -2985,6 +4224,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; + bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -3038,6 +4278,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Form = Arithmetic; break; + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_max: + IsMinMax = true; + Form = Arithmetic; + break; + case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: @@ -3120,12 +4366,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // gcc does not enforce these rules for GNU atomics, but we do so for sanity. - if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { + if (IsAddSub && !ValType->isIntegerType() + && !ValType->isPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (!IsAddSub && !ValType->isIntegerType()) { + if (IsMinMax) { + const BuiltinType *BT = ValType->getAs<BuiltinType>(); + if (!BT || (BT->getKind() != BuiltinType::Int && + BT->getKind() != BuiltinType::UInt)) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_int32_or_ptr); + return ExprError(); + } + } + if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); @@ -3168,9 +4423,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } - // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the - // volatile-ness of the pointee-type inject itself into the result or the - // other operands. Similarly atomic_load can take a pointer to a const 'A'. + // All atomic operations have an overload which takes a pointer to a volatile + // 'A'. We shouldn't let the volatile-ness of the pointee-type inject itself + // into the result or the other operands. Similarly atomic_load takes a + // pointer to a const 'A'. ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; @@ -3183,16 +4439,27 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The type of a parameter passed 'by value'. In the GNU atomics, such // arguments are actually passed as pointers. QualType ByValType = ValType; // 'CP' - if (!IsC11 && !IsN) + bool IsPassedByAddress = false; + if (!IsC11 && !IsN) { ByValType = Ptr->getType(); + IsPassedByAddress = true; + } - // The first argument --- the pointer --- has a fixed type; we - // deduce the types of the rest of the arguments accordingly. Walk - // the remaining arguments, converting them to the deduced value type. - for (unsigned i = 1; i != TheCall->getNumArgs(); ++i) { + // The first argument's non-CV pointer type is used to deduce the type of + // subsequent arguments, except for: + // - weak flag (always converted to bool) + // - memory order (always converted to int) + // - scope (always converted to int) + for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { + case 0: + // The first argument is always a pointer. It has a fixed type. + // It is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); + // Nothing else to do: we already know all we want about this pointer. + continue; case 1: // The second argument is the non-atomic operand. For arithmetic, this // is always passed by value, and for a compare_exchange it is always @@ -3201,14 +4468,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, assert(Form != Load); if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; - else if (Form == Copy || Form == Xchg) + else if (Form == Copy || Form == Xchg) { + if (IsPassedByAddress) + // The value pointer is always dereferenced, a nullptr is undefined. + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; - else if (Form == Arithmetic) + } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); - // Treat this argument as _Nonnull as we want to show a warning if - // NULL is passed into it. + // The value pointer is always dereferenced, a nullptr is undefined. CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. @@ -3221,8 +4490,10 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } break; case 2: - // The third argument to compare_exchange / GNU exchange is a - // (pointer to a) desired value. + // The third argument to compare_exchange / GNU exchange is the desired + // value, either by-value (for the C11 and *_n variant) or as a pointer. + if (IsPassedByAddress) + CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getLocStart()); Ty = ByValType; break; case 3: @@ -3393,6 +4664,12 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return ExprError(); } + if (ValType.isConstQualified()) { + Diag(DRE->getLocStart(), diag::err_atomic_builtin_cannot_be_const) + << FirstArg->getType() << FirstArg->getSourceRange(); + return ExprError(); + } + switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: @@ -3598,7 +4875,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { ResultType = Context.BoolTy; break; - case Builtin::BI__sync_lock_test_and_set: + case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: @@ -4115,15 +5392,19 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> float or double, remove it. + // If this is an implicit conversion from float -> float, double, or + // long double, remove it. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { // Only remove standard FloatCasts, leaving other casts inplace if (Cast->getCastKind() == CK_FloatingCast) { Expr *CastArg = Cast->getSubExpr(); if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && - "promotion from float to either float or double is the only expected cast here"); + assert( + (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && + "promotion from float to either float, double, or long double is " + "the only expected cast here"); Cast->setSubExpr(nullptr); TheCall->setArg(NumArgs-1, CastArg); } @@ -4519,7 +5800,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, /// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High) { + int Low, int High, bool RangeIsError) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -4531,9 +5812,18 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; - if (Result.getSExtValue() < Low || Result.getSExtValue() > High) - return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << Low << High << Arg->getSourceRange(); + if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { + if (RangeIsError) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << Result.toString(10) << Low << High << Arg->getSourceRange(); + else + // Defer the warning until we know if the code will be emitted so that + // dead code can ignore this. + DiagRuntimeBehavior(TheCall->getLocStart(), TheCall, + PDiag(diag::warn_argument_invalid_range) + << Result.toString(10) << Low << High + << Arg->getSourceRange()); + } return false; } @@ -5018,18 +6308,22 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { - if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) - if (MD->isInstance()) - --ArgIndex; - const Expr *Arg = CE->getArg(ArgIndex - 1); - - return checkFormatStringExpr(S, Arg, Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg, Offset); - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + bool IsFirst = true; + StringLiteralCheckType CommonResult; + for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) { + const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex()); + StringLiteralCheckType Result = checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + if (IsFirst) { + CommonResult = Result; + IsFirst = false; + } + } + if (!IsFirst) + return CommonResult; + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { @@ -5049,8 +6343,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, const auto *ME = cast<ObjCMessageExpr>(E); if (const auto *ND = ME->getMethodDecl()) { if (const auto *FA = ND->getAttr<FormatArgAttr>()) { - unsigned ArgIndex = FA->getFormatIdx(); - const Expr *Arg = ME->getArg(ArgIndex - 1); + const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex()); return checkFormatStringExpr( S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); @@ -5654,7 +6947,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, Loc, IsStringLocation, StringRange, FixIt); } -/// \brief If the format string is not within the funcion call, emit a note +/// If the format string is not within the function call, emit a note /// so that the function call and string are in diagnostic messages. /// /// \param InFunctionCall if true, the format string is within the function @@ -6311,11 +7604,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ExprTy = TET->getUnderlyingExpr()->getType(); } - analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy); - - if (match == analyze_printf::ArgType::Match) { + const analyze_printf::ArgType::MatchKind Match = + AT.matchesType(S.Context, ExprTy); + bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic; + if (Match == analyze_printf::ArgType::Match) return true; - } // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array @@ -6391,6 +7684,12 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, QualType CastTy; std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { + // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int + // (long in ASTContext). Only complain to pedants. + if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") && + (AT.isSizeT() || AT.isPtrdiffT()) && + AT.matchesType(S.Context, CastTy)) + Pedantic = true; IntendedTy = CastTy; ShouldNotPrintDirectly = true; } @@ -6398,10 +7697,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = + bool Success = fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); - if (success) { + if (Success) { // Get the fix string from the fixed format specifier SmallString<16> buf; llvm::raw_svector_ostream os(buf); @@ -6410,13 +7709,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; // In this case, the specifier is wrong and should be changed to match // the argument. - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum << E->getSourceRange(), E->getLocStart(), @@ -6469,9 +7768,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; - EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) - << Name << IntendedTy << IsEnum - << E->getSourceRange(), + unsigned Diag = Pedantic + ? diag::warn_format_argument_needs_cast_pedantic + : diag::warn_format_argument_needs_cast; + EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum + << E->getSourceRange(), E->getLocStart(), /*IsStringLocation=*/false, SpecRange, Hints); } else { @@ -6495,13 +7796,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_printf::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic + ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/ false, CSR); break; @@ -6684,29 +7985,28 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } - analyze_format_string::ArgType::MatchKind match = + analyze_format_string::ArgType::MatchKind Match = AT.matchesType(S.Context, Ex->getType()); - if (match == analyze_format_string::ArgType::Match) { + bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; + if (Match == analyze_format_string::ArgType::Match) return true; - } ScanfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), + bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), S.getLangOpts(), S.Context); - unsigned diag = diag::warn_format_conversion_argument_type_mismatch; - if (match == analyze_format_string::ArgType::NoMatchPedantic) { - diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; - } + unsigned Diag = + Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic + : diag::warn_format_conversion_argument_type_mismatch; - if (success) { + if (Success) { // Get the fix string from the fixed format specifier. SmallString<128> buf; llvm::raw_svector_ostream os(buf); fixedFS.toString(os); EmitFormatDiagnostic( - S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) + S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/ false, @@ -6714,7 +8014,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( FixItHint::CreateReplacement( getSpecifierRange(startSpecifier, specifierLen), os.str())); } else { - EmitFormatDiagnostic(S.PDiag(diag) + EmitFormatDiagnostic(S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), @@ -7267,7 +8567,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call, //===--- CHECK: Standard memory functions ---------------------------------===// -/// \brief Takes the expression passed to the size_t parameter of functions +/// Takes the expression passed to the size_t parameter of functions /// such as memcmp, strncat, etc and warns if it's a comparison. /// /// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`. @@ -7298,7 +8598,7 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, return true; } -/// \brief Determine whether the given type is or contains a dynamic class type +/// Determine whether the given type is or contains a dynamic class type /// (e.g., whether it has a vtable). static const CXXRecordDecl *getContainedDynamicClass(QualType T, bool &IsContained) { @@ -7329,28 +8629,205 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, return nullptr; } -/// \brief If E is a sizeof expression, returns its argument expression, +static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) { + if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) + if (Unary->getKind() == UETT_SizeOf) + return Unary; + return nullptr; +} + +/// If E is a sizeof expression, returns its argument expression, /// otherwise returns NULL. static const Expr *getSizeOfExprArg(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf && !SizeOf->isArgumentType()) + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + if (!SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); - return nullptr; } -/// \brief If E is a sizeof expression, returns its argument type. +/// If E is a sizeof expression, returns its argument type. static QualType getSizeOfArgType(const Expr *E) { - if (const UnaryExprOrTypeTraitExpr *SizeOf = - dyn_cast<UnaryExprOrTypeTraitExpr>(E)) - if (SizeOf->getKind() == UETT_SizeOf) - return SizeOf->getTypeOfArgument(); - + if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E)) + return SizeOf->getTypeOfArgument(); return QualType(); } -/// \brief Check for dangerous or invalid arguments to memset(). +namespace { + +struct SearchNonTrivialToInitializeField + : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> { + using Super = + DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>; + + SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PDIK, AT, SL); + return; + } + + Super::visitWithKind(PDIK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, + const ArrayType *AT, SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void visitTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +struct SearchNonTrivialToCopyField + : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> { + using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>; + + SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {} + + void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) { + if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { + asDerived().visitArray(PCK, AT, SL); + return; + } + + Super::visitWithKind(PCK, FT, SL); + } + + void visitARCStrong(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitARCWeak(QualType FT, SourceLocation SL) { + S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); + } + void visitStruct(QualType FT, SourceLocation SL) { + for (const FieldDecl *FD : FT->castAs<RecordType>()->getDecl()->fields()) + visit(FD->getType(), FD->getLocation()); + } + void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, + SourceLocation SL) { + visit(getContext().getBaseElementType(AT), SL); + } + void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, + SourceLocation SL) {} + void visitTrivial(QualType FT, SourceLocation SL) {} + void visitVolatileTrivial(QualType FT, SourceLocation SL) {} + + static void diag(QualType RT, const Expr *E, Sema &S) { + SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation()); + } + + ASTContext &getContext() { return S.getASTContext(); } + + const Expr *E; + Sema &S; +}; + +} + +/// Detect if \c SizeofExpr is likely to calculate the sizeof an object. +static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) { + SizeofExpr = SizeofExpr->IgnoreParenImpCasts(); + + if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) { + if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add) + return false; + + return doesExprLikelyComputeSize(BO->getLHS()) || + doesExprLikelyComputeSize(BO->getRHS()); + } + + return getAsSizeOfExpr(SizeofExpr) != nullptr; +} + +/// Check if the ArgLoc originated from a macro passed to the call at CallLoc. +/// +/// \code +/// #define MACRO 0 +/// foo(MACRO); +/// foo(0); +/// \endcode +/// +/// This should return true for the first call to foo, but not for the second +/// (regardless of whether foo is a macro or function). +static bool isArgumentExpandedFromMacro(SourceManager &SM, + SourceLocation CallLoc, + SourceLocation ArgLoc) { + if (!CallLoc.isMacroID()) + return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc); + + return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) != + SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc)); +} + +/// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the +/// last two arguments transposed. +static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) { + if (BId != Builtin::BImemset && BId != Builtin::BIbzero) + return; + + const Expr *SizeArg = + Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts(); + + auto isLiteralZero = [](const Expr *E) { + return isa<IntegerLiteral>(E) && cast<IntegerLiteral>(E)->getValue() == 0; + }; + + // If we're memsetting or bzeroing 0 bytes, then this is likely an error. + SourceLocation CallLoc = Call->getRParenLoc(); + SourceManager &SM = S.getSourceManager(); + if (isLiteralZero(SizeArg) && + !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) { + + SourceLocation DiagLoc = SizeArg->getExprLoc(); + + // Some platforms #define bzero to __builtin_memset. See if this is the + // case, and if so, emit a better diagnostic. + if (BId == Builtin::BIbzero || + (CallLoc.isMacroID() && Lexer::getImmediateMacroName( + CallLoc, SM, S.getLangOpts()) == "bzero")) { + S.Diag(DiagLoc, diag::warn_suspicious_bzero_size); + S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence); + } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) { + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0; + } + return; + } + + // If the second argument to a memset is a sizeof expression and the third + // isn't, this is also likely an error. This should catch + // 'memset(buf, sizeof(buf), 0xff)'. + if (BId == Builtin::BImemset && + doesExprLikelyComputeSize(Call->getArg(1)) && + !doesExprLikelyComputeSize(Call->getArg(2))) { + SourceLocation DiagLoc = Call->getArg(1)->getExprLoc(); + S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1; + S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1; + return; + } +} + +/// Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified /// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' @@ -7379,6 +8856,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, Call->getLocStart(), Call->getRParenLoc())) return; + // Catch cases like 'memset(buf, sizeof(buf), 0)'. + CheckMemaccessSize(*this, BId, Call); + // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); @@ -7515,7 +8995,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); - else + else if (const auto *RT = PointeeTy->getAs<RecordType>()) { + if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && + RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 0); + SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); + } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && + RT->getDecl()->isNonTrivialToPrimitiveCopy()) { + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cstruct_memaccess) + << ArgIdx << FnName << PointeeTy << 1); + SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); + } else { + continue; + } + } else continue; DiagRuntimeBehavior( @@ -7736,421 +9232,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, << FixItHint::CreateReplacement(SR, OS.str()); } -//===--- CHECK: Return Address of Stack Variable --------------------------===// - -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl); - -/// CheckReturnStackAddr - Check if a return statement returns the address -/// of a stack variable. -static void -CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc) { - const Expr *stackE = nullptr; - SmallVector<const DeclRefExpr *, 8> refVars; - - // Perform checking for returned stack addresses, local blocks, - // label addresses or references to temporaries. - if (lhsType->isPointerType() || - (!S.getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) { - stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/nullptr); - } else if (lhsType->isReferenceType()) { - stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/nullptr); - } - - if (!stackE) - return; // Nothing suspicious was found. - - // Parameters are initialized in the calling scope, so taking the address - // of a parameter reference doesn't need a warning. - for (auto *DRE : refVars) - if (isa<ParmVarDecl>(DRE->getDecl())) - return; - - SourceLocation diagLoc; - SourceRange diagRange; - if (refVars.empty()) { - diagLoc = stackE->getLocStart(); - diagRange = stackE->getSourceRange(); - } else { - // We followed through a reference variable. 'stackE' contains the - // problematic expression but we will warn at the return statement pointing - // at the reference variable. We will later display the "trail" of - // reference variables using notes. - diagLoc = refVars[0]->getLocStart(); - diagRange = refVars[0]->getSourceRange(); - } - - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { - // address of local var - S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() - << DR->getDecl()->getDeclName() << diagRange; - } else if (isa<BlockExpr>(stackE)) { // local block. - S.Diag(diagLoc, diag::err_ret_local_block) << diagRange; - } else if (isa<AddrLabelExpr>(stackE)) { // address of label. - S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; - } else { // local temporary. - // If there is an LValue->RValue conversion, then the value of the - // reference type is used, not the reference. - if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) { - if (ICE->getCastKind() == CK_LValueToRValue) { - return; - } - } - S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) - << lhsType->isReferenceType() << diagRange; - } - - // Display the "trail" of reference variables that we followed until we - // found the problematic expression using notes. - for (unsigned i = 0, e = refVars.size(); i != e; ++i) { - const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); - // If this var binds to another reference var, show the range of the next - // var, otherwise the var binds to the problematic expression, in which case - // show the range of the expression. - SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() - : stackE->getSourceRange(); - S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) - << VD->getDeclName() << range; - } -} - -/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that -/// check if the expression in a return statement evaluates to an address -/// to a location on the stack, a local block, an address of a label, or a -/// reference to local temporary. The recursion is used to traverse the -/// AST of the return expression, with recursion backtracking when we -/// encounter a subexpression that (1) clearly does not lead to one of the -/// above problematic expressions (2) is something we cannot determine leads to -/// a problematic expression based on such local checking. -/// -/// Both EvalAddr and EvalVal follow through reference variables to evaluate -/// the expression that they point to. Such variables are added to the -/// 'refVars' vector so that we know what the reference variable "trail" was. -/// -/// EvalAddr processes expressions that are pointers that are used as -/// references (and not L-values). EvalVal handles all other values. -/// At the base case of the recursion is a check for the above problematic -/// expressions. -/// -/// This implementation handles: -/// -/// * pointer-to-pointer casts -/// * implicit conversions from array references to pointers -/// * taking the address of fields -/// * arbitrary interplay between "&" and "*" operators -/// * pointer arithmetic from an address of a stack variable -/// * taking the address of an array element where the array is on the stack -static const Expr *EvalAddr(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - if (E->isTypeDependent()) - return nullptr; - - // We should only be called for evaluating pointer expressions. - assert((E->getType()->isAnyPointerType() || - E->getType()->isBlockPointerType() || - E->getType()->isObjCQualifiedIdType()) && - "EvalAddr only works on pointers"); - - E = E->IgnoreParens(); - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: { - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) - // If this is a reference variable, follow through to the expression that - // it points to. - if (V->hasLocalStorage() && - V->getType()->isReferenceType() && V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalAddr(V->getInit(), refVars, ParentDecl); - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is AddrOf. All others don't make sense as pointers. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_AddrOf) - return EvalVal(U->getSubExpr(), refVars, ParentDecl); - return nullptr; - } - - case Stmt::BinaryOperatorClass: { - // Handle pointer arithmetic. All other binary operators are not valid - // in this context. - const BinaryOperator *B = cast<BinaryOperator>(E); - BinaryOperatorKind op = B->getOpcode(); - - if (op != BO_Add && op != BO_Sub) - return nullptr; - - const Expr *Base = B->getLHS(); - - // Determine which argument is the real pointer base. It could be - // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) - Base = B->getRHS(); - - assert(Base->getType()->isPointerType()); - return EvalAddr(Base, refVars, ParentDecl); - } - - // For conditional operators we need to see if either the LHS or RHS are - // valid DeclRefExpr*s. If one of them is valid, we return it. - case Stmt::ConditionalOperatorClass: { - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - // FIXME: That isn't a ConditionalOperator, so doesn't get here. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalAddr(C->getRHS(), refVars, ParentDecl); - } - - case Stmt::BlockExprClass: - if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures()) - return E; // local block. - return nullptr; - - case Stmt::AddrLabelExprClass: - return E; // address of label. - - case Stmt::ExprWithCleanupsClass: - return EvalAddr(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - // For casts, we need to handle conversions from arrays to - // pointer values, and pointer-to-pointer conversions. - case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::ObjCBridgedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXReinterpretCastExprClass: { - const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); - switch (cast<CastExpr>(E)->getCastKind()) { - case CK_LValueToRValue: - case CK_NoOp: - case CK_BaseToDerived: - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - case CK_Dynamic: - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - return EvalAddr(SubExpr, refVars, ParentDecl); - - case CK_ArrayToPointerDecay: - return EvalVal(SubExpr, refVars, ParentDecl); - - case CK_BitCast: - if (SubExpr->getType()->isAnyPointerType() || - SubExpr->getType()->isBlockPointerType() || - SubExpr->getType()->isObjCQualifiedIdType()) - return EvalAddr(SubExpr, refVars, ParentDecl); - else - return nullptr; - - default: - return nullptr; - } - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - // Everything else: we simply don't reason about them. - default: - return nullptr; - } -} - -/// EvalVal - This function is complements EvalAddr in the mutual recursion. -/// See the comments for EvalAddr for more details. -static const Expr *EvalVal(const Expr *E, - SmallVectorImpl<const DeclRefExpr *> &refVars, - const Decl *ParentDecl) { - do { - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but - // instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - - E = E->IgnoreParens(); - switch (E->getStmtClass()) { - case Stmt::ImplicitCastExprClass: { - const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); - if (IE->getValueKind() == VK_LValue) { - E = IE->getSubExpr(); - continue; - } - return nullptr; - } - - case Stmt::ExprWithCleanupsClass: - return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, - ParentDecl); - - case Stmt::DeclRefExprClass: { - // When we hit a DeclRefExpr we are looking at code that refers to a - // variable's name. If it's not a reference variable we check if it has - // local storage within the function, and if so, return the expression. - const DeclRefExpr *DR = cast<DeclRefExpr>(E); - - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; - - if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { - // Check if it refers to itself, e.g. "int& i = i;". - if (V == ParentDecl) - return DR; - - if (V->hasLocalStorage()) { - if (!V->getType()->isReferenceType()) - return DR; - - // Reference variable, follow through to the expression that - // it points to. - if (V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalVal(V->getInit(), refVars, V); - } - } - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - const UnaryOperator *U = cast<UnaryOperator>(E); - - if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars, ParentDecl); - - return nullptr; - } - - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - const auto *ASE = cast<ArraySubscriptExpr>(E); - if (ASE->isTypeDependent()) - return nullptr; - return EvalAddr(ASE->getBase(), refVars, ParentDecl); - } - - case Stmt::OMPArraySectionExprClass: { - return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, - ParentDecl); - } - - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL Expr's. If one is non-NULL, we return it. - const ConditionalOperator *C = cast<ConditionalOperator>(E); - - // Handle the GNU extension for missing LHS. - if (const Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) - return LHS; - } - - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; - - return EvalVal(C->getRHS(), refVars, ParentDecl); - } - - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - const MemberExpr *M = cast<MemberExpr>(E); - - // Check for indirect access. We only want direct field accesses. - if (M->isArrow()) - return nullptr; - - // Check whether the member type is itself a reference, in which case - // we're not going to refer to the member, but to what the member refers - // to. - if (M->getMemberDecl()->getType()->isReferenceType()) - return nullptr; - - return EvalVal(M->getBase(), refVars, ParentDecl); - } - - case Stmt::MaterializeTemporaryExprClass: - if (const Expr *Result = - EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - return E; - - default: - // Check that we don't return or take the address of a reference to a - // temporary. This is only useful in C++. - if (!E->isTypeDependent() && E->isRValue()) - return E; - - // Everything else: we simply don't reason about them. - return nullptr; - } - } while (true); -} - void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod, const AttrVec *Attrs, const FunctionDecl *FD) { - CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); - // Check if the return value is null but should not be. if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || (!isObjCMethod && isNonNullType(Context, lhsType))) && @@ -8168,7 +9255,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, if (Op == OO_New || Op == OO_Array_New) { const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>(); - if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && + if (!Proto->isNothrow(/*ResultIfDependent*/true) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_operator_new_returns_null) << FD << getLangOpts().CPlusPlus11; @@ -8917,7 +10004,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } -/// \brief Implements -Wsign-compare. +/// Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings static void AnalyzeComparison(Sema &S, BinaryOperator *E) { @@ -9205,6 +10292,32 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } +/// Analyze the given compound assignment for the possible losing of +/// floating-point precision. +static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) { + assert(isa<CompoundAssignOperator>(E) && + "Must be compound assignment operation"); + // Recurse on the LHS and RHS in here + AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); + AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); + + // Now check the outermost expression + const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>(); + const auto *RBT = cast<CompoundAssignOperator>(E) + ->getComputationResultType() + ->getAs<BuiltinType>(); + + // If both source and target are floating points. + if (ResultBT && ResultBT->isFloatingPoint() && RBT && RBT->isFloatingPoint()) + // Builtin FP kinds are ordered by increasing FP rank. + if (ResultBT->getKind() < RBT->getKind()) + // We don't want to warn for system macro. + if (!S.SourceMgr.isInSystemMacro(E->getOperatorLoc())) + // warn about dropping FP rank. + DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), + E->getOperatorLoc(), + diag::warn_impcast_float_result_precision); +} /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, @@ -9233,14 +10346,24 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, - &isExact) == llvm::APFloat::opOK && - isExact) { + llvm::APFloat::opStatus Result = Value.convertToInteger( + IntegerValue, llvm::APFloat::rmTowardZero, &isExact); + + if (Result == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } + // Conversion of a floating-point value to a non-bool integer where the + // integral part cannot be represented by the integer type is undefined. + if (!IsBool && Result == llvm::APFloat::opInvalidOp) + return DiagnoseImpCast( + S, E, T, CContext, + IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range + : diag::warn_impcast_float_to_integer_out_of_range, + PruneWarnings); + unsigned DiagID = 0; if (IsLiteral) { // Warn on floating point literal to integer. @@ -9374,18 +10497,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, // Venture through the macro stacks to get to the source of macro arguments. // The new location is a better location than the complete location that was // passed in. - while (S.SourceMgr.isMacroArgExpansion(Loc)) - Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); - - while (S.SourceMgr.isMacroArgExpansion(CC)) - CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); + Loc = S.SourceMgr.getTopMacroCallerLoc(Loc); + CC = S.SourceMgr.getTopMacroCallerLoc(CC); // __null is usually wrapped in a macro. Go up a macro if that is the case. if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( Loc, S.SourceMgr, S.getLangOpts()); if (MacroName == "NULL") - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin(); } // Only warn if the null and context location are in the same macro expansion. @@ -9575,7 +10695,7 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } - + // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) @@ -9852,7 +10972,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, if (E->isTypeDependent() || E->isValueDependent()) return; - + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa<ConditionalOperator>(E)) { @@ -9896,6 +11016,9 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); + // And with compound assignments. + if (BO->isAssignmentOp()) + return AnalyzeCompoundAssignment(S, BO); } // These break the otherwise-useful invariant below. Fortunately, @@ -9939,7 +11062,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } -/// Diagnose integer type and any valid implicit convertion to it. +/// Diagnose integer type and any valid implicit conversion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, // allow any integer. @@ -10002,7 +11125,7 @@ static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { return false; } -/// \brief Diagnose pointers that are always non-null. +/// 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 /// compared to a null pointer @@ -10106,8 +11229,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, return; } - for (unsigned ArgNo : NonNull->args()) { - if (ArgNo == ParamNo) { + for (const ParamIdx &ArgNo : NonNull->args()) { + if (ArgNo.getASTIndex() == ParamNo) { ComplainAboutNonnullParamOrCall(NonNull); return; } @@ -10228,29 +11351,33 @@ void Sema::CheckForIntOverflow (Expr *E) { SmallVector<Expr *, 2> Exprs(1, E); do { - Expr *E = Exprs.pop_back_val(); + Expr *OriginalE = Exprs.pop_back_val(); + Expr *E = OriginalE->IgnoreParenCasts(); - if (isa<BinaryOperator>(E->IgnoreParenCasts())) { - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + if (isa<BinaryOperator>(E)) { + E->EvaluateForOverflow(Context); continue; } - if (auto InitList = dyn_cast<InitListExpr>(E)) + if (auto InitList = dyn_cast<InitListExpr>(OriginalE)) Exprs.append(InitList->inits().begin(), InitList->inits().end()); - - if (isa<ObjCBoxedExpr>(E)) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + else if (isa<ObjCBoxedExpr>(OriginalE)) + E->EvaluateForOverflow(Context); + else if (auto Call = dyn_cast<CallExpr>(E)) + Exprs.append(Call->arg_begin(), Call->arg_end()); + else if (auto Message = dyn_cast<ObjCMessageExpr>(E)) + Exprs.append(Message->arg_begin(), Message->arg_end()); } while (!Exprs.empty()); } namespace { -/// \brief Visitor for expressions which looks for unsequenced operations on the +/// Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { using Base = EvaluatedExprVisitor<SequenceChecker>; - /// \brief A tree of sequenced regions within an expression. Two regions are + /// A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we /// finish processing an expression with sequencing, such as a comma /// expression, we fold its tree nodes into its parent, since they are @@ -10264,7 +11391,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SmallVector<Value, 8> Values; public: - /// \brief A region within an expression which may be sequenced with respect + /// A region within an expression which may be sequenced with respect /// to some other region. class Seq { friend class SequenceTree; @@ -10280,7 +11407,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { SequenceTree() { Values.push_back(Value(0)); } Seq root() const { return Seq(0); } - /// \brief Create a new sequence of operations, which is an unsequenced + /// Create a new sequence of operations, which is an unsequenced /// subset of \p Parent. This sequence of operations is sequenced with /// respect to other children of \p Parent. Seq allocate(Seq Parent) { @@ -10288,12 +11415,12 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return Seq(Values.size() - 1); } - /// \brief Merge a sequence of operations into its parent. + /// Merge a sequence of operations into its parent. void merge(Seq S) { Values[S.Index].Merged = true; } - /// \brief Determine whether two operations are unsequenced. This operation + /// Determine whether two operations are unsequenced. This operation /// is asymmetric: \p Cur should be the more recent sequence, and \p Old /// should have been merged into its parent as appropriate. bool isUnsequenced(Seq Cur, Seq Old) { @@ -10308,7 +11435,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } private: - /// \brief Pick a representative for a sequence. + /// Pick a representative for a sequence. unsigned representative(unsigned K) { if (Values[K].Merged) // Perform path compression as we go. @@ -10429,7 +11556,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { bool EvalOK = true; } *EvalTracker = nullptr; - /// \brief Find the object which is produced by the specified expression, + /// Find the object which is produced by the specified expression, /// if any. Object getObject(Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); @@ -10451,7 +11578,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { return nullptr; } - /// \brief Note that an object was modified or used by an expression. + /// Note that an object was modified or used by an expression. void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { Usage &U = UI.Uses[UK]; if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { @@ -10462,7 +11589,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } } - /// \brief Check whether a modification or use conflicts with a prior usage. + /// Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) @@ -10841,23 +11968,18 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, // information is added for it. diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); - // MSVC destroys objects passed by value in the callee. Therefore a - // function definition which takes such a parameter must be able to call the - // object's destructor. However, we don't perform any direct access check - // on the dtor. - if (getLangOpts().CPlusPlus && Context.getTargetInfo() - .getCXXABI() - .areArgsDestroyedLeftToRightInCallee()) { - if (!Param->isInvalidDecl()) { - if (const RecordType *RT = Param->getType()->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->isInvalidDecl() && - !ClassDecl->hasIrrelevantDestructor() && - !ClassDecl->isDependentContext()) { - CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - MarkFunctionReferenced(Param->getLocation(), Destructor); - DiagnoseUseOfDecl(Destructor, Param->getLocation()); - } + // If the parameter is a c++ class type and it has to be destructed in the + // callee function, declare the destructor so that it can be called by the + // callee function. Do not perform any direct access check on the dtor here. + if (!Param->isInvalidDecl()) { + if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) { + if (!ClassDecl->isInvalidDecl() && + !ClassDecl->hasIrrelevantDestructor() && + !ClassDecl->isDependentContext() && + ClassDecl->isParamDestroyedInCallee()) { + CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); + MarkFunctionReferenced(Param->getLocation(), Destructor); + DiagnoseUseOfDecl(Destructor, Param->getLocation()); } } } @@ -10940,7 +12062,7 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -/// \brief Check whether this array fits the idiom of a size-one tail padded +/// Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are @@ -11010,9 +12132,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const NamedDecl *ND = nullptr; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); @@ -11095,9 +12217,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, dyn_cast<ArraySubscriptExpr>(BaseExpr)) BaseExpr = ASE->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(DRE->getDecl()); + ND = DRE->getDecl(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); + ND = ME->getMemberDecl(); } if (ND) @@ -11115,7 +12237,12 @@ void Sema::CheckArrayAccess(const Expr *expr) { const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0); - return; + expr = ASE->getBase(); + break; + } + case Stmt::MemberExprClass: { + expr = cast<MemberExpr>(expr)->getBase(); + break; } case Stmt::OMPArraySectionExprClass: { const OMPArraySectionExpr *ASE = cast<OMPArraySectionExpr>(expr); @@ -11525,7 +12652,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { if (ArgRE->isObjCSelfExpr()) { Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << ArgRE->getDecl()->getName() << StringRef("super"); + << ArgRE->getDecl() << StringRef("'super'"); } } } else { @@ -11541,11 +12668,11 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ValueDecl *Decl = ReceiverRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; if (!ArgRE->isObjCSelfExpr()) { Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11555,10 +12682,10 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { ObjCIvarDecl *Decl = IvarRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) - << Decl->getName() << Decl->getName(); + << Decl << Decl; Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) - << Decl->getName(); + << Decl; } } } @@ -11951,7 +13078,7 @@ void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); -/// \brief Check if two enumeration types are layout-compatible. +/// Check if two enumeration types are layout-compatible. static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same @@ -11960,7 +13087,7 @@ static bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); } -/// \brief Check if two fields are layout-compatible. +/// Check if two fields are layout-compatible. static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) @@ -11981,7 +13108,7 @@ static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, return true; } -/// \brief Check if two standard-layout structs are layout-compatible. +/// Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12025,7 +13152,7 @@ static bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, return true; } -/// \brief Check if two standard-layout unions are layout-compatible. +/// Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) static bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { @@ -12064,7 +13191,7 @@ static bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, return isLayoutCompatibleStruct(C, RD1, RD2); } -/// \brief Check if two types are layout-compatible in C++11 sense. +/// Check if two types are layout-compatible in C++11 sense. static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; @@ -12102,7 +13229,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// -/// \brief Given a type tag expression find the type tag itself. +/// Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. /// @@ -12173,7 +13300,7 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, } } -/// \brief Retrieve the C type corresponding to type tag TypeExpr. +/// Retrieve the C type corresponding to type tag TypeExpr. /// /// \param TypeExpr Expression that specifies a type tag. /// @@ -12267,13 +13394,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, bool IsPointerAttr = Attr->getIsPointer(); // Retrieve the argument representing the 'type_tag'. - if (Attr->getTypeTagIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex(); + if (TypeTagIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 0 << Attr->getTypeTagIdx() + 1; + << 0 << Attr->getTypeTagIdx().getSourceIndex(); return; } - const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; + const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST]; bool FoundWrongKind; TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, @@ -12287,13 +13414,13 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, } // Retrieve the argument representing the 'arg_idx'. - if (Attr->getArgumentIdx() >= ExprArgs.size()) { - // Add 1 to display the user's specified value. + unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex(); + if (ArgumentIdxAST >= ExprArgs.size()) { Diag(CallSiteLoc, diag::err_tag_index_out_of_range) - << 1 << Attr->getArgumentIdx() + 1; + << 1 << Attr->getArgumentIdx().getSourceIndex(); return; } - const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; + const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index 2acc896d53d7..4e571eba17e9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -40,39 +40,39 @@ using namespace clang; using namespace sema; namespace { - /// \brief A container of code-completion results. + /// A container of code-completion results. class ResultBuilder { public: - /// \brief The type of a name-lookup filter, which can be provided to the + /// The type of a name-lookup filter, which can be provided to the /// name-lookup routines to specify which declarations should be included in /// the result set (when it returns true) and which declarations should be /// filtered out (returns false). typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const; typedef CodeCompletionResult Result; - + private: - /// \brief The actual results we have found. + /// The actual results we have found. std::vector<Result> Results; - - /// \brief A record of all of the declarations we have found and placed + + /// A record of all of the declarations we have found and placed /// into the result set, used to ensure that no declaration ever gets into /// the result set twice. llvm::SmallPtrSet<const Decl*, 16> AllDeclsFound; - + typedef std::pair<const NamedDecl *, unsigned> DeclIndexPair; - /// \brief An entry in the shadow map, which is optimized to store + /// An entry in the shadow map, which is optimized to store /// a single (declaration, index) mapping (the common case) but /// can also store a list of (declaration, index) mappings. class ShadowMapEntry { typedef SmallVector<DeclIndexPair, 4> DeclIndexPairVector; - /// \brief Contains either the solitary NamedDecl * or a vector + /// Contains either the solitary NamedDecl * or a vector /// of (declaration, index) pairs. llvm::PointerUnion<const NamedDecl *, DeclIndexPairVector*> DeclOrVector; - /// \brief When the entry contains a single declaration, this is + /// When the entry contains a single declaration, this is /// the index associated with that entry. unsigned SingleDeclIndex; @@ -115,72 +115,72 @@ namespace { iterator end() const; }; - /// \brief A mapping from declaration names to the declarations that have + /// A mapping from declaration names to the declarations that have /// this name within a particular scope and their index within the list of /// results. typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap; - - /// \brief The semantic analysis object for which results are being + + /// The semantic analysis object for which results are being /// produced. Sema &SemaRef; - /// \brief The allocator used to allocate new code-completion strings. + /// The allocator used to allocate new code-completion strings. CodeCompletionAllocator &Allocator; CodeCompletionTUInfo &CCTUInfo; - - /// \brief If non-NULL, a filter function used to remove any code-completion + + /// If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. LookupFilter Filter; - /// \brief Whether we should allow declarations as + /// Whether we should allow declarations as /// nested-name-specifiers that would otherwise be filtered out. bool AllowNestedNameSpecifiers; - /// \brief If set, the type that we would prefer our resulting value + /// If set, the type that we would prefer our resulting value /// declarations to have. /// - /// Closely matching the preferred type gives a boost to a result's + /// Closely matching the preferred type gives a boost to a result's /// priority. CanQualType PreferredType; - - /// \brief A list of shadow maps, which is used to model name hiding at + + /// A list of shadow maps, which is used to model name hiding at /// different levels of, e.g., the inheritance hierarchy. std::list<ShadowMap> ShadowMaps; - - /// \brief If we're potentially referring to a C++ member function, the set + + /// If we're potentially referring to a C++ member function, the set /// of qualifiers applied to the object type. Qualifiers ObjectTypeQualifiers; - - /// \brief Whether the \p ObjectTypeQualifiers field is active. + + /// Whether the \p ObjectTypeQualifiers field is active. bool HasObjectTypeQualifiers; - - /// \brief The selector that we prefer. + + /// The selector that we prefer. Selector PreferredSelector; - - /// \brief The completion context in which we are gathering results. + + /// The completion context in which we are gathering results. CodeCompletionContext CompletionContext; - - /// \brief If we are in an instance method definition, the \@implementation + + /// If we are in an instance method definition, the \@implementation /// object. ObjCImplementationDecl *ObjCImplementation; void AdjustResultPriorityForDecl(Result &R); void MaybeAddConstructorResults(Result R); - + public: explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, const CodeCompletionContext &CompletionContext, LookupFilter Filter = nullptr) : SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo), - Filter(Filter), - AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false), + Filter(Filter), + AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false), CompletionContext(CompletionContext), ObjCImplementation(nullptr) - { - // If this is an Objective-C instance method definition, dig out the + { + // If this is an Objective-C instance method definition, dig out the // corresponding implementation. switch (CompletionContext.getKind()) { case CodeCompletionContext::CCC_Expression: @@ -193,23 +193,23 @@ namespace { if (ObjCInterfaceDecl *Interface = Method->getClassInterface()) ObjCImplementation = Interface->getImplementation(); break; - + default: break; } } - /// \brief Determine the priority for a reference to the given declaration. + /// Determine the priority for a reference to the given declaration. unsigned getBasePriority(const NamedDecl *D); - /// \brief Whether we should include code patterns in the completion + /// Whether we should include code patterns in the completion /// results. bool includeCodePatterns() const { - return SemaRef.CodeCompleter && + return SemaRef.CodeCompleter && SemaRef.CodeCompleter->includeCodePatterns(); } - - /// \brief Set the filter used for code-completion results. + + /// Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { this->Filter = Filter; } @@ -217,25 +217,25 @@ namespace { Result *data() { return Results.empty()? nullptr : &Results.front(); } unsigned size() const { return Results.size(); } bool empty() const { return Results.empty(); } - - /// \brief Specify the preferred type. - void setPreferredType(QualType T) { - PreferredType = SemaRef.Context.getCanonicalType(T); + + /// Specify the preferred type. + void setPreferredType(QualType T) { + PreferredType = SemaRef.Context.getCanonicalType(T); } - - /// \brief Set the cv-qualifiers on the object type, for us in filtering + + /// Set the cv-qualifiers on the object type, for us in filtering /// calls to member functions. /// /// When there are qualifiers in this set, they will be used to filter - /// out member functions that aren't available (because there will be a + /// out member functions that aren't available (because there will be a /// cv-qualifier mismatch) or prefer functions with an exact qualifier /// match. void setObjectTypeQualifiers(Qualifiers Quals) { ObjectTypeQualifiers = Quals; HasObjectTypeQualifiers = true; } - - /// \brief Set the preferred selector. + + /// Set the preferred selector. /// /// When an Objective-C method declaration result is added, and that /// method's selector matches this preferred selector, we give that method @@ -243,28 +243,28 @@ namespace { void setPreferredSelector(Selector Sel) { PreferredSelector = Sel; } - - /// \brief Retrieve the code-completion context for which results are + + /// Retrieve the code-completion context for which results are /// being collected. - const CodeCompletionContext &getCompletionContext() const { - return CompletionContext; + const CodeCompletionContext &getCompletionContext() const { + return CompletionContext; } - - /// \brief Specify whether nested-name-specifiers are allowed. + + /// Specify whether nested-name-specifiers are allowed. void allowNestedNameSpecifiers(bool Allow = true) { AllowNestedNameSpecifiers = Allow; } - /// \brief Return the semantic analysis object for which we are collecting + /// Return the semantic analysis object for which we are collecting /// code completion results. Sema &getSema() const { return SemaRef; } - - /// \brief Retrieve the allocator used to allocate code completion strings. + + /// Retrieve the allocator used to allocate code completion strings. CodeCompletionAllocator &getAllocator() const { return Allocator; } CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; } - - /// \brief Determine whether the given declaration is at all interesting + + /// Determine whether the given declaration is at all interesting /// as a code-completion result. /// /// \param ND the declaration that we are inspecting. @@ -273,8 +273,8 @@ namespace { /// only interesting when it is a nested-name-specifier. bool isInterestingDecl(const NamedDecl *ND, bool &AsNestedNameSpecifier) const; - - /// \brief Check whether the result is hidden by the Hiding declaration. + + /// Check whether the result is hidden by the Hiding declaration. /// /// \returns true if the result is hidden and cannot be found, false if /// the hidden result could still be found. When false, \p R may be @@ -282,9 +282,9 @@ namespace { /// qualification). bool CheckHiddenResult(Result &R, DeclContext *CurContext, const NamedDecl *Hiding); - - /// \brief Add a new result to this result set (if it isn't already in one - /// of the shadow maps), or replace an existing result (for, e.g., a + + /// Add a new result to this result set (if it isn't already in one + /// of the shadow maps), or replace an existing result (for, e.g., a /// redeclaration). /// /// \param R the result to add (if it is unique). @@ -292,7 +292,7 @@ namespace { /// \param CurContext the context in which this result will be named. void MaybeAddResult(Result R, DeclContext *CurContext = nullptr); - /// \brief Add a new result to this result set, where we already know + /// Add a new result to this result set, where we already know /// the hiding declaration (if any). /// /// \param R the result to add (if it is unique). @@ -305,24 +305,29 @@ namespace { /// class of the searched context. void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, bool InBaseClass); - - /// \brief Add a new non-declaration result to this result set. + + /// Add a new non-declaration result to this result set. void AddResult(Result R); - /// \brief Enter into a new scope. + /// Enter into a new scope. void EnterNewScope(); - - /// \brief Exit from the current scope. + + /// Exit from the current scope. void ExitScope(); - - /// \brief Ignore this declaration, if it is seen again. + + /// Ignore this declaration, if it is seen again. void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); } + /// Add a visited context. + void addVisitedContext(DeclContext *Ctx) { + CompletionContext.addVisitedContext(Ctx); + } + /// \name Name lookup predicates /// /// These predicates can be passed to the name lookup functions to filter the /// results of name lookup. All of the predicates have the same type, so that - /// + /// //@{ bool IsOrdinaryName(const NamedDecl *ND) const; bool IsOrdinaryNonTypeName(const NamedDecl *ND) const; @@ -341,8 +346,8 @@ namespace { bool IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const; bool IsObjCCollection(const NamedDecl *ND) const; bool IsImpossibleToSatisfy(const NamedDecl *ND) const; - //@} - }; + //@} + }; } class ResultBuilder::ShadowMapEntry::iterator { @@ -354,7 +359,7 @@ public: typedef value_type reference; typedef std::ptrdiff_t difference_type; typedef std::input_iterator_tag iterator_category; - + class pointer { DeclIndexPair Value; @@ -415,7 +420,7 @@ public: } }; -ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::iterator ResultBuilder::ShadowMapEntry::begin() const { if (DeclOrVector.isNull()) return iterator(); @@ -426,7 +431,7 @@ ResultBuilder::ShadowMapEntry::begin() const { return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin()); } -ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::iterator ResultBuilder::ShadowMapEntry::end() const { if (DeclOrVector.is<const NamedDecl *>() || DeclOrVector.isNull()) return iterator(); @@ -434,7 +439,7 @@ ResultBuilder::ShadowMapEntry::end() const { return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end()); } -/// \brief Compute the qualification required to get from the current context +/// Compute the qualification required to get from the current context /// (\p CurContext) to the target context (\p TargetContext). /// /// \param Context the AST context in which the qualification will be used. @@ -442,7 +447,7 @@ ResultBuilder::ShadowMapEntry::end() const { /// \param CurContext the context where an entity is being named, which is /// typically based on the current scope. /// -/// \param TargetContext the context in which the named entity actually +/// \param TargetContext the context in which the named entity actually /// resides. /// /// \returns a nested name specifier that refers into the target context, or @@ -452,14 +457,14 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, const DeclContext *TargetContext) { SmallVector<const DeclContext *, 4> TargetParents; - + for (const DeclContext *CommonAncestor = TargetContext; CommonAncestor && !CommonAncestor->Encloses(CurContext); CommonAncestor = CommonAncestor->getLookupParent()) { if (CommonAncestor->isTransparentContext() || CommonAncestor->isFunctionOrMethod()) continue; - + TargetParents.push_back(CommonAncestor); } @@ -477,7 +482,7 @@ getRequiredQualification(ASTContext &Context, Result = NestedNameSpecifier::Create(Context, Result, false, Context.getTypeDeclType(TD).getTypePtr()); - } + } return Result; } @@ -526,17 +531,17 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND, // Skip unnamed entities. if (!ND->getDeclName()) return false; - + // Friend declarations and declarations introduced due to friends are never // added as results. if (ND->getFriendObjectKind() == Decl::FOK_Undeclared) return false; - + // Class template (partial) specializations are never added as results. if (isa<ClassTemplateSpecializationDecl>(ND) || isa<ClassTemplatePartialSpecializationDecl>(ND)) return false; - + // Using declarations themselves are never added as results. if (isa<UsingDecl>(ND)) return false; @@ -554,17 +559,17 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND, // Filter out any unwanted results. if (Filter && !(this->*Filter)(Named)) { // Check whether it is interesting as a nested-name-specifier. - if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus && + if (AllowNestedNameSpecifiers && SemaRef.getLangOpts().CPlusPlus && IsNestedNameSpecifier(ND) && (Filter != &ResultBuilder::IsMember || - (isa<CXXRecordDecl>(ND) && + (isa<CXXRecordDecl>(ND) && cast<CXXRecordDecl>(ND)->isInjectedClassName()))) { AsNestedNameSpecifier = true; return true; } return false; - } + } // ... then it must be interesting! return true; } @@ -576,29 +581,29 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, // name if we introduce the tag type. if (!SemaRef.getLangOpts().CPlusPlus) return true; - + const DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext(); - + // There is no way to qualify a name declared in a function or method. if (HiddenCtx->isFunctionOrMethod()) return true; - + if (HiddenCtx == Hiding->getDeclContext()->getRedeclContext()) return true; - + // We can refer to the result with the appropriate qualification. Do it. R.Hidden = true; R.QualifierIsInformative = false; - + if (!R.Qualifier) - R.Qualifier = getRequiredQualification(SemaRef.Context, - CurContext, + R.Qualifier = getRequiredQualification(SemaRef.Context, + CurContext, R.Declaration->getDeclContext()); return false; } -/// \brief A simplified classification of types used to determine whether two +/// A simplified classification of types used to determine whether two /// types are "similar enough" when adjusting priorities. SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { switch (T->getTypeClass()) { @@ -606,77 +611,77 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { switch (cast<BuiltinType>(T)->getKind()) { case BuiltinType::Void: return STC_Void; - + case BuiltinType::NullPtr: return STC_Pointer; - + case BuiltinType::Overload: case BuiltinType::Dependent: return STC_Other; - + case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: return STC_ObjectiveC; - + default: return STC_Arithmetic; } case Type::Complex: return STC_Arithmetic; - + case Type::Pointer: return STC_Pointer; - + case Type::BlockPointer: return STC_Block; - + case Type::LValueReference: case Type::RValueReference: return getSimplifiedTypeClass(T->getAs<ReferenceType>()->getPointeeType()); - + case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: return STC_Array; - + case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: return STC_Arithmetic; - + case Type::FunctionProto: case Type::FunctionNoProto: return STC_Function; - + case Type::Record: return STC_Record; - + case Type::Enum: return STC_Arithmetic; - + case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: return STC_ObjectiveC; - + default: return STC_Other; } } -/// \brief Get the type that a given expression will have if this declaration +/// Get the type that a given expression will have if this declaration /// is used as an expression in its "typical" code-completion form. QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) { - ND = cast<NamedDecl>(ND->getUnderlyingDecl()); - + ND = ND->getUnderlyingDecl(); + if (const TypeDecl *Type = dyn_cast<TypeDecl>(ND)) return C.getTypeDeclType(Type); if (const ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND)) return C.getObjCInterfaceType(Iface); - + QualType T; if (const FunctionDecl *Function = ND->getAsFunction()) T = Function->getCallResultType(); @@ -721,7 +726,7 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) { break; } while (true); - + return T; } @@ -781,7 +786,7 @@ void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration)) if (PreferredSelector == Method->getSelector()) R.Priority += CCD_SelectorMatch; - + // If we have a preferred type, adjust the priority for results with exactly- // matching or nearly-matching types. if (!PreferredType.isNull()) { @@ -795,16 +800,16 @@ void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { else if ((getSimplifiedTypeClass(PreferredType) == getSimplifiedTypeClass(TC)) && !(PreferredType->isEnumeralType() && TC->isEnumeralType())) - R.Priority /= CCF_SimilarTypeMatch; + R.Priority /= CCF_SimilarTypeMatch; } - } + } } void ResultBuilder::MaybeAddConstructorResults(Result R) { if (!SemaRef.getLangOpts().CPlusPlus || !R.Declaration || !CompletionContext.wantConstructorResults()) return; - + ASTContext &Context = SemaRef.Context; const NamedDecl *D = R.Declaration; const CXXRecordDecl *Record = nullptr; @@ -818,12 +823,12 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) { // There are no constructors here. return; } - + Record = Record->getDefinition(); if (!Record) return; - + QualType RecordTy = Context.getTypeDeclType(Record); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( @@ -838,9 +843,15 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) { } } +static bool isConstructor(const Decl *ND) { + if (const auto *Tmpl = dyn_cast<FunctionTemplateDecl>(ND)) + ND = Tmpl->getTemplatedDecl(); + return isa<CXXConstructorDecl>(ND); +} + void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { assert(!ShadowMaps.empty() && "Must enter into a results scope"); - + if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. Results.push_back(R); @@ -848,24 +859,24 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { } // Look through using declarations. - if (const UsingShadowDecl *Using = - dyn_cast<UsingShadowDecl>(R.Declaration)) { - MaybeAddResult(Result(Using->getTargetDecl(), - getBasePriority(Using->getTargetDecl()), - R.Qualifier), - CurContext); + if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { + CodeCompletionResult Result(Using->getTargetDecl(), + getBasePriority(Using->getTargetDecl()), + R.Qualifier); + Result.ShadowDecl = Using; + MaybeAddResult(Result, CurContext); return; } - + const Decl *CanonDecl = R.Declaration->getCanonicalDecl(); unsigned IDNS = CanonDecl->getIdentifierNamespace(); bool AsNestedNameSpecifier = false; if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; - + // C++ constructors are never found by name lookup. - if (isa<CXXConstructorDecl>(R.Declaration)) + if (isConstructor(R.Declaration)) return; ShadowMap &SMap = ShadowMaps.back(); @@ -882,12 +893,12 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (ND->getCanonicalDecl() == CanonDecl) { // This is a redeclaration. Always pick the newer declaration. Results[Index].Declaration = R.Declaration; - + // We're done. return; } } - + // This is a new declaration in this scope. However, check whether this // declaration name is hidden by a similarly-named declaration in an outer // scope. @@ -906,21 +917,21 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern | Decl::IDNS_ObjCProtocol))) continue; - + // Protocols are in distinct namespaces from everything else. if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && I->first->getIdentifierNamespace() != IDNS) continue; - + // The newly-added result is hidden by an entry in the shadow map. if (CheckHiddenResult(R, CurContext, I->first)) return; - + break; } } - + // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(CanonDecl).second) return; @@ -930,9 +941,9 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; - } else + } else AdjustResultPriorityForDecl(R); - + // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { @@ -946,17 +957,17 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { else R.QualifierIsInformative = false; } - + // Insert this result into the set of results and into the current shadow // map. SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size()); Results.push_back(R); - + if (!AsNestedNameSpecifier) MaybeAddConstructorResults(R); } -void ResultBuilder::AddResult(Result R, DeclContext *CurContext, +void ResultBuilder::AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, bool InBaseClass = false) { if (R.Kind != Result::RK_Declaration) { // For non-declaration results, just add the result. @@ -966,19 +977,20 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, // Look through using declarations. if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { - AddResult(Result(Using->getTargetDecl(), - getBasePriority(Using->getTargetDecl()), - R.Qualifier), - CurContext, Hiding); + CodeCompletionResult Result(Using->getTargetDecl(), + getBasePriority(Using->getTargetDecl()), + R.Qualifier); + Result.ShadowDecl = Using; + AddResult(Result, CurContext, Hiding); return; } - + bool AsNestedNameSpecifier = false; if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) return; - + // C++ constructors are never found by name lookup. - if (isa<CXXConstructorDecl>(R.Declaration)) + if (isConstructor(R.Declaration)) return; if (Hiding && CheckHiddenResult(R, CurContext, Hiding)) @@ -987,16 +999,16 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl()).second) return; - + // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { R.StartsNestedNameSpecifier = true; R.Priority = CCP_NestedNameSpecifier; - } - else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && - isa<CXXRecordDecl>(R.Declaration->getDeclContext() - ->getRedeclContext())) + } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && + InBaseClass && + isa<CXXRecordDecl>( + R.Declaration->getDeclContext()->getRedeclContext())) R.QualifierIsInformative = true; // If this result is supposed to have an informative qualifier, add one. @@ -1012,13 +1024,13 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, else R.QualifierIsInformative = false; } - + // Adjust the priority if this result comes from a base class. if (InBaseClass) R.Priority += CCD_InBaseClass; - + AdjustResultPriorityForDecl(R); - + if (HasObjectTypeQualifiers) if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration)) if (Method->isInstance()) { @@ -1027,43 +1039,43 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (ObjectTypeQualifiers == MethodQuals) R.Priority += CCD_ObjectQualifierMatch; else if (ObjectTypeQualifiers - MethodQuals) { - // The method cannot be invoked, because doing so would drop + // The method cannot be invoked, because doing so would drop // qualifiers. return; } } - + // Insert this result into the set of results. Results.push_back(R); - + if (!AsNestedNameSpecifier) MaybeAddConstructorResults(R); } void ResultBuilder::AddResult(Result R) { - assert(R.Kind != Result::RK_Declaration && + assert(R.Kind != Result::RK_Declaration && "Declaration results need more context"); Results.push_back(R); } -/// \brief Enter into a new scope. +/// Enter into a new scope. void ResultBuilder::EnterNewScope() { ShadowMaps.emplace_back(); } -/// \brief Exit from the current scope. +/// Exit from the current scope. void ResultBuilder::ExitScope() { for (ShadowMap::iterator E = ShadowMaps.back().begin(), EEnd = ShadowMaps.back().end(); E != EEnd; ++E) E->second.Destroy(); - + ShadowMaps.pop_back(); } -/// \brief Determines whether this given declaration will be found by +/// Determines whether this given declaration will be found by /// ordinary name lookup. bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { - ND = cast<NamedDecl>(ND->getUnderlyingDecl()); + ND = ND->getUnderlyingDecl(); // If name lookup finds a local extern declaration, then we are in a // context where it behaves like an ordinary name. @@ -1074,14 +1086,14 @@ bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const { if (isa<ObjCIvarDecl>(ND)) return true; } - + return ND->getIdentifierNamespace() & IDNS; } -/// \brief Determines whether this given declaration will be found by +/// Determines whether this given declaration will be found by /// ordinary name lookup but is not a type name. bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { - ND = cast<NamedDecl>(ND->getUnderlyingDecl()); + ND = ND->getUnderlyingDecl(); if (isa<TypeDecl>(ND)) return false; // Objective-C interfaces names are not filtered by this method because they @@ -1099,51 +1111,51 @@ bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const { if (isa<ObjCIvarDecl>(ND)) return true; } - + return ND->getIdentifierNamespace() & IDNS; } bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const { if (!IsOrdinaryNonTypeName(ND)) return 0; - + if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl())) if (VD->getType()->isIntegralOrEnumerationType()) return true; - + return false; } -/// \brief Determines whether this given declaration will be found by +/// Determines whether this given declaration will be found by /// ordinary name lookup. bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const { - ND = cast<NamedDecl>(ND->getUnderlyingDecl()); + ND = ND->getUnderlyingDecl(); unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_LocalExtern; if (SemaRef.getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; - - return (ND->getIdentifierNamespace() & IDNS) && - !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND) && + + return (ND->getIdentifierNamespace() & IDNS) && + !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND) && !isa<ObjCPropertyDecl>(ND); } -/// \brief Determines whether the given declaration is suitable as the +/// Determines whether the given declaration is suitable as the /// start of a C++ nested-name-specifier, e.g., a class or namespace. bool ResultBuilder::IsNestedNameSpecifier(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) ND = ClassTemplate->getTemplatedDecl(); - + return SemaRef.isAcceptableNestedNameSpecifier(ND); } -/// \brief Determines whether the given declaration is an enumeration. +/// Determines whether the given declaration is an enumeration. bool ResultBuilder::IsEnum(const NamedDecl *ND) const { return isa<EnumDecl>(ND); } -/// \brief Determines whether the given declaration is a class or struct. +/// Determines whether the given declaration is a class or struct. bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) @@ -1154,40 +1166,40 @@ bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const { return RD->getTagKind() == TTK_Class || RD->getTagKind() == TTK_Struct || RD->getTagKind() == TTK_Interface; - + return false; } -/// \brief Determines whether the given declaration is a union. +/// Determines whether the given declaration is a union. bool ResultBuilder::IsUnion(const NamedDecl *ND) const { // Allow us to find class templates, too. if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) ND = ClassTemplate->getTemplatedDecl(); - + if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND)) return RD->getTagKind() == TTK_Union; - + return false; } -/// \brief Determines whether the given declaration is a namespace. +/// Determines whether the given declaration is a namespace. bool ResultBuilder::IsNamespace(const NamedDecl *ND) const { return isa<NamespaceDecl>(ND); } -/// \brief Determines whether the given declaration is a namespace or +/// Determines whether the given declaration is a namespace or /// namespace alias. bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const { return isa<NamespaceDecl>(ND->getUnderlyingDecl()); } -/// \brief Determines whether the given declaration is a type. +/// Determines whether the given declaration is a type. bool ResultBuilder::IsType(const NamedDecl *ND) const { ND = ND->getUnderlyingDecl(); return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND); } -/// \brief Determines which members of a class should be visible via +/// Determines which members of a class should be visible via /// "." or "->". Only value declarations, nested name specifiers, and /// using declarations thereof should show up. bool ResultBuilder::IsMember(const NamedDecl *ND) const { @@ -1199,31 +1211,31 @@ bool ResultBuilder::IsMember(const NamedDecl *ND) const { static bool isObjCReceiverType(ASTContext &C, QualType T) { T = C.getCanonicalType(T); switch (T->getTypeClass()) { - case Type::ObjCObject: + case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: return true; - + case Type::Builtin: switch (cast<BuiltinType>(T)->getKind()) { case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: return true; - + default: break; } return false; - + default: break; } - + if (!C.getLangOpts().CPlusPlus) return false; - // FIXME: We could perform more analysis here to determine whether a + // FIXME: We could perform more analysis here to determine whether a // particular class type has any conversions to Objective-C types. For now, // just accept all class types. return T->isDependentType() || T->isRecordType(); @@ -1233,7 +1245,7 @@ bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const { QualType T = getDeclUsageType(SemaRef.Context, ND); if (T.isNull()) return false; - + T = SemaRef.Context.getBaseElementType(T); return isObjCReceiverType(SemaRef.Context, T); } @@ -1241,11 +1253,11 @@ bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const { bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const { if (IsObjCMessageReceiver(ND)) return true; - + const VarDecl *Var = dyn_cast<VarDecl>(ND); if (!Var) return false; - + return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>(); } @@ -1253,14 +1265,14 @@ bool ResultBuilder::IsObjCCollection(const NamedDecl *ND) const { if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) || (!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND))) return false; - + QualType T = getDeclUsageType(SemaRef.Context, ND); if (T.isNull()) return false; - + T = SemaRef.Context.getBaseElementType(T); return T->isObjCObjectType() || T->isObjCObjectPointerType() || - T->isObjCIdType() || + T->isObjCIdType() || (SemaRef.getLangOpts().CPlusPlus && T->isRecordType()); } @@ -1268,37 +1280,69 @@ bool ResultBuilder::IsImpossibleToSatisfy(const NamedDecl *ND) const { return false; } -/// \brief Determines whether the given declaration is an Objective-C +/// Determines whether the given declaration is an Objective-C /// instance variable. bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const { return isa<ObjCIvarDecl>(ND); } namespace { - /// \brief Visible declaration consumer that adds a code-completion result + /// Visible declaration consumer that adds a code-completion result /// for each visible declaration. class CodeCompletionDeclConsumer : public VisibleDeclConsumer { ResultBuilder &Results; DeclContext *CurContext; - + std::vector<FixItHint> FixIts; + public: - CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) - : Results(Results), CurContext(CurContext) { } + CodeCompletionDeclConsumer( + ResultBuilder &Results, DeclContext *CurContext, + std::vector<FixItHint> FixIts = std::vector<FixItHint>()) + : Results(Results), CurContext(CurContext), FixIts(std::move(FixIts)) {} void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) override { bool Accessible = true; - if (Ctx) - Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx); + if (Ctx) { + DeclContext *AccessingCtx = Ctx; + // If ND comes from a base class, set the naming class back to the + // derived class if the search starts from the derived class (i.e. + // InBaseClass is true). + // + // Example: + // class B { protected: int X; } + // class D : public B { void f(); } + // void D::f() { this->^; } + // The completion after "this->" will have `InBaseClass` set to true and + // `Ctx` set to "B", when looking up in `B`. We need to set the actual + // accessing context (i.e. naming class) to "D" so that access can be + // calculated correctly. + if (InBaseClass && isa<CXXRecordDecl>(Ctx)) { + CXXRecordDecl *RC = nullptr; + // Get the enclosing record. + for (DeclContext *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if ((RC = dyn_cast<CXXRecordDecl>(DC))) + break; + } + if (RC) + AccessingCtx = RC; + } + Accessible = Results.getSema().IsSimplyAccessible(ND, AccessingCtx); + } ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr, - false, Accessible); + false, Accessible, FixIts); Results.AddResult(Result, CurContext, Hiding, InBaseClass); } + + void EnteredContext(DeclContext* Ctx) override { + Results.addVisitedContext(Ctx); + } }; } -/// \brief Add type specifiers for the current language as keyword results. +/// Add type specifiers for the current language as keyword results. static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; @@ -1324,16 +1368,16 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Results.AddResult(Result("_Bool", CCP_Type)); Results.AddResult(Result("restrict", CCP_Type)); } - + CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (LangOpts.CPlusPlus) { // C++-specific - Results.AddResult(Result("bool", CCP_Type + + Results.AddResult(Result("bool", CCP_Type + (LangOpts.ObjC1? CCD_bool_in_ObjC : 0))); Results.AddResult(Result("class", CCP_Type)); Results.AddResult(Result("wchar_t", CCP_Type)); - + // typename qualified-id Builder.AddTypedTextChunk("typename"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -1341,12 +1385,12 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); - + if (LangOpts.CPlusPlus11) { Results.AddResult(Result("auto", CCP_Type)); Results.AddResult(Result("char16_t", CCP_Type)); Results.AddResult(Result("char32_t", CCP_Type)); - + Builder.AddTypedTextChunk("decltype"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); @@ -1356,13 +1400,13 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, } else Results.AddResult(Result("__auto_type", CCP_Type)); - // GNU extensions - if (LangOpts.GNUMode) { + // GNU keywords + if (LangOpts.GNUKeywords) { // FIXME: Enable when we actually support decimal floating point. // Results.AddResult(Result("_Decimal32")); // Results.AddResult(Result("_Decimal64")); // Results.AddResult(Result("_Decimal128")); - + Builder.AddTypedTextChunk("typeof"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); @@ -1382,7 +1426,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, } static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC, - const LangOptions &LangOpts, + const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; // Note: we don't suggest either "auto" or "register", because both @@ -1408,7 +1452,7 @@ static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC, } static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, - const LangOptions &LangOpts, + const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; switch (CCC) { @@ -1419,7 +1463,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, Results.AddResult(Result("friend")); Results.AddResult(Result("mutable")); Results.AddResult(Result("virtual")); - } + } LLVM_FALLTHROUGH; case Sema::PCC_ObjCInterface: @@ -1447,7 +1491,7 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt); static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt); static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, - bool NeedAt); + bool NeedAt); static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt); @@ -1464,7 +1508,7 @@ static void AddTypedefResult(ResultBuilder &Results) { Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); - Results.AddResult(CodeCompletionResult(Builder.TakeString())); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); } static bool WantTypesInContext(Sema::ParserCompletionContext CCC, @@ -1481,15 +1525,15 @@ static bool WantTypesInContext(Sema::ParserCompletionContext CCC, case Sema::PCC_ParenthesizedExpression: case Sema::PCC_LocalDeclarationSpecifiers: return true; - + case Sema::PCC_Expression: case Sema::PCC_Condition: return LangOpts.CPlusPlus; - + case Sema::PCC_ObjCInterface: case Sema::PCC_ObjCImplementation: return false; - + case Sema::PCC_ForInit: return LangOpts.CPlusPlus || LangOpts.ObjC1 || LangOpts.C99; } @@ -1507,12 +1551,12 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, return Policy; } -/// \brief Retrieve a printing policy suitable for code completion. +/// Retrieve a printing policy suitable for code completion. static PrintingPolicy getCompletionPrintingPolicy(Sema &S) { return getCompletionPrintingPolicy(S.Context, S.PP); } -/// \brief Retrieve the string representation of the given type as a string +/// Retrieve the string representation of the given type as a string /// that has the appropriate lifetime for code completion. /// /// This routine provides a fast path where we provide constant strings for @@ -1525,7 +1569,7 @@ static const char *GetCompletionTypeString(QualType T, // Built-in type names are constant strings. if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) return BT->getNameAsCString(Policy); - + // Anonymous tag types are constant strings. if (const TagType *TagT = dyn_cast<TagType>(T)) if (TagDecl *Tag = TagT->getDecl()) @@ -1539,24 +1583,24 @@ static const char *GetCompletionTypeString(QualType T, } } } - + // Slow path: format the type as a string. std::string Result; T.getAsStringInternal(Result, Policy); return Allocator.CopyString(Result); } -/// \brief Add a completion for "this", if we're in a member function. +/// Add a completion for "this", if we're in a member function. static void addThisCompletion(Sema &S, ResultBuilder &Results) { QualType ThisTy = S.getCurrentThisType(); if (ThisTy.isNull()) return; - + CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); PrintingPolicy Policy = getCompletionPrintingPolicy(S); - Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy, - S.Context, + Builder.AddResultTypeChunk(GetCompletionTypeString(ThisTy, + S.Context, Policy, Allocator)); Builder.AddTypedTextChunk("this"); @@ -1578,14 +1622,14 @@ static void AddStaticAssertResult(CodeCompletionBuilder &Builder, Results.AddResult(CodeCompletionResult(Builder.TakeString())); } -/// \brief Add language constructs that show up for "ordinary" names. +/// Add language constructs that show up for "ordinary" names. static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Sema &SemaRef, ResultBuilder &Results) { CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); - + typedef CodeCompletionResult Result; switch (CCC) { case Sema::PCC_Namespace: @@ -1601,7 +1645,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } - + // namespace identifier = identifier ; Builder.AddTypedTextChunk("namespace"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -1618,7 +1662,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("identifier"); Results.AddResult(Result(Builder.TakeString())); - // asm(string-literal) + // asm(string-literal) Builder.AddTypedTextChunk("asm"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("string-literal"); @@ -1633,10 +1677,10 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result(Builder.TakeString())); } } - + if (SemaRef.getLangOpts().ObjC1) AddObjCTopLevelResults(Results, true); - + AddTypedefResult(Results); LLVM_FALLTHROUGH; @@ -1649,7 +1693,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); - + // using typename qualifier::name (only in a dependent context) if (SemaRef.CurContext->isDependentContext()) { Builder.AddTypedTextChunk("using"); @@ -1710,17 +1754,17 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results); break; - + case Sema::PCC_ObjCImplementation: AddObjCImplementationResults(SemaRef.getLangOpts(), Results, true); AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOpts(), Results); break; - + case Sema::PCC_ObjCInstanceVariableList: AddObjCVisibilityResults(SemaRef.getLangOpts(), Results, true); break; - + case Sema::PCC_RecoveryInFunction: case Sema::PCC_Statement: { AddTypedefResult(Results); @@ -1744,7 +1788,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, } if (SemaRef.getLangOpts().ObjC1) AddObjCStatementResults(Results, true); - + if (Results.includeCodePatterns()) { // if (condition) { statements } Builder.AddTypedTextChunk("if"); @@ -1773,7 +1817,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } - + // Switch-specific statements. if (!SemaRef.getCurFunction()->SwitchStack.empty()) { // case expression: @@ -1835,7 +1879,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } - + if (S->getContinueParent()) { // continue ; Builder.AddTypedTextChunk("continue"); @@ -1856,7 +1900,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext)) isVoid = Method->getReturnType()->isVoidType(); - else if (SemaRef.getCurBlock() && + else if (SemaRef.getCurBlock() && !SemaRef.getCurBlock()->ReturnType.isNull()) isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType(); Builder.AddTypedTextChunk("return"); @@ -1870,7 +1914,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddTypedTextChunk("goto"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("label"); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // Using directives Builder.AddTypedTextChunk("using"); @@ -1900,7 +1944,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // (__bridge_transfer <Objective-C type>)<expression> Builder.AddTypedTextChunk("__bridge_transfer"); @@ -1908,7 +1952,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("Objective-C type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // (__bridge_retained <CF type>)<expression> Builder.AddTypedTextChunk("__bridge_retained"); @@ -1916,7 +1960,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("CF type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddPlaceholderChunk("expression"); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); } // Fall through LLVM_FALLTHROUGH; @@ -1925,12 +1969,12 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, if (SemaRef.getLangOpts().CPlusPlus) { // 'this', if we're in a non-static member function. addThisCompletion(SemaRef, Results); - + // true Builder.AddResultTypeChunk("bool"); Builder.AddTypedTextChunk("true"); Results.AddResult(Result(Builder.TakeString())); - + // false Builder.AddResultTypeChunk("bool"); Builder.AddTypedTextChunk("false"); @@ -1945,9 +1989,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); } - + // static_cast < type-id > ( expression ) Builder.AddTypedTextChunk("static_cast"); Builder.AddChunk(CodeCompletionString::CK_LeftAngle); @@ -1956,7 +2000,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // reinterpret_cast < type-id > ( expression ) Builder.AddTypedTextChunk("reinterpret_cast"); @@ -1966,7 +2010,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // const_cast < type-id > ( expression ) Builder.AddTypedTextChunk("const_cast"); @@ -1976,7 +2020,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); if (SemaRef.getLangOpts().RTTI) { // typeid ( expression-or-type ) @@ -1985,9 +2029,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expression-or-type"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); } - + // new T ( ... ) Builder.AddTypedTextChunk("new"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -1995,7 +2039,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expressions"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // new T [ ] ( ... ) Builder.AddTypedTextChunk("new"); @@ -2007,14 +2051,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("expressions"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // delete expression Builder.AddResultTypeChunk("void"); Builder.AddTypedTextChunk("delete"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); - Results.AddResult(Result(Builder.TakeString())); + Results.AddResult(Result(Builder.TakeString())); // delete [] expression Builder.AddResultTypeChunk("void"); @@ -2034,7 +2078,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); } - + // FIXME: Rethrow? if (SemaRef.getLangOpts().CPlusPlus11) { @@ -2079,7 +2123,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, SuperType = ID->getSuperClass()->getNameAsString(); if (Method->isInstanceMethod()) SuperType += " *"; - + Builder.AddResultTypeChunk(Allocator.CopyString(SuperType)); Builder.AddTypedTextChunk("super"); Results.AddResult(Result(Builder.TakeString())); @@ -2111,7 +2155,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result(Builder.TakeString())); break; } - + case Sema::PCC_Type: case Sema::PCC_LocalDeclarationSpecifiers: break; @@ -2124,7 +2168,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("operator")); } -/// \brief If the given declaration has an associated type, add it as a result +/// If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, const PrintingPolicy &Policy, @@ -2136,7 +2180,7 @@ static void AddResultTypeChunk(ASTContext &Context, // Skip constructors and conversion functions, which have their return types // built into their names. - if (isa<CXXConstructorDecl>(ND) || isa<CXXConversionDecl>(ND)) + if (isConstructor(ND) || isa<CXXConversionDecl>(ND)) return; // Determine the type of the declaration (if it has a type). @@ -2166,10 +2210,10 @@ static void AddResultTypeChunk(ASTContext &Context, else T = Property->getType(); } - + if (T.isNull() || Context.hasSameType(T, Context.DependentTy)) return; - + Result.AddResultTypeChunk(GetCompletionTypeString(T, Context, Policy, Result.getAllocator())); } @@ -2188,7 +2232,7 @@ static void MaybeAddSentinel(Preprocessor &PP, } } -static std::string formatObjCParamQualifiers(unsigned ObjCQuals, +static std::string formatObjCParamQualifiers(unsigned ObjCQuals, QualType &Type) { std::string Result; if (ObjCQuals & Decl::OBJC_TQ_In) @@ -2223,7 +2267,7 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals, return Result; } -/// \brief Tries to find the most appropriate type location for an Objective-C +/// Tries to find the most appropriate type location for an Objective-C /// block placeholder. /// /// This function ignores things like typedefs and qualifiers in order to @@ -2285,13 +2329,13 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext()); if (Param->getType()->isDependentType() || !Param->getType()->isBlockPointerType()) { - // The argument for a dependent or non-block parameter is a placeholder + // The argument for a dependent or non-block parameter is a placeholder // containing that parameter's type. std::string Result; - + if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) Result = Param->getIdentifier()->getName(); - + QualType Type = Param->getType(); if (ObjCSubsts) Type = Type.substObjCTypeArgs(Param->getASTContext(), *ObjCSubsts, @@ -2332,7 +2376,7 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Result = Param->getIdentifier()->getName(); QualType Type = Param->getType().getUnqualifiedType(); - + if (ObjCMethodParam) { Result = Type.getAsString(Policy); std::string Quals = @@ -2346,7 +2390,7 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, } else { Type.getAsStringInternal(Result, Policy); } - + return Result; } @@ -2357,14 +2401,14 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, ObjCSubsts); } -/// \brief Returns a placeholder string that corresponds to an Objective-C block +/// Returns a placeholder string that corresponds to an Objective-C block /// declaration. /// /// \param BlockDecl A declaration with an Objective-C block type. /// /// \param Block The most relevant type location for that block type. /// -/// \param SuppressBlockName Determines wether or not the name of the block +/// \param SuppressBlockName Determines whether or not the name of the block /// declaration is included in the resulting string. static std::string formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, @@ -2449,7 +2493,7 @@ static std::string GetDefaultValueString(const ParmVarDecl *Param, return " " + DefValue; } -/// \brief Add function parameter chunks to the given code completion string. +/// Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(Preprocessor &PP, const PrintingPolicy &Policy, const FunctionDecl *Function, @@ -2457,10 +2501,10 @@ static void AddFunctionParameterChunks(Preprocessor &PP, unsigned Start = 0, bool InOptional = false) { bool FirstParameter = true; - + for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) { const ParmVarDecl *Param = Function->getParamDecl(P); - + if (Param->hasDefaultArg() && !InOptional) { // When we see an optional default argument, put that argument and // the remaining default arguments into a new, optional string. @@ -2472,14 +2516,14 @@ static void AddFunctionParameterChunks(Preprocessor &PP, Result.AddOptionalChunk(Opt.TakeString()); break; } - + if (FirstParameter) FirstParameter = false; else Result.AddChunk(CodeCompletionString::CK_Comma); - + InOptional = false; - + // Format the placeholder string. std::string PlaceholderStr = FormatFunctionParameter(Policy, Param); if (Param->hasDefaultArg()) @@ -2492,8 +2536,8 @@ static void AddFunctionParameterChunks(Preprocessor &PP, Result.AddPlaceholderChunk( Result.getAllocator().CopyString(PlaceholderStr)); } - - if (const FunctionProtoType *Proto + + if (const FunctionProtoType *Proto = Function->getType()->getAs<FunctionProtoType>()) if (Proto->isVariadic()) { if (Proto->getNumParams() == 0) @@ -2503,7 +2547,7 @@ static void AddFunctionParameterChunks(Preprocessor &PP, } } -/// \brief Add template parameter chunks to the given code completion string. +/// Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks(ASTContext &Context, const PrintingPolicy &Policy, const TemplateDecl *Template, @@ -2521,7 +2565,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, TemplateParameterList::iterator PEnd = Params->end(); if (MaxParameters) PEnd = Params->begin() + MaxParameters; - for (TemplateParameterList::iterator P = Params->begin() + Start; + for (TemplateParameterList::iterator P = Params->begin() + Start; P != PEnd; ++P) { bool HasDefaultArg = false; std::string PlaceholderStr; @@ -2530,14 +2574,14 @@ static void AddTemplateParameterChunks(ASTContext &Context, PlaceholderStr = "typename"; else PlaceholderStr = "class"; - + if (TTP->getIdentifier()) { PlaceholderStr += ' '; PlaceholderStr += TTP->getIdentifier()->getName(); } - + HasDefaultArg = TTP->hasDefaultArgument(); - } else if (NonTypeTemplateParmDecl *NTTP + } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) PlaceholderStr = NTTP->getIdentifier()->getName(); @@ -2546,7 +2590,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, } else { assert(isa<TemplateTemplateParmDecl>(*P)); TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); - + // Since putting the template argument list into the placeholder would // be very, very long, we just use an abbreviation. PlaceholderStr = "template<...> class"; @@ -2554,10 +2598,10 @@ static void AddTemplateParameterChunks(ASTContext &Context, PlaceholderStr += ' '; PlaceholderStr += TTP->getIdentifier()->getName(); } - + HasDefaultArg = TTP->hasDefaultArgument(); } - + if (HasDefaultArg && !InDefaultArg) { // When we see an optional default argument, put that argument and // the remaining default arguments into a new, optional string. @@ -2570,31 +2614,31 @@ static void AddTemplateParameterChunks(ASTContext &Context, Result.AddOptionalChunk(Opt.TakeString()); break; } - + InDefaultArg = false; - + if (FirstParameter) FirstParameter = false; else Result.AddChunk(CodeCompletionString::CK_Comma); - + // Add the placeholder string. Result.AddPlaceholderChunk( Result.getAllocator().CopyString(PlaceholderStr)); - } + } } -/// \brief Add a qualifier to the given code-completion string, if the +/// Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. -static void -AddQualifierToCompletionString(CodeCompletionBuilder &Result, - NestedNameSpecifier *Qualifier, +static void +AddQualifierToCompletionString(CodeCompletionBuilder &Result, + NestedNameSpecifier *Qualifier, bool QualifierIsInformative, ASTContext &Context, const PrintingPolicy &Policy) { if (!Qualifier) return; - + std::string PrintedNNS; { llvm::raw_string_ostream OS(PrintedNNS); @@ -2606,7 +2650,7 @@ AddQualifierToCompletionString(CodeCompletionBuilder &Result, Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS)); } -static void +static void AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, const FunctionDecl *Function) { const FunctionProtoType *Proto @@ -2615,7 +2659,7 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, return; // FIXME: Add ref-qualifier! - + // Handle single qualifiers without copying if (Proto->getTypeQuals() == Qualifiers::Const) { Result.AddInformativeChunk(" const"); @@ -2643,29 +2687,29 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); } -/// \brief Add the name of the given declaration +/// Add the name of the given declaration static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, const NamedDecl *ND, CodeCompletionBuilder &Result) { DeclarationName Name = ND->getDeclName(); if (!Name) return; - + switch (Name.getNameKind()) { case DeclarationName::CXXOperatorName: { const char *OperatorName = nullptr; switch (Name.getCXXOverloadedOperator()) { - case OO_None: + case OO_None: case OO_Conditional: case NUM_OVERLOADED_OPERATORS: - OperatorName = "operator"; + OperatorName = "operator"; break; - + #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case OO_##Name: OperatorName = "operator" Spelling; break; #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) #include "clang/Basic/OperatorKinds.def" - + case OO_New: OperatorName = "operator new"; break; case OO_Delete: OperatorName = "operator delete"; break; case OO_Array_New: OperatorName = "operator new[]"; break; @@ -2676,7 +2720,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, Result.AddTypedTextChunk(OperatorName); break; } - + case DeclarationName::Identifier: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXDestructorName: @@ -2684,14 +2728,14 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, Result.AddTypedTextChunk( Result.getAllocator().CopyString(ND->getNameAsString())); break; - + case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: break; - + case DeclarationName::CXXConstructorName: { CXXRecordDecl *Record = nullptr; QualType Ty = Name.getCXXNameType(); @@ -2705,7 +2749,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, Result.getAllocator().CopyString(ND->getNameAsString())); break; } - + Result.AddTypedTextChunk( Result.getAllocator().CopyString(Record->getNameAsString())); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { @@ -2727,7 +2771,53 @@ CodeCompletionString *CodeCompletionResult::CreateCodeCompletionString(Sema &S, CCTUInfo, IncludeBriefComments); } -/// \brief If possible, create a new code completion string for the given +CodeCompletionString *CodeCompletionResult::CreateCodeCompletionStringForMacro( + Preprocessor &PP, CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo) { + assert(Kind == RK_Macro); + CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); + const MacroInfo *MI = PP.getMacroInfo(Macro); + Result.AddTypedTextChunk(Result.getAllocator().CopyString(Macro->getName())); + + if (!MI || !MI->isFunctionLike()) + return Result.TakeString(); + + // Format a function-like macro with placeholders for the arguments. + Result.AddChunk(CodeCompletionString::CK_LeftParen); + MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end(); + + // C99 variadic macros add __VA_ARGS__ at the end. Skip it. + if (MI->isC99Varargs()) { + --AEnd; + + if (A == AEnd) { + Result.AddPlaceholderChunk("..."); + } + } + + for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) { + if (A != MI->param_begin()) + Result.AddChunk(CodeCompletionString::CK_Comma); + + if (MI->isVariadic() && (A + 1) == AEnd) { + SmallString<32> Arg = (*A)->getName(); + if (MI->isC99Varargs()) + Arg += ", ..."; + else + Arg += "..."; + Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); + break; + } + + // Non-variadic macros are simple. + Result.AddPlaceholderChunk( + Result.getAllocator().CopyString((*A)->getName())); + } + Result.AddChunk(CodeCompletionString::CK_RightParen); + return Result.TakeString(); +} + +/// If possible, create a new code completion string for the given /// result. /// /// \returns Either a new, heap-allocated code completion string describing @@ -2740,104 +2830,42 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) { + if (Kind == RK_Macro) + return CreateCodeCompletionStringForMacro(PP, Allocator, CCTUInfo); + CodeCompletionBuilder Result(Allocator, CCTUInfo, Priority, Availability); - + PrintingPolicy Policy = getCompletionPrintingPolicy(Ctx, PP); if (Kind == RK_Pattern) { Pattern->Priority = Priority; Pattern->Availability = Availability; - + if (Declaration) { Result.addParentContext(Declaration->getDeclContext()); Pattern->ParentName = Result.getParentName(); - // Provide code completion comment for self.GetterName where - // GetterName is the getter method for a property with name - // different from the property name (declared via a property - // getter attribute. - const NamedDecl *ND = Declaration; - if (const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(ND)) - if (M->isPropertyAccessor()) - if (const ObjCPropertyDecl *PDecl = M->findPropertyDecl()) - if (PDecl->getGetterName() == M->getSelector() && - PDecl->getIdentifier() != M->getIdentifier()) { - if (const RawComment *RC = - Ctx.getRawCommentForAnyRedecl(M)) { - Result.addBriefComment(RC->getBriefText(Ctx)); - Pattern->BriefComment = Result.getBriefComment(); - } - else if (const RawComment *RC = - Ctx.getRawCommentForAnyRedecl(PDecl)) { - Result.addBriefComment(RC->getBriefText(Ctx)); - Pattern->BriefComment = Result.getBriefComment(); - } - } - } - - return Pattern; - } - - if (Kind == RK_Keyword) { - Result.AddTypedTextChunk(Keyword); - return Result.TakeString(); - } - - if (Kind == RK_Macro) { - const MacroInfo *MI = PP.getMacroInfo(Macro); - Result.AddTypedTextChunk( - Result.getAllocator().CopyString(Macro->getName())); - - if (!MI || !MI->isFunctionLike()) - return Result.TakeString(); - - // Format a function-like macro with placeholders for the arguments. - Result.AddChunk(CodeCompletionString::CK_LeftParen); - MacroInfo::param_iterator A = MI->param_begin(), AEnd = MI->param_end(); - - // C99 variadic macros add __VA_ARGS__ at the end. Skip it. - if (MI->isC99Varargs()) { - --AEnd; - - if (A == AEnd) { - Result.AddPlaceholderChunk("..."); + if (const RawComment *RC = + getPatternCompletionComment(Ctx, Declaration)) { + Result.addBriefComment(RC->getBriefText(Ctx)); + Pattern->BriefComment = Result.getBriefComment(); } } - - for (MacroInfo::param_iterator A = MI->param_begin(); A != AEnd; ++A) { - if (A != MI->param_begin()) - Result.AddChunk(CodeCompletionString::CK_Comma); - if (MI->isVariadic() && (A+1) == AEnd) { - SmallString<32> Arg = (*A)->getName(); - if (MI->isC99Varargs()) - Arg += ", ..."; - else - Arg += "..."; - Result.AddPlaceholderChunk(Result.getAllocator().CopyString(Arg)); - break; - } + return Pattern; + } - // Non-variadic macros are simple. - Result.AddPlaceholderChunk( - Result.getAllocator().CopyString((*A)->getName())); - } - Result.AddChunk(CodeCompletionString::CK_RightParen); + if (Kind == RK_Keyword) { + Result.AddTypedTextChunk(Keyword); return Result.TakeString(); } - assert(Kind == RK_Declaration && "Missed a result kind?"); const NamedDecl *ND = Declaration; Result.addParentContext(ND->getDeclContext()); if (IncludeBriefComments) { // Add documentation comment, if it exists. - if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) { + if (const RawComment *RC = getCompletionComment(Ctx, Declaration)) { Result.addBriefComment(RC->getBriefText(Ctx)); - } - else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) - if (OMD->isPropertyAccessor()) - if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl()) - if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(PDecl)) - Result.addBriefComment(RC->getBriefText(Ctx)); + } } if (StartsNestedNameSpecifier) { @@ -2851,9 +2879,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); - + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { - AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); AddTypedNameChunk(Ctx, Policy, ND, Result); Result.AddChunk(CodeCompletionString::CK_LeftParen); @@ -2862,9 +2890,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); } - + if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { - AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); AddTypedNameChunk(Ctx, Policy, Function, Result); @@ -2885,30 +2913,30 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, LastDeducibleArgument - 1); if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) HasDefaultArg = TTP->hasDefaultArgument(); - else if (NonTypeTemplateParmDecl *NTTP + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) HasDefaultArg = NTTP->hasDefaultArgument(); else { assert(isa<TemplateTemplateParmDecl>(Param)); - HasDefaultArg + HasDefaultArg = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); } - + if (!HasDefaultArg) break; } } - + if (LastDeducibleArgument) { // Some of the function template arguments cannot be deduced from a // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. Result.AddChunk(CodeCompletionString::CK_LeftAngle); - AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result, + AddTemplateParameterChunks(Ctx, Policy, FunTmpl, Result, LastDeducibleArgument); Result.AddChunk(CodeCompletionString::CK_RightAngle); } - + // Add the function parameters Result.AddChunk(CodeCompletionString::CK_LeftParen); AddFunctionParameterChunks(PP, Policy, Function, Result); @@ -2916,9 +2944,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, AddFunctionTypeQualsToCompletionString(Result, Function); return Result.TakeString(); } - + if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) { - AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); Result.AddTypedTextChunk( Result.getAllocator().CopyString(Template->getNameAsString())); @@ -2927,7 +2955,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Result.AddChunk(CodeCompletionString::CK_RightAngle); return Result.TakeString(); } - + if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { @@ -2942,7 +2970,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Result.AddTypedTextChunk(Result.getAllocator().CopyString(SelName)); else { Result.AddInformativeChunk(Result.getAllocator().CopyString(SelName)); - + // If there is only one parameter, and we're past it, add an empty // typed-text chunk since there is nothing to type. if (Method->param_size() == 1) @@ -2961,10 +2989,10 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) Result.AddInformativeChunk(Result.getAllocator().CopyString(Keyword)); - else + else Result.AddTypedTextChunk(Result.getAllocator().CopyString(Keyword)); } - + // If we're before the starting parameter, skip the placeholder. if (Idx < StartParameter) continue; @@ -2990,10 +3018,10 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); } - + if (Method->isVariadic() && (P + 1) == PEnd) Arg += ", ..."; - + if (DeclaringEntity) Result.AddTextChunk(Result.getAllocator().CopyString(Arg)); else if (AllParametersAreInformative) @@ -3011,15 +3039,15 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, else Result.AddPlaceholderChunk(", ..."); } - + MaybeAddSentinel(PP, Method, Result); } - + return Result.TakeString(); } if (Qualifier) - AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, + AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); Result.AddTypedTextChunk( @@ -3027,7 +3055,60 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, return Result.TakeString(); } -/// \brief Add function overload parameter chunks to the given code completion +const RawComment *clang::getCompletionComment(const ASTContext &Ctx, + const NamedDecl *ND) { + if (!ND) + return nullptr; + if (auto *RC = Ctx.getRawCommentForAnyRedecl(ND)) + return RC; + + // Try to find comment from a property for ObjC methods. + const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(ND); + if (!M) + return nullptr; + const ObjCPropertyDecl *PDecl = M->findPropertyDecl(); + if (!PDecl) + return nullptr; + + return Ctx.getRawCommentForAnyRedecl(PDecl); +} + +const RawComment *clang::getPatternCompletionComment(const ASTContext &Ctx, + const NamedDecl *ND) { + const ObjCMethodDecl *M = dyn_cast_or_null<ObjCMethodDecl>(ND); + if (!M || !M->isPropertyAccessor()) + return nullptr; + + // Provide code completion comment for self.GetterName where + // GetterName is the getter method for a property with name + // different from the property name (declared via a property + // getter attribute. + const ObjCPropertyDecl *PDecl = M->findPropertyDecl(); + if (!PDecl) + return nullptr; + if (PDecl->getGetterName() == M->getSelector() && + PDecl->getIdentifier() != M->getIdentifier()) { + if (auto *RC = Ctx.getRawCommentForAnyRedecl(M)) + return RC; + if (auto *RC = Ctx.getRawCommentForAnyRedecl(PDecl)) + return RC; + } + return nullptr; +} + +const RawComment *clang::getParameterComment( + const ASTContext &Ctx, + const CodeCompleteConsumer::OverloadCandidate &Result, + unsigned ArgIndex) { + auto FDecl = Result.getFunction(); + if (!FDecl) + return nullptr; + if (ArgIndex < FDecl->getNumParams()) + return Ctx.getRawCommentForAnyRedecl(FDecl->getParamDecl(ArgIndex)); + return nullptr; +} + +/// Add function overload parameter chunks to the given code completion /// string. static void AddOverloadParameterChunks(ASTContext &Context, const PrintingPolicy &Policy, @@ -3110,7 +3191,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(getFunctionType()); if (!FDecl && !Proto) { - // Function without a prototype. Just give the return type and a + // Function without a prototype. Just give the return type and a // highlighted ellipsis. const FunctionType *FT = getFunctionType(); Result.AddResultTypeChunk(Result.getAllocator().CopyString( @@ -3122,10 +3203,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( } if (FDecl) { - if (IncludeBriefComments && CurrentArg < FDecl->getNumParams()) - if (auto RC = S.getASTContext().getRawCommentForAnyRedecl( - FDecl->getParamDecl(CurrentArg))) + if (IncludeBriefComments) { + if (auto RC = getParameterComment(S.getASTContext(), *this, CurrentArg)) Result.addBriefComment(RC->getBriefText(S.getASTContext())); + } AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result); Result.AddTextChunk( Result.getAllocator().CopyString(FDecl->getNameAsString())); @@ -3143,18 +3224,18 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( return Result.TakeString(); } -unsigned clang::getMacroUsagePriority(StringRef MacroName, +unsigned clang::getMacroUsagePriority(StringRef MacroName, const LangOptions &LangOpts, bool PreferredTypeIsPointer) { unsigned Priority = CCP_Macro; - + // Treat the "nil", "Nil" and "NULL" macros as null pointer constants. - if (MacroName.equals("nil") || MacroName.equals("NULL") || + if (MacroName.equals("nil") || MacroName.equals("NULL") || MacroName.equals("Nil")) { Priority = CCP_Constant; if (PreferredTypeIsPointer) Priority = Priority / CCF_SimilarTypeMatch; - } + } // Treat "YES", "NO", "true", and "false" as constants. else if (MacroName.equals("YES") || MacroName.equals("NO") || MacroName.equals("true") || MacroName.equals("false")) @@ -3162,27 +3243,27 @@ unsigned clang::getMacroUsagePriority(StringRef MacroName, // Treat "bool" as a type. else if (MacroName.equals("bool")) Priority = CCP_Type + (LangOpts.ObjC1? CCD_bool_in_ObjC : 0); - - + + return Priority; } CXCursorKind clang::getCursorKindForDecl(const Decl *D) { if (!D) return CXCursor_UnexposedDecl; - + switch (D->getKind()) { case Decl::Enum: return CXCursor_EnumDecl; case Decl::EnumConstant: return CXCursor_EnumConstantDecl; case Decl::Field: return CXCursor_FieldDecl; - case Decl::Function: + case Decl::Function: return CXCursor_FunctionDecl; case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; - case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; + case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; case Decl::ObjCMethod: return cast<ObjCMethodDecl>(D)->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; @@ -3211,17 +3292,17 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { case Decl::StaticAssert: return CXCursor_StaticAssert; case Decl::Friend: return CXCursor_FriendDecl; case Decl::TranslationUnit: return CXCursor_TranslationUnit; - + case Decl::Using: case Decl::UnresolvedUsingValue: - case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingTypename: return CXCursor_UsingDeclaration; - + case Decl::ObjCPropertyImpl: switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) { case ObjCPropertyImplDecl::Dynamic: return CXCursor_ObjCDynamicDecl; - + case ObjCPropertyImplDecl::Synthesize: return CXCursor_ObjCSynthesizeDecl; } @@ -3242,7 +3323,7 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { } } } - + return CXCursor_UnexposedDecl; } @@ -3250,10 +3331,10 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, bool IncludeUndefined, bool TargetTypeIsPointer = false) { typedef CodeCompletionResult Result; - + Results.EnterNewScope(); - - for (Preprocessor::macro_iterator M = PP.macro_begin(), + + for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { auto MD = PP.getMacroDefinition(M->first); @@ -3268,17 +3349,17 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, TargetTypeIsPointer))); } } - + Results.ExitScope(); - + } -static void AddPrettyFunctionResults(const LangOptions &LangOpts, +static void AddPrettyFunctionResults(const LangOptions &LangOpts, ResultBuilder &Results) { typedef CodeCompletionResult Result; - + Results.EnterNewScope(); - + Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant)); Results.AddResult(Result("__FUNCTION__", CCP_Constant)); if (LangOpts.C99 || LangOpts.CPlusPlus11) @@ -3295,24 +3376,24 @@ static void HandleCodeCompleteResults(Sema *S, CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults); } -static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, +static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, Sema::ParserCompletionContext PCC) { switch (PCC) { case Sema::PCC_Namespace: return CodeCompletionContext::CCC_TopLevel; - + case Sema::PCC_Class: return CodeCompletionContext::CCC_ClassStructUnion; case Sema::PCC_ObjCInterface: return CodeCompletionContext::CCC_ObjCInterface; - + case Sema::PCC_ObjCImplementation: return CodeCompletionContext::CCC_ObjCImplementation; case Sema::PCC_ObjCInstanceVariableList: return CodeCompletionContext::CCC_ObjCIvarList; - + case Sema::PCC_Template: case Sema::PCC_MemberTemplate: if (S.CurContext->isFileContext()) @@ -3320,7 +3401,7 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, if (S.CurContext->isRecord()) return CodeCompletionContext::CCC_ClassStructUnion; return CodeCompletionContext::CCC_Other; - + case Sema::PCC_RecoveryInFunction: return CodeCompletionContext::CCC_Recovery; @@ -3334,7 +3415,7 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, case Sema::PCC_Expression: case Sema::PCC_Condition: return CodeCompletionContext::CCC_Expression; - + case Sema::PCC_Statement: return CodeCompletionContext::CCC_Statement; @@ -3343,7 +3424,7 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, case Sema::PCC_ParenthesizedExpression: return CodeCompletionContext::CCC_ParenthesizedExpression; - + case Sema::PCC_LocalDeclarationSpecifiers: return CodeCompletionContext::CCC_Type; } @@ -3351,27 +3432,27 @@ static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, llvm_unreachable("Invalid ParserCompletionContext!"); } -/// \brief If we're in a C++ virtual member function, add completion results -/// that invoke the functions we override, since it's common to invoke the +/// If we're in a C++ virtual member function, add completion results +/// that invoke the functions we override, since it's common to invoke the /// overridden function as well as adding new functionality. /// /// \param S The semantic analysis object for which we are generating results. /// /// \param InContext This context in which the nested-name-specifier preceding -/// the code-completion point +/// the code-completion point static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, ResultBuilder &Results) { // Look through blocks. DeclContext *CurContext = S.CurContext; while (isa<BlockDecl>(CurContext)) CurContext = CurContext->getParent(); - - + + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(CurContext); if (!Method || !Method->isVirtual()) return; - - // We need to have names for all of the parameters, if we're going to + + // We need to have names for all of the parameters, if we're going to // generate a forwarding call. for (auto P : Method->parameters()) if (!P->getDeclName()) @@ -3383,7 +3464,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, Results.getCodeCompletionTUInfo()); if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) continue; - + // If we need a nested-name-specifier, add one now. if (!InContext) { NestedNameSpecifier *NNS @@ -3397,8 +3478,8 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, } } else if (!InContext->Equals(Overridden->getDeclContext())) continue; - - Builder.AddTypedTextChunk(Results.getAllocator().CopyString( + + Builder.AddTypedTextChunk(Results.getAllocator().CopyString( Overridden->getNameAsString())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; @@ -3421,14 +3502,14 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, } } -void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, +void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - + CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); typedef CodeCompletionResult Result; @@ -3440,7 +3521,7 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, Builder.AddTypedTextChunk( Builder.getAllocator().CopyString(Modules[I]->Name)); Results.AddResult(Result(Builder.TakeString(), - CCP_Declaration, + CCP_Declaration, CXCursor_ModuleImportDecl, Modules[I]->isAvailable() ? CXAvailability_Available @@ -3453,14 +3534,14 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, /*IsInclusionDirective=*/false); // Enumerate submodules. if (Mod) { - for (Module::submodule_iterator Sub = Mod->submodule_begin(), + for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) { - + Builder.AddTypedTextChunk( Builder.getAllocator().CopyString((*Sub)->Name)); Results.AddResult(Result(Builder.TakeString(), - CCP_Declaration, + CCP_Declaration, CXCursor_ModuleImportDecl, (*Sub)->isAvailable() ? CXAvailability_Available @@ -3468,18 +3549,18 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, } } } - Results.ExitScope(); + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } -void Sema::CodeCompleteOrdinaryName(Scope *S, +void Sema::CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, CompletionContext)); Results.EnterNewScope(); - + // Determine how to filter results, e.g., so that the names of // values (functions, enumerators, function templates, etc.) are // only allowed where we can have an expression. @@ -3505,11 +3586,11 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); - + if (getLangOpts().CPlusPlus) MaybeAddOverrideCalls(*this, /*InContext=*/nullptr, Results); break; - + case PCC_RecoveryInFunction: // Unfiltered break; @@ -3521,10 +3602,11 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, if (CurMethod->isInstance()) Results.setObjectTypeQualifiers( Qualifiers::fromCVRMask(CurMethod->getTypeQualifiers())); - + CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); @@ -3537,7 +3619,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); break; - + case PCC_Namespace: case PCC_Class: case PCC_ObjCInterface: @@ -3551,15 +3633,15 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, case PCC_LocalDeclarationSpecifiers: break; } - + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false); - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, +static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, ArrayRef<IdentifierInfo *> SelIdents, bool AtArgumentExpression, @@ -3576,7 +3658,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, ? CodeCompletionContext::CCC_PotentiallyQualifiedName : CodeCompletionContext::CCC_Name); Results.EnterNewScope(); - + // Type qualifiers can come after names. Results.AddResult(Result("const")); Results.AddResult(Result("volatile")); @@ -3590,16 +3672,17 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, Results.AddResult("final"); if (AllowNonIdentifiers) { - Results.AddResult(Result("operator")); + Results.AddResult(Result("operator")); } - + // Add nested-name-specifiers. if (AllowNestedNameSpecifiers) { Results.allowNestedNameSpecifiers(); Results.setFilter(&ResultBuilder::IsImpossibleToSatisfy); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.setFilter(nullptr); } } @@ -3618,7 +3701,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, S && (S->getFlags() & Scope::DeclScope) != 0 && (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope | - Scope::FunctionPrototypeScope | + Scope::FunctionPrototypeScope | Scope::AtCatchScope)) == 0) { ParsedType T = DS.getRepAsType(); if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) @@ -3628,29 +3711,31 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, // Note that we intentionally suppress macro results here, since we do not // encourage using macros to produce the names of entities. - HandleCodeCompleteResults(this, CodeCompleter, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } struct Sema::CodeCompleteExpressionData { - CodeCompleteExpressionData(QualType PreferredType = QualType()) + CodeCompleteExpressionData(QualType PreferredType = QualType()) : PreferredType(PreferredType), IntegralConstantExpression(false), ObjCCollection(false) { } - + QualType PreferredType; bool IntegralConstantExpression; bool ObjCCollection; SmallVector<Decl *, 4> IgnoreDecls; }; -/// \brief Perform code-completion in an expression context when we know what +/// Perform code-completion in an expression context when we know what /// type we're looking for. -void Sema::CodeCompleteExpression(Scope *S, +void Sema::CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data) { - ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext::CCC_Expression); + ResultBuilder Results( + *this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext(CodeCompletionContext::CCC_Expression, + Data.PreferredType)); if (Data.ObjCCollection) Results.setFilter(&ResultBuilder::IsObjCCollection); else if (Data.IntegralConstantExpression) @@ -3662,36 +3747,35 @@ void Sema::CodeCompleteExpression(Scope *S, if (!Data.PreferredType.isNull()) Results.setPreferredType(Data.PreferredType.getNonReferenceType()); - + // Ignore any declarations that we were told that we don't care about. for (unsigned I = 0, N = Data.IgnoreDecls.size(); I != N; ++I) Results.Ignore(Data.IgnoreDecls[I]); - + CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + Results.EnterNewScope(); AddOrdinaryNameResults(PCC_Expression, S, *this, Results); Results.ExitScope(); - + bool PreferredTypeIsPointer = false; if (!Data.PreferredType.isNull()) PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() - || Data.PreferredType->isMemberPointerType() + || Data.PreferredType->isMemberPointerType() || Data.PreferredType->isBlockPointerType(); - - if (S->getFnParent() && - !Data.ObjCCollection && + + if (S->getFnParent() && + !Data.ObjCCollection && !Data.IntegralConstantExpression) AddPrettyFunctionResults(getLangOpts(), Results); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false, PreferredTypeIsPointer); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext(CodeCompletionContext::CCC_Expression, - Data.PreferredType), - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { @@ -3701,29 +3785,29 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) { CodeCompleteObjCInstanceMessage(S, E.get(), None, false); } -/// \brief The set of properties that have already been added, referenced by +/// The set of properties that have already been added, referenced by /// property name. typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet; -/// \brief Retrieve the container definition, if any? +/// Retrieve the container definition, if any? static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { if (Interface->hasDefinition()) return Interface->getDefinition(); - + return Interface; } - + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { if (Protocol->hasDefinition()) return Protocol->getDefinition(); - + return Protocol; } return Container; } -/// \brief Adds a block invocation code completion result for the given block +/// Adds a block invocation code completion result for the given block /// declaration \p BD. static void AddObjCBlockCall(ASTContext &Context, const PrintingPolicy &Policy, CodeCompletionBuilder &Builder, @@ -3770,7 +3854,7 @@ static void AddObjCProperties( // Retrieve the definition. Container = getContainerDef(Container); - + // Add properties in this container. const auto AddProperty = [&](const ObjCPropertyDecl *P) { if (!AddedProperties.insert(P->getIdentifier()).second) @@ -3889,7 +3973,7 @@ static void AddObjCProperties( } } } - + // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (auto *P : Protocol->protocols()) @@ -3929,17 +4013,22 @@ static void AddObjCProperties( static void AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType, - RecordDecl *RD) { + RecordDecl *RD, + Optional<FixItHint> AccessOpFixIt) { // Indicate that we are performing a member access, and the cv-qualifiers // for the base object type. Results.setObjectTypeQualifiers(BaseType.getQualifiers()); // Access to a C/C++ class, struct, or union. Results.allowNestedNameSpecifiers(); - CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext); + std::vector<FixItHint> FixIts; + if (AccessOpFixIt) + FixIts.emplace_back(AccessOpFixIt.getValue()); + CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext, std::move(FixIts)); SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer, SemaRef.CodeCompleter->includeGlobals(), - /*IncludeDependentBases=*/true); + /*IncludeDependentBases=*/true, + SemaRef.CodeCompleter->loadExternal()); if (SemaRef.getLangOpts().CPlusPlus) { if (!Results.empty()) { @@ -3962,106 +4051,138 @@ static void AddRecordMembersCompletionResults(Sema &SemaRef, } void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, + Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement) { if (!Base || !CodeCompleter) return; - + ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); if (ConvertedBase.isInvalid()) return; - Base = ConvertedBase.get(); - - QualType BaseType = Base->getType(); + QualType ConvertedBaseType = ConvertedBase.get()->getType(); + + enum CodeCompletionContext::Kind contextKind; if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs<PointerType>()) - BaseType = Ptr->getPointeeType(); - else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/ ; - else - return; + if (const PointerType *Ptr = ConvertedBaseType->getAs<PointerType>()) + ConvertedBaseType = Ptr->getPointeeType(); } - - enum CodeCompletionContext::Kind contextKind; - + if (IsArrow) { contextKind = CodeCompletionContext::CCC_ArrowMemberAccess; - } - else { - if (BaseType->isObjCObjectPointerType() || - BaseType->isObjCObjectOrInterfaceType()) { + } else { + if (ConvertedBaseType->isObjCObjectPointerType() || + ConvertedBaseType->isObjCObjectOrInterfaceType()) { contextKind = CodeCompletionContext::CCC_ObjCPropertyAccess; - } - else { + } else { contextKind = CodeCompletionContext::CCC_DotMemberAccess; } } - CodeCompletionContext CCContext(contextKind, BaseType); + CodeCompletionContext CCContext(contextKind, ConvertedBaseType); ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompleter->getCodeCompletionTUInfo(), - CCContext, + CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); - Results.EnterNewScope(); - if (const RecordType *Record = BaseType->getAs<RecordType>()) { - AddRecordMembersCompletionResults(*this, Results, S, BaseType, - Record->getDecl()); - } else if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) { - TemplateName TN = TST->getTemplateName(); - if (const auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { - CXXRecordDecl *RD = TD->getTemplatedDecl(); - AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); - } - } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { - if (auto *RD = ICNT->getDecl()) - AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD); - } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { - // Objective-C property reference. - AddedPropertiesSet AddedProperties; - - if (const ObjCObjectPointerType *ObjCPtr = - BaseType->getAsObjCInterfacePointerType()) { - // Add property results based on our interface. - assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, - /*AllowNullaryMethods=*/true, CurContext, - AddedProperties, Results, IsBaseExprStatement); - } - - // Add properties from the protocols in a qualified interface. - for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) - AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, - CurContext, AddedProperties, Results, - IsBaseExprStatement); - } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || - (!IsArrow && BaseType->isObjCObjectType())) { - // Objective-C instance variable access. - ObjCInterfaceDecl *Class = nullptr; - if (const ObjCObjectPointerType *ObjCPtr - = BaseType->getAs<ObjCObjectPointerType>()) - Class = ObjCPtr->getInterfaceDecl(); - else - Class = BaseType->getAs<ObjCObjectType>()->getInterface(); - - // Add all ivars from this class and its superclasses. - if (Class) { - CodeCompletionDeclConsumer Consumer(Results, CurContext); - Results.setFilter(&ResultBuilder::IsObjCIvar); - LookupVisibleDecls(Class, LookupMemberName, Consumer, - CodeCompleter->includeGlobals()); + + auto DoCompletion = [&](Expr *Base, bool IsArrow, Optional<FixItHint> AccessOpFixIt) -> bool { + if (!Base) + return false; + + ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow); + if (ConvertedBase.isInvalid()) + return false; + Base = ConvertedBase.get(); + + QualType BaseType = Base->getType(); + + if (IsArrow) { + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + else if (BaseType->isObjCObjectPointerType()) + /*Do nothing*/; + else + return false; + } + + if (const RecordType *Record = BaseType->getAs<RecordType>()) { + AddRecordMembersCompletionResults(*this, Results, S, BaseType, + Record->getDecl(), + std::move(AccessOpFixIt)); + } else if (const auto *TST = + BaseType->getAs<TemplateSpecializationType>()) { + TemplateName TN = TST->getTemplateName(); + if (const auto *TD = + dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { + CXXRecordDecl *RD = TD->getTemplatedDecl(); + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD, + std::move(AccessOpFixIt)); + } + } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { + if (auto *RD = ICNT->getDecl()) + AddRecordMembersCompletionResults(*this, Results, S, BaseType, RD, + std::move(AccessOpFixIt)); + } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { + // Objective-C property reference. + AddedPropertiesSet AddedProperties; + + if (const ObjCObjectPointerType *ObjCPtr = + BaseType->getAsObjCInterfacePointerType()) { + // Add property results based on our interface. + assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); + AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, + /*AllowNullaryMethods=*/true, CurContext, + AddedProperties, Results, IsBaseExprStatement); + } + + // Add properties from the protocols in a qualified interface. + for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) + AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, + CurContext, AddedProperties, Results, + IsBaseExprStatement); + } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCObjectType())) { + // Objective-C instance variable access. + ObjCInterfaceDecl *Class = nullptr; + if (const ObjCObjectPointerType *ObjCPtr = + BaseType->getAs<ObjCObjectPointerType>()) + Class = ObjCPtr->getInterfaceDecl(); + else + Class = BaseType->getAs<ObjCObjectType>()->getInterface(); + + // Add all ivars from this class and its superclasses. + if (Class) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + Results.setFilter(&ResultBuilder::IsObjCIvar); + LookupVisibleDecls( + Class, LookupMemberName, Consumer, CodeCompleter->includeGlobals(), + /*IncludeDependentBases=*/false, CodeCompleter->loadExternal()); + } } + + // FIXME: How do we cope with isa? + return true; + }; + + Results.EnterNewScope(); + + bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + if (CodeCompleter->includeFixIts()) { + const CharSourceRange OpRange = + CharSourceRange::getTokenRange(OpLoc, OpLoc); + CompletionSucceded |= DoCompletion( + OtherOpBase, !IsArrow, + FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); } - - // FIXME: How do we cope with isa? - + Results.ExitScope(); + if (!CompletionSucceded) + return; + // Hand off the results found for code completion. - HandleCodeCompleteResults(this, CodeCompleter, - Results.getCompletionContext(), - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, @@ -4100,23 +4221,23 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { Filter = &ResultBuilder::IsEnum; ContextKind = CodeCompletionContext::CCC_EnumTag; break; - + case DeclSpec::TST_union: Filter = &ResultBuilder::IsUnion; ContextKind = CodeCompletionContext::CCC_UnionTag; break; - + case DeclSpec::TST_struct: case DeclSpec::TST_class: case DeclSpec::TST_interface: Filter = &ResultBuilder::IsClassOrStruct; ContextKind = CodeCompletionContext::CCC_ClassOrStructTag; break; - + default: llvm_unreachable("Unknown type specifier kind in CodeCompleteTag"); } - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), ContextKind); CodeCompletionDeclConsumer Consumer(Results, CurContext); @@ -4124,14 +4245,17 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // First pass: look for tags. Results.setFilter(Filter); LookupVisibleDecls(S, LookupTagName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); if (CodeCompleter->includeGlobals()) { // Second pass: look for nested name specifiers. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); } - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } @@ -4157,7 +4281,7 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { Results.EnterNewScope(); AddTypeQualifierResults(DS, Results, LangOpts); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } @@ -4192,7 +4316,7 @@ void Sema::CodeCompleteCase(Scope *S) { if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; - SwitchStmt *Switch = getCurFunction()->SwitchStack.back(); + SwitchStmt *Switch = getCurFunction()->SwitchStack.back().getPointer(); QualType type = Switch->getCond()->IgnoreImplicit()->getType(); if (!type->isEnumeralType()) { CodeCompleteExpressionData Data(type); @@ -4200,20 +4324,20 @@ void Sema::CodeCompleteCase(Scope *S) { CodeCompleteExpression(S, Data); return; } - + // Code-complete the cases of a switch statement over an enumeration type - // by providing the list of + // by providing the list of EnumDecl *Enum = type->castAs<EnumType>()->getDecl(); if (EnumDecl *Def = Enum->getDefinition()) Enum = Def; - + // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion // token, in case we are code-completing in the middle of the switch and not // at the end. However, we aren't able to do so at the moment. llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen; NestedNameSpecifier *Qualifier = nullptr; - for (SwitchCase *SC = Switch->getSwitchCaseList(); SC; + for (SwitchCase *SC = Switch->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { CaseStmt *Case = dyn_cast<CaseStmt>(SC); if (!Case) @@ -4221,16 +4345,16 @@ void Sema::CodeCompleteCase(Scope *S) { Expr *CaseVal = Case->getLHS()->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseVal)) - if (EnumConstantDecl *Enumerator + if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(DRE->getDecl())) { - // We look into the AST of the case statement to determine which - // enumerator was named. Alternatively, we could compute the value of + // We look into the AST of the case statement to determine which + // enumerator was named. Alternatively, we could compute the value of // the integral constant expression, then compare it against the - // values of each enumerator. However, value-based approach would not - // work as well with C++ templates where enumerators declared within a + // values of each enumerator. However, value-based approach would not + // work as well with C++ templates where enumerators declared within a // template are type- and value-dependent. EnumeratorsSeen.insert(Enumerator); - + // If this is a qualified-id, keep track of the nested-name-specifier // so that we can reproduce it as part of code completion, e.g., // @@ -4245,14 +4369,14 @@ void Sema::CodeCompleteCase(Scope *S) { Qualifier = DRE->getQualifier(); } } - + if (getLangOpts().CPlusPlus && !Qualifier && EnumeratorsSeen.empty()) { - // If there are no prior enumerators in C++, check whether we have to + // If there are no prior enumerators in C++, check whether we have to // qualify the names of the enumerators that we suggest, because they // may not be visible in this scope. Qualifier = getRequiredQualification(Context, CurContext, Enum); } - + // Add any enumerators that have not yet been mentioned. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), @@ -4261,23 +4385,17 @@ void Sema::CodeCompleteCase(Scope *S) { for (auto *E : Enum->enumerators()) { if (EnumeratorsSeen.count(E)) continue; - + CodeCompletionResult R(E, CCP_EnumInCase, Qualifier); Results.AddResult(R, CurContext, nullptr, false); } Results.ExitScope(); - //We need to make sure we're setting the right context, - //so only say we include macros if the code completer says we do - enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other; if (CodeCompleter->includeMacros()) { AddMacroResults(PP, Results, false); - kind = CodeCompletionContext::CCC_OtherWithMacros; } - - HandleCodeCompleteResults(this, CodeCompleter, - kind, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } static bool anyNullArguments(ArrayRef<Expr *> Args) { @@ -4316,7 +4434,7 @@ static void mergeCandidatesWithResults(Sema &SemaRef, } } -/// \brief Get the type of the Nth parameter from a given set of overload +/// Get the type of the Nth parameter from a given set of overload /// candidates. static QualType getParamType(Sema &SemaRef, ArrayRef<ResultCandidate> Candidates, @@ -4470,10 +4588,8 @@ void Sema::CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, return; // A complete type is needed to lookup for constructors. - if (!isCompleteType(Loc, Type)) - return; - - CXXRecordDecl *RD = Type->getAsCXXRecordDecl(); + CXXRecordDecl *RD = + isCompleteType(Loc, Type) ? Type->getAsCXXRecordDecl() : nullptr; if (!RD) { CodeCompleteExpression(S, Type); return; @@ -4511,7 +4627,7 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { CodeCompleteOrdinaryName(S, PCC_Expression); return; } - + CodeCompleteExpression(S, VD->getType()); } @@ -4537,13 +4653,14 @@ void Sema::CodeCompleteAfterIf(Scope *S) { mapCodeCompletionContext(*this, PCC_Statement)); Results.setFilter(&ResultBuilder::IsOrdinaryName); Results.EnterNewScope(); - + CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + AddOrdinaryNameResults(PCC_Statement, S, *this, Results); - + // "else" block CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -4580,13 +4697,13 @@ void Sema::CodeCompleteAfterIf(Scope *S) { Results.AddResult(Builder.TakeString()); Results.ExitScope(); - + if (S->getFnParent()) AddPrettyFunctionResults(getLangOpts(), Results); - + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false); - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } @@ -4649,7 +4766,8 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/true, - /*IncludeDependentBases=*/true); + /*IncludeDependentBases=*/true, + CodeCompleter->loadExternal()); } auto CC = Results.getCompletionContext(); @@ -4662,33 +4780,33 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, void Sema::CodeCompleteUsing(Scope *S) { if (!CodeCompleter) return; - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PotentiallyQualifiedName, &ResultBuilder::IsNestedNameSpecifier); Results.EnterNewScope(); - + // If we aren't in class scope, we could see the "namespace" keyword. if (!S->isClassScope()) Results.AddResult(CodeCompletionResult("namespace")); - - // After "using", we can see anything that would start a + + // After "using", we can see anything that would start a // nested-name-specifier. CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_PotentiallyQualifiedName, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { if (!CodeCompleter) return; - + // After "using namespace", we expect to see a namespace name or namespace // alias. ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -4698,46 +4816,46 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Namespace, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { if (!CodeCompleter) return; - + DeclContext *Ctx = S->getEntity(); if (!S->getParent()) Ctx = Context.getTranslationUnitDecl(); - + bool SuppressedGlobalResults = Ctx && !CodeCompleter->includeGlobals() && isa<TranslationUnitDecl>(Ctx); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), SuppressedGlobalResults ? CodeCompletionContext::CCC_Namespace : CodeCompletionContext::CCC_Other, &ResultBuilder::IsNamespace); - + if (Ctx && Ctx->isFileContext() && !SuppressedGlobalResults) { // We only want to see those namespaces that have already been defined // within this scope, because its likely that the user is creating an - // extended namespace declaration. Keep track of the most recent + // extended namespace declaration. Keep track of the most recent // definition of each namespace. std::map<NamespaceDecl *, NamespaceDecl *> OrigToLatest; - for (DeclContext::specific_decl_iterator<NamespaceDecl> + for (DeclContext::specific_decl_iterator<NamespaceDecl> NS(Ctx->decls_begin()), NSEnd(Ctx->decls_end()); NS != NSEnd; ++NS) OrigToLatest[NS->getOriginalNamespace()] = *NS; - - // Add the most recent definition (or extended definition) of each + + // Add the most recent definition (or extended definition) of each // namespace to the list of results. Results.EnterNewScope(); - for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator + for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); NS != NSEnd; ++NS) @@ -4747,8 +4865,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { CurContext, nullptr, false); Results.ExitScope(); } - - HandleCodeCompleteResults(this, CodeCompleter, + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } @@ -4756,7 +4874,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { if (!CodeCompleter) return; - + // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), @@ -4764,8 +4882,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - HandleCodeCompleteResults(this, CodeCompleter, + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } @@ -4780,26 +4899,26 @@ void Sema::CodeCompleteOperatorName(Scope *S) { CodeCompletionContext::CCC_Type, &ResultBuilder::IsType); Results.EnterNewScope(); - + // Add the names of overloadable operators. #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ if (std::strcmp(Spelling, "?")) \ Results.AddResult(Result(Spelling)); #include "clang/Basic/OperatorKinds.def" - + // Add any type names visible from the current scope Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + // Add any type specifiers AddTypeSpecifierResults(getLangOpts(), Results); Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Type, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteConstructorInitializer( @@ -4813,12 +4932,12 @@ void Sema::CodeCompleteConstructorInitializer( CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ConstructorD); if (!Constructor) return; - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PotentiallyQualifiedName); Results.EnterNewScope(); - + // Fill in any already-initialized fields or base classes. llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields; llvm::SmallPtrSet<CanQualType, 4> InitializedBases; @@ -4830,7 +4949,7 @@ void Sema::CodeCompleteConstructorInitializer( InitializedFields.insert(cast<FieldDecl>( Initializers[I]->getAnyMember())); } - + // Add completions for base classes. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -4841,69 +4960,69 @@ void Sema::CodeCompleteConstructorInitializer( if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) .second) { SawLastInitializer - = !Initializers.empty() && + = !Initializers.empty() && Initializers.back()->isBaseInitializer() && Context.hasSameUnqualifiedType(Base.getType(), QualType(Initializers.back()->getBaseClass(), 0)); continue; } - + Builder.AddTypedTextChunk( Results.getAllocator().CopyString( Base.getType().getAsString(Policy))); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Builder.TakeString(), + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer : CCP_MemberDeclaration)); SawLastInitializer = false; } - + // Add completions for virtual base classes. for (const auto &Base : ClassDecl->vbases()) { if (!InitializedBases.insert(Context.getCanonicalType(Base.getType())) .second) { SawLastInitializer - = !Initializers.empty() && + = !Initializers.empty() && Initializers.back()->isBaseInitializer() && Context.hasSameUnqualifiedType(Base.getType(), QualType(Initializers.back()->getBaseClass(), 0)); continue; } - + Builder.AddTypedTextChunk( Builder.getAllocator().CopyString( Base.getType().getAsString(Policy))); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Builder.TakeString(), + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer : CCP_MemberDeclaration)); SawLastInitializer = false; } - + // Add completions for members. for (auto *Field : ClassDecl->fields()) { if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl())) .second) { SawLastInitializer - = !Initializers.empty() && + = !Initializers.empty() && Initializers.back()->isAnyMemberInitializer() && Initializers.back()->getAnyMember() == Field; continue; } - + if (!Field->getDeclName()) continue; - + Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( Field->getIdentifier()->getName())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Builder.TakeString(), + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SawLastInitializer? CCP_NextInitializer : CCP_MemberDeclaration, CXCursor_MemberRef, @@ -4912,12 +5031,12 @@ void Sema::CodeCompleteConstructorInitializer( SawLastInitializer = false; } Results.ExitScope(); - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } -/// \brief Determine whether this scope denotes a namespace. +/// Determine whether this scope denotes a namespace. static bool isNamespaceScope(Scope *S) { DeclContext *DC = S->getEntity(); if (!DC) @@ -4941,10 +5060,10 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, IncludedThis = true; continue; } - + Known.insert(C.Id); } - + // Look for other capturable variables. for (; S && !isNamespaceScope(S); S = S->getParent()) { for (const auto *D : S->decls()) { @@ -4953,7 +5072,7 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, !Var->hasLocalStorage() || Var->hasAttr<BlocksAttr>()) continue; - + if (Known.insert(Var->getIdentifier()).second) Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration), CurContext, nullptr, false); @@ -4963,9 +5082,9 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, // Add 'this', if it would be valid. if (!IncludedThis && !AfterAmpersand && Intro.Default != LCD_ByCopy) addThisCompletion(*this, Results); - + Results.ExitScope(); - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } @@ -4980,7 +5099,7 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, typedef CodeCompletionResult Result; // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"end"))); - + CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); if (LangOpts.ObjC2) { @@ -4989,30 +5108,30 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("property"); Results.AddResult(Result(Builder.TakeString())); - + // @synthesize Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"synthesize")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("property"); Results.AddResult(Result(Builder.TakeString())); - } + } } static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; - + // Since we have an interface or protocol, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"end"))); - + if (LangOpts.ObjC2) { // @property Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"property"))); - + // @required Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"required"))); - + // @optional Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,"optional"))); } @@ -5022,35 +5141,35 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + // @class name ; Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"class")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); - + if (Results.includeCodePatterns()) { - // @interface name - // FIXME: Could introduce the whole pattern, including superclasses and + // @interface name + // FIXME: Could introduce the whole pattern, including superclasses and // such. Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"interface")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("class"); Results.AddResult(Result(Builder.TakeString())); - + // @protocol name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"protocol")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("protocol"); Results.AddResult(Result(Builder.TakeString())); - + // @implementation name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"implementation")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("class"); Results.AddResult(Result(Builder.TakeString())); } - + // @compatibility_alias name Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"compatibility_alias")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -5080,9 +5199,8 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S) { else AddObjCTopLevelResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { @@ -5101,7 +5219,7 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { Builder.AddPlaceholderChunk("type-name"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); - + // @protocol ( protocol-name ) Builder.AddResultTypeChunk("Protocol *"); Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"protocol")); @@ -5154,7 +5272,7 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompletionResult Result; CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + if (Results.includeCodePatterns()) { // @try { statements } @catch ( declaration ) { statements } @finally // { statements } @@ -5175,13 +5293,13 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { Builder.AddChunk(CodeCompletionString::CK_RightBrace); Results.AddResult(Result(Builder.TakeString())); } - + // @throw Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"throw")); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); - + if (Results.includeCodePatterns()) { // @synchronized ( expression ) { statements } Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,"synchronized")); @@ -5214,9 +5332,8 @@ void Sema::CodeCompleteObjCAtVisibility(Scope *S) { Results.EnterNewScope(); AddObjCVisibilityResults(getLangOpts(), Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCAtStatement(Scope *S) { @@ -5227,9 +5344,8 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { AddObjCStatementResults(Results, false); AddObjCExpressionResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCAtExpression(Scope *S) { @@ -5239,25 +5355,24 @@ void Sema::CodeCompleteObjCAtExpression(Scope *S) { Results.EnterNewScope(); AddObjCExpressionResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -/// \brief Determine whether the addition of the given flag to an Objective-C +/// Determine whether the addition of the given flag to an Objective-C /// property's attributes will cause a conflict. static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { // Check if we've already added this flag. if (Attributes & NewFlag) return true; - + Attributes |= NewFlag; - + // Check for collisions with "readonly". if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) return true; - + // Check for more than one of { assign, copy, retain, strong, weak }. unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_unsafe_unretained | @@ -5273,16 +5388,16 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak) return true; - + return false; } -void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { +void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { if (!CodeCompleter) return; - + unsigned Attributes = ODS.getPropertyAttributes(); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); @@ -5335,12 +5450,11 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("null_resettable")); } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -/// \brief Describes the kind of Objective-C method that we want to find +/// Describes the kind of Objective-C method that we want to find /// via code completion. enum ObjCMethodKind { MK_Any, ///< Any kind of method, provided it means other specified criteria. @@ -5355,20 +5469,20 @@ static bool isAcceptableObjCSelector(Selector Sel, unsigned NumSelIdents = SelIdents.size(); if (NumSelIdents > Sel.getNumArgs()) return false; - + switch (WantKind) { case MK_Any: break; case MK_ZeroArgSelector: return Sel.isUnarySelector(); case MK_OneArgSelector: return Sel.getNumArgs() == 1; } - + if (!AllowSameLength && NumSelIdents && NumSelIdents == Sel.getNumArgs()) return false; - + for (unsigned I = 0; I != NumSelIdents; ++I) if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I)) return false; - + return true; } @@ -5381,16 +5495,16 @@ static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, } namespace { - /// \brief A set of selectors, which is used to avoid introducing multiple + /// A set of selectors, which is used to avoid introducing multiple /// completions with the same selector into the result set. typedef llvm::SmallPtrSet<Selector, 16> VisitedSelectorSet; } -/// \brief Add all of the Objective-C methods in the given Objective-C +/// Add all of the Objective-C methods in the given Objective-C /// container to the set of results. /// -/// The container will be a class, protocol, category, or implementation of -/// any of the above. This mether will recurse to include methods from +/// The container will be a class, protocol, category, or implementation of +/// any of the above. This mether will recurse to include methods from /// the superclasses of classes along with their categories, protocols, and /// implementations. /// @@ -5422,7 +5536,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, // metaclass. if (M->isInstanceMethod() == WantInstanceMethods || (IsRootClass && !WantInstanceMethods)) { - // Check whether the selector identifiers we've been given are a + // Check whether the selector identifiers we've been given are a // subset of the identifiers for this particular method. if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength)) continue; @@ -5438,23 +5552,23 @@ static void AddObjCMethods(ObjCContainerDecl *Container, Results.MaybeAddResult(R, CurContext); } } - + // Visit the protocols of protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { if (Protocol->hasDefinition()) { const ObjCList<ObjCProtocolDecl> &Protocols = Protocol->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, CurContext, Selectors, AllowSameLength, Results, false, IsRootClass); } } - + if (!IFace || !IFace->hasDefinition()) return; - + // Add methods in protocols. for (auto *I : IFace->protocols()) AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents, CurContext, @@ -5467,7 +5581,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, InOriginalClass, IsRootClass); // Add a categories protocol methods. - const ObjCList<ObjCProtocolDecl> &Protocols + const ObjCList<ObjCProtocolDecl> &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); @@ -5481,7 +5595,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, Selectors, AllowSameLength, Results, InOriginalClass, IsRootClass); } - + // Add methods in superclass. // Avoid passing in IsRootClass since root classes won't have super classes. if (IFace->getSuperClass()) @@ -5519,9 +5633,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCPropertySetter(Scope *S) { @@ -5548,9 +5661,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) { Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, @@ -5559,22 +5671,22 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Type); Results.EnterNewScope(); - + // Add context-sensitive, Objective-C parameter-passing keywords. bool AddedInOut = false; - if ((DS.getObjCDeclQualifier() & + if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_In | ObjCDeclSpec::DQ_Inout)) == 0) { Results.AddResult("in"); Results.AddResult("inout"); AddedInOut = true; } - if ((DS.getObjCDeclQualifier() & + if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_Out | ObjCDeclSpec::DQ_Inout)) == 0) { Results.AddResult("out"); if (!AddedInOut) Results.AddResult("inout"); } - if ((DS.getObjCDeclQualifier() & + if ((DS.getObjCDeclQualifier() & (ObjCDeclSpec::DQ_Bycopy | ObjCDeclSpec::DQ_Byref | ObjCDeclSpec::DQ_Oneway)) == 0) { Results.AddResult("bycopy"); @@ -5586,8 +5698,8 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, Results.AddResult("nullable"); Results.AddResult("null_unspecified"); } - - // If we're completing the return type of an Objective-C method and the + + // If we're completing the return type of an Objective-C method and the // identifier IBAction refers to a macro, provide a completion item for // an action, e.g., // IBAction)<#selector#>:(id)sender @@ -5611,26 +5723,26 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, if (!IsParameter) { Results.AddResult(CodeCompletionResult("instancetype")); } - + // Add various builtin type names and specifiers. AddOrdinaryNameResults(PCC_Type, S, *this, Results); Results.ExitScope(); - + // Add the various type names Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Type, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } -/// \brief When we have an expression with type "id", we may assume +/// When we have an expression with type "id", we may assume /// that it has some more-specific class type based on knowledge of /// common uses of Objective-C. This routine returns that class type, /// or NULL if no better result could be determined. @@ -5702,7 +5814,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { } // Add a special completion for a message send to "super", which fills in the -// most likely case of forwarding all of our arguments to the superclass +// most likely case of forwarding all of our arguments to the superclass // function. /// /// \param S The semantic analysis object. @@ -5715,7 +5827,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { /// /// \param Results The set of results to augment. /// -/// \returns the Objective-C method declaration that would be invoked by +/// \returns the Objective-C method declaration that would be invoked by /// this "super" completion. If NULL, no completion was added. static ObjCMethodDecl *AddSuperSendCompletion( Sema &S, bool NeedSuperKeyword, @@ -5733,7 +5845,7 @@ static ObjCMethodDecl *AddSuperSendCompletion( ObjCMethodDecl *SuperMethod = nullptr; while ((Class = Class->getSuperClass()) && !SuperMethod) { // Check in the class - SuperMethod = Class->getMethod(CurMethod->getSelector(), + SuperMethod = Class->getMethod(CurMethod->getSelector(), CurMethod->isInstanceMethod()); // Check in categories or class extensions. @@ -5759,7 +5871,7 @@ static ObjCMethodDecl *AddSuperSendCompletion( SuperP = SuperMethod->param_begin(); CurP != CurPEnd; ++CurP, ++SuperP) { // Make sure the parameter types are compatible. - if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(), + if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(), (*SuperP)->getType())) return nullptr; @@ -5767,11 +5879,11 @@ static ObjCMethodDecl *AddSuperSendCompletion( if (!(*CurP)->getIdentifier()) return nullptr; } - + // We have a superclass method. Now, form the send-to-super completion. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + // Give this completion a return type. AddResultTypeChunk(S.Context, getCompletionPrintingPolicy(S), SuperMethod, Results.getCompletionContext().getBaseType(), @@ -5782,7 +5894,7 @@ static ObjCMethodDecl *AddSuperSendCompletion( Builder.AddTypedTextChunk("super"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); } - + Selector Sel = CurMethod->getSelector(); if (Sel.isUnarySelector()) { if (NeedSuperKeyword) @@ -5796,7 +5908,7 @@ static ObjCMethodDecl *AddSuperSendCompletion( for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) { if (I > SelIdents.size()) Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - + if (I < SelIdents.size()) Builder.AddInformativeChunk( Builder.getAllocator().CopyString( @@ -5812,16 +5924,16 @@ static ObjCMethodDecl *AddSuperSendCompletion( Builder.getAllocator().CopyString( Sel.getNameForSlot(I) + ":")); Builder.AddPlaceholderChunk(Builder.getAllocator().CopyString( - (*CurP)->getIdentifier()->getName())); + (*CurP)->getIdentifier()->getName())); } } } - + Results.AddResult(CodeCompletionResult(Builder.TakeString(), SuperMethod, CCP_SuperCompletion)); return SuperMethod; } - + void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -5830,32 +5942,33 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { getLangOpts().CPlusPlus11 ? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture : &ResultBuilder::IsObjCMessageReceiver); - + CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, - CodeCompleter->includeGlobals()); - + CodeCompleter->includeGlobals(), + CodeCompleter->loadExternal()); + // If we are in an Objective-C method inside a class that has a superclass, // add "super" as an option. if (ObjCMethodDecl *Method = getCurMethodDecl()) if (ObjCInterfaceDecl *Iface = Method->getClassInterface()) if (Iface->getSuperClass()) { Results.AddResult(Result("super")); - + AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results); } - + if (getLangOpts().CPlusPlus11) addThisCompletion(*this, Results); - + Results.ExitScope(); - + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); - + } void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, @@ -5867,7 +5980,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, CDecl = CurMethod->getClassInterface(); if (!CDecl) return; - + // Find the superclass of this class. CDecl = CDecl->getSuperClass(); if (!CDecl) @@ -5887,7 +6000,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, // "super" may be the name of a type or variable. Figure out which // it is. IdentifierInfo *Super = getSuperIdentifier(); - NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, + NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, LookupOrdinaryName); if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { // "super" names an interface. Use it. @@ -5916,24 +6029,24 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ParsedType Receiver; if (CDecl) Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl)); - return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, + return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, AtArgumentExpression, /*IsSuper=*/true); } -/// \brief Given a set of code-completion results for the argument of a message +/// Given a set of code-completion results for the argument of a message /// send, determine the preferred type (if any) for that argument expression. static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, unsigned NumSelIdents) { - typedef CodeCompletionResult Result; + typedef CodeCompletionResult Result; ASTContext &Context = Results.getSema().Context; - + QualType PreferredType; unsigned BestPriority = CCP_Unlikely * 2; Result *ResultsData = Results.data(); for (unsigned I = 0, N = Results.size(); I != N; ++I) { Result &R = ResultsData[I]; - if (R.Kind == Result::RK_Declaration && + if (R.Kind == Result::RK_Declaration && isa<ObjCMethodDecl>(R.Declaration)) { if (R.Priority <= BestPriority) { const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration); @@ -5955,7 +6068,7 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, return PreferredType; } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, +static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, ArrayRef<IdentifierInfo *> SelIdents, bool AtArgumentExpression, @@ -5968,55 +6081,55 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, // corresponding declaration. if (Receiver) { QualType T = SemaRef.GetTypeFromParser(Receiver, nullptr); - if (!T.isNull()) + if (!T.isNull()) if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>()) CDecl = Interface->getInterface(); } - + // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. Results.EnterNewScope(); - - // If this is a send-to-super, try to add the special "super" send + + // If this is a send-to-super, try to add the special "super" send // completion. if (IsSuper) { if (ObjCMethodDecl *SuperMethod = AddSuperSendCompletion(SemaRef, false, SelIdents, Results)) Results.Ignore(SuperMethod); } - + // If we're inside an Objective-C method definition, prefer its selector to // others. if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); - + VisitedSelectorSet Selectors; - if (CDecl) + if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, SemaRef.CurContext, Selectors, AtArgumentExpression, - Results); + Results); else { // We're messaging "id" as a type; provide all class/factory methods. - + // If we have an external source, load the entire class method // pool from the AST file. if (SemaRef.getExternalSource()) { - for (uint32_t I = 0, + for (uint32_t I = 0, N = SemaRef.getExternalSource()->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I); if (Sel.isNull() || SemaRef.MethodPool.count(Sel)) continue; - + SemaRef.ReadMethodPool(Sel); } } - + for (Sema::GlobalMethodPool::iterator M = SemaRef.MethodPool.begin(), MEnd = SemaRef.MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; - MethList && MethList->getMethod(); + MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; @@ -6029,32 +6142,32 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, } } } - - Results.ExitScope(); + + Results.ExitScope(); } void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef<IdentifierInfo *> SelIdents, bool AtArgumentExpression, bool IsSuper) { - + QualType T = this->GetTypeFromParser(Receiver); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCClassMessage, T, SelIdents)); - + AddClassMessageCompletions(*this, S, Receiver, SelIdents, AtArgumentExpression, IsSuper, Results); - - // If we're actually at the argument expression (rather than prior to the + + // If we're actually at the argument expression (rather than prior to the // selector), we're actually performing code completion for an expression. - // Determine whether we have a single, best method. If so, we can + // Determine whether we have a single, best method. If so, we can // code-complete the expression using the corresponding parameter type as // our preferred type, improving completion results. if (AtArgumentExpression) { - QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, SelIdents.size()); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); @@ -6063,7 +6176,7 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, return; } - HandleCodeCompleteResults(this, CodeCompleter, + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } @@ -6073,9 +6186,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, bool AtArgumentExpression, ObjCInterfaceDecl *Super) { typedef CodeCompletionResult Result; - + Expr *RecExpr = static_cast<Expr *>(Receiver); - + // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. if (RecExpr) { @@ -6084,18 +6197,18 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, return; RecExpr = Conv.get(); } - QualType ReceiverType = RecExpr? RecExpr->getType() + QualType ReceiverType = RecExpr? RecExpr->getType() : Super? Context.getObjCObjectPointerType( Context.getObjCInterfaceType(Super)) : Context.getObjCIdType(); - + // If we're messaging an expression with type "id" or "Class", check // whether we know something special about the receiver that allows // us to assume a more-specific receiver type. if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) { if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) { if (ReceiverType->isObjCClassType()) - return CodeCompleteObjCClassMessage(S, + return CodeCompleteObjCClassMessage(S, ParsedType::make(Context.getObjCInterfaceType(IFace)), SelIdents, AtArgumentExpression, Super); @@ -6116,36 +6229,36 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext(CodeCompletionContext::CCC_ObjCInstanceMessage, ReceiverType, SelIdents)); - + Results.EnterNewScope(); - // If this is a send-to-super, try to add the special "super" send + // If this is a send-to-super, try to add the special "super" send // completion. if (Super) { if (ObjCMethodDecl *SuperMethod = AddSuperSendCompletion(*this, false, SelIdents, Results)) Results.Ignore(SuperMethod); } - + // If we're inside an Objective-C method definition, prefer its selector to // others. if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); - + // Keep track of the selectors we've already added. VisitedSelectorSet Selectors; - + // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a // class method. - if (ReceiverType->isObjCClassType() || + if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); } - } + } // Handle messages to a qualified ID ("id<foo>"). else if (const ObjCObjectPointerType *QualID = ReceiverType->getAsObjCQualifiedIdType()) { @@ -6161,7 +6274,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents, CurContext, Selectors, AtArgumentExpression, Results); - + // Search protocols for instance methods. for (auto *I : IFacePtr->quals()) AddObjCMethods(I, true, MK_Any, SelIdents, CurContext, @@ -6189,11 +6302,11 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, MEnd = MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; - MethList && MethList->getMethod(); + MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; - + if (!Selectors.insert(MethList->getMethod()->getSelector()).second) continue; @@ -6206,15 +6319,15 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, } } Results.ExitScope(); - - - // If we're actually at the argument expression (rather than prior to the + + + // If we're actually at the argument expression (rather than prior to the // selector), we're actually performing code completion for an expression. - // Determine whether we have a single, best method. If so, we can + // Determine whether we have a single, best method. If so, we can // code-complete the expression using the corresponding parameter type as // our preferred type, improving completion results. if (AtArgumentExpression) { - QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, + QualType PreferredType = getPreferredArgumentTypeForMessageSend(Results, SelIdents.size()); if (PreferredType.isNull()) CodeCompleteOrdinaryName(S, PCC_Expression); @@ -6222,17 +6335,17 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, CodeCompleteExpression(S, PreferredType); return; } - - HandleCodeCompleteResults(this, CodeCompleter, + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); } -void Sema::CodeCompleteObjCForCollection(Scope *S, +void Sema::CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar) { CodeCompleteExpressionData Data; Data.ObjCCollection = true; - + if (IterationVar.getAsOpaquePtr()) { DeclGroupRef DG = IterationVar.get(); for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) { @@ -6240,7 +6353,7 @@ void Sema::CodeCompleteObjCForCollection(Scope *S, Data.IgnoreDecls.push_back(*I); } } - + CodeCompleteExpression(S, Data); } @@ -6254,11 +6367,11 @@ void Sema::CodeCompleteObjCSelector(Scope *S, Selector Sel = ExternalSource->GetExternalSelector(I); if (Sel.isNull() || MethodPool.count(Sel)) continue; - + ReadMethodPool(Sel); } } - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_SelectorName); @@ -6266,7 +6379,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { - + Selector Sel = M->first; if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents)) continue; @@ -6279,7 +6392,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, Results.AddResult(Builder.TakeString()); continue; } - + std::string Accumulator; for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) { if (I == SelIdents.size()) { @@ -6289,7 +6402,7 @@ void Sema::CodeCompleteObjCSelector(Scope *S, Accumulator.clear(); } } - + Accumulator += Sel.getNameForSlot(I); Accumulator += ':'; } @@ -6297,19 +6410,18 @@ void Sema::CodeCompleteObjCSelector(Scope *S, Results.AddResult(Builder.TakeString()); } Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_SelectorName, + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } -/// \brief Add all of the protocol declarations that we find in the given +/// Add all of the protocol declarations that we find in the given /// (translation unit) context. static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, ResultBuilder &Results) { typedef CodeCompletionResult Result; - + for (const auto *D : Ctx->decls()) { // Record any protocols we find. if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(D)) @@ -6324,10 +6436,10 @@ void Sema::CodeCompleteObjCProtocolReferences( ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); - + if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); - + // Tell the result set to ignore all of the protocols we have // already seen. // FIXME: This doesn't work when caching code-completion results. @@ -6342,40 +6454,38 @@ void Sema::CodeCompleteObjCProtocolReferences( Results.ExitScope(); } - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCProtocolName, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCProtocolDecl(Scope *) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); - + if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); - + // Add all protocols. AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, Results); Results.ExitScope(); } - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCProtocolName, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -/// \brief Add all of the Objective-C interface declarations that we find in +/// Add all of the Objective-C interface declarations that we find in /// the given (translation unit) context. static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, bool OnlyUnimplemented, ResultBuilder &Results) { typedef CodeCompletionResult Result; - + for (const auto *D : Ctx->decls()) { // Record any interfaces we find. if (const auto *Class = dyn_cast<ObjCInterfaceDecl>(D)) @@ -6386,32 +6496,31 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, } } -void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { +void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); - + if (CodeCompleter->includeGlobals()) { // Add all classes. AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, false, Results); } - + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCInterfaceName, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, - SourceLocation ClassNameLoc) { + SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCInterfaceName); Results.EnterNewScope(); - + // Make sure that we ignore the class we're currently defining. NamedDecl *CurClass = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); @@ -6423,18 +6532,17 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, false, Results); } - + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCInterfaceName, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { +void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext::CCC_Other); + CodeCompletionContext::CCC_ObjCImplementation); Results.EnterNewScope(); if (CodeCompleter->includeGlobals()) { @@ -6442,23 +6550,22 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, true, Results); } - + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCInterfaceName, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, +void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { typedef CodeCompletionResult Result; - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); - + // Ignore any categories we find that have already been implemented by this // interface. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; @@ -6472,24 +6579,23 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, // Add all of the categories we know about. Results.EnterNewScope(); TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - for (const auto *D : TU->decls()) + for (const auto *D : TU->decls()) if (const auto *Category = dyn_cast<ObjCCategoryDecl>(D)) if (CategoryNames.insert(Category->getIdentifier()).second) Results.AddResult(Result(Category, Results.getBasePriority(Category), nullptr), CurContext, nullptr, false); Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCCategoryName, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -void Sema::CodeCompleteObjCImplementationCategory(Scope *S, +void Sema::CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { typedef CodeCompletionResult Result; - + // Find the corresponding interface. If we couldn't find the interface, the // program itself is ill-formed. However, we'll try to be helpful still by // providing the list of all of the categories we know about. @@ -6498,12 +6604,12 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass); if (!Class) return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); - + ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); - - // Add all of the categories that have have corresponding interface + + // Add all of the categories that have have corresponding interface // declarations in this class and any of its superclasses, except for // already-implemented categories in the class itself. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; @@ -6516,15 +6622,14 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Results.AddResult(Result(Cat, Results.getBasePriority(Cat), nullptr), CurContext, nullptr, false); } - + Class = Class->getSuperClass(); IgnoreImplemented = false; } Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_ObjCCategoryName, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { @@ -6536,38 +6641,37 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { // Figure out where this @synthesize lives. ObjCContainerDecl *Container = dyn_cast_or_null<ObjCContainerDecl>(CurContext); - if (!Container || - (!isa<ObjCImplementationDecl>(Container) && + if (!Container || + (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) - return; + return; // Ignore any properties that have already been implemented. Container = getContainerDef(Container); for (const auto *D : Container->decls()) if (const auto *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(D)) Results.Ignore(PropertyImpl->getPropertyDecl()); - + // Add any properties that we find. AddedPropertiesSet AddedProperties; Results.EnterNewScope(); if (ObjCImplementationDecl *ClassImpl = dyn_cast<ObjCImplementationDecl>(Container)) AddObjCProperties(CCContext, ClassImpl->getClassInterface(), false, - /*AllowNullaryMethods=*/false, CurContext, + /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); else AddObjCProperties(CCContext, cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(), - false, /*AllowNullaryMethods=*/false, CurContext, + false, /*AllowNullaryMethods=*/false, CurContext, AddedProperties, Results); Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, +void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName) { typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -6577,11 +6681,11 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, // Figure out where this @synthesize lives. ObjCContainerDecl *Container = dyn_cast_or_null<ObjCContainerDecl>(CurContext); - if (!Container || - (!isa<ObjCImplementationDecl>(Container) && + if (!Container || + (!isa<ObjCImplementationDecl>(Container) && !isa<ObjCCategoryImplDecl>(Container))) - return; - + return; + // Figure out which interface we're looking into. ObjCInterfaceDecl *Class = nullptr; if (ObjCImplementationDecl *ClassImpl @@ -6596,10 +6700,10 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, if (Class) { if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration( PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { - PropertyType + PropertyType = Property->getType().getNonReferenceType().getUnqualifiedType(); - - // Give preference to ivars + + // Give preference to ivars Results.setPreferredType(PropertyType); } } @@ -6613,32 +6717,32 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, std::string NameWithSuffix = PropertyName->getName().str(); NameWithSuffix += '_'; for(; Class; Class = Class->getSuperClass()) { - for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar; + for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar; Ivar = Ivar->getNextIvar()) { Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), nullptr), CurContext, nullptr, false); - // Determine whether we've seen an ivar with a name similar to the + // Determine whether we've seen an ivar with a name similar to the // property. if ((PropertyName == Ivar->getIdentifier() || NameWithPrefix == Ivar->getName() || NameWithSuffix == Ivar->getName())) { SawSimilarlyNamedIvar = true; - + // Reduce the priority of this result by one, to give it a slight // advantage over other results whose names don't match so closely. - if (Results.size() && - Results.data()[Results.size() - 1].Kind + if (Results.size() && + Results.data()[Results.size() - 1].Kind == CodeCompletionResult::RK_Declaration && Results.data()[Results.size() - 1].Declaration == Ivar) Results.data()[Results.size() - 1].Priority--; } } } - + if (!SawSimilarlyNamedIvar) { // Create ivar result _propName, that the user can use to synthesize - // an ivar of the appropriate type. + // an ivar of the appropriate type. unsigned Priority = CCP_MemberDeclaration + 1; typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); @@ -6649,15 +6753,14 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context, Policy, Allocator)); Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix)); - Results.AddResult(Result(Builder.TakeString(), Priority, + Results.AddResult(Result(Builder.TakeString(), Priority, CXCursor_ObjCIvarDecl)); } - + Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } // Mapping from selectors to the methods that implement that selector, along @@ -6665,7 +6768,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, typedef llvm::DenseMap< Selector, llvm::PointerIntPair<ObjCMethodDecl *, 1, bool> > KnownMethodsMap; -/// \brief Find all of the methods that reside in the given container +/// Find all of the methods that reside in the given container /// (and its superclasses, protocols, etc.) that meet the given /// criteria. Insert those methods into the map of known methods, /// indexed by selector so they can be easily found. @@ -6682,11 +6785,11 @@ static void FindImplementableMethods(ASTContext &Context, IFace = IFace->getDefinition(); Container = IFace; - + const ObjCList<ObjCProtocolDecl> &Protocols = IFace->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, InOriginalClass); @@ -6694,12 +6797,12 @@ static void FindImplementableMethods(ASTContext &Context, // Add methods from any class extensions and categories. for (auto *Cat : IFace->visible_categories()) { FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType, - KnownMethods, false); + KnownMethods, false); } // Visit the superclass. if (IFace->getSuperClass()) - FindImplementableMethods(Context, IFace->getSuperClass(), + FindImplementableMethods(Context, IFace->getSuperClass(), WantInstanceMethods, ReturnType, KnownMethods, false); } @@ -6709,14 +6812,14 @@ static void FindImplementableMethods(ASTContext &Context, const ObjCList<ObjCProtocolDecl> &Protocols = Category->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, InOriginalClass); - + // If this category is the original class, jump to the interface. if (InOriginalClass && Category->getClassInterface()) - FindImplementableMethods(Context, Category->getClassInterface(), + FindImplementableMethods(Context, Category->getClassInterface(), WantInstanceMethods, ReturnType, KnownMethods, false); } @@ -6727,12 +6830,12 @@ static void FindImplementableMethods(ASTContext &Context, return; Protocol = Protocol->getDefinition(); Container = Protocol; - + // Recurse into protocols. const ObjCList<ObjCProtocolDecl> &Protocols = Protocol->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); + E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, KnownMethods, false); @@ -6753,7 +6856,7 @@ static void FindImplementableMethods(ASTContext &Context, } } -/// \brief Add the parenthesized return or parameter type chunk to a code +/// Add the parenthesized return or parameter type chunk to a code /// completion string. static void AddObjCPassingTypeChunk(QualType Type, unsigned ObjCDeclQuals, @@ -6769,20 +6872,20 @@ static void AddObjCPassingTypeChunk(QualType Type, Builder.AddChunk(CodeCompletionString::CK_RightParen); } -/// \brief Determine whether the given class is or inherits from a class by +/// Determine whether the given class is or inherits from a class by /// the given name. -static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, +static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, StringRef Name) { if (!Class) return false; - + if (Class->getIdentifier() && Class->getIdentifier()->getName() == Name) return true; - + return InheritsFromClassNamed(Class->getSuperClass(), Name); } - -/// \brief Add code completions for Objective-C Key-Value Coding (KVC) and + +/// Add code completions for Objective-C Key-Value Coding (KVC) and /// Key-Value Observing (KVO). static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, bool IsInstanceMethod, @@ -6793,17 +6896,17 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, IdentifierInfo *PropName = Property->getIdentifier(); if (!PropName || PropName->getLength() == 0) return; - + PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); // Builder that will create each code completion. typedef CodeCompletionResult Result; CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); - + // The selector table. SelectorTable &Selectors = Context.Selectors; - + // The property name, copied into the code completion allocation region // on demand. struct KeyHolder { @@ -6817,22 +6920,22 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, operator const char *() { if (CopiedKey) return CopiedKey; - + return CopiedKey = Allocator.CopyString(Key); } } Key(Allocator, PropName->getName()); - + // The uppercased name of the property name. std::string UpperKey = PropName->getName(); if (!UpperKey.empty()) UpperKey[0] = toUppercase(UpperKey[0]); - + bool ReturnTypeMatchesProperty = ReturnType.isNull() || - Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(), + Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(), Property->getType()); - bool ReturnTypeMatchesVoid + bool ReturnTypeMatchesVoid = ReturnType.isNull() || ReturnType->isVoidType(); - + // Add the normal accessor -(type)key. if (IsInstanceMethod && KnownSelectors.insert(Selectors.getNullarySelector(PropName)).second && @@ -6840,19 +6943,19 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (ReturnType.isNull()) AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy, Builder); - + Builder.AddTypedTextChunk(Key); - Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } - + // If we have an integral or boolean property (or the user has provided // an integral or boolean return type), add the accessor -(type)isKey. if (IsInstanceMethod && - ((!ReturnType.isNull() && + ((!ReturnType.isNull() && (ReturnType->isIntegerType() || ReturnType->isBooleanType())) || - (ReturnType.isNull() && - (Property->getType()->isIntegerType() || + (ReturnType.isNull() && + (Property->getType()->isIntegerType() || Property->getType()->isBooleanType())))) { std::string SelectorName = (Twine("is") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); @@ -6863,16 +6966,16 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("BOOL"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName())); - Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } } - + // Add the normal mutator. - if (IsInstanceMethod && ReturnTypeMatchesVoid && + if (IsInstanceMethod && ReturnTypeMatchesVoid && !Property->getSetterMethodDecl()) { std::string SelectorName = (Twine("set") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); @@ -6882,36 +6985,36 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName())); Builder.AddTypedTextChunk(":"); AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy, Builder); Builder.AddTextChunk(Key); - Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCInstanceMethodDecl)); } } - + // Indexed and unordered accessors unsigned IndexedGetterPriority = CCP_CodePattern; unsigned IndexedSetterPriority = CCP_CodePattern; unsigned UnorderedGetterPriority = CCP_CodePattern; unsigned UnorderedSetterPriority = CCP_CodePattern; - if (const ObjCObjectPointerType *ObjCPointer + if (const ObjCObjectPointerType *ObjCPointer = Property->getType()->getAs<ObjCObjectPointerType>()) { if (ObjCInterfaceDecl *IFace = ObjCPointer->getInterfaceDecl()) { // If this interface type is not provably derived from a known // collection, penalize the corresponding completions. if (!InheritsFromClassNamed(IFace, "NSMutableArray")) { - IndexedSetterPriority += CCD_ProbablyNotObjCCollection; + IndexedSetterPriority += CCD_ProbablyNotObjCCollection; if (!InheritsFromClassNamed(IFace, "NSArray")) IndexedGetterPriority += CCD_ProbablyNotObjCCollection; } if (!InheritsFromClassNamed(IFace, "NSMutableSet")) { - UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; + UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; if (!InheritsFromClassNamed(IFace, "NSSet")) UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; } @@ -6922,9 +7025,9 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, UnorderedGetterPriority += CCD_ProbablyNotObjCCollection; UnorderedSetterPriority += CCD_ProbablyNotObjCCollection; } - + // Add -(NSUInteger)countOf<key> - if (IsInstanceMethod && + if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isIntegerType())) { std::string SelectorName = (Twine("countOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); @@ -6935,16 +7038,16 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk( Allocator.CopyString(SelectorId->getName())); - Results.AddResult(Result(Builder.TakeString(), - std::min(IndexedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), + std::min(IndexedGetterPriority, UnorderedGetterPriority), CXCursor_ObjCInstanceMethodDecl)); } } - + // Indexed getters // Add -(id)objectInKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && @@ -6958,20 +7061,20 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("id"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); - Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // Add -(NSArray *)keyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && - (ReturnType.isNull() || + (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() @@ -6985,17 +7088,17 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSArray *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); - Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("get") + UpperKey).str(); @@ -7003,14 +7106,14 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName), &Context.Idents.get("range") }; - + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); @@ -7023,13 +7126,13 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSRange"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("inRange"); - Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // Mutable indexed accessors - + // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); @@ -7037,14 +7140,14 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get("insertObject"), &Context.Idents.get(SelectorName) }; - + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk("insertObject:"); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); @@ -7057,11 +7160,11 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddPlaceholderChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("insert") + UpperKey).str(); @@ -7069,14 +7172,14 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName), &Context.Idents.get("atIndexes") }; - + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSArray *"); @@ -7088,55 +7191,55 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddPlaceholderChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSUInteger"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("index"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSIndexSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("indexes"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName @@ -7145,14 +7248,14 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, &Context.Idents.get(SelectorName), &Context.Idents.get("withObject") }; - + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSUInteger"); @@ -7164,28 +7267,28 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("id"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array if (IsInstanceMethod && ReturnTypeMatchesVoid) { - std::string SelectorName1 + std::string SelectorName1 = (Twine("replace") + UpperKey + "AtIndexes").str(); std::string SelectorName2 = (Twine("with") + UpperKey).str(); IdentifierInfo *SelectorIds[2] = { &Context.Idents.get(SelectorName1), &Context.Idents.get(SelectorName2) }; - + if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName1 + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("NSIndexSet *"); @@ -7197,15 +7300,15 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSArray *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("array"); - Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } - + } + // Unordered getters // - (NSEnumerator *)enumeratorOfKey - if (IsInstanceMethod && - (ReturnType.isNull() || + if (IsInstanceMethod && + (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() @@ -7219,15 +7322,15 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSEnumerator *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); - Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } // - (type *)memberOfKey:(type *)object - if (IsInstanceMethod && + if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("memberOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); @@ -7238,24 +7341,24 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); if (ReturnType.isNull()) { Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); } else { - Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, + Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, Policy, Builder.getAllocator())); } Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); - Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, CXCursor_ObjCInstanceMethodDecl)); } } - + // Mutable unordered accessors // - (void)addKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { @@ -7268,17 +7371,17 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); - Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } + } // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { @@ -7290,17 +7393,17 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); - Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } - + } + // - (void)removeKeyObject:(type *)object if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName @@ -7312,18 +7415,18 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddPlaceholderChunk("object-type"); Builder.AddTextChunk(" *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("object"); - Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } - + } + // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey).str(); @@ -7334,16 +7437,16 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); - Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } + } // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { @@ -7355,26 +7458,26 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("void"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":")); Builder.AddChunk(CodeCompletionString::CK_LeftParen); Builder.AddTextChunk("NSSet *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Builder.AddTextChunk("objects"); - Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, + Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, CXCursor_ObjCInstanceMethodDecl)); } - } - + } + // Key-Value Observing // + (NSSet *)keyPathsForValuesAffectingKey - if (!IsInstanceMethod && - (ReturnType.isNull() || + if (!IsInstanceMethod && + (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() ->getName() == "NSSet"))) { - std::string SelectorName + std::string SelectorName = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) @@ -7384,9 +7487,9 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("NSSet<NSString *> *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); - Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCClassMethodDecl)); } } @@ -7394,9 +7497,9 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // + (BOOL)automaticallyNotifiesObserversForKey if (!IsInstanceMethod && (ReturnType.isNull() || - ReturnType->isIntegerType() || + ReturnType->isIntegerType() || ReturnType->isBooleanType())) { - std::string SelectorName + std::string SelectorName = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) @@ -7406,9 +7509,9 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddTextChunk("BOOL"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } - + Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName)); - Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, + Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, CXCursor_ObjCClassMethodDecl)); } } @@ -7422,7 +7525,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, Decl *IDecl = nullptr; if (CurContext->isObjCContainer()) { ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); - IDecl = cast<Decl>(OCD); + IDecl = OCD; } // Determine where we should start searching for methods. ObjCContainerDecl *SearchDecl = nullptr; @@ -7431,7 +7534,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) { SearchDecl = Impl->getClassInterface(); IsInImplementation = true; - } else if (ObjCCategoryImplDecl *CatImpl + } else if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D)) { SearchDecl = CatImpl->getCategoryDecl(); IsInImplementation = true; @@ -7445,17 +7548,17 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, } if (!SearchDecl) { - HandleCodeCompleteResults(this, CodeCompleter, + HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, nullptr, 0); return; } - + // Find all of the methods that we could declare/implement here. KnownMethodsMap KnownMethods; - FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, + FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, ReturnType, KnownMethods); - + // Add declarations or definitions for each of the known methods. typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -7463,7 +7566,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, CodeCompletionContext::CCC_Other); Results.EnterNewScope(); PrintingPolicy Policy = getCompletionPrintingPolicy(*this); - for (KnownMethodsMap::iterator M = KnownMethods.begin(), + for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { ObjCMethodDecl *Method = M->second.getPointer(); @@ -7494,7 +7597,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, // Add parameters to the pattern. unsigned I = 0; - for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; (void)++P, ++I) { // Add the part of the selector name. @@ -7520,16 +7623,16 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, (*P)->getObjCDeclQualifier(), Context, Policy, Builder); - + if (IdentifierInfo *Id = (*P)->getIdentifier()) - Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); + Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); } if (Method->isVariadic()) { if (Method->param_size() > 0) Builder.AddChunk(CodeCompletionString::CK_Comma); Builder.AddTextChunk("..."); - } + } if (IsInImplementation && Results.includeCodePatterns()) { // We will be defining the method here, so add a compound statement. @@ -7544,7 +7647,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, Builder.AddChunk(CodeCompletionString::CK_SemiColon); } else Builder.AddPlaceholderChunk("statements"); - + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); Builder.AddChunk(CodeCompletionString::CK_RightBrace); } @@ -7552,28 +7655,28 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, unsigned Priority = CCP_CodePattern; if (!M->second.getInt()) Priority += CCD_InBaseClass; - + Results.AddResult(Result(Builder.TakeString(), Method, Priority)); } - // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of + // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of // the properties in this class and its categories. if (Context.getLangOpts().ObjC2) { SmallVector<ObjCContainerDecl *, 4> Containers; Containers.push_back(SearchDecl); - + VisitedSelectorSet KnownSelectors; - for (KnownMethodsMap::iterator M = KnownMethods.begin(), + for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) KnownSelectors.insert(M->first); - + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl); if (!IFace) if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl)) IFace = Category->getClassInterface(); - + if (IFace) for (auto *Cat : IFace->visible_categories()) Containers.push_back(Cat); @@ -7585,15 +7688,14 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, KnownSelectors, Results); } } - + Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } -void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, +void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnTy, @@ -7616,21 +7718,21 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); - + if (ReturnTy) Results.setPreferredType(GetTypeFromParser(ReturnTy).getNonReferenceType()); - Results.EnterNewScope(); + Results.EnterNewScope(); for (GlobalMethodPool::iterator M = MethodPool.begin(), MEnd = MethodPool.end(); M != MEnd; ++M) { for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; - MethList && MethList->getMethod(); + MethList && MethList->getMethod(); MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->getMethod(), MK_Any, SelIdents)) continue; - + if (AtParameterName) { // Suggest parameter names we've seen before. unsigned NumSelIdents = SelIdents.size(); @@ -7646,7 +7748,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, Results.AddResult(Builder.TakeString()); } } - + continue; } @@ -7658,7 +7760,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, Results.MaybeAddResult(R, CurContext); } } - + Results.ExitScope(); if (!AtParameterName && !SelIdents.empty() && @@ -7677,9 +7779,8 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, } } - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, - Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompletePreprocessorDirective(bool InConditional) { @@ -7687,7 +7788,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PreprocessorDirective); Results.EnterNewScope(); - + // #if <condition> CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -7695,13 +7796,13 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("condition"); Results.AddResult(Builder.TakeString()); - + // #ifdef <macro> Builder.AddTypedTextChunk("ifdef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); - + // #ifndef <macro> Builder.AddTypedTextChunk("ifndef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7723,7 +7824,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddTypedTextChunk("endif"); Results.AddResult(Builder.TakeString()); } - + // #include "header" Builder.AddTypedTextChunk("include"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7739,13 +7840,13 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk(">"); Results.AddResult(Builder.TakeString()); - + // #define <macro> Builder.AddTypedTextChunk("define"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("macro"); Results.AddResult(Builder.TakeString()); - + // #define <macro>(<args>) Builder.AddTypedTextChunk("define"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7754,7 +7855,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddPlaceholderChunk("args"); Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Builder.TakeString()); - + // #undef <macro> Builder.AddTypedTextChunk("undef"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7766,7 +7867,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); Builder.AddPlaceholderChunk("number"); Results.AddResult(Builder.TakeString()); - + // #line <number> "filename" Builder.AddTypedTextChunk("line"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7776,7 +7877,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddPlaceholderChunk("filename"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); - + // #error <message> Builder.AddTypedTextChunk("error"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7797,7 +7898,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); - + // #import <header> Builder.AddTypedTextChunk("import"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7806,7 +7907,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddTextChunk(">"); Results.AddResult(Builder.TakeString()); } - + // #include_next "header" Builder.AddTypedTextChunk("include_next"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7814,7 +7915,7 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { Builder.AddPlaceholderChunk("header"); Builder.AddTextChunk("\""); Results.AddResult(Builder.TakeString()); - + // #include_next <header> Builder.AddTypedTextChunk("include_next"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -7835,15 +7936,14 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) { // FIXME: we don't support #assert or #unassert, so don't suggest them. Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_PreprocessorDirective, + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { CodeCompleteOrdinaryName(S, - S->getFnParent()? Sema::PCC_RecoveryInFunction + S->getFnParent()? Sema::PCC_RecoveryInFunction : Sema::PCC_Namespace); } @@ -7853,11 +7953,11 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { IsDefinition? CodeCompletionContext::CCC_MacroName : CodeCompletionContext::CCC_MacroNameUse); if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) { - // Add just the names of macros, not their arguments. + // Add just the names of macros, not their arguments. CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Results.EnterNewScope(); - for (Preprocessor::macro_iterator M = PP.macro_begin(), + for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( @@ -7870,19 +7970,19 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { } else if (IsDefinition) { // FIXME: Can we detect when the user just wrote an include guard above? } - + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), - Results.data(), Results.size()); + Results.data(), Results.size()); } void Sema::CodeCompletePreprocessorExpression() { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_PreprocessorExpression); - + if (!CodeCompleter || CodeCompleter->includeMacros()) AddMacroResults(PP, Results, true); - + // defined (<macro>) Results.EnterNewScope(); CodeCompletionBuilder Builder(Results.getAllocator(), @@ -7894,10 +7994,9 @@ void Sema::CodeCompletePreprocessorExpression() { Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Builder.TakeString()); Results.ExitScope(); - - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_PreprocessorExpression, - Results.data(), Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, @@ -7906,7 +8005,7 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, unsigned Argument) { // FIXME: In the future, we could provide "overload" results, much like we // do for function calls. - + // Now just ignore this. There will be another code-completion callback // for the expanded tokens. } @@ -7929,9 +8028,8 @@ void Sema::CodeCompleteAvailabilityPlatformName() { Twine(Platform) + "ApplicationExtension"))); } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext::CCC_Other, Results.data(), - Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, @@ -7940,16 +8038,17 @@ void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, ResultBuilder Builder(*this, Allocator, CCTUInfo, CodeCompletionContext::CCC_Recovery); if (!CodeCompleter || CodeCompleter->includeGlobals()) { - CodeCompletionDeclConsumer Consumer(Builder, + CodeCompletionDeclConsumer Consumer(Builder, Context.getTranslationUnitDecl()); - LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, - Consumer); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, + Consumer, + !CodeCompleter || CodeCompleter->loadExternal()); } - + if (!CodeCompleter || CodeCompleter->includeMacros()) AddMacroResults(PP, Builder, true); - + Results.clear(); - Results.insert(Results.end(), + Results.insert(Results.end(), Builder.data(), Builder.data() + Builder.size()); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp index e6b640f878c2..1d5454ca778b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp @@ -9,15 +9,20 @@ // // This file implements semantic analysis for C++ Coroutines. // +// This file contains references to sections of the Coroutines TS, which +// can be found at http://wg21.link/coroutines. +// //===----------------------------------------------------------------------===// #include "CoroutineStmtBuilder.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" using namespace clang; @@ -55,20 +60,8 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, return QualType(); } - LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), - FuncLoc, Sema::LookupOrdinaryName); - if (!S.LookupQualifiedName(Result, StdExp)) { - S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) - << "std::experimental::coroutine_traits"; - return QualType(); - } - - ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>(); + ClassTemplateDecl *CoroTraits = S.lookupCoroutineTraits(KwLoc, FuncLoc); if (!CoroTraits) { - Result.suppressDiagnostics(); - // We found something weird. Complain about the first thing we found. - NamedDecl *Found = *Result.begin(); - S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); return QualType(); } @@ -194,13 +187,25 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { - // 'co_await' and 'co_yield' are not permitted in unevaluated operands. + // 'co_await' and 'co_yield' are not permitted in unevaluated operands, + // such as subexpressions of \c sizeof. + // + // [expr.await]p2, emphasis added: "An await-expression shall appear only in + // a *potentially evaluated* expression within the compound-statement of a + // function-body outside of a handler [...] A context within a function where + // an await-expression can appear is called a suspension context of the + // function." And per [expr.yield]p1: "A yield-expression shall appear only + // within a suspension context of a function." if (S.isUnevaluatedContext()) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; return false; } - // Any other usage must be within a function. + // Per [expr.await]p2, any other usage must be within a function. + // FIXME: This also covers [expr.await]p2: "An await-expression shall not + // appear in a default argument." But the diagnostic QoI here could be + // improved to inform the user that default arguments specifically are not + // allowed. auto *FD = dyn_cast<FunctionDecl>(S.CurContext); if (!FD) { S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) @@ -231,22 +236,37 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, // Diagnose when a constructor, destructor, copy/move assignment operator, // or the function 'main' are declared as a coroutine. auto *MD = dyn_cast<CXXMethodDecl>(FD); + // [class.ctor]p6: "A constructor shall not be a coroutine." if (MD && isa<CXXConstructorDecl>(MD)) return DiagInvalid(DiagCtor); + // [class.dtor]p17: "A destructor shall not be a coroutine." else if (MD && isa<CXXDestructorDecl>(MD)) return DiagInvalid(DiagDtor); + // N4499 [special]p6: "A special member function shall not be a coroutine." + // Per C++ [special]p1, special member functions are the "default constructor, + // copy constructor and copy assignment operator, move constructor and move + // assignment operator, and destructor." else if (MD && MD->isCopyAssignmentOperator()) return DiagInvalid(DiagCopyAssign); else if (MD && MD->isMoveAssignmentOperator()) return DiagInvalid(DiagMoveAssign); + // [basic.start.main]p3: "The function main shall not be a coroutine." else if (FD->isMain()) return DiagInvalid(DiagMain); // Emit a diagnostics for each of the following conditions which is not met. + // [expr.const]p2: "An expression e is a core constant expression unless the + // evaluation of e [...] would evaluate one of the following expressions: + // [...] an await-expression [...] a yield-expression." if (FD->isConstexpr()) DiagInvalid(DiagConstexpr); + // [dcl.spec.auto]p15: "A function declared with a return type that uses a + // placeholder type shall not be a coroutine." if (FD->getReturnType()->isUndeducedType()) DiagInvalid(DiagAutoRet); + // [dcl.fct.def.coroutine]p1: "The parameter-declaration-clause of the + // coroutine shall not terminate with an ellipsis that is not part of a + // parameter-declaration." if (FD->isVariadic()) DiagInvalid(DiagVarargs); @@ -360,12 +380,21 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, if (Result.isInvalid()) return ExprError(); + // We meant exactly what we asked for. No need for typo correction. + if (auto *TE = dyn_cast<TypoExpr>(Result.get())) { + S.clearDelayedTypo(TE); + S.Diag(Loc, diag::err_no_member) + << NameInfo.getName() << Base->getType()->getAsCXXRecordDecl() + << Base->getSourceRange(); + return ExprError(); + } + return S.ActOnCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr); } // See if return type is coroutine-handle and if so, invoke builtin coro-resume // on its address. This is to enable experimental support for coroutine-handle -// returning await_suspend that results in a guranteed tail call to the target +// returning await_suspend that results in a guaranteed tail call to the target // coroutine. static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, SourceLocation Loc) { @@ -494,9 +523,72 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { CheckVariableDeclarationType(VD); if (VD->isInvalidDecl()) return nullptr; - ActOnUninitializedDecl(VD); + + auto *ScopeInfo = getCurFunction(); + // Build a list of arguments, based on the coroutine functions arguments, + // that will be passed to the promise type's constructor. + llvm::SmallVector<Expr *, 4> CtorArgExprs; + + // Add implicit object parameter. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isInstance() && !isLambdaCallOperator(MD)) { + ExprResult ThisExpr = ActOnCXXThis(Loc); + if (ThisExpr.isInvalid()) + return nullptr; + ThisExpr = CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get()); + if (ThisExpr.isInvalid()) + return nullptr; + CtorArgExprs.push_back(ThisExpr.get()); + } + } + + auto &Moves = ScopeInfo->CoroutineParameterMoves; + for (auto *PD : FD->parameters()) { + if (PD->getType()->isDependentType()) + continue; + + auto RefExpr = ExprEmpty(); + auto Move = Moves.find(PD); + assert(Move != Moves.end() && + "Coroutine function parameter not inserted into move map"); + // If a reference to the function parameter exists in the coroutine + // frame, use that reference. + auto *MoveDecl = + cast<VarDecl>(cast<DeclStmt>(Move->second)->getSingleDecl()); + RefExpr = + BuildDeclRefExpr(MoveDecl, MoveDecl->getType().getNonReferenceType(), + ExprValueKind::VK_LValue, FD->getLocation()); + if (RefExpr.isInvalid()) + return nullptr; + CtorArgExprs.push_back(RefExpr.get()); + } + + // Create an initialization sequence for the promise type using the + // constructor arguments, wrapped in a parenthesized list expression. + Expr *PLE = new (Context) ParenListExpr(Context, FD->getLocation(), + CtorArgExprs, FD->getLocation()); + InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); + InitializationKind Kind = InitializationKind::CreateForInit( + VD->getLocation(), /*DirectInit=*/true, PLE); + InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); + + // Attempt to initialize the promise type with the arguments. + // If that fails, fall back to the promise type's default constructor. + if (InitSeq) { + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs); + if (Result.isInvalid()) { + VD->setInvalidDecl(); + } else if (Result.get()) { + VD->setInit(MaybeCreateExprWithCleanups(Result.get())); + VD->setInitStyle(VarDecl::CallInit); + CheckCompleteVariableDeclaration(VD); + } + } else + ActOnUninitializedDecl(VD); + FD->addDecl(VD); - assert(!VD->isInvalidDecl()); return VD; } @@ -518,6 +610,9 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc, if (ScopeInfo->CoroutinePromise) return ScopeInfo; + if (!S.buildCoroutineParameterMoves(Loc)) + return nullptr; + ScopeInfo->CoroutinePromise = S.buildCoroutinePromise(Loc); if (!ScopeInfo->CoroutinePromise) return nullptr; @@ -654,9 +749,14 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E, if (E->getValueKind() == VK_RValue) E = CreateMaterializeTemporaryExpr(E->getType(), E, true); + // The location of the `co_await` token cannot be used when constructing + // the member call expressions since it's before the location of `Expr`, which + // is used as the start of the member call expression. + SourceLocation CallLoc = E->getExprLoc(); + // Build the await_ready, await_suspend, await_resume calls. ReadySuspendResumeResult RSS = - buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E); + buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, E); if (RSS.IsInvalid) return ExprError(); @@ -861,6 +961,11 @@ CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, !Fn.CoroutinePromise || Fn.CoroutinePromise->getType()->isDependentType()) { this->Body = Body; + + for (auto KV : Fn.CoroutineParameterMoves) + this->ParamMovesVector.push_back(KV.second); + this->ParamMoves = this->ParamMovesVector; + if (!IsPromiseDependentType) { PromiseRecordDecl = Fn.CoroutinePromise->getType()->getAsCXXRecordDecl(); assert(PromiseRecordDecl && "Type should have already been checked"); @@ -870,7 +975,7 @@ CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, bool CoroutineStmtBuilder::buildStatements() { assert(this->IsValid && "coroutine already invalid"); - this->IsValid = makeReturnObject() && makeParamMoves(); + this->IsValid = makeReturnObject(); if (this->IsValid && !IsPromiseDependentType) buildDependentStatements(); return this->IsValid; @@ -886,12 +991,6 @@ bool CoroutineStmtBuilder::buildDependentStatements() { return this->IsValid; } -bool CoroutineStmtBuilder::buildParameterMoves() { - assert(this->IsValid && "coroutine already invalid"); - assert(this->ParamMoves.empty() && "param moves already built"); - return this->IsValid = makeParamMoves(); -} - bool CoroutineStmtBuilder::makePromiseStmt() { // Form a declaration statement for the promise declaration, so that AST // visitors can more easily find it. @@ -990,7 +1089,12 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr; - // FIXME: Add support for stateful allocators. + // [dcl.fct.def.coroutine]/7 + // Lookup allocation functions using a parameter list composed of the + // requested size of the coroutine state being allocated, followed by + // the coroutine function's arguments. If a matching allocation function + // exists, use it. Otherwise, use an allocation function that just takes + // the requested size. FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; @@ -998,10 +1102,73 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { bool PassAlignment = false; SmallVector<Expr *, 1> PlacementArgs; - S.FindAllocationFunctions(Loc, SourceRange(), - /*UseGlobal*/ false, PromiseType, + // [dcl.fct.def.coroutine]/7 + // "The allocation function’s name is looked up in the scope of P. + // [...] If the lookup finds an allocation function in the scope of P, + // overload resolution is performed on a function call created by assembling + // an argument list. The first argument is the amount of space requested, + // and has type std::size_t. The lvalues p1 ... pn are the succeeding + // arguments." + // + // ...where "p1 ... pn" are defined earlier as: + // + // [dcl.fct.def.coroutine]/3 + // "For a coroutine f that is a non-static member function, let P1 denote the + // type of the implicit object parameter (13.3.1) and P2 ... Pn be the types + // of the function parameters; otherwise let P1 ... Pn be the types of the + // function parameters. Let p1 ... pn be lvalues denoting those objects." + if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) { + if (MD->isInstance() && !isLambdaCallOperator(MD)) { + ExprResult ThisExpr = S.ActOnCXXThis(Loc); + if (ThisExpr.isInvalid()) + return false; + ThisExpr = S.CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get()); + if (ThisExpr.isInvalid()) + return false; + PlacementArgs.push_back(ThisExpr.get()); + } + } + for (auto *PD : FD.parameters()) { + if (PD->getType()->isDependentType()) + continue; + + // Build a reference to the parameter. + auto PDLoc = PD->getLocation(); + ExprResult PDRefExpr = + S.BuildDeclRefExpr(PD, PD->getOriginalType().getNonReferenceType(), + ExprValueKind::VK_LValue, PDLoc); + if (PDRefExpr.isInvalid()) + return false; + + PlacementArgs.push_back(PDRefExpr.get()); + } + S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Class, + /*DeleteScope*/ Sema::AFS_Both, PromiseType, /*isArray*/ false, PassAlignment, PlacementArgs, - OperatorNew, UnusedResult); + OperatorNew, UnusedResult, /*Diagnose*/ false); + + // [dcl.fct.def.coroutine]/7 + // "If no matching function is found, overload resolution is performed again + // on a function call created by passing just the amount of space required as + // an argument of type std::size_t." + if (!OperatorNew && !PlacementArgs.empty()) { + PlacementArgs.clear(); + S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Class, + /*DeleteScope*/ Sema::AFS_Both, PromiseType, + /*isArray*/ false, PassAlignment, PlacementArgs, + OperatorNew, UnusedResult, /*Diagnose*/ false); + } + + // [dcl.fct.def.coroutine]/7 + // "The allocation function’s name is looked up in the scope of P. If this + // lookup fails, the allocation function’s name is looked up in the global + // scope." + if (!OperatorNew) { + S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Global, + /*DeleteScope*/ Sema::AFS_Both, PromiseType, + /*isArray*/ false, PassAlignment, PlacementArgs, + OperatorNew, UnusedResult); + } bool IsGlobalOverload = OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext()); @@ -1014,17 +1181,18 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { return false; PlacementArgs = {StdNoThrow}; OperatorNew = nullptr; - S.FindAllocationFunctions(Loc, SourceRange(), - /*UseGlobal*/ true, PromiseType, + S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Both, + /*DeleteScope*/ Sema::AFS_Both, PromiseType, /*isArray*/ false, PassAlignment, PlacementArgs, OperatorNew, UnusedResult); } - assert(OperatorNew && "expected definition of operator new to be found"); + if (!OperatorNew) + return false; if (RequiresNoThrowAlloc) { const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>(); - if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) { + if (!FT->isNothrow(/*ResultIfDependent*/ false)) { S.Diag(OperatorNew->getLocation(), diag::err_coroutine_promise_new_requires_nothrow) << OperatorNew; @@ -1256,10 +1424,6 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { if (Res.isInvalid()) return false; - if (GroType == FnRetType) { - GroDecl->setNRVOVariable(true); - } - S.AddInitializerToDecl(GroDecl, Res.get(), /*DirectInit=*/false); @@ -1283,6 +1447,8 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { noteMemberDeclaredHere(S, ReturnValue, Fn); return false; } + if (cast<clang::ReturnStmt>(ReturnStmt.get())->getNRVOCandidate() == GroDecl) + GroDecl->setNRVOVariable(true); this->ReturnStmt = ReturnStmt.get(); return true; @@ -1304,47 +1470,53 @@ static Expr *castForMoving(Sema &S, Expr *E, QualType T = QualType()) { .get(); } - -/// \brief Build a variable declaration for move parameter. +/// Build a variable declaration for move parameter. static VarDecl *buildVarDecl(Sema &S, SourceLocation Loc, QualType Type, IdentifierInfo *II) { TypeSourceInfo *TInfo = S.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = - VarDecl::Create(S.Context, S.CurContext, Loc, Loc, II, Type, TInfo, SC_None); + VarDecl *Decl = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, II, Type, + TInfo, SC_None); Decl->setImplicit(); return Decl; } -bool CoroutineStmtBuilder::makeParamMoves() { - for (auto *paramDecl : FD.parameters()) { - auto Ty = paramDecl->getType(); - if (Ty->isDependentType()) +// Build statements that move coroutine function parameters to the coroutine +// frame, and store them on the function scope info. +bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) { + assert(isa<FunctionDecl>(CurContext) && "not in a function scope"); + auto *FD = cast<FunctionDecl>(CurContext); + + auto *ScopeInfo = getCurFunction(); + assert(ScopeInfo->CoroutineParameterMoves.empty() && + "Should not build parameter moves twice"); + + for (auto *PD : FD->parameters()) { + if (PD->getType()->isDependentType()) continue; - // No need to copy scalars, llvm will take care of them. - if (Ty->getAsCXXRecordDecl()) { - ExprResult ParamRef = - S.BuildDeclRefExpr(paramDecl, paramDecl->getType(), - ExprValueKind::VK_LValue, Loc); // FIXME: scope? - if (ParamRef.isInvalid()) - return false; + ExprResult PDRefExpr = + BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(), + ExprValueKind::VK_LValue, Loc); // FIXME: scope? + if (PDRefExpr.isInvalid()) + return false; - Expr *RCast = castForMoving(S, ParamRef.get()); + Expr *CExpr = nullptr; + if (PD->getType()->getAsCXXRecordDecl() || + PD->getType()->isRValueReferenceType()) + CExpr = castForMoving(*this, PDRefExpr.get()); + else + CExpr = PDRefExpr.get(); - auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()); - S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true); + auto D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier()); + AddInitializerToDecl(D, CExpr, /*DirectInit=*/true); - // Convert decl to a statement. - StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc); - if (Stmt.isInvalid()) - return false; + // Convert decl to a statement. + StmtResult Stmt = ActOnDeclStmt(ConvertDeclToDeclGroup(D), Loc, Loc); + if (Stmt.isInvalid()) + return false; - ParamMovesVector.push_back(Stmt.get()); - } + ScopeInfo->CoroutineParameterMoves.insert(std::make_pair(PD, Stmt.get())); } - - // Convert to ArrayRef in CtorArgs structure that builder inherits from. - ParamMoves = ParamMovesVector; return true; } @@ -1354,3 +1526,27 @@ StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) { return StmtError(); return Res; } + +ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, + SourceLocation FuncLoc) { + if (!StdCoroutineTraitsCache) { + if (auto StdExp = lookupStdExperimentalNamespace()) { + LookupResult Result(*this, + &PP.getIdentifierTable().get("coroutine_traits"), + FuncLoc, LookupOrdinaryName); + if (!LookupQualifiedName(Result, StdExp)) { + Diag(KwLoc, diag::err_implied_coroutine_type_not_found) + << "std::experimental::coroutine_traits"; + return nullptr; + } + if (!(StdCoroutineTraitsCache = + Result.getAsSingle<ClassTemplateDecl>())) { + Result.suppressDiagnostics(); + NamedDecl *Found = *Result.begin(); + Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + return nullptr; + } + } + } + return StdCoroutineTraitsCache; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index 0ceaf7c6d691..55542828f783 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -115,7 +115,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback { } // end anonymous namespace -/// \brief Determine whether the token kind starts a simple-type-specifier. +/// Determine whether the token kind starts a simple-type-specifier. bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { switch (Kind) { // FIXME: Take into account the current language when deciding whether a @@ -148,6 +148,9 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw_decltype: return getLangOpts().CPlusPlus; + case tok::kw_char8_t: + return getLangOpts().Char8; + default: break; } @@ -163,7 +166,7 @@ enum class UnqualifiedTypeNameLookupResult { }; } // end anonymous namespace -/// \brief Tries to perform unqualified lookup of the type decls in bases for +/// Tries to perform unqualified lookup of the type decls in bases for /// dependent class. /// \return \a NotFound if no any decls is found, \a FoundNotType if found not a /// type decl, \a FoundType if only type decls are found. @@ -263,7 +266,7 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } -/// \brief If the identifier refers to a type name within this scope, +/// If the identifier refers to a type name within this scope, /// return the declaration of that type. /// /// This routine performs ordinary name lookup of the identifier II @@ -724,13 +727,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, Name, nullptr, true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { - TemplateName TplName = TemplateResult.get(); - Diag(IILoc, diag::err_template_missing_args) - << (int)getTemplateNameKindForDiagnostics(TplName) << TplName; - if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { - Diag(TplDecl->getLocation(), diag::note_template_decl_here) - << TplDecl->getTemplateParameters()->getSourceRange(); - } + diagnoseMissingTemplateArguments(TemplateResult.get(), IILoc); return; } } @@ -763,7 +760,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, } } -/// \brief Determine whether the given result set contains either a type name +/// Determine whether the given result set contains either a type name /// or static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus && @@ -1318,7 +1315,7 @@ void Sema::ActOnExitFunctionContext() { assert(CurContext && "Popped translation unit!"); } -/// \brief Determine whether we allow overloading of the function +/// Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// /// This routine determines whether overloading is possible, not @@ -1504,7 +1501,7 @@ static void RemoveUsingDecls(LookupResult &R) { F.done(); } -/// \brief Check for this common pattern: +/// Check for this common pattern: /// @code /// class S { /// S(const S&); // DO NOT IMPLEMENT @@ -1519,9 +1516,7 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) return CD->isCopyConstructor(); - if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) - return Method->isCopyAssignmentOperator(); - return false; + return D->isCopyAssignmentOperator(); } // We need this to handle @@ -1843,7 +1838,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { } } -/// \brief Look for an Objective-C class in the translation unit. +/// Look for an Objective-C class in the translation unit. /// /// \param Id The name of the Objective-C class we're looking for. If /// typo-correction fixes this name, the Id will be updated @@ -1913,7 +1908,7 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) { return S; } -/// \brief Looks up the declaration of "struct objc_super" and +/// Looks up the declaration of "struct objc_super" and /// saves it for later use in building builtin declaration of /// objc_msgSendSuper and objc_msgSendSuper_stret. If no such /// pre-existing declaration exists no action takes place. @@ -2457,6 +2452,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, else if (const auto *SA = dyn_cast<SectionAttr>(Attr)) NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(), AttrSpellingListIndex); + else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr)) + NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(), + AttrSpellingListIndex); else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr)) NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), AttrSpellingListIndex, @@ -2495,7 +2493,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, else if (const auto *UA = dyn_cast<UuidAttr>(Attr)) NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, UA->getGuid()); - else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr)) + else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast<InheritableAttr>(Attr->clone(S.Context)); if (NewAttr) { @@ -2675,6 +2673,15 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, } } + // Redeclaration adds code-seg attribute. + const auto *NewCSA = New->getAttr<CodeSegAttr>(); + if (NewCSA && !Old->hasAttr<CodeSegAttr>() && + !NewCSA->isImplicit() && isa<CXXMethodDecl>(New)) { + Diag(New->getLocation(), diag::warn_mismatched_section) + << 0 /*codeseg*/; + Diag(Old->getLocation(), diag::note_previous_declaration); + } + if (!Old->hasAttrs()) return; @@ -2875,7 +2882,7 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { template<typename T> static bool isExternC(T *D) { return D->isExternC(); } static bool isExternC(VarTemplateDecl *) { return false; } -/// \brief Check whether a redeclaration of an entity introduced by a +/// Check whether a redeclaration of an entity introduced by a /// using-declaration is valid, given that we know it's not an overload /// (nor a hidden tag declaration). template<typename ExpectedDecl> @@ -2929,6 +2936,48 @@ static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A, return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq); } +/// If necessary, adjust the semantic declaration context for a qualified +/// declaration to name the correct inline namespace within the qualifier. +static void adjustDeclContextForDeclaratorDecl(DeclaratorDecl *NewD, + DeclaratorDecl *OldD) { + // The only case where we need to update the DeclContext is when + // redeclaration lookup for a qualified name finds a declaration + // in an inline namespace within the context named by the qualifier: + // + // inline namespace N { int f(); } + // int ::f(); // Sema DC needs adjusting from :: to N::. + // + // For unqualified declarations, the semantic context *can* change + // along the redeclaration chain (for local extern declarations, + // extern "C" declarations, and friend declarations in particular). + if (!NewD->getQualifier()) + return; + + // NewD is probably already in the right context. + auto *NamedDC = NewD->getDeclContext()->getRedeclContext(); + auto *SemaDC = OldD->getDeclContext()->getRedeclContext(); + if (NamedDC->Equals(SemaDC)) + return; + + assert((NamedDC->InEnclosingNamespaceSetOf(SemaDC) || + NewD->isInvalidDecl() || OldD->isInvalidDecl()) && + "unexpected context for redeclaration"); + + auto *LexDC = NewD->getLexicalDeclContext(); + auto FixSemaDC = [=](NamedDecl *D) { + if (!D) + return; + D->setDeclContext(SemaDC); + D->setLexicalDeclContext(LexDC); + }; + + FixSemaDC(NewD); + if (auto *FD = dyn_cast<FunctionDecl>(NewD)) + FixSemaDC(FD->getDescribedFunctionTemplate()); + else if (auto *VD = dyn_cast<VarDecl>(NewD)) + FixSemaDC(VD->getDescribedVarTemplate()); +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2971,6 +3020,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, if (Old->isInvalidDecl()) return true; + // Disallow redeclaration of some builtins. + if (!getASTContext().canBuiltinBeRedeclared(Old)) { + Diag(New->getLocation(), diag::err_builtin_redeclare) << Old->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_builtin_declaration) + << Old << Old->getType(); + return true; + } + diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = @@ -3518,7 +3575,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, return true; } -/// \brief Completes the merge of two function declarations that are +/// Completes the merge of two function declarations that are /// known to be compatible. /// /// This routine handles the merging of attributes and other @@ -3581,6 +3638,8 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne && oi != oe; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, *this); + + CheckObjCMethodOverride(newMethod, oldMethod); } static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { @@ -3953,6 +4012,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setPreviousDecl(Old); if (NewTemplate) NewTemplate->setPreviousDecl(OldTemplate); + adjustDeclContextForDeclaratorDecl(New, Old); // Inherit access appropriately. New->setAccess(Old->getAccess()); @@ -4014,7 +4074,8 @@ void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) { } // Redefinition coming from different files or couldn't do better above. - Diag(Old->getLocation(), diag::note_previous_definition); + if (Old->getLocation().isValid()) + Diag(Old->getLocation(), diag::note_previous_definition); } /// We've just determined that \p Old and \p New both appear to be definitions @@ -4398,10 +4459,9 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { - for (AttributeList* attrs = DS.getAttributes().getList(); attrs; - attrs = attrs->getNext()) - Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored) - << attrs->getName() << GetDiagnosticTypeSpecifierID(TypeSpecType); + for (const ParsedAttr &AL : DS.getAttributes()) + Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) + << AL.getName() << GetDiagnosticTypeSpecifierID(TypeSpecType); } } @@ -4593,12 +4653,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, unsigned DiagID; if (Record->isUnion()) { // C++ [class.union]p6: + // C++17 [class.union.anon]p2: // Anonymous unions declared in a named namespace or in the // global namespace shall be declared static. + DeclContext *OwnerScope = Owner->getRedeclContext(); if (DS.getStorageClassSpec() != DeclSpec::SCS_static && - (isa<TranslationUnitDecl>(Owner) || - (isa<NamespaceDecl>(Owner) && - cast<NamespaceDecl>(Owner)->getDeclName()))) { + (OwnerScope->isTranslationUnit() || + (OwnerScope->isNamespace() && + !cast<NamespaceDecl>(OwnerScope)->isAnonymousNamespace()))) { Diag(Record->getLocation(), diag::err_anonymous_union_not_static) << FixItHint::CreateInsertion(Record->getLocation(), "static "); @@ -4889,7 +4951,7 @@ DeclarationNameInfo Sema::GetNameForDeclarator(Declarator &D) { return GetNameFromUnqualifiedId(D.getName()); } -/// \brief Retrieves the declaration name from a parsed unqualified-id. +/// Retrieves the declaration name from a parsed unqualified-id. DeclarationNameInfo Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { DeclarationNameInfo NameInfo; @@ -5176,7 +5238,7 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, return false; } -/// \brief Diagnose a declaration whose declarator-id has the given +/// Diagnose a declaration whose declarator-id has the given /// nested-name-specifier. /// /// \param SS The nested-name-specifier of the declarator-id. @@ -5188,10 +5250,13 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, /// /// \param Loc The location of the name of the entity being declared. /// +/// \param IsTemplateId Whether the name is a (simple-)template-id, and thus +/// we're declaring an explicit / partial specialization / instantiation. +/// /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, bool IsTemplateId) { DeclContext *Cur = CurContext; while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur)) Cur = Cur->getParent(); @@ -5218,8 +5283,9 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, } // Check whether the qualifying scope encloses the scope of the original - // declaration. - if (!Cur->Encloses(DC)) { + // declaration. For a template-id, we perform the checks in + // CheckTemplateSpecializationScope. + if (!Cur->Encloses(DC) && !IsTemplateId) { if (Cur->isRecord()) Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); @@ -5331,8 +5397,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, return nullptr; } if (!D.getDeclSpec().isFriendSpecified()) { - if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, - Name, D.getIdentifierLoc())) { + if (diagnoseQualifiedDeclaration( + D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId)) { if (DC->isRecord()) return nullptr; @@ -5609,7 +5676,7 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, return FixedTInfo; } -/// \brief Register the given locally-scoped extern "C" declaration so +/// Register the given locally-scoped extern "C" declaration so /// that it can be found later for redeclarations. We include any extern "C" /// declaration that is not visible in the translation unit here, not just /// function-scope declarations. @@ -5630,7 +5697,7 @@ NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { return Result.empty() ? nullptr : *Result.begin(); } -/// \brief Diagnose function specifiers on a declaration of an identifier that +/// Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { // FIXME: We should probably indicate the identifier in question to avoid @@ -5704,7 +5771,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo(); QualType T = TInfo->getType(); if (T->isVariablyModifiedType()) { - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); if (S->getFnParent() == nullptr) { bool SizeIsNegative; @@ -5772,7 +5839,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, return NewTD; } -/// \brief Determines whether the given declaration is an out-of-scope +/// Determines whether the given declaration is an out-of-scope /// previous declaration. /// /// This routine should be invoked when name lookup has found a @@ -6148,29 +6215,21 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { llvm_unreachable("Unexpected context"); } -static bool hasParsedAttr(Scope *S, const AttributeList *AttrList, - AttributeList::Kind Kind) { - for (const AttributeList *L = AttrList; L; L = L->getNext()) - if (L->getKind() == Kind) - return true; - return false; -} - static bool hasParsedAttr(Scope *S, const Declarator &PD, - AttributeList::Kind Kind) { + ParsedAttr::Kind Kind) { // Check decl attributes on the DeclSpec. - if (hasParsedAttr(S, PD.getDeclSpec().getAttributes().getList(), Kind)) + if (PD.getDeclSpec().getAttributes().hasAttribute(Kind)) return true; // Walk the declarator structure, checking decl attributes that were in a type // position to the decl itself. for (unsigned I = 0, E = PD.getNumTypeObjects(); I != E; ++I) { - if (hasParsedAttr(S, PD.getTypeObject(I).getAttrs(), Kind)) + if (PD.getTypeObject(I).getAttrs().hasAttribute(Kind)) return true; } // Finally, check attributes on the decl itself. - return hasParsedAttr(S, PD.getAttributes(), Kind); + return PD.getAttributes().hasAttribute(Kind); } /// Adjust the \c DeclContext for a function or variable that might be a @@ -6197,7 +6256,7 @@ bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) { return true; } -/// \brief Returns true if given declaration has external C language linkage. +/// Returns true if given declaration has external C language linkage. static bool isDeclExternC(const Decl *D) { if (const auto *FD = dyn_cast<FunctionDecl>(D)) return FD->isExternC(); @@ -6303,6 +6362,20 @@ NamedDecl *Sema::ActOnVariableDeclarator( D.setInvalidType(); } } + + // OpenCL C++ 1.0 s2.9: the thread_local storage qualifier is not + // supported. OpenCL C does not support thread_local either, and + // also reject all other thread storage class specifiers. + DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec(); + if (TSC != TSCS_unspecified) { + bool IsCXX = getLangOpts().OpenCLCPlusPlus; + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_opencl_unknown_type_specifier) + << IsCXX << getLangOpts().getOpenCLVersionTuple().getAsString() + << DeclSpec::getSpecifierName(TSC) << 1; + D.setInvalidType(); + return nullptr; + } } DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); @@ -6311,8 +6384,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( // dllimport globals without explicit storage class are treated as extern. We // have to change the storage class this early to get the right DeclContext. if (SC == SC_None && !DC->isRecord() && - hasParsedAttr(S, D, AttributeList::AT_DLLImport) && - !hasParsedAttr(S, D, AttributeList::AT_DLLExport)) + hasParsedAttr(S, D, ParsedAttr::AT_DLLImport) && + !hasParsedAttr(S, D, ParsedAttr::AT_DLLExport)) SC = SC_Extern; DeclContext *OriginalDC = DC; @@ -6842,9 +6915,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( } if (D.isRedeclaration() && !Previous.empty()) { - checkDLLAttributeRedeclaration( - *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD, - IsMemberSpecialization, D.isFunctionDefinition()); + NamedDecl *Prev = Previous.getRepresentativeDecl(); + checkDLLAttributeRedeclaration(*this, Prev, NewVD, IsMemberSpecialization, + D.isFunctionDefinition()); } if (NewTemplate) { @@ -6887,7 +6960,7 @@ static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl, /// variable \p VD, or an invalid source location otherwise. static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI, const VarDecl *VD) { - for (const LambdaScopeInfo::Capture &Capture : LSI->Captures) { + for (const Capture &Capture : LSI->Captures) { if (Capture.isVariableCapture() && Capture.getVariable() == VD) return Capture.getLocation(); } @@ -6904,7 +6977,7 @@ static bool shouldWarnIfShadowedDecl(const DiagnosticsEngine &Diags, return !Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc()); } -/// \brief Return the declaration shadowed by the given variable \p D, or null +/// Return the declaration shadowed by the given variable \p D, or null /// if it doesn't shadow any declaration or shadowing warnings are disabled. NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D, const LookupResult &R) { @@ -6921,14 +6994,14 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D, : nullptr; } -/// \brief Return the declaration shadowed by the given typedef \p D, or null +/// Return the declaration shadowed by the given typedef \p D, or null /// if it doesn't shadow any declaration or shadowing warnings are disabled. NamedDecl *Sema::getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R) { // Don't warn if typedef declaration is part of a class if (D->getDeclContext()->isRecord()) return nullptr; - + if (!shouldWarnIfShadowedDecl(Diags, R)) return nullptr; @@ -6936,7 +7009,7 @@ NamedDecl *Sema::getShadowedDeclaration(const TypedefNameDecl *D, return isa<TypedefNameDecl>(ShadowedDecl) ? ShadowedDecl : nullptr; } -/// \brief Diagnose variable or built-in function shadowing. Implements +/// Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// /// This method is called whenever a VarDecl is added to a "useful" @@ -7067,7 +7140,7 @@ void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) { } } -/// \brief Check -Wshadow without the advantage of a previous lookup. +/// Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation())) return; @@ -7225,8 +7298,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { if (NewVD->isInvalidDecl()) return; - TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); - QualType T = TInfo->getType(); + QualType T = NewVD->getType(); // Defer checking an 'auto' type until its initializer is attached. if (T->isUndeducedType()) @@ -7364,16 +7436,24 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || NewVD->hasAttr<BlocksAttr>()) - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; llvm::APSInt Oversized; - TypeSourceInfo *FixedTInfo = - TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, - SizeIsNegative, Oversized); - if (!FixedTInfo && T->isVariableArrayType()) { + TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo( + NewVD->getTypeSourceInfo(), Context, SizeIsNegative, Oversized); + QualType FixedT; + if (FixedTInfo && T == NewVD->getTypeSourceInfo()->getType()) + FixedT = FixedTInfo->getType(); + else if (FixedTInfo) { + // Type and type-as-written are canonically different. We need to fix up + // both types separately. + FixedT = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, + Oversized); + } + if ((!FixedTInfo || FixedT.isNull()) && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; @@ -7402,7 +7482,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); - NewVD->setType(FixedTInfo->getType()); + NewVD->setType(FixedT); NewVD->setTypeSourceInfo(FixedTInfo); } @@ -7437,7 +7517,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } } -/// \brief Perform semantic checking on a newly-created variable +/// Perform semantic checking on a newly-created variable /// declaration. /// /// This routine performs all of the type-checking required for a @@ -7508,8 +7588,8 @@ struct FindOverriddenMethod { enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; } // end anonymous namespace -/// \brief Report an error regarding overriding, along with any relevant -/// overriden methods. +/// Report an error regarding overriding, along with any relevant +/// overridden methods. /// /// \param DiagID the primary error to report. /// \param MD the overriding method. @@ -7624,7 +7704,7 @@ void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { TypoCorrectedFunctionDefinitions.insert(F); } -/// \brief Generate diagnostics for an invalid function redeclaration. +/// Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid /// function redeclaration, including finding possible similar declarations @@ -8176,7 +8256,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool &AddToScope) { QualType R = TInfo->getType(); - assert(R.getTypePtr()->isFunctionType()); + assert(R->isFunctionType()); // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); @@ -8655,6 +8735,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->dropAttr<SectionAttr>(); } + // Apply an implicit CodeSegAttr from class declspec or + // apply an implicit SectionAttr from #pragma code_seg if active. + if (!NewFD->hasAttr<CodeSegAttr>()) { + if (Attr *SAttr = getImplicitCodeSegOrSectionAttrForFunction(NewFD, + D.isFunctionDefinition())) { + NewFD->addAttr(SAttr); + } + } + // Handle attributes. ProcessDeclAttributes(S, NewFD, D); @@ -8785,10 +8874,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; - Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? - diag::ext_function_specialization_in_class : - diag::err_function_specialization_in_class) - << NewFD->getDeclName(); } else if (!NewFD->isInvalidDecl() && CheckFunctionTemplateSpecialization( NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), @@ -8994,19 +9079,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setRangeEnd(D.getSourceRange().getEnd()); if (D.isRedeclaration() && !Previous.empty()) { - checkDLLAttributeRedeclaration( - *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD, - isMemberSpecialization || isFunctionTemplateSpecialization, - D.isFunctionDefinition()); + NamedDecl *Prev = Previous.getRepresentativeDecl(); + checkDLLAttributeRedeclaration(*this, Prev, NewFD, + isMemberSpecialization || + isFunctionTemplateSpecialization, + D.isFunctionDefinition()); } if (getLangOpts().CUDA) { IdentifierInfo *II = NewFD->getIdentifier(); - if (II && II->isStr("cudaConfigureCall") && !NewFD->isInvalidDecl() && + if (II && + II->isStr(getLangOpts().HIP ? "hipConfigureCall" + : "cudaConfigureCall") && + !NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (!R->getAs<FunctionType>()->getReturnType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return); - Context.setcudaConfigureCallDecl(NewFD); } @@ -9073,22 +9161,95 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Here we have an function template explicit specialization at class scope. - // The actually specialization will be postponed to template instatiation + // The actual specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, CurContext, NewFD->getLocation(), cast<CXXMethodDecl>(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); AddToScope = false; } + // Diagnose availability attributes. Availability cannot be used on functions + // that are run during load/unload. + if (const auto *attr = NewFD->getAttr<AvailabilityAttr>()) { + if (NewFD->hasAttr<ConstructorAttr>()) { + Diag(attr->getLocation(), diag::warn_availability_on_static_initializer) + << 1; + NewFD->dropAttr<AvailabilityAttr>(); + } + if (NewFD->hasAttr<DestructorAttr>()) { + Diag(attr->getLocation(), diag::warn_availability_on_static_initializer) + << 2; + NewFD->dropAttr<AvailabilityAttr>(); + } + } + return NewFD; } -/// \brief Checks if the new declaration declared in dependent context must be +/// Return a CodeSegAttr from a containing class. The Microsoft docs say +/// when __declspec(code_seg) "is applied to a class, all member functions of +/// the class and nested classes -- this includes compiler-generated special +/// member functions -- are put in the specified segment." +/// The actual behavior is a little more complicated. The Microsoft compiler +/// won't check outer classes if there is an active value from #pragma code_seg. +/// The CodeSeg is always applied from the direct parent but only from outer +/// classes when the #pragma code_seg stack is empty. See: +/// https://reviews.llvm.org/D22931, the Microsoft feedback page is no longer +/// available since MS has removed the page. +static Attr *getImplicitCodeSegAttrFromClass(Sema &S, const FunctionDecl *FD) { + const auto *Method = dyn_cast<CXXMethodDecl>(FD); + if (!Method) + return nullptr; + const CXXRecordDecl *Parent = Method->getParent(); + if (const auto *SAttr = Parent->getAttr<CodeSegAttr>()) { + Attr *NewAttr = SAttr->clone(S.getASTContext()); + NewAttr->setImplicit(true); + return NewAttr; + } + + // The Microsoft compiler won't check outer classes for the CodeSeg + // when the #pragma code_seg stack is active. + if (S.CodeSegStack.CurrentValue) + return nullptr; + + while ((Parent = dyn_cast<CXXRecordDecl>(Parent->getParent()))) { + if (const auto *SAttr = Parent->getAttr<CodeSegAttr>()) { + Attr *NewAttr = SAttr->clone(S.getASTContext()); + NewAttr->setImplicit(true); + return NewAttr; + } + } + return nullptr; +} + +/// Returns an implicit CodeSegAttr if a __declspec(code_seg) is found on a +/// containing class. Otherwise it will return implicit SectionAttr if the +/// function is a definition and there is an active value on CodeSegStack +/// (from the current #pragma code-seg value). +/// +/// \param FD Function being declared. +/// \param IsDefinition Whether it is a definition or just a declarartion. +/// \returns A CodeSegAttr or SectionAttr to apply to the function or +/// nullptr if no attribute should be added. +Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, + bool IsDefinition) { + if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD)) + return A; + if (!FD->hasAttr<SectionAttr>() && IsDefinition && + CodeSegStack.CurrentValue) { + return SectionAttr::CreateImplicit(getASTContext(), + SectionAttr::Declspec_allocate, + CodeSegStack.CurrentValue->getString(), + CodeSegStack.CurrentPragmaLocation); + } + return nullptr; +} +/// Checks if the new declaration declared in dependent context must be /// put in the same redeclaration chain as the specified declaration. /// /// \param D Declaration that is checked. @@ -9114,7 +9275,524 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { D->getFriendObjectKind() != Decl::FOK_None); } -/// \brief Perform semantic checking of a new function declaration. +namespace MultiVersioning { +enum Type { None, Target, CPUSpecific, CPUDispatch}; +} // MultiVersionType + +static MultiVersioning::Type +getMultiVersionType(const FunctionDecl *FD) { + if (FD->hasAttr<TargetAttr>()) + return MultiVersioning::Target; + if (FD->hasAttr<CPUDispatchAttr>()) + return MultiVersioning::CPUDispatch; + if (FD->hasAttr<CPUSpecificAttr>()) + return MultiVersioning::CPUSpecific; + return MultiVersioning::None; +} +/// Check the target attribute of the function for MultiVersion +/// validity. +/// +/// Returns true if there was an error, false otherwise. +static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { + const auto *TA = FD->getAttr<TargetAttr>(); + assert(TA && "MultiVersion Candidate requires a target attribute"); + TargetAttr::ParsedTargetAttr ParseInfo = TA->parse(); + const TargetInfo &TargetInfo = S.Context.getTargetInfo(); + enum ErrType { Feature = 0, Architecture = 1 }; + + if (!ParseInfo.Architecture.empty() && + !TargetInfo.validateCpuIs(ParseInfo.Architecture)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Architecture << ParseInfo.Architecture; + return true; + } + + for (const auto &Feat : ParseInfo.Features) { + auto BareFeat = StringRef{Feat}.substr(1); + if (Feat[0] == '-') { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << ("no-" + BareFeat).str(); + return true; + } + + if (!TargetInfo.validateCpuSupports(BareFeat) || + !TargetInfo.isValidFeatureName(BareFeat)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << BareFeat; + return true; + } + } + return false; +} + +static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, + const FunctionDecl *NewFD, + bool CausesMV, + MultiVersioning::Type MVType) { + enum DoesntSupport { + FuncTemplates = 0, + VirtFuncs = 1, + DeducedReturn = 2, + Constructors = 3, + Destructors = 4, + DeletedFuncs = 5, + DefaultedFuncs = 6, + ConstexprFuncs = 7, + }; + enum Different { + CallingConv = 0, + ReturnType = 1, + ConstexprSpec = 2, + InlineSpec = 3, + StorageClass = 4, + Linkage = 5 + }; + + bool IsCPUSpecificCPUDispatchMVType = + MVType == MultiVersioning::CPUDispatch || + MVType == MultiVersioning::CPUSpecific; + + if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto); + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + } + + if (!NewFD->getType()->getAs<FunctionProtoType>()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto); + + if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + if (OldFD) + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + return true; + } + + // For now, disallow all other attributes. These should be opt-in, but + // an analysis of all of them is a future FIXME. + if (CausesMV && OldFD && + std::distance(OldFD->attr_begin(), OldFD->attr_end()) != 1) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + } + + if (std::distance(NewFD->attr_begin(), NewFD->attr_end()) != 1) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + + if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << FuncTemplates; + + if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) { + if (NewCXXFD->isVirtual()) + return S.Diag(NewCXXFD->getLocation(), + diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << VirtFuncs; + + if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD)) + return S.Diag(NewCXXCtor->getLocation(), + diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << Constructors; + + if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD)) + return S.Diag(NewCXXDtor->getLocation(), + diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << Destructors; + } + + if (NewFD->isDeleted()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << DeletedFuncs; + + if (NewFD->isDefaulted()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs; + + if (NewFD->isConstexpr() && (MVType == MultiVersioning::CPUDispatch || + MVType == MultiVersioning::CPUSpecific)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << ConstexprFuncs; + + QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType()); + const auto *NewType = cast<FunctionType>(NewQType); + QualType NewReturnType = NewType->getReturnType(); + + if (NewReturnType->isUndeducedType()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType << DeducedReturn; + + // Only allow transition to MultiVersion if it hasn't been used. + if (OldFD && CausesMV && OldFD->isUsed(false)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + + // Ensure the return type is identical. + if (OldFD) { + QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType()); + const auto *OldType = cast<FunctionType>(OldQType); + FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + + if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << CallingConv; + + QualType OldReturnType = OldType->getReturnType(); + + if (OldReturnType != NewReturnType) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << ReturnType; + + if (OldFD->isConstexpr() != NewFD->isConstexpr()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << ConstexprSpec; + + if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << InlineSpec; + + if (OldFD->getStorageClass() != NewFD->getStorageClass()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << StorageClass; + + if (OldFD->isExternC() != NewFD->isExternC()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << Linkage; + + if (S.CheckEquivalentExceptionSpec( + OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(), + NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation())) + return true; + } + return false; +} + +/// Check the validity of a multiversion function declaration that is the +/// first of its kind. Also sets the multiversion'ness' of the function itself. +/// +/// This sets NewFD->isInvalidDecl() to true if there was an error. +/// +/// Returns true if there was an error, false otherwise. +static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD, + MultiVersioning::Type MVType, + const TargetAttr *TA, + const CPUDispatchAttr *CPUDisp, + const CPUSpecificAttr *CPUSpec) { + assert(MVType != MultiVersioning::None && + "Function lacks multiversion attribute"); + + // Target only causes MV if it is default, otherwise this is a normal + // function. + if (MVType == MultiVersioning::Target && !TA->isDefaultVersion()) + return false; + + if (MVType == MultiVersioning::Target && CheckMultiVersionValue(S, FD)) { + FD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionAdditionalRules(S, nullptr, FD, true, MVType)) { + FD->setInvalidDecl(); + return true; + } + + FD->setIsMultiVersion(); + return false; +} + +static bool CheckTargetCausesMultiVersioning( + Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA, + bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious, + LookupResult &Previous) { + const auto *OldTA = OldFD->getAttr<TargetAttr>(); + TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse(); + // Sort order doesn't matter, it just needs to be consistent. + llvm::sort(NewParsed.Features.begin(), NewParsed.Features.end()); + + // If the old decl is NOT MultiVersioned yet, and we don't cause that + // to change, this is a simple redeclaration. + if (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()) + return false; + + // Otherwise, this decl causes MultiVersioning. + if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true, + MultiVersioning::Target)) { + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionValue(S, NewFD)) { + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionValue(S, OldFD)) { + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + + TargetAttr::ParsedTargetAttr OldParsed = + OldTA->parse(std::less<std::string>()); + + if (OldParsed == NewParsed) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + for (const auto *FD : OldFD->redecls()) { + const auto *CurTA = FD->getAttr<TargetAttr>(); + if (!CurTA || CurTA->isInherited()) { + S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl) + << 0; + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + } + + OldFD->setIsMultiVersion(); + NewFD->setIsMultiVersion(); + Redeclaration = false; + MergeTypeWithPrevious = false; + OldDecl = nullptr; + Previous.clear(); + return false; +} + +/// Check the validity of a new function declaration being added to an existing +/// multiversioned declaration collection. +static bool CheckMultiVersionAdditionalDecl( + Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, + MultiVersioning::Type NewMVType, const TargetAttr *NewTA, + const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, + bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious, + LookupResult &Previous) { + + MultiVersioning::Type OldMVType = getMultiVersionType(OldFD); + // Disallow mixing of multiversioning types. + if ((OldMVType == MultiVersioning::Target && + NewMVType != MultiVersioning::Target) || + (NewMVType == MultiVersioning::Target && + OldMVType != MultiVersioning::Target)) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + TargetAttr::ParsedTargetAttr NewParsed; + if (NewTA) { + NewParsed = NewTA->parse(); + llvm::sort(NewParsed.Features.begin(), NewParsed.Features.end()); + } + + bool UseMemberUsingDeclRules = + S.CurContext->isRecord() && !NewFD->getFriendObjectKind(); + + // Next, check ALL non-overloads to see if this is a redeclaration of a + // previous member of the MultiVersion set. + for (NamedDecl *ND : Previous) { + FunctionDecl *CurFD = ND->getAsFunction(); + if (!CurFD) + continue; + if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) + continue; + + if (NewMVType == MultiVersioning::Target) { + const auto *CurTA = CurFD->getAttr<TargetAttr>(); + if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + + TargetAttr::ParsedTargetAttr CurParsed = + CurTA->parse(std::less<std::string>()); + if (CurParsed == NewParsed) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } else { + const auto *CurCPUSpec = CurFD->getAttr<CPUSpecificAttr>(); + const auto *CurCPUDisp = CurFD->getAttr<CPUDispatchAttr>(); + // Handle CPUDispatch/CPUSpecific versions. + // Only 1 CPUDispatch function is allowed, this will make it go through + // the redeclaration errors. + if (NewMVType == MultiVersioning::CPUDispatch && + CurFD->hasAttr<CPUDispatchAttr>()) { + if (CurCPUDisp->cpus_size() == NewCPUDisp->cpus_size() && + std::equal( + CurCPUDisp->cpus_begin(), CurCPUDisp->cpus_end(), + NewCPUDisp->cpus_begin(), + [](const IdentifierInfo *Cur, const IdentifierInfo *New) { + return Cur->getName() == New->getName(); + })) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + + // If the declarations don't match, this is an error condition. + S.Diag(NewFD->getLocation(), diag::err_cpu_dispatch_mismatch); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + if (NewMVType == MultiVersioning::CPUSpecific && CurCPUSpec) { + + if (CurCPUSpec->cpus_size() == NewCPUSpec->cpus_size() && + std::equal( + CurCPUSpec->cpus_begin(), CurCPUSpec->cpus_end(), + NewCPUSpec->cpus_begin(), + [](const IdentifierInfo *Cur, const IdentifierInfo *New) { + return Cur->getName() == New->getName(); + })) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + + // Only 1 version of CPUSpecific is allowed for each CPU. + for (const IdentifierInfo *CurII : CurCPUSpec->cpus()) { + for (const IdentifierInfo *NewII : NewCPUSpec->cpus()) { + if (CurII == NewII) { + S.Diag(NewFD->getLocation(), diag::err_cpu_specific_multiple_defs) + << NewII; + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } + } + } + // If the two decls aren't the same MVType, there is no possible error + // condition. + } + } + + // Else, this is simply a non-redecl case. Checking the 'value' is only + // necessary in the Target case, since The CPUSpecific/Dispatch cases are + // handled in the attribute adding step. + if (NewMVType == MultiVersioning::Target && + CheckMultiVersionValue(S, NewFD)) { + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, false, NewMVType)) { + NewFD->setInvalidDecl(); + return true; + } + + NewFD->setIsMultiVersion(); + Redeclaration = false; + MergeTypeWithPrevious = false; + OldDecl = nullptr; + Previous.clear(); + return false; +} + + +/// Check the validity of a mulitversion function declaration. +/// Also sets the multiversion'ness' of the function itself. +/// +/// This sets NewFD->isInvalidDecl() to true if there was an error. +/// +/// Returns true if there was an error, false otherwise. +static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, + bool &Redeclaration, NamedDecl *&OldDecl, + bool &MergeTypeWithPrevious, + LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr<TargetAttr>(); + const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>(); + const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>(); + + // Mixing Multiversioning types is prohibited. + if ((NewTA && NewCPUDisp) || (NewTA && NewCPUSpec) || + (NewCPUDisp && NewCPUSpec)) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); + NewFD->setInvalidDecl(); + return true; + } + + MultiVersioning::Type MVType = getMultiVersionType(NewFD); + + // Main isn't allowed to become a multiversion function, however it IS + // permitted to have 'main' be marked with the 'target' optimization hint. + if (NewFD->isMain()) { + if ((MVType == MultiVersioning::Target && NewTA->isDefaultVersion()) || + MVType == MultiVersioning::CPUDispatch || + MVType == MultiVersioning::CPUSpecific) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); + NewFD->setInvalidDecl(); + return true; + } + return false; + } + + if (!OldDecl || !OldDecl->getAsFunction() || + OldDecl->getDeclContext()->getRedeclContext() != + NewFD->getDeclContext()->getRedeclContext()) { + // If there's no previous declaration, AND this isn't attempting to cause + // multiversioning, this isn't an error condition. + if (MVType == MultiVersioning::None) + return false; + return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA, NewCPUDisp, + NewCPUSpec); + } + + FunctionDecl *OldFD = OldDecl->getAsFunction(); + + if (!OldFD->isMultiVersion() && MVType == MultiVersioning::None) + return false; + + if (OldFD->isMultiVersion() && MVType == MultiVersioning::None) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl) + << (getMultiVersionType(OldFD) != MultiVersioning::Target); + NewFD->setInvalidDecl(); + return true; + } + + // Handle the target potentially causes multiversioning case. + if (!OldFD->isMultiVersion() && MVType == MultiVersioning::Target) + return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, + Redeclaration, OldDecl, + MergeTypeWithPrevious, Previous); + // Previous declarations lack CPUDispatch/CPUSpecific. + if (!OldFD->isMultiVersion()) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_required_in_redecl) + << 1; + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + + // At this point, we have a multiversion function decl (in OldFD) AND an + // appropriate attribute in the current function decl. Resolve that these are + // still compatible with previous declarations. + return CheckMultiVersionAdditionalDecl( + S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, Redeclaration, + OldDecl, MergeTypeWithPrevious, Previous); +} + +/// Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration /// NewFD. This routine performs all semantic checking that does not @@ -9201,6 +9879,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } + if (CheckMultiVersionFunction(*this, NewFD, Redeclaration, OldDecl, + MergeTypeWithPrevious, Previous)) + return Redeclaration; + // 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. @@ -9250,15 +9932,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Previous.clear(); Previous.addDecl(OldDecl); - if (FunctionTemplateDecl *OldTemplateDecl - = dyn_cast<FunctionTemplateDecl>(OldDecl)) { - NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); + if (FunctionTemplateDecl *OldTemplateDecl = + dyn_cast<FunctionTemplateDecl>(OldDecl)) { + auto *OldFD = OldTemplateDecl->getTemplatedDecl(); + NewFD->setPreviousDeclaration(OldFD); + adjustDeclContextForDeclaratorDecl(NewFD, OldFD); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); - if (CXXMethodDecl *Method - = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) { - Method->setAccess(OldTemplateDecl->getAccess()); + if (NewFD->isCXXClassMember()) { + NewFD->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } @@ -9270,22 +9953,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, assert(OldTemplateDecl->isMemberSpecialization()); // Explicit specializations of a member template do not inherit deleted // status from the parent member template that they are specializing. - if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) { - FunctionDecl *const OldTemplatedDecl = - OldTemplateDecl->getTemplatedDecl(); + if (OldFD->isDeleted()) { // FIXME: This assert will not hold in the presence of modules. - assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl); + assert(OldFD->getCanonicalDecl() == OldFD); // FIXME: We need an update record for this AST mutation. - OldTemplatedDecl->setDeletedAsWritten(false); + OldFD->setDeletedAsWritten(false); } } } else { if (shouldLinkDependentDeclWithPrevious(NewFD, OldDecl)) { + auto *OldFD = cast<FunctionDecl>(OldDecl); // This needs to happen first so that 'inline' propagates. - NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); - if (isa<CXXMethodDecl>(NewFD)) - NewFD->setAccess(OldDecl->getAccess()); + NewFD->setPreviousDeclaration(OldFD); + adjustDeclContextForDeclaratorDecl(NewFD, OldFD); + if (NewFD->isCXXClassMember()) + NewFD->setAccess(OldFD->getAccess()); } } } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks && @@ -9440,7 +10123,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, else if (auto *MPT = T->getAs<MemberPointerType>()) T = MPT->getPointeeType(); if (auto *FPT = T->getAs<FunctionProtoType>()) - if (FPT->isNothrow(Context)) + if (FPT->isNothrow()) return true; return false; }; @@ -9951,7 +10634,7 @@ namespace { S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag) - << DRE->getNameInfo().getName() + << DRE->getDecl() << OrigDecl->getLocation() << DRE->getSourceRange()); } @@ -10011,12 +10694,22 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, // C++11 [dcl.spec.auto]p3 if (!Init) { assert(VDecl && "no init for init capture deduction?"); - Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) - << VDecl->getDeclName() << Type; - return QualType(); + + // Except for class argument deduction, and then for an initializing + // declaration only, i.e. no static at class scope or extern. + if (!isa<DeducedTemplateSpecializationType>(Deduced) || + VDecl->hasExternalStorage() || + VDecl->isStaticDataMember()) { + Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) + << VDecl->getDeclName() << Type; + return QualType(); + } } - ArrayRef<Expr*> DeduceInits = Init; + ArrayRef<Expr*> DeduceInits; + if (Init) + DeduceInits = Init; + if (DirectInit) { if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init)) DeduceInits = PL->exprs(); @@ -10260,7 +10953,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { } if (VDecl->hasLocalStorage()) - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) { VDecl->setInvalidDecl(); @@ -10360,11 +11053,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // we do not warn to warn spuriously when 'x' and 'y' are on separate // paths through the function. This should be revisited if // -Wrepeated-use-of-weak is made flow-sensitive. - if ((VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong || - VDecl->getType().isNonWeakInMRRWithObjCWeak(Context)) && - !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, - Init->getLocStart())) - getCurFunction()->markSafeWeakUse(Init); + if (FunctionScopeInfo *FSI = getCurFunction()) + if ((VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong || + VDecl->getType().isNonWeakInMRRWithObjCWeak(Context)) && + !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, + Init->getLocStart())) + FSI->markSafeWeakUse(Init); } // The initialization is usually a full-expression. @@ -10471,6 +11165,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { ; // Nothing to check. else if (Init->isIntegerConstantExpr(Context, &Loc)) ; // Ok, it's an ICE! + else if (Init->getType()->isScopedEnumeralType() && + Init->isCXX11ConstantExpr(Context)) + ; // Ok, it is a scoped-enum constant expression. else if (Init->isEvaluatable(Context)) { // If we can constant fold the initializer through heroics, accept it, // but report this as a use of an extension for -pedantic. @@ -10521,7 +11218,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { } else if (VDecl->isFileVarDecl()) { // In C, extern is typically used to avoid tentative definitions when // declaring variables in headers, but adding an intializer makes it a - // defintion. This is somewhat confusing, so GCC and Clang both warn on it. + // definition. This is somewhat confusing, so GCC and Clang both warn on it. // In C++, extern is often used to give implictly static const variables // external linkage, so don't warn in that case. If selectany is present, // this might be header code intended for C and C++ inclusion, so apply the @@ -10794,11 +11491,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { if (const RecordType *Record = Context.getBaseElementType(Type)->getAs<RecordType>()) { CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl()); - // Mark the function for further checking even if the looser rules of - // C++11 do not require such checks, so that we can diagnose - // incompatibilities with C++98. + // Mark the function (if we're in one) for further checking even if the + // looser rules of C++11 do not require such checks, so that we can + // diagnose incompatibilities with C++98. if (!CXXRecord->isPOD()) - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); } } @@ -10898,8 +11595,8 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, D.takeAttributes(Attrs, AttrEnd); ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory()); - D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/false), - EmptyAttrs, IdentLoc); + D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/ false), + IdentLoc); Decl *Var = ActOnDeclarator(S, D); cast<VarDecl>(Var)->setCXXForRangeDecl(true); FinalizeDeclaration(Var); @@ -10934,11 +11631,15 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); break; } } + if (var->hasLocalStorage() && + var->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + setFunctionHasBranchProtectedScope(); + // Warn about externally-visible variables being defined without a // prior declaration. We only want to do this for global // declarations, but we also specifically need to avoid doing it for @@ -11142,7 +11843,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Context.addModuleInitializer(ModuleScopes.back().Module, var); } -/// \brief Determines if a variable's alignment is dependent. +/// Determines if a variable's alignment is dependent. static bool hasDependentAlignment(VarDecl *VD) { if (VD->getType()->isDependentType()) return true; @@ -11229,58 +11930,8 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { // 7.5). We must also apply the same checks to all __shared__ // variables whether they are local or not. CUDA also allows // constant initializers for __constant__ and __device__ variables. - if (getLangOpts().CUDA) { - const Expr *Init = VD->getInit(); - if (Init && VD->hasGlobalStorage()) { - if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || - VD->hasAttr<CUDASharedAttr>()) { - assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()); - bool AllowedInit = false; - if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) - AllowedInit = - isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); - // We'll allow constant initializers even if it's a non-empty - // constructor according to CUDA rules. This deviates from NVCC, - // but allows us to handle things like constexpr constructors. - if (!AllowedInit && - (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) - AllowedInit = VD->getInit()->isConstantInitializer( - Context, VD->getType()->isReferenceType()); - - // Also make sure that destructor, if there is one, is empty. - if (AllowedInit) - if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl()) - AllowedInit = - isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); - - if (!AllowedInit) { - Diag(VD->getLocation(), VD->hasAttr<CUDASharedAttr>() - ? diag::err_shared_var_init - : diag::err_dynamic_var_init) - << Init->getSourceRange(); - VD->setInvalidDecl(); - } - } else { - // This is a host-side global variable. Check that the initializer is - // callable from the host side. - const FunctionDecl *InitFn = nullptr; - if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) { - InitFn = CE->getConstructor(); - } else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) { - InitFn = CE->getDirectCallee(); - } - if (InitFn) { - CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn); - if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) { - Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) - << InitFnTarget << InitFn; - Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; - VD->setInvalidDecl(); - } - } - } - } - } + if (getLangOpts().CUDA) + checkAllowedCUDAInitializer(VD); // Grab the dllimport or dllexport attribute off of the VarDecl. const InheritableAttr *DLLAttr = getDLLAttr(VD); @@ -11659,7 +12310,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { return New; } -/// \brief Synthesizes a variable for a parameter arising from a +/// Synthesizes a variable for a parameter arising from a /// typedef. ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, @@ -11896,9 +12547,45 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, const FunctionDecl *EffectiveDefinition, SkipBodyInfo *SkipBody) { const FunctionDecl *Definition = EffectiveDefinition; + if (!Definition && !FD->isDefined(Definition) && !FD->isCXXClassMember()) { + // If this is a friend function defined in a class template, it does not + // have a body until it is used, nevertheless it is a definition, see + // [temp.inst]p2: + // + // ... for the purpose of determining whether an instantiated redeclaration + // is valid according to [basic.def.odr] and [class.mem], a declaration that + // corresponds to a definition in the template is considered to be a + // definition. + // + // The following code must produce redefinition error: + // + // template<typename T> struct C20 { friend void func_20() {} }; + // C20<int> c20i; + // void func_20() {} + // + for (auto I : FD->redecls()) { + if (I != FD && !I->isInvalidDecl() && + I->getFriendObjectKind() != Decl::FOK_None) { + if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) { + if (FunctionDecl *OrigFD = FD->getInstantiatedFromMemberFunction()) { + // A merged copy of the same function, instantiated as a member of + // the same class, is OK. + if (declaresSameEntity(OrigFD, Original) && + declaresSameEntity(cast<Decl>(I->getLexicalDeclContext()), + cast<Decl>(FD->getLexicalDeclContext()))) + continue; + } + + if (Original->isThisDeclarationADefinition()) { + Definition = I; + break; + } + } + } + } + } if (!Definition) - if (!FD->isDefined(Definition)) - return; + return; if (canRedefineFunction(Definition, getLangOpts())) return; @@ -11983,8 +12670,13 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, SkipBodyInfo *SkipBody) { - if (!D) + if (!D) { + // Parsing the function declaration failed in some way. Push on a fake scope + // anyway so we can try to parse the function body. + PushFunctionScope(); return D; + } + FunctionDecl *FD = nullptr; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) @@ -12121,7 +12813,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, return D; } -/// \brief Given the set of return statements within a function body, +/// Given the set of return statements within a function body, /// compute the variables that are subject to the named return value /// optimization. /// @@ -12174,9 +12866,15 @@ bool Sema::canSkipFunctionBody(Decl *D) { // rest of the file. // We cannot skip the body of a function with an undeduced return type, // because any callers of that function need to know the type. - if (const FunctionDecl *FD = D->getAsFunction()) - if (FD->isConstexpr() || FD->getReturnType()->isUndeducedType()) + if (const FunctionDecl *FD = D->getAsFunction()) { + if (FD->isConstexpr()) return false; + // We can't simply call Type::isUndeducedType here, because inside template + // auto can be deduced to a dependent type, which is not considered + // "undeduced". + if (FD->getReturnType()->getContainedDeducedType()) + return false; + } return Consumer.shouldSkipFunctionBody(D); } @@ -12272,8 +12970,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around // to deduce an implicit return type. - if (getLangOpts().CPlusPlus && FD->getReturnType()->isRecordType() && - !FD->isDependentContext()) + if (FD->getReturnType()->isRecordType() && + (!getLangOpts().CPlusPlus || !FD->isDependentContext())) computeNRVO(Body, getCurFunction()); } @@ -12316,6 +13014,13 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } } + // Warn on CPUDispatch with an actual body. + if (FD->isMultiVersion() && FD->hasAttr<CPUDispatchAttr>() && Body) + if (const auto *CmpndBody = dyn_cast<CompoundStmt>(Body)) + if (!CmpndBody->body_empty()) + Diag(CmpndBody->body_front()->getLocStart(), + diag::warn_dispatch_body_ignored); + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { const CXXMethodDecl *KeyFunction; if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && @@ -12393,6 +13098,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, getCurFunction()->ObjCWarnForNoInitDelegation = false; } } else { + // Parsing the function declaration failed in some way. Pop the fake scope + // we pushed on. + PopFunctionScopeInfo(ActivePolicy, dcl); return nullptr; } @@ -12498,7 +13206,7 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) D = TD->getTemplatedDecl(); - ProcessDeclAttributeList(S, D, Attrs.getList()); + ProcessDeclAttributeList(S, D, Attrs); if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D)) if (Method->isStatic()) @@ -12600,18 +13308,16 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, - /*MutableLoc=*/NoLoc, - EST_None, + /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, - Loc, Loc, D), - DS.getAttributes(), - SourceLocation()); + /*DeclsInPrototype=*/None, Loc, + Loc, D), + std::move(DS.getAttributes()), SourceLocation()); D.SetIdentifier(&II, Loc); // Insert this function into the enclosing block scope. @@ -12623,7 +13329,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, return FD; } -/// \brief Adds any function attributes that we know a priori based on +/// Adds any function attributes that we know a priori based on /// the declaration of this function. /// /// These attributes can apply both to implicitly-declared builtins @@ -12673,11 +13379,11 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); - // We make "fma" on GNU or Windows const because we know it does not set + // We make "fma" on some platforms const because we know it does not set // errno in those environments even though it could set errno based on the // C standard. const llvm::Triple &Trip = Context.getTargetInfo().getTriple(); - if ((Trip.isGNUEnvironment() || Trip.isOSMSVCRT()) && + if ((Trip.isGNUEnvironment() || Trip.isAndroid() || Trip.isOSMSVCRT()) && !FD->hasAttr<ConstAttr>()) { switch (BuiltinID) { case Builtin::BI__builtin_fma: @@ -12753,7 +13459,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { // We already have a __builtin___CFStringMakeConstantString, // but builds that use -fno-constant-cfstrings don't go through that. if (!FD->hasAttr<FormatArgAttr>()) - FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1, + FD->addAttr(FormatArgAttr::CreateImplicit(Context, ParamIdx(1, FD), FD->getLocation())); } } @@ -12815,7 +13521,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } -/// \brief Check that this is a valid underlying type for an enum declaration. +/// Check that this is a valid underlying type for an enum declaration. bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); QualType T = TI->getType(); @@ -12833,11 +13539,9 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { /// Check whether this is a valid redeclaration of a previous enumeration. /// \return true if the redeclaration was invalid. -bool Sema::CheckEnumRedeclaration( - SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, - bool EnumUnderlyingIsImplicit, const EnumDecl *Prev) { - bool IsFixed = !EnumUnderlyingTy.isNull(); - +bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, + QualType EnumUnderlyingTy, bool IsFixed, + const EnumDecl *Prev) { if (IsScoped != Prev->isScoped()) { Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch) << Prev->isScoped(); @@ -12857,10 +13561,6 @@ bool Sema::CheckEnumRedeclaration( << Prev->getIntegerTypeRange(); return true; } - } else if (IsFixed && !Prev->isFixed() && EnumUnderlyingIsImplicit) { - ; - } else if (!IsFixed && Prev->isFixed() && !Prev->getIntegerTypeSourceInfo()) { - ; } else if (IsFixed != Prev->isFixed()) { Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch) << Prev->isFixed(); @@ -12871,7 +13571,7 @@ bool Sema::CheckEnumRedeclaration( return false; } -/// \brief Get diagnostic %select index for tag kind for +/// Get diagnostic %select index for tag kind for /// redeclaration diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// @@ -12885,7 +13585,7 @@ static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) { } } -/// \brief Determine if tag kind is a class-key compatible with +/// Determine if tag kind is a class-key compatible with /// class for redeclaration (class, struct, or __interface). /// /// \returns true iff the tag kind is compatible. @@ -12919,7 +13619,7 @@ Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl, llvm_unreachable("invalid TTK"); } -/// \brief Determine whether a tag with a given kind is acceptable +/// Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// /// \returns true if the new tag kind is acceptable, false otherwise. @@ -13055,8 +13755,8 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, return FixItHint::CreateInsertion(NameLoc, Insertion); } -/// \brief Determine whether a tag originally declared in context \p OldDC can -/// be redeclared with an unqualfied name in \p NewDC (assuming name lookup +/// Determine whether a tag originally declared in context \p OldDC can +/// be redeclared with an unqualified name in \p NewDC (assuming name lookup /// found a declaration in \p OldDC as a previous decl, perhaps through a /// using-declaration). static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, @@ -13076,7 +13776,7 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, return false; } -/// \brief This is invoked when we see 'struct foo' or 'struct {'. In the +/// This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. @@ -13089,13 +13789,12 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, + const ParsedAttributesView &Attrs, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, - bool ScopedEnumUsesClassTag, - TypeResult UnderlyingType, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. @@ -13134,14 +13833,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return nullptr; OwnedDecl = false; - DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, - SS, Name, NameLoc, Attr, - TemplateParams, AS, - ModulePrivateLoc, - /*FriendLoc*/SourceLocation(), - TemplateParameterLists.size()-1, - TemplateParameterLists.data(), - SkipBody); + DeclResult Result = CheckClassTemplate( + S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, + AS, ModulePrivateLoc, + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, + TemplateParameterLists.data(), SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. @@ -13156,14 +13852,14 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // this early, because it's needed to detect if this is an incompatible // redeclaration. llvm::PointerUnion<const Type*, TypeSourceInfo*> EnumUnderlying; - bool EnumUnderlyingIsImplicit = false; + bool IsFixed = !UnderlyingType.isUnset() || ScopedEnum; if (Kind == TTK_Enum) { - if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) + if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) { // No underlying type explicitly specified, or we failed to parse the // type, default to int. EnumUnderlying = Context.IntTy.getTypePtr(); - else if (UnderlyingType.get()) { + } else if (UnderlyingType.get()) { // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. TypeSourceInfo *TI = nullptr; @@ -13179,11 +13875,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, EnumUnderlying = Context.IntTy.getTypePtr(); } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { - if (getLangOpts().MSVCCompat || TUK == TUK_Definition) { - // Microsoft enums are always of int type. + // For MSVC ABI compatibility, unfixed enums must use an underlying type + // of 'int'. However, if this is an unfixed forward declaration, don't set + // the underlying type unless the user enables -fms-compatibility. This + // makes unfixed forward declared enums incomplete and is more conforming. + if (TUK == TUK_Definition || getLangOpts().MSVCCompat) EnumUnderlying = Context.IntTy.getTypePtr(); - EnumUnderlyingIsImplicit = true; - } } } @@ -13209,8 +13906,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Kind == TTK_Enum) { New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr, - ScopedEnum, ScopedEnumUsesClassTag, - !EnumUnderlying.isNull()); + ScopedEnum, ScopedEnumUsesClassTag, IsFixed); // If this is an undefined enum, bail. if (TUK != TUK_Definition && !Invalid) return nullptr; @@ -13589,7 +14285,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // in which case we want the caller to bail out. if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc, ScopedEnum, EnumUnderlyingTy, - EnumUnderlyingIsImplicit, PrevEnum)) + IsFixed, PrevEnum)) return TUK == TUK_Declaration ? PrevTagDecl : nullptr; } @@ -13607,7 +14303,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // If this is a use, just return the declaration we found, unless // we have attributes. if (TUK == TUK_Reference || TUK == TUK_Friend) { - if (Attr) { + if (!Attrs.empty()) { // FIXME: Diagnose these attributes. For now, we create a new // declaration to hold them. } else if (TUK == TUK_Reference && @@ -13799,13 +14495,12 @@ CreateNewDecl: // PrevDecl. TagDecl *New; - bool IsForwardReference = false; if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, - ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); + ScopedEnumUsesClassTag, IsFixed); if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit())) StdAlignValT = cast<EnumDecl>(New); @@ -13813,8 +14508,7 @@ CreateNewDecl: // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; - if (!EnumUnderlyingIsImplicit && - (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && + if (IsFixed && (getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && cast<EnumDecl>(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. @@ -13830,12 +14524,6 @@ CreateNewDecl: else if (getLangOpts().CPlusPlus) DiagID = diag::err_forward_ref_enum; Diag(Loc, DiagID); - - // If this is a forward-declared reference to an enumeration, make a - // note of it; we won't actually be introducing the declaration into - // the declaration context. - if (TUK == TUK_Reference) - IsForwardReference = true; } } @@ -13846,6 +14534,7 @@ CreateNewDecl: else ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); ED->setPromotionType(ED->getIntegerType()); + assert(ED->isComplete() && "enum with type should be complete"); } } else { // struct/union/class @@ -13884,13 +14573,10 @@ CreateNewDecl: if (SS.isNotEmpty()) { if (SS.isSet()) { // If this is either a declaration or a definition, check the - // nested-name-specifier against the current context. We don't do this - // for explicit specializations, because they have similar checking - // (with more specific diagnostics) in the call to - // CheckMemberSpecialization, below. - if (!isMemberSpecialization && - (TUK == TUK_Definition || TUK == TUK_Declaration) && - diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) + // nested-name-specifier against the current context. + if ((TUK == TUK_Definition || TUK == TUK_Declaration) && + diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc, + isMemberSpecialization)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); @@ -13977,8 +14663,7 @@ CreateNewDecl: if (TUK == TUK_Definition) New->startDefinition(); - if (Attr) - ProcessDeclAttributeList(S, New, Attr); + ProcessDeclAttributeList(S, New, Attrs); AddPragmaAttributes(S, New); // If this has an identifier, add it to the scope stack. @@ -13995,9 +14680,7 @@ CreateNewDecl: PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); } else if (Name) { S = getNonFieldDeclScope(S); - PushOnScopeChains(New, S, !IsForwardReference); - if (IsForwardReference) - SearchDC->makeDeclVisibleInContext(New); + PushOnScopeChains(New, S, true); } else { CurContext->addDecl(New); } @@ -14381,7 +15064,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, return NewFD; } -/// \brief Build a new FieldDecl and check its well-formedness. +/// Build a new FieldDecl and check its well-formedness. /// /// This routine builds a new FieldDecl given the fields name, type, /// record, etc. \p PrevDecl should refer to any previous declaration @@ -14432,6 +15115,13 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, InvalidDecl = true; } + // Anonymous bit-fields cannot be cv-qualified (CWG 2229). + if (!InvalidDecl && getLangOpts().CPlusPlus && !II && BitWidth && + T.hasQualifiers()) { + InvalidDecl = true; + Diag(Loc, diag::err_anon_bitfield_qualifiers); + } + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { @@ -14764,7 +15454,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl); - if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) + if (!Ivar->isBitField() || Ivar->isZeroLengthBitField(Context)) return; ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext); if (!ID) { @@ -14792,7 +15482,8 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ArrayRef<Decl *> Fields, SourceLocation LBrac, - SourceLocation RBrac, AttributeList *Attr) { + SourceLocation RBrac, + const ParsedAttributesView &Attrs) { assert(EnclosingDecl && "missing record or interface decl"); // If this is an Objective-C @implementation or category and we have @@ -14975,8 +15666,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && - Record && !ObjCFieldLifetimeErrReported && - (!getLangOpts().CPlusPlus || Record->isUnion())) { + Record && !ObjCFieldLifetimeErrReported && Record->isUnion()) { // It's an error in ARC or Weak if a field has lifetime. // We don't want to report this in a system header, though, // so we just make the field unavailable. @@ -15012,6 +15702,27 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); } } + + if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) { + QualType FT = FD->getType(); + if (FT.isNonTrivialToPrimitiveDefaultInitialize()) + Record->setNonTrivialToPrimitiveDefaultInitialize(true); + QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy(); + if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) + Record->setNonTrivialToPrimitiveCopy(true); + if (FT.isDestructedType()) { + Record->setNonTrivialToPrimitiveDestroy(true); + Record->setParamDestroyedInCallee(true); + } + + if (const auto *RT = FT->getAs<RecordType>()) { + if (RT->getDecl()->getArgPassingRestrictions() == + RecordDecl::APK_CanNeverPassInRegs) + Record->setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); + } else if (FT.getQualifiers().getObjCLifetime() == Qualifiers::OCL_Weak) + Record->setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); + } + if (Record && FD->getType().isVolatileQualified()) Record->setHasVolatileMember(true); // Keep track of the number of named members. @@ -15039,10 +15750,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, CXXRecord->getDestructor()); } - if (!CXXRecord->isInvalidDecl()) { - // Add any implicitly-declared members to this class. - AddImplicitlyDeclaredMembersToClass(CXXRecord); + // Add any implicitly-declared members to this class. + AddImplicitlyDeclaredMembersToClass(CXXRecord); + if (!CXXRecord->isInvalidDecl()) { // If we have virtual base classes, we may end up finding multiple // final overriders for a given virtual function. Check for this // problem now. @@ -15057,7 +15768,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, SOEnd = M->second.end(); SO != SOEnd; ++SO) { assert(SO->second.size() > 0 && - "Virtual function without overridding functions?"); + "Virtual function without overriding functions?"); if (SO->second.size() == 1) continue; @@ -15089,6 +15800,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (!Completed) Record->completeDefinition(); + // Handle attributes before checking the layout. + ProcessDeclAttributeList(S, Record, Attrs); + // We may have deferred checking for a deleted destructor. Check now. if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) { auto *Dtor = CXXRecord->getDestructor(); @@ -15131,7 +15845,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, (NonBitFields == 0 || ZeroSize) && I != E; ++I) { IsEmpty = false; if (I->isUnnamedBitfield()) { - if (I->getBitWidthValue(Context) > 0) + if (!I->isZeroLengthBitField(Context)) ZeroSize = false; } else { ++NonBitFields; @@ -15219,12 +15933,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, CDecl->setIvarRBraceLoc(RBrac); } } - - if (Attr) - ProcessDeclAttributeList(S, Record, Attr); } -/// \brief Determine whether the given integral value is representable within +/// Determine whether the given integral value is representable within /// the given type T. static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, @@ -15241,7 +15952,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, return Value.getMinSignedBits() <= BitWidth; } -// \brief Given an integral type, return the next larger integral type +// Given an integral type, return the next larger integral type // (or a NULL type of no such type exists). static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { // FIXME: Int128/UInt128 support, which also needs to be introduced into @@ -15304,7 +16015,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, &EnumVal).get())) { // C99 6.7.2.2p2: Make sure we have an integer constant expression. } else { - if (Enum->isFixed()) { + if (Enum->isComplete()) { EltTy = Enum->getIntegerType(); // In Obj-C and Microsoft mode, require the enumeration value to be @@ -15468,7 +16179,7 @@ Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, - AttributeList *Attr, + const ParsedAttributesView &Attrs, SourceLocation EqualLoc, Expr *Val) { EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl); EnumConstantDecl *LastEnumConst = @@ -15519,7 +16230,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, } // Process attributes. - if (Attr) ProcessDeclAttributeList(S, New, Attr); + ProcessDeclAttributeList(S, New, Attrs); AddPragmaAttributes(S, New); // Register this decl in the current scope stack. @@ -15571,39 +16282,10 @@ static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) { return false; } -namespace { -struct DupKey { - int64_t val; - bool isTombstoneOrEmptyKey; - DupKey(int64_t val, bool isTombstoneOrEmptyKey) - : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {} -}; - -static DupKey GetDupKey(const llvm::APSInt& Val) { - return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(), - false); -} - -struct DenseMapInfoDupKey { - static DupKey getEmptyKey() { return DupKey(0, true); } - static DupKey getTombstoneKey() { return DupKey(1, true); } - static unsigned getHashValue(const DupKey Key) { - return (unsigned)(Key.val * 37); - } - static bool isEqual(const DupKey& LHS, const DupKey& RHS) { - return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey && - LHS.val == RHS.val; - } -}; -} // end anonymous namespace - // Emits a warning when an element is implicitly set a value that // a previous element has already been set to. static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, - EnumDecl *Enum, - QualType EnumType) { - if (S.Diags.isIgnored(diag::warn_duplicate_enum_values, Enum->getLocation())) - return; + EnumDecl *Enum, QualType EnumType) { // Avoid anonymous enums if (!Enum->getIdentifier()) return; @@ -15612,20 +16294,28 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64) return; + if (S.Diags.isIgnored(diag::warn_duplicate_enum_values, Enum->getLocation())) + return; + typedef SmallVector<EnumConstantDecl *, 3> ECDVector; - typedef SmallVector<ECDVector *, 3> DuplicatesVector; + typedef SmallVector<std::unique_ptr<ECDVector>, 3> DuplicatesVector; typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector; - typedef llvm::DenseMap<DupKey, DeclOrVector, DenseMapInfoDupKey> - ValueToVectorMap; + typedef llvm::DenseMap<int64_t, DeclOrVector> ValueToVectorMap; + + // Use int64_t as a key to avoid needing special handling for DenseMap keys. + auto EnumConstantToKey = [](const EnumConstantDecl *D) { + llvm::APSInt Val = D->getInitVal(); + return Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(); + }; DuplicatesVector DupVector; ValueToVectorMap EnumMap; // Populate the EnumMap with all values represented by enum constants without - // an initialier. - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); + // an initializer. + for (auto *Element : Elements) { + EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Element); // Null EnumConstantDecl means a previous diagnostic has been emitted for // this constant. Skip this enum since it may be ill-formed. @@ -15633,45 +16323,45 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, return; } + // Constants with initalizers are handled in the next loop. if (ECD->getInitExpr()) continue; - DupKey Key = GetDupKey(ECD->getInitVal()); - DeclOrVector &Entry = EnumMap[Key]; - - // First time encountering this value. - if (Entry.isNull()) - Entry = ECD; + // Duplicate values are handled in the next loop. + EnumMap.insert({EnumConstantToKey(ECD), ECD}); } + if (EnumMap.size() == 0) + return; + // Create vectors for any values that has duplicates. - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]); + for (auto *Element : Elements) { + // The last loop returned if any constant was null. + EnumConstantDecl *ECD = cast<EnumConstantDecl>(Element); if (!ValidDuplicateEnum(ECD, Enum)) continue; - DupKey Key = GetDupKey(ECD->getInitVal()); - - DeclOrVector& Entry = EnumMap[Key]; - if (Entry.isNull()) + auto Iter = EnumMap.find(EnumConstantToKey(ECD)); + if (Iter == EnumMap.end()) continue; + DeclOrVector& Entry = Iter->second; if (EnumConstantDecl *D = Entry.dyn_cast<EnumConstantDecl*>()) { // Ensure constants are different. if (D == ECD) continue; // Create new vector and push values onto it. - ECDVector *Vec = new ECDVector(); + auto Vec = llvm::make_unique<ECDVector>(); Vec->push_back(D); Vec->push_back(ECD); // Update entry to point to the duplicates vector. - Entry = Vec; + Entry = Vec.get(); // Store the vector somewhere we can consult later for quick emission of // diagnostics. - DupVector.push_back(Vec); + DupVector.emplace_back(std::move(Vec)); continue; } @@ -15684,26 +16374,21 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, } // Emit diagnostics. - for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(), - DupVectorEnd = DupVector.end(); - DupVectorIter != DupVectorEnd; ++DupVectorIter) { - ECDVector *Vec = *DupVectorIter; + for (const auto &Vec : DupVector) { assert(Vec->size() > 1 && "ECDVector should have at least 2 elements."); // Emit warning for one enum constant. - ECDVector::iterator I = Vec->begin(); - S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values) - << (*I)->getName() << (*I)->getInitVal().toString(10) - << (*I)->getSourceRange(); - ++I; + auto *FirstECD = Vec->front(); + S.Diag(FirstECD->getLocation(), diag::warn_duplicate_enum_values) + << FirstECD << FirstECD->getInitVal().toString(10) + << FirstECD->getSourceRange(); // Emit one note for each of the remaining enum constants with // the same value. - for (ECDVector::iterator E = Vec->end(); I != E; ++I) - S.Diag((*I)->getLocation(), diag::note_duplicate_element) - << (*I)->getName() << (*I)->getInitVal().toString(10) - << (*I)->getSourceRange(); - delete Vec; + for (auto *ECD : llvm::make_range(Vec->begin() + 1, Vec->end())) + S.Diag(ECD->getLocation(), diag::note_duplicate_element) + << ECD << ECD->getInitVal().toString(10) + << ECD->getSourceRange(); } } @@ -15737,14 +16422,12 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, } void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, - Decl *EnumDeclX, - ArrayRef<Decl *> Elements, - Scope *S, AttributeList *Attr) { + Decl *EnumDeclX, ArrayRef<Decl *> Elements, Scope *S, + const ParsedAttributesView &Attrs) { EnumDecl *Enum = cast<EnumDecl>(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); - if (Attr) - ProcessDeclAttributeList(S, Enum, Attr); + ProcessDeclAttributeList(S, Enum, Attrs); if (Enum->isDependentType()) { for (unsigned i = 0, e = Elements.size(); i != e; ++i) { @@ -15815,7 +16498,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, if (LangOpts.ShortEnums) Packed = true; - if (Enum->isFixed()) { + // If the enum already has a type because it is fixed or dictated by the + // target, promote that type instead of analyzing the enumerators. + if (Enum->isComplete()) { BestType = Enum->getIntegerType(); if (BestType->isPromotableIntegerType()) BestPromotionType = Context.getPromotedIntegerType(BestType); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 21fe46ad9dd1..320eabd5ec2f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -58,7 +59,7 @@ static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } -/// \brief Return true if the given decl has function type (function or +/// Return true if the given decl has function type (function or /// function-typed variable) or an Objective-C method or a block. static bool isFunctionOrMethodOrBlock(const Decl *D) { return isFunctionOrMethod(D) || isa<BlockDecl>(D); @@ -87,7 +88,7 @@ static bool hasFunctionProto(const Decl *D) { static unsigned getFunctionOrMethodNumParams(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getNumParams(); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getNumParams(); return cast<ObjCMethodDecl>(D)->param_size(); } @@ -95,7 +96,7 @@ static unsigned getFunctionOrMethodNumParams(const Decl *D) { static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) { if (const FunctionType *FnTy = D->getFunctionType()) return cast<FunctionProtoType>(FnTy)->getParamType(Idx); - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->getParamDecl(Idx)->getType(); return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType(); @@ -113,7 +114,7 @@ static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) { static QualType getFunctionOrMethodResultType(const Decl *D) { if (const FunctionType *FnTy = D->getFunctionType()) - return cast<FunctionType>(FnTy)->getReturnType(); + return FnTy->getReturnType(); return cast<ObjCMethodDecl>(D)->getReturnType(); } @@ -126,24 +127,21 @@ static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) { } static bool isFunctionOrMethodVariadic(const Decl *D) { - if (const FunctionType *FnTy = D->getFunctionType()) { - const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); - return proto->isVariadic(); - } - if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + if (const FunctionType *FnTy = D->getFunctionType()) + return cast<FunctionProtoType>(FnTy)->isVariadic(); + if (const auto *BD = dyn_cast<BlockDecl>(D)) return BD->isVariadic(); - return cast<ObjCMethodDecl>(D)->isVariadic(); } static bool isInstanceMethod(const Decl *D) { - if (const CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) + if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D)) return MethodDecl->isInstance(); return false; } static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); + const auto *PT = T->getAs<ObjCObjectPointerType>(); if (!PT) return false; @@ -159,11 +157,11 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) { } static inline bool isCFStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAs<PointerType>(); + const auto *PT = T->getAs<PointerType>(); if (!PT) return false; - const RecordType *RT = PT->getPointeeType()->getAs<RecordType>(); + const auto *RT = PT->getPointeeType()->getAs<RecordType>(); if (!RT) return false; @@ -174,89 +172,86 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); } -static unsigned getNumAttributeArgs(const AttributeList &Attr) { +static unsigned getNumAttributeArgs(const ParsedAttr &AL) { // FIXME: Include the type in the argument list. - return Attr.getNumArgs() + Attr.hasParsedType(); + return AL.getNumArgs() + AL.hasParsedType(); } template <typename Compare> -static bool checkAttributeNumArgsImpl(Sema &S, const AttributeList &Attr, +static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, unsigned Num, unsigned Diag, Compare Comp) { - if (Comp(getNumAttributeArgs(Attr), Num)) { - S.Diag(Attr.getLoc(), Diag) << Attr.getName() << Num; + if (Comp(getNumAttributeArgs(AL), Num)) { + S.Diag(AL.getLoc(), Diag) << AL.getName() << Num; return false; } return true; } -/// \brief Check if the attribute has exactly as many args as Num. May +/// 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, +static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, 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 +/// Check if the attribute has at least as many args as Num. May /// output an error. -static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr, +static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { - return checkAttributeNumArgsImpl(S, Attr, Num, + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_few_arguments, std::less<unsigned>()); } -/// \brief Check if the attribute has at most as many args as Num. May +/// 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, +static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, + unsigned Num) { + return checkAttributeNumArgsImpl(S, AL, Num, diag::err_attribute_too_many_arguments, std::greater<unsigned>()); } -/// \brief A helper function to provide Attribute Location for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Location for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>::type -getAttrLoc(const AttrInfo &Attr) { - return Attr.getLocation(); -} -static SourceLocation getAttrLoc(const clang::AttributeList &Attr) { - return Attr.getLoc(); +getAttrLoc(const AttrInfo &AL) { + return AL.getLocation(); } +static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); } -/// \brief A helper function to provide Attribute Name for the Attr types -/// AND the AttributeList. +/// A helper function to provide Attribute Name for the Attr types +/// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<clang::Attr, AttrInfo>::value, +static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, const AttrInfo *>::type -getAttrName(const AttrInfo &Attr) { - return &Attr; +getAttrName(const AttrInfo &AL) { + return &AL; } -static const IdentifierInfo *getAttrName(const clang::AttributeList &Attr) { - return Attr.getName(); +static const IdentifierInfo *getAttrName(const ParsedAttr &AL) { + return AL.getName(); } -/// \brief If Expr is a valid integer constant, get the value of the integer +/// If Expr is a valid integer constant, get the value of the integer /// expression and return success or failure. May output an error. -template<typename AttrInfo> -static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX) { llvm::APSInt I(32); if (Expr->isTypeDependent() || Expr->isValueDependent() || !Expr->isIntegerConstantExpr(I, S.Context)) { if (Idx != UINT_MAX) - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << Idx << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << Idx << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); else - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_type) - << getAttrName(Attr) << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type) + << getAttrName(AI) << AANT_ArgumentIntegerConstant << Expr->getSourceRange(); return false; } @@ -271,14 +266,14 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo& Attr, const Expr *Expr, return true; } -/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure +/// Wrapper around checkUInt32Argument, with an extra check to be sure /// that the result will fit into a regular (signed) int. All args have the same /// purpose as they do in checkUInt32Argument. -template<typename AttrInfo> -static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr *Expr, +template <typename AttrInfo> +static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, int &Val, unsigned Idx = UINT_MAX) { uint32_t UVal; - if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx)) + if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) return false; if (UVal > (uint32_t)std::numeric_limits<int>::max()) { @@ -293,12 +288,12 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo& Attr, const Expr * return true; } -/// \brief Diagnose mutually exclusive attributes when present on a given +/// Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, IdentifierInfo *Ident) { - if (AttrTy *A = D->getAttr<AttrTy>()) { + if (const auto *A = D->getAttr<AttrTy>()) { S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident << A; S.Diag(A->getLocation(), diag::note_conflicting_attribute); @@ -307,14 +302,14 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, return false; } -/// \brief Check if IdxExpr is a valid parameter index for a function or +/// Check if IdxExpr is a valid parameter index for a function or /// instance method D. May output an error. /// /// \returns true if IdxExpr is a valid index. template <typename AttrInfo> static bool checkFunctionOrMethodParameterIndex( - Sema &S, const Decl *D, const AttrInfo &Attr, unsigned AttrArgNum, - const Expr *IdxExpr, uint64_t &Idx, bool AllowImplicitThis = false) { + Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum, + const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) { assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. @@ -328,44 +323,43 @@ static bool checkFunctionOrMethodParameterIndex( llvm::APSInt IdxInt; if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_n_type) - << getAttrName(Attr) << AttrArgNum << AANT_ArgumentIntegerConstant + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) + << getAttrName(AI) << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange(); return false; } - Idx = IdxInt.getLimitedValue(); - if (Idx < 1 || (!IV && Idx > NumParams)) { - S.Diag(getAttrLoc(Attr), diag::err_attribute_argument_out_of_bounds) - << getAttrName(Attr) << AttrArgNum << IdxExpr->getSourceRange(); + unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX); + if (IdxSource < 1 || (!IV && IdxSource > NumParams)) { + S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds) + << getAttrName(AI) << AttrArgNum << IdxExpr->getSourceRange(); return false; } - Idx--; // Convert to zero-based. - if (HasImplicitThisParam && !AllowImplicitThis) { - if (Idx == 0) { - S.Diag(getAttrLoc(Attr), + if (HasImplicitThisParam && !CanIndexImplicitThis) { + if (IdxSource == 1) { + S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument) - << getAttrName(Attr) << IdxExpr->getSourceRange(); + << getAttrName(AI) << IdxExpr->getSourceRange(); return false; } - --Idx; } + Idx = ParamIdx(IdxSource, D); return true; } -/// \brief Check if the argument \p ArgNum of \p Attr is a ASCII string literal. +/// Check if the argument \p ArgNum of \p Attr is a ASCII string literal. /// If not emit an error and return false. If the argument is an identifier it /// will emit an error with a fixit hint and treat it as if it was a string /// literal. -bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, - unsigned ArgNum, StringRef &Str, +bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, + StringRef &Str, SourceLocation *ArgLocation) { // Look for identifiers. If we have one emit a hint to fix it to a literal. - if (Attr.isArgIdent(ArgNum)) { - IdentifierLoc *Loc = Attr.getArgAsIdent(ArgNum); + if (AL.isArgIdent(ArgNum)) { + IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum); Diag(Loc->Loc, diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString + << AL.getName() << AANT_ArgumentString << FixItHint::CreateInsertion(Loc->Loc, "\"") << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); Str = Loc->Ident->getName(); @@ -375,14 +369,14 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, } // Now check for an actual string literal. - Expr *ArgExpr = Attr.getArgAsExpr(ArgNum); - StringLiteral *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); + Expr *ArgExpr = AL.getArgAsExpr(ArgNum); + const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); if (ArgLocation) *ArgLocation = ArgExpr->getLocStart(); if (!Literal || !Literal->isAscii()) { Diag(ArgExpr->getLocStart(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentString; + << AL.getName() << AANT_ArgumentString; return false; } @@ -390,35 +384,34 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, return true; } -/// \brief Applies the given attribute to the Decl without performing any +/// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> -static void handleSimpleAttribute(Sema &S, Decl *D, - const AttributeList &Attr) { - D->addAttr(::new (S.Context) AttrType(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); +static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } template <typename AttrType> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - handleSimpleAttribute<AttrType>(S, D, Attr); + const ParsedAttr &AL) { + handleSimpleAttribute<AttrType>(S, D, AL); } -/// \brief Applies the given attribute to the Decl so long as the Decl doesn't +/// Applies the given attribute to the Decl so long as the Decl doesn't /// already have one of the given incompatible attributes. template <typename AttrType, typename IncompatibleAttrType, typename... IncompatibleAttrTypes> static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, Attr.getRange(), - Attr.getName())) + const ParsedAttr &AL) { + if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL.getRange(), + AL.getName())) return; handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D, - Attr); + AL); } -/// \brief Check if the passed-in expression is of type int or bool. +/// Check if the passed-in expression is of type int or bool. static bool isIntOrBool(Expr *Exp) { QualType QT = Exp->getType(); return QT->isBooleanType() || QT->isIntegerType(); @@ -441,17 +434,17 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return true; } -/// \brief Check if passed in Decl is a pointer type. +/// Check if passed in Decl is a pointer type. /// Note that this function may produce an error message. /// \return true if the Decl is a pointer type; false otherwise static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, - const AttributeList &Attr) { - const ValueDecl *vd = cast<ValueDecl>(D); - QualType QT = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); if (QT->isAnyPointerType()) return true; - if (const RecordType *RT = QT->getAs<RecordType>()) { + if (const auto *RT = QT->getAs<RecordType>()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) @@ -462,19 +455,19 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, return true; } - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer) - << Attr.getName() << QT; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) + << AL.getName() << QT; return false; } -/// \brief Checks that the passed in QualType either is of RecordType or points +/// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. static const RecordType *getRecordType(QualType QT) { - if (const RecordType *RT = QT->getAs<RecordType>()) + if (const auto *RT = QT->getAs<RecordType>()) return RT; // Now check if we point to record type. - if (const PointerType *PT = QT->getAs<PointerType>()) + if (const auto *PT = QT->getAs<PointerType>()) return PT->getPointeeType()->getAs<RecordType>(); return nullptr; @@ -501,7 +494,7 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { return true; // Else check if any base classes have a capability. - if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) { CXXBasePaths BPaths(false, false); if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { const auto *Type = BS->getType()->getAs<RecordType>(); @@ -559,18 +552,18 @@ static bool isCapabilityExpr(Sema &S, const Expr *Ex) { return typeHasCapability(S, Ex->getType()); } -/// \brief Checks that all attribute arguments, starting from Sidx, resolve to +/// Checks that all attribute arguments, starting from Sidx, resolve to /// a capability object. /// \param Sidx The attribute argument index to start checking with. /// \param ParamIdxOk Whether an argument can be indexing into a function /// parameter list. static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args, int Sidx = 0, bool ParamIdxOk = false) { - for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) { - Expr *ArgExp = Attr.getArgAsExpr(Idx); + for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) { + Expr *ArgExp = AL.getArgAsExpr(Idx); if (ArgExp->isTypeDependent()) { // FIXME -- need to check this again on template instantiation @@ -578,7 +571,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, continue; } - if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) { + if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) { if (StrLit->getLength() == 0 || (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) { // Pass empty strings to the analyzer without warnings. @@ -589,8 +582,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) << - Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL.getName(); Args.push_back(ArgExp); continue; } @@ -599,9 +591,9 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // A pointer to member expression of the form &MyClass::mu is treated // specially -- we need to look at the type of the member. - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(ArgExp)) + if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp)) if (UOp->getOpcode() == UO_AddrOf) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) + if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr())) if (DRE->getDecl()->isCXXInstanceMember()) ArgTy = DRE->getDecl()->getType(); @@ -610,16 +602,16 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Now check if we index into a record type function param. if(!RT && ParamIdxOk) { - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp); + const auto *FD = dyn_cast<FunctionDecl>(D); + const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); if(FD && IL) { unsigned int NumParams = FD->getNumParams(); llvm::APInt ArgValue = IL->getValue(); uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); uint64_t ParamIdxFromZero = ParamIdxFromOne - 1; - if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range) - << Attr.getName() << Idx + 1 << NumParams; + if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range) + << AL.getName() << Idx + 1 << NumParams; continue; } ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType(); @@ -631,8 +623,8 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // capability may be on the type, and the expression is a capability // boolean logic expression. Eg) requires_capability(A || B && !C) if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp)) - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable) - << Attr.getName() << ArgTy; + S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable) + << AL.getName() << ArgTy; Args.push_back(ArgExp); } @@ -642,22 +634,20 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, // Attribute Implementations //===----------------------------------------------------------------------===// -static void handlePtGuardedVarAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!threadSafetyCheckIsPointer(S, D, Attr)) +static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!threadSafetyCheckIsPointer(S, D, AL)) return; D->addAttr(::new (S.Context) - PtGuardedVarAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PtGuardedVarAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static bool checkGuardedByAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, - Expr* &Arg) { - SmallVector<Expr*, 1> Args; +static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, + Expr *&Arg) { + SmallVector<Expr *, 1> Args; // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size != 1) return false; @@ -667,273 +657,239 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D, return true; } -static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) GuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static void handlePtGuardedByAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *Arg = nullptr; - if (!checkGuardedByAttrCommon(S, D, Attr, Arg)) + if (!checkGuardedByAttrCommon(S, D, AL, Arg)) return; - if (!threadSafetyCheckIsPointer(S, D, Attr)) + if (!threadSafetyCheckIsPointer(S, D, AL)) return; - D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(), - S.Context, Arg, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PtGuardedByAttr( + AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex())); } -static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; // Check that this attribute only applies to lockable types. QualType QT = cast<ValueDecl>(D)->getType(); if (!QT->isDependentType() && !typeHasCapability(S, QT)) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) + << AL.getName(); return false; } // Check that all arguments are lockable objects. - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return false; return true; } -static void handleAcquiredAfterAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredAfterAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredAfterAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static void handleAcquiredBeforeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkAcquireOrderAttrCommon(S, D, Attr, Args)) +static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkAcquireOrderAttrCommon(S, D, AL, Args)) return; Expr **StartArg = &Args[0]; - D->addAttr(::new (S.Context) - AcquiredBeforeAttr(Attr.getRange(), S.Context, - StartArg, Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AcquiredBeforeAttr( + AL.getRange(), S.Context, StartArg, Args.size(), + AL.getAttributeSpellingListIndex())); } -static bool checkLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { // zero or more arguments ok // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true); return true; } -static void handleAssertSharedLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) +static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; D->addAttr(::new (S.Context) - AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + const ParsedAttr &AL) { + SmallVector<Expr *, 1> Args; + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; unsigned Size = Args.size(); Expr **StartArg = Size == 0 ? nullptr : &Args[0]; - D->addAttr(::new (S.Context) - AssertExclusiveLockAttr(Attr.getRange(), S.Context, - StartArg, Size, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AssertExclusiveLockAttr( + AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns +/// Checks to be sure that the given parameter number is in bounds, and +/// is an integral type. Will emit appropriate diagnostics if this returns /// false. /// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. +/// AttrArgNo is used to actually retrieve the argument, so it's base-0. template <typename AttrInfo> static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttrInfo &Attr, Expr *AttrArg, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, AttrArg, + const AttrInfo &AI, unsigned AttrArgNo) { + assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument"); + Expr *AttrArg = AI.getArgAsExpr(AttrArgNo); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg, Idx)) return false; - const ParmVarDecl *Param = FD->getParamDecl(Idx); - if (AllowDependentType && Param->getType()->isDependentType()) - return true; + const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex()); if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { SourceLocation SrcLoc = AttrArg->getLocStart(); S.Diag(SrcLoc, diag::err_attribute_integers_only) - << getAttrName(Attr) << Param->getSourceRange(); + << getAttrName(AI) << Param->getSourceRange(); return false; } return true; } -/// \brief Checks to be sure that the given parameter number is in bounds, and is -/// an integral type. Will emit appropriate diagnostics if this returns false. -/// -/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used -/// to actually retrieve the argument, so it's base-0. -static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, - const AttributeList &Attr, - unsigned FuncParamNo, unsigned AttrArgNo, - bool AllowDependentType = false) { - assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); - return checkParamIsIntegerType(S, FD, Attr, Attr.getArgAsExpr(AttrArgNo), - FuncParamNo, AttrArgNo, AllowDependentType); -} - -static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName(); return; } - const Expr *SizeExpr = Attr.getArgAsExpr(0); - int SizeArgNo; + const Expr *SizeExpr = AL.getArgAsExpr(0); + int SizeArgNoVal; // Parameter indices are 1-indexed, hence Index=1 - if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1)) + if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Index=*/1)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, SizeArgNo, /*AttrArgNo=*/0)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0)) return; + ParamIdx SizeArgNo(SizeArgNoVal, D); - // Args are 1-indexed, so 0 implies that the arg was not present - int NumberArgNo = 0; - if (Attr.getNumArgs() == 2) { - const Expr *NumberExpr = Attr.getArgAsExpr(1); + ParamIdx NumberArgNo; + if (AL.getNumArgs() == 2) { + const Expr *NumberExpr = AL.getArgAsExpr(1); + int Val; // Parameter indices are 1-based, hence Index=2 - if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo, - /*Index=*/2)) + if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Index=*/2)) return; - - if (!checkParamIsIntegerType(S, FD, Attr, NumberArgNo, /*AttrArgNo=*/1)) + if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1)) return; + NumberArgNo = ParamIdx(Val, D); } - D->addAttr(::new (S.Context) AllocSizeAttr( - Attr.getRange(), S.Context, SizeArgNo, NumberArgNo, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo, + AL.getAttributeSpellingListIndex())); } -static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, SmallVectorImpl<Expr *> &Args) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return false; - if (!isIntOrBool(Attr.getArgAsExpr(0))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntOrBool; + if (!isIntOrBool(AL.getArgAsExpr(0))) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntOrBool; return false; } // check that all arguments are lockable objects - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1); return true; } static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) - SharedTrylockFunctionAttr(Attr.getRange(), S.Context, - Attr.getArgAsExpr(0), - Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) SharedTrylockFunctionAttr( + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr( - Attr.getRange(), S.Context, Attr.getArgAsExpr(0), Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), + Args.size(), AL.getAttributeSpellingListIndex())); } -static void handleLockReturnedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check that the argument is lockable object SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; D->addAttr(::new (S.Context) - LockReturnedAttr(Attr.getRange(), S.Context, Args[0], - Attr.getAttributeSpellingListIndex())); + LockReturnedAttr(AL.getRange(), S.Context, Args[0], + AL.getAttributeSpellingListIndex())); } -static void handleLocksExcludedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) return; Expr **StartArg = &Args[0]; D->addAttr(::new (S.Context) - LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size, - Attr.getAttributeSpellingListIndex())); + LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size, + AL.getAttributeSpellingListIndex())); } -static bool checkFunctionConditionAttr(Sema &S, Decl *D, - const AttributeList &Attr, +static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL, Expr *&Cond, StringRef &Msg) { - Cond = Attr.getArgAsExpr(0); + Cond = AL.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) @@ -941,7 +897,7 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, Cond = Converted.get(); } - if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg)) + if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg)) return false; if (Msg.empty()) @@ -951,8 +907,8 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, if (isa<FunctionDecl>(D) && !Cond->isValueDependent() && !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { - S.Diag(Attr.getLoc(), diag::err_attr_cond_never_constant_expr) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) + << AL.getName(); for (const PartialDiagnosticAt &PDiag : Diags) S.Diag(PDiag.first, PDiag.second); return false; @@ -960,15 +916,15 @@ static bool checkFunctionConditionAttr(Sema &S, Decl *D, return true; } -static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); +static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_enable_if); Expr *Cond; StringRef Msg; - if (checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (checkFunctionConditionAttr(S, D, AL, Cond, Msg)) D->addAttr(::new (S.Context) - EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg, - Attr.getAttributeSpellingListIndex())); + EnableIfAttr(AL.getRange(), S.Context, Cond, Msg, + AL.getAttributeSpellingListIndex())); } namespace { @@ -1017,21 +973,21 @@ public: }; } -static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.Diag(Attr.getLoc(), diag::ext_clang_diagnose_if); +static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if); Expr *Cond; StringRef Msg; - if (!checkFunctionConditionAttr(S, D, Attr, Cond, Msg)) + if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg)) return; StringRef DiagTypeStr; - if (!S.checkStringLiteralArgumentAttr(Attr, 2, DiagTypeStr)) + if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr)) return; DiagnoseIfAttr::DiagnosticType DiagType; if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) { - S.Diag(Attr.getArgAsExpr(2)->getLocStart(), + S.Diag(AL.getArgAsExpr(2)->getLocStart(), diag::err_diagnose_if_invalid_diagnostic_type); return; } @@ -1040,21 +996,20 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const auto *FD = dyn_cast<FunctionDecl>(D)) ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond); D->addAttr(::new (S.Context) DiagnoseIfAttr( - Attr.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent, + cast<NamedDecl>(D), AL.getAttributeSpellingListIndex())); } -static void handlePassObjectSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr<PassObjectSizeAttr>()) { S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) - << Attr.getName(); + << AL.getName(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t Type; - if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1)) + if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1)) return; // pass_object_size's argument is passed in as the second argument of @@ -1062,7 +1017,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // argument; namely, it must be in the range [0, 3]. if (Type > 3) { S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) - << Attr.getName() << 0 << 3 << E->getSourceRange(); + << AL.getName() << 0 << 3 << E->getSourceRange(); return; } @@ -1072,45 +1027,44 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, // definition, so we defer the constness check until later. if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) - << Attr.getName() << 1; + << AL.getName() << 1; return; } - D->addAttr(::new (S.Context) - PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) PassObjectSizeAttr( + AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex())); } -static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ConsumableAttr::ConsumedState DefaultState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), DefaultState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; return; } D->addAttr(::new (S.Context) - ConsumableAttr(Attr.getRange(), S.Context, DefaultState, - Attr.getAttributeSpellingListIndex())); + ConsumableAttr(AL.getRange(), S.Context, DefaultState, + AL.getAttributeSpellingListIndex())); } static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, - const AttributeList &Attr) { + const ParsedAttr &AL) { ASTContext &CurrContext = S.getASTContext(); QualType ThisType = MD->getThisType(CurrContext)->getPointeeType(); if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_attr_on_unconsumable_class) << + S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD->getNameAsString(); return false; @@ -1120,33 +1074,32 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, return true; } -static void handleCallableWhenAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; SmallVector<CallableWhenAttr::ConsumedState, 3> States; - for (unsigned ArgIndex = 0; ArgIndex < Attr.getNumArgs(); ++ArgIndex) { + for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) { CallableWhenAttr::ConsumedState CallableState; StringRef StateString; SourceLocation Loc; - if (Attr.isArgIdent(ArgIndex)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(ArgIndex); + if (AL.isArgIdent(ArgIndex)) { + IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex); StateString = Ident->Ident->getName(); Loc = Ident->Loc; } else { - if (!S.checkStringLiteralArgumentAttr(Attr, ArgIndex, StateString, &Loc)) + if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc)) return; } if (!CallableWhenAttr::ConvertStrToConsumedState(StateString, CallableState)) { S.Diag(Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } @@ -1154,27 +1107,26 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - CallableWhenAttr(Attr.getRange(), S.Context, States.data(), - States.size(), Attr.getAttributeSpellingListIndex())); + CallableWhenAttr(AL.getRange(), S.Context, States.data(), + States.size(), AL.getAttributeSpellingListIndex())); } -static void handleParamTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParamTypestateAttr::ConsumedState ParamState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef StateString = Ident->Ident->getName(); if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString, ParamState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << StateString; + << AL.getName() << StateString; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } @@ -1185,31 +1137,30 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); // //if (!RD || !RD->hasAttr<ConsumableAttr>()) { - // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) << + // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) << // ReturnType.getAsString(); // return; //} D->addAttr(::new (S.Context) - ParamTypestateAttr(Attr.getRange(), S.Context, ParamState, - Attr.getAttributeSpellingListIndex())); + ParamTypestateAttr(AL.getRange(), S.Context, ParamState, + AL.getAttributeSpellingListIndex())); } -static void handleReturnTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ReturnTypestateAttr::ConsumedState ReturnState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *IL = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), ReturnState)) { S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << IL->Ident; + << AL.getName() << IL->Ident; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } @@ -1237,72 +1188,70 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, // ReturnType.getAsString(); // return; //} - + D->addAttr(::new (S.Context) - ReturnTypestateAttr(Attr.getRange(), S.Context, ReturnState, - Attr.getAttributeSpellingListIndex())); + ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState, + AL.getAttributeSpellingListIndex())); } -static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; SetTypestateAttr::ConsumedState NewState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } D->addAttr(::new (S.Context) - SetTypestateAttr(Attr.getRange(), S.Context, NewState, - Attr.getAttributeSpellingListIndex())); + SetTypestateAttr(AL.getRange(), S.Context, NewState, + AL.getAttributeSpellingListIndex())); } -static void handleTestTypestateAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) +static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL)) return; TestTypestateAttr::ConsumedState TestState; - if (Attr.isArgIdent(0)) { - IdentifierLoc *Ident = Attr.getArgAsIdent(0); + if (AL.isArgIdent(0)) { + IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) - << Attr.getName() << Param; + << AL.getName() << Param; return; } } else { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << - Attr.getName() << AANT_ArgumentIdentifier; + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << + AL.getName() << AANT_ArgumentIdentifier; return; } D->addAttr(::new (S.Context) - TestTypestateAttr(Attr.getRange(), S.Context, TestState, - Attr.getAttributeSpellingListIndex())); + TestTypestateAttr(AL.getRange(), S.Context, TestState, + AL.getAttributeSpellingListIndex())); } -static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D)); } -static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { +static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (auto *TD = dyn_cast<TagDecl>(D)) + TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); + else if (auto *FD = dyn_cast<FieldDecl>(D)) { bool BitfieldByteAligned = (!FD->getType()->isDependentType() && !FD->getType()->isIncompleteType() && FD->isBitField() && @@ -1311,81 +1260,80 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { if (BitfieldByteAligned) // The PS4 target needs to maintain ABI backwards compatibility. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) - << Attr.getName() << FD->getType(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type) + << AL.getName() << FD->getType(); else FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } else { // Report warning about changed offset in the newer compiler versions. if (BitfieldByteAligned) - S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield); FD->addAttr(::new (S.Context) PackedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } } else - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); } -static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) { +static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) { // The IBOutlet/IBOutletCollection attributes only apply to instance // variables or properties of Objective-C classes. The outlet must also // have an object reference type. - if (const ObjCIvarDecl *VD = dyn_cast<ObjCIvarDecl>(D)) { + if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) { if (!VD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << VD->getType() << 0; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << VD->getType() << 0; return false; } } - else if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { if (!PD->getType()->getAs<ObjCObjectPointerType>()) { - S.Diag(Attr.getLoc(), diag::warn_iboutlet_object_type) - << Attr.getName() << PD->getType() << 1; + S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) + << AL.getName() << PD->getType() << 1; return false; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_iboutlet) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL.getName(); return false; } return true; } -static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkIBOutletCommon(S, D, Attr)) +static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkIBOutletCommon(S, D, AL)) return; D->addAttr(::new (S.Context) - IBOutletAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IBOutletAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIBOutletCollection(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) { // The iboutletcollection attribute can have zero or one arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (!checkIBOutletCommon(S, D, Attr)) + if (!checkIBOutletCommon(S, D, AL)) return; ParsedType PT; - if (Attr.hasParsedType()) - PT = Attr.getTypeArg(); + if (AL.hasParsedType()) + PT = AL.getTypeArg(); else { - PT = S.getTypeName(S.Context.Idents.get("NSObject"), Attr.getLoc(), + PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(), S.getScopeForContext(D->getDeclContext()->getParent())); if (!PT) { - S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; + S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject"; return; } } @@ -1393,22 +1341,22 @@ static void handleIBOutletCollection(Sema &S, Decl *D, TypeSourceInfo *QTLoc = nullptr; QualType QT = S.GetTypeFromParser(PT, &QTLoc); if (!QTLoc) - QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc()); + QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc()); // Diagnose use of non-object type in iboutletcollection attribute. // FIXME. Gnu attribute extension ignores use of builtin types in // attributes. So, __attribute__((iboutletcollection(char))) will be // treated as __attribute__((iboutletcollection())). if (!QT->isObjCIdType() && !QT->isObjCObjectType()) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype : diag::err_iboutletcollection_type) << QT; return; } D->addAttr(::new (S.Context) - IBOutletCollectionAttr(Attr.getRange(), S.Context, QTLoc, - Attr.getAttributeSpellingListIndex())); + IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc, + AL.getAttributeSpellingListIndex())); } bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { @@ -1435,35 +1383,36 @@ bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) { return T->isAnyPointerType() || T->isBlockPointerType(); } -static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, +static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL, SourceRange AttrParmRange, SourceRange TypeRange, bool isReturnValue = false) { if (!S.isValidPointerAttrType(T)) { if (isReturnValue) - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange; + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << AttrParmRange << TypeRange; else - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AttrParmRange << TypeRange << 0; return false; } return true; } -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); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, I + 1, Ex, Idx)) +static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + SmallVector<ParamIdx, 8> NonNullArgs; + for (unsigned I = 0; I < AL.getNumArgs(); ++I) { + Expr *Ex = AL.getArgAsExpr(I); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx)) return; // Is the function argument a pointer type? - if (Idx < getFunctionOrMethodNumParams(D) && - !attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr, - Ex->getSourceRange(), - getFunctionOrMethodParamRange(D, Idx))) + if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) && + !attrNonNullArgCheck( + S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL, + Ex->getSourceRange(), + getFunctionOrMethodParamRange(D, Idx.getASTIndex()))) continue; NonNullArgs.push_back(Idx); @@ -1473,7 +1422,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { // 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() && + if (NonNullArgs.empty() && AL.getLoc().isFileID() && !S.inTemplateInstantiation()) { bool AnyPointers = isFunctionOrMethodVariadic(D); for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); @@ -1484,80 +1433,77 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) { } if (!AnyPointers) - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers); } - unsigned *Start = NonNullArgs.data(); + ParamIdx *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, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, Start, Size, + AL.getAttributeSpellingListIndex())); } static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D, - const AttributeList &Attr) { - if (Attr.getNumArgs() > 0) { + const ParsedAttr &AL) { + if (AL.getNumArgs() > 0) { if (D->getFunctionType()) { - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args) + S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args) << D->getSourceRange(); } return; } // Is the argument a pointer type? - if (!attrNonNullArgCheck(S, D->getType(), Attr, SourceRange(), + if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(), D->getSourceRange())) return; D->addAttr(::new (S.Context) - NonNullAttr(Attr.getRange(), S.Context, nullptr, 0, - Attr.getAttributeSpellingListIndex())); + NonNullAttr(AL.getRange(), S.Context, nullptr, 0, + AL.getAttributeSpellingListIndex())); } -static void handleReturnsNonNullAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); SourceRange SR = getFunctionOrMethodResultSourceRange(D); - if (!attrNonNullArgCheck(S, ResultType, Attr, SourceRange(), SR, + if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR, /* isReturnValue */ true)) return; D->addAttr(::new (S.Context) - ReturnsNonNullAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ReturnsNonNullAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoEscapeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // noescape only applies to pointer types. QualType T = cast<ParmVarDecl>(D)->getType(); if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) - << Attr.getName() << Attr.getRange() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only) + << AL.getName() << AL.getRange() << 0; return; } D->addAttr(::new (S.Context) NoEscapeAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.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()); +static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0), + *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr; + S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE, + AL.getAttributeSpellingListIndex()); } -static void handleAllocAlignAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAllocAlignAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -1615,7 +1561,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, unsigned SpellingListIndex) { QualType ResultType = getFunctionOrMethodResultType(D); - AllocAlignAttr TmpAttr(AttrRange, Context, 0, SpellingListIndex); + AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex); SourceLocation AttrLoc = AttrRange.getBegin(); if (!ResultType->isDependentType() && @@ -1625,28 +1571,22 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr, return; } - uint64_t IndexVal; + ParamIdx Idx; const auto *FuncDecl = cast<FunctionDecl>(D); if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr, - /*AttrArgNo=*/1, ParamExpr, - IndexVal)) + /*AttrArgNo=*/1, ParamExpr, Idx)) return; - QualType Ty = getFunctionOrMethodParamType(D, IndexVal); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { Diag(ParamExpr->getLocStart(), diag::err_attribute_integers_only) - << &TmpAttr << FuncDecl->getParamDecl(IndexVal)->getSourceRange(); + << &TmpAttr + << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - ParamExpr->EvaluateAsInt(Val, Context); - - D->addAttr(::new (Context) AllocAlignAttr( - AttrRange, Context, Val.getZExtValue(), SpellingListIndex)); + D->addAttr(::new (Context) + AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex)); } /// Normalize the attribute, __foo__ becomes foo. @@ -1660,7 +1600,7 @@ static bool normalizeName(StringRef &AttrName) { return false; } -static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { +static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &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, // for example: malloc. The following arguments must be argument indexes, the @@ -1706,15 +1646,15 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { Module = &S.PP.getIdentifierTable().get(ModuleName); } - SmallVector<unsigned, 8> OwnershipArgs; + SmallVector<ParamIdx, 8> OwnershipArgs; for (unsigned i = 1; i < AL.getNumArgs(); ++i) { Expr *Ex = AL.getArgAsExpr(i); - uint64_t Idx; + ParamIdx Idx; if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx)) return; // Is the function argument a pointer type? - QualType T = getFunctionOrMethodParamType(D, Idx); + QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); int Err = -1; // No error switch (K) { case OwnershipAttr::Takes: @@ -1745,14 +1685,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { } 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. + // a different index. 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; + << I->args_begin()->getSourceIndex(); if (I->args_size()) S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch) - << (unsigned)Idx + 1 << Ex->getSourceRange(); + << Idx.getSourceIndex() << Ex->getSourceRange(); return; } } @@ -1760,25 +1699,22 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { OwnershipArgs.push_back(Idx); } - unsigned* start = OwnershipArgs.data(); - unsigned size = OwnershipArgs.size(); - llvm::array_pod_sort(start, start + size); - + ParamIdx *Start = OwnershipArgs.data(); + unsigned Size = OwnershipArgs.size(); + llvm::array_pod_sort(Start, Start + Size); D->addAttr(::new (S.Context) - OwnershipAttr(AL.getLoc(), S.Context, Module, start, size, - AL.getAttributeSpellingListIndex())); + OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size, + AL.getAttributeSpellingListIndex())); } -static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - NamedDecl *nd = cast<NamedDecl>(D); - // gcc rejects // class c { // static int a __attribute__((weakref ("v2"))); @@ -1791,8 +1727,8 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // we reject them const DeclContext *Ctx = D->getDeclContext()->getRedeclContext(); if (!Ctx->isFileContext()) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) - << nd; + S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context) + << cast<NamedDecl>(D); return; } @@ -1822,88 +1758,71 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { // of transforming it into an AliasAttr. The WeakRefAttr never uses the // StringRef parameter it was given anyway. StringRef Str; - if (Attr.getNumArgs() && S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str)) // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); D->addAttr(::new (S.Context) - WeakRefAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakRefAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Aliases should be on declarations, not definitions. const auto *FD = cast<FunctionDecl>(D); if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1; return; } - D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin); return; } if (S.Context.getTargetInfo().getTriple().isNVPTX()) { - S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx); + S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx); } // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; + S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } // FIXME: check if target symbol exists in current file - D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); -} - -static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName())) - return; - - D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleTLSModelAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Model; SourceLocation LiteralLoc; // Check that it is a string. - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc)) return; // Check that the value. @@ -1914,60 +1833,101 @@ static void handleTLSModelAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) - TLSModelAttr(Attr.getRange(), S.Context, Model, - Attr.getAttributeSpellingListIndex())); + TLSModelAttr(AL.getRange(), S.Context, Model, + AL.getAttributeSpellingListIndex())); } -static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ResultType = getFunctionOrMethodResultType(D); if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { D->addAttr(::new (S.Context) RestrictAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; } - S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) - << Attr.getName() << getFunctionOrMethodResultSourceRange(D); + S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) + << AL.getName() << getFunctionOrMethodResultSourceRange(D); } -static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + FunctionDecl *FD = cast<FunctionDecl>(D); + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) + return; + + SmallVector<IdentifierInfo *, 8> CPUs; + for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) { + if (!AL.isArgIdent(ArgNo)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo); + StringRef CPUName = CPUArg->Ident->getName().trim(); + + if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) { + S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value) + << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch); + return; + } + + const TargetInfo &Target = S.Context.getTargetInfo(); + if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) { + return Target.CPUSpecificManglingCharacter(CPUName) == + Target.CPUSpecificManglingCharacter(Cur->getName()); + })) { + S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries); + return; + } + CPUs.push_back(CPUArg->Ident); + } + + FD->setIsMultiVersion(true); + if (AL.getKind() == ParsedAttr::AT_CPUSpecific) + D->addAttr(::new (S.Context) CPUSpecificAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); + else + D->addAttr(::new (S.Context) CPUDispatchAttr( + AL.getRange(), S.Context, CPUs.data(), CPUs.size(), + AL.getAttributeSpellingListIndex())); +} + +static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::Cpp; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::Cpp; return; } - if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + if (CommonAttr *CA = S.mergeCommonAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(CA); } -static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL.getRange(), + AL.getName())) return; - if (Attr.isDeclspecAttribute()) { + if (AL.isDeclspecAttribute()) { const auto &Triple = S.getASTContext().getTargetInfo().getTriple(); const auto &Arch = Triple.getArch(); if (Arch != llvm::Triple::x86 && (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_on_arch) - << Attr.getName() << Triple.getArchName(); + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch) + << AL.getName() << Triple.getArchName(); return; } } - D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { +static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (hasDeclarator(D)) return; - if (S.CheckNoReturnAttr(Attrs)) - return; - if (!isa<ObjCMethodDecl>(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) << Attrs.getName() << ExpectedFunctionOrMethod; @@ -1978,16 +1938,14 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &Attrs) { Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleNoCallerSavedRegsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (S.CheckNoCallerSavedRegsAttr(Attr)) - return; - - D->addAttr(::new (S.Context) AnyX86NoCallerSavedRegistersAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { + if (!S.getLangOpts().CFProtectionBranch) + S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored); + else + handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs); } -bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { +bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { if (!checkAttributeNumArgs(*this, Attrs, 0)) { Attrs.setInvalid(); return true; @@ -1996,221 +1954,167 @@ bool Sema::CheckNoReturnAttr(const AttributeList &Attrs) { return false; } -bool Sema::CheckNoCallerSavedRegsAttr(const AttributeList &Attr) { +bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. - if (!Attr.existsInTarget(Context.getTargetInfo())) { - Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) << Attr.getName(); - Attr.setInvalid(); - return true; - } - - if (!checkAttributeNumArgs(*this, Attr, 0)) { - Attr.setInvalid(); + if (!AL.existsInTarget(Context.getTargetInfo())) { + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName(); + AL.setInvalid(); return true; } return false; } -static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - +static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. if (!isFunctionOrMethodOrBlock(D)) { ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { - S.Diag(Attr.getLoc(), - Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type + S.Diag(AL.getLoc(), + AL.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } D->addAttr(::new (S.Context) - AnalyzerNoReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AnalyzerNoReturnAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // PS3 PPU-specific. -static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { -/* - Returning a Vector Class in Registers - - According to the PPU ABI specifications, a class with a single member of - vector type is returned in memory when used as the return value of a function. - This results in inefficient code when implementing vector classes. To return - the value in a single vector register, add the vecreturn attribute to the - class definition. This attribute is also applicable to struct types. - - Example: - - struct Vector - { - __vector float xyzw; - } __attribute__((vecreturn)); - - Vector Add(Vector lhs, Vector rhs) - { - Vector result; - result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); - return result; // This will be returned in a register - } -*/ +static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + /* + Returning a Vector Class in Registers + + According to the PPU ABI specifications, a class with a single member of + vector type is returned in memory when used as the return value of a + function. + This results in inefficient code when implementing vector classes. To return + the value in a single vector register, add the vecreturn attribute to the + class definition. This attribute is also applicable to struct types. + + Example: + + struct Vector + { + __vector float xyzw; + } __attribute__((vecreturn)); + + Vector Add(Vector lhs, Vector rhs) + { + Vector result; + result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); + return result; // This will be returned in a register + } + */ if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) { - S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A; + S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A; return; } - RecordDecl *record = cast<RecordDecl>(D); + const auto *R = cast<RecordDecl>(D); int count = 0; - if (!isa<CXXRecordDecl>(record)) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + if (!isa<CXXRecordDecl>(R)) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } - if (!cast<CXXRecordDecl>(record)->isPOD()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_pod_record); + if (!cast<CXXRecordDecl>(R)->isPOD()) { + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record); return; } - for (const auto *I : record->fields()) { + for (const auto *I : R->fields()) { if ((count == 1) || !I->getType()->isVectorType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member); + S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member); return; } count++; } - D->addAttr(::new (S.Context) - VecReturnAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) VecReturnAttr( + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (isa<ParmVarDecl>(D)) { // [[carries_dependency]] can only be applied to a parameter if it is a // parameter of a function declaration or lambda. if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_carries_dependency_param_not_function_decl); return; } } D->addAttr(::new (S.Context) CarriesDependencyAttr( - Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleNotTailCalledAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) NotTailCalledAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleDisableTailCallsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NakedAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) DisableTailCallsAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); -} - -static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); - return; - } - } else if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; - return; - } - - D->addAttr(::new (S.Context) - UsedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - bool IsCXX17Attr = Attr.isCXX11Attribute() && !Attr.getScopeName(); - - if (IsCXX17Attr && isa<VarDecl>(D)) { - // The C++17 spelling of this attribute cannot be applied to a static data - // member per [dcl.attr.unused]p2. - if (cast<VarDecl>(D)->isStaticDataMember()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedForMaybeUnused; - return; - } - } +static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName(); // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); D->addAttr(::new (S.Context) UnusedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = ConstructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - ConstructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + ConstructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } -static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = DestructorAttr::DefaultPriority; - if (Attr.getNumArgs() && - !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority)) + if (AL.getNumArgs() && + !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; D->addAttr(::new (S.Context) - DestructorAttr(Attr.getRange(), S.Context, priority, - Attr.getAttributeSpellingListIndex())); + DestructorAttr(AL.getRange(), S.Context, priority, + AL.getAttributeSpellingListIndex())); } template <typename AttrTy> -static void handleAttrWithMessage(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) { // Handle the case where the attribute has a text message. StringRef Str; - if (Attr.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; - D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_protocol_requires_definition) - << Attr.getName() << Attr.getRange(); + S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition) + << AL.getName() << AL.getRange(); return; } D->addAttr(::new (S.Context) - ObjCExplicitProtocolImplAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } static bool checkAvailabilityAttr(Sema &S, SourceRange Range, @@ -2252,7 +2156,7 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range, return false; } -/// \brief Check whether the two versions match. +/// Check whether the two versions match. /// /// If either version tuple is empty, then they are assumed to match. If /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y. @@ -2302,7 +2206,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (unsigned i = 0, e = Attrs.size(); i != e;) { - const AvailabilityAttr *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); + const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]); if (!OldAA) { ++i; continue; @@ -2434,37 +2338,34 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, return nullptr; } -static void handleAvailabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - IdentifierLoc *Platform = Attr.getArgAsIdent(0); - unsigned Index = Attr.getAttributeSpellingListIndex(); + IdentifierLoc *Platform = AL.getArgAsIdent(0); + unsigned Index = AL.getAttributeSpellingListIndex(); IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) << Platform->Ident; - NamedDecl *ND = dyn_cast<NamedDecl>(D); + auto *ND = dyn_cast<NamedDecl>(D); if (!ND) // We warned about this already, so just return. return; - AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); - AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); - AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); - bool IsUnavailable = Attr.getUnavailableLoc().isValid(); - bool IsStrict = Attr.getStrictLoc().isValid(); + AvailabilityChange Introduced = AL.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = AL.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted(); + bool IsUnavailable = AL.getUnavailableLoc().isValid(); + bool IsStrict = AL.getStrictLoc().isValid(); StringRef Str; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr())) Str = SE->getString(); StringRef Replacement; - if (const StringLiteral *SE = - dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr())) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr())) Replacement = SE->getString(); - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II, + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, AL.getRange(), II, false/*Implicit*/, Introduced.Version, Deprecated.Version, @@ -2509,7 +2410,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, NewIntroduced, @@ -2534,7 +2435,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - Attr.getRange(), + AL.getRange(), NewII, true/*Implicit*/, Introduced.Version, @@ -2552,23 +2453,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; - assert(checkAttributeAtMostNumArgs(S, Attr, 3) && + assert(checkAttributeAtMostNumArgs(S, AL, 3) && "Invalid number of arguments in an external_source_symbol attribute"); StringRef Language; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0))) Language = SE->getString(); StringRef DefinedIn; - if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1))) + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1))) DefinedIn = SE->getString(); - bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr; + bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, + AL.getAttributeSpellingListIndex())); } template <class T> @@ -2601,12 +2502,12 @@ TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, +static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, bool isTypeVisibility) { // Visibility attributes don't mean anything on a typedef. if (isa<TypedefNameDecl>(D)) { - S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) - << Attr.getName(); + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) + << AL.getName(); return; } @@ -2615,21 +2516,21 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, !(isa<TagDecl>(D) || isa<ObjCInterfaceDecl>(D) || isa<NamespaceDecl>(D))) { - S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedTypeOrNamespace; + S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedTypeOrNamespace; return; } // Check that the argument is a string literal. StringRef TypeStr; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, TypeStr, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc)) return; VisibilityAttr::VisibilityType type; if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) - << Attr.getName() << TypeStr; + << AL.getName() << TypeStr; return; } @@ -2637,62 +2538,60 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr, // (like Darwin) that don't support it. if (type == VisibilityAttr::Protected && !S.Context.getTargetInfo().hasProtectedVisibility()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_protected_visibility); + S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility); type = VisibilityAttr::Default; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - clang::Attr *newAttr; + unsigned Index = AL.getAttributeSpellingListIndex(); + Attr *newAttr; if (isTypeVisibility) { - newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(), + newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(), (TypeVisibilityAttr::VisibilityType) type, Index); } else { - newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index); + newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index); } if (newAttr) D->addAttr(newAttr); } -static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl, - const AttributeList &Attr) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(decl); - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *M = cast<ObjCMethodDecl>(D); + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierLoc *IL = Attr.getArgAsIdent(0); + IdentifierLoc *IL = AL.getArgAsIdent(0); ObjCMethodFamilyAttr::FamilyKind F; if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << Attr.getName() - << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) + << AL.getName() << IL->Ident; return; } if (F == ObjCMethodFamilyAttr::OMF_init && - !method->getReturnType()->isObjCObjectPointerType()) { - S.Diag(method->getLocation(), diag::err_init_method_bad_return_type) - << method->getReturnType(); + !M->getReturnType()->isObjCObjectPointerType()) { + S.Diag(M->getLocation(), diag::err_init_method_bad_return_type) + << M->getReturnType(); // Ignore the attribute. return; } - method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(), - S.Context, F, - Attr.getAttributeSpellingListIndex())); + D->addAttr(new (S.Context) ObjCMethodFamilyAttr( + AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex())); } -static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isCARCBridgableType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } } - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { QualType T = PD->getType(); if (!T->isCARCBridgableType()) { S.Diag(PD->getLocation(), diag::err_nsobject_attribute); @@ -2709,12 +2608,12 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(D->getLocation(), diag::warn_nsobject_attribute); } D->addAttr(::new (S.Context) - ObjCNSObjectAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCNSObjectAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &Attr) { - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { +static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isObjCObjectPointerType()) { S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); @@ -2725,45 +2624,45 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &At return; } D->addAttr(::new (S.Context) - ObjCIndependentClassAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCIndependentClassAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; BlocksAttr::BlockType type; if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) - BlocksAttr(Attr.getRange(), S.Context, type, - Attr.getAttributeSpellingListIndex())); + BlocksAttr(AL.getRange(), S.Context, type, + AL.getAttributeSpellingListIndex())); } -static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; - if (Attr.getNumArgs() > 0) { - Expr *E = Attr.getArgAsExpr(0); + if (AL.getNumArgs() > 0) { + Expr *E = AL.getArgAsExpr(0); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } if (Idx.isSigned() && Idx.isNegative()) { - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) << E->getSourceRange(); return; } @@ -2772,13 +2671,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { } unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; - if (Attr.getNumArgs() > 1) { - Expr *E = Attr.getArgAsExpr(1); + if (AL.getNumArgs() > 1) { + Expr *E = AL.getArgAsExpr(1); llvm::APSInt Idx(32); if (E->isTypeDependent() || E->isValueDependent() || !E->isIntegerConstantExpr(Idx, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 2 << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } @@ -2787,34 +2686,34 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) { // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. - S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) + S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) << E->getSourceRange(); return; } } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { const FunctionType *FT = FD->getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments); return; } if (!cast<FunctionProtoType>(FT)->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (!MD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; return; } - } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + } else if (const auto *BD = dyn_cast<BlockDecl>(D)) { if (!BD->isVariadic()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1; return; } - } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + } else if (const auto *V = dyn_cast<VarDecl>(D)) { QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() @@ -2822,84 +2721,83 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) { : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>(); if (!cast<FunctionProtoType>(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; - S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; + S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } } else { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) - SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos, - Attr.getAttributeSpellingListIndex())); + SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos, + AL.getAttributeSpellingListIndex())); } -static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->getFunctionType() && D->getFunctionType()->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 0; return; } - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) if (MD->getReturnType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) + << AL.getName() << 1; return; } // If this is spelled as the standard C++17 attribute, but not in C++17, warn // about using it as an extension. - if (!S.getLangOpts().CPlusPlus17 && Attr.isCXX11Attribute() && - !Attr.getScopeName()) - S.Diag(Attr.getLoc(), diag::ext_cxx17_attr) << Attr.getName(); + if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() && + !AL.getScopeName()) + S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL.getName(); D->addAttr(::new (S.Context) - WarnUnusedResultAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WarnUnusedResultAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // weak_import only applies to variable & function declarations. bool isDef = false; if (!D->canBeWeakImported(isDef)) { if (isDef) - S.Diag(Attr.getLoc(), diag::warn_attribute_invalid_on_definition) + S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition) << "weak_import"; else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || (S.Context.getTargetInfo().getTriple().isOSDarwin() && (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) { // Nothing to warn about here. } else - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariableOrFunction; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariableOrFunction; return; } D->addAttr(::new (S.Context) - WeakImportAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + WeakImportAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } // Handles reqd_work_group_size and work_group_size_hint. template <typename WorkGroupAttr> -static void handleWorkGroupSize(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t WGSize[3]; for (unsigned i = 0; i < 3; ++i) { - const Expr *E = Attr.getArgAsExpr(i); - if (!checkUInt32Argument(S, Attr, E, WGSize[i], i)) + const Expr *E = AL.getArgAsExpr(i); + if (!checkUInt32Argument(S, AL, E, WGSize[i], i)) return; if (WGSize[i] == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } } @@ -2908,73 +2806,81 @@ static void handleWorkGroupSize(Sema &S, Decl *D, if (Existing && !(Existing->getXDim() == WGSize[0] && Existing->getYDim() == WGSize[1] && Existing->getZDim() == WGSize[2])) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); - D->addAttr(::new (S.Context) WorkGroupAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context, WGSize[0], WGSize[1], WGSize[2], - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // Handles intel_reqd_sub_group_size. -static void handleSubGroupSize(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t SGSize; - const Expr *E = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, E, SGSize)) + const Expr *E = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, E, SGSize)) return; if (SGSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero) - << Attr.getName() << E->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) + << AL.getName() << E->getSourceRange(); return; } OpenCLIntelReqdSubGroupSizeAttr *Existing = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); if (Existing && Existing->getSubGroupSize() != SGSize) - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr( - Attr.getRange(), S.Context, SGSize, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, SGSize, + AL.getAttributeSpellingListIndex())); } -static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.hasParsedType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; +static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.hasParsedType()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } TypeSourceInfo *ParmTSI = nullptr; - QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI); + QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI); assert(ParmTSI && "no type source info for attribute argument"); if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() && (ParmType->isBooleanType() || !ParmType->isIntegralType(S.getASTContext()))) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint) + S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint) << ParmType; return; } if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) { if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) { - S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); return; } } - D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context, + D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context, ParmTSI, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the section attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (AttrSpellingListIndex == SectionAttr::Declspec_allocate && + FD->isFunctionTemplateSpecialization()) + return nullptr; + } if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) { if (ExistingAttr->getName() == Name) return nullptr; - Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section); + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 1 /*section*/; Diag(Range.getBegin(), diag::note_previous_attribute); return nullptr; } @@ -2985,18 +2891,19 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); if (!Error.empty()) { - Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error; + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 1 /*'section'*/; return false; } return true; } -static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is a string literal as the sections's single // argument. StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) return; if (!S.checkSectionName(LiteralLoc, Str)) @@ -3010,12 +2917,65 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); - SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index); + unsigned Index = AL.getAttributeSpellingListIndex(); + SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index); if (NewAttr) D->addAttr(NewAttr); } +static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) { + std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName); + if (!Error.empty()) { + S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error + << 0 /*'code-seg'*/; + return false; + } + return true; +} + +CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range, + StringRef Name, + unsigned AttrSpellingListIndex) { + // Explicit or partial specializations do not inherit + // the code_seg attribute from the primary template. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isFunctionTemplateSpecialization()) + return nullptr; + } + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (ExistingAttr->getName() == Name) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) + << 0 /*codeseg*/; + Diag(Range.getBegin(), diag::note_previous_attribute); + return nullptr; + } + return ::new (Context) CodeSegAttr(Range, Context, Name, + AttrSpellingListIndex); +} + +static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc)) + return; + if (!checkCodeSegName(S, LiteralLoc, Str)) + return; + if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) { + if (!ExistingAttr->isImplicit()) { + S.Diag(AL.getLoc(), + ExistingAttr->getName() == Str + ? diag::warn_duplicate_codeseg_attribute + : diag::err_conflicting_codeseg_attribute); + return; + } + D->dropAttr<CodeSegAttr>(); + } + if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str, + AL.getAttributeSpellingListIndex())) + D->addAttr(CSA); +} + // Check for things we'd like to warn about. Multiversioning issues are // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { @@ -3044,30 +3004,50 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { << Unsupported << None << CurFeature; } - return true; + return false; } -static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc) || - !S.checkTargetAttr(LiteralLoc, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetAttr(LiteralLoc, Str)) return; - unsigned Index = Attr.getAttributeSpellingListIndex(); + + unsigned Index = AL.getAttributeSpellingListIndex(); TargetAttr *NewAttr = - ::new (S.Context) TargetAttr(Attr.getRange(), S.Context, Str, Index); + ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index); D->addAttr(NewAttr); } -static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *E = Attr.getArgAsExpr(0); +static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); + uint32_t VecWidth; + if (!checkUInt32Argument(S, AL, E, VecWidth)) { + AL.setInvalid(); + return; + } + + MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>(); + if (Existing && Existing->getVectorWidth() != VecWidth) { + S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL.getName(); + return; + } + + D->addAttr(::new (S.Context) + MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth, + AL.getAttributeSpellingListIndex())); +} + +static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *E = AL.getArgAsExpr(0); SourceLocation Loc = E->getExprLoc(); FunctionDecl *FD = nullptr; DeclarationNameInfo NI; // gcc only allows for simple identifiers. Since we support more than gcc, we // will warn the user. - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { if (DRE->hasQualifier()) S.Diag(Loc, diag::warn_cleanup_ext); FD = dyn_cast<FunctionDecl>(DRE->getDecl()); @@ -3077,7 +3057,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { << NI.getName(); return; } - } else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { if (ULE->hasExplicitTemplateArgs()) S.Diag(Loc, diag::warn_cleanup_ext); FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); @@ -3112,49 +3092,49 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - CleanupAttr(Attr.getRange(), S.Context, FD, - Attr.getAttributeSpellingListIndex())); + CleanupAttr(AL.getRange(), S.Context, FD, + AL.getAttributeSpellingListIndex())); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 0 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 0 << AANT_ArgumentIdentifier; return; } EnumExtensibilityAttr::Kind ExtensibilityKind; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(), ExtensibilityKind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II; return; } D->addAttr(::new (S.Context) EnumExtensibilityAttr( - Attr.getRange(), S.Context, ExtensibilityKind, - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, ExtensibilityKind, + AL.getAttributeSpellingListIndex())); } /// Handle __attribute__((format_arg((idx)))) attribute based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { - Expr *IdxExpr = Attr.getArgAsExpr(0); - uint64_t Idx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx)) +static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + Expr *IdxExpr = AL.getArgAsExpr(0); + ParamIdx Idx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) return; // Make sure the format string is really a string. - QualType Ty = getFunctionOrMethodParamType(D, Idx); + QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); bool NotNSStringTy = !isNSStringType(Ty, S.Context); if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; @@ -3164,21 +3144,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) << (NotNSStringTy ? "string type" : "NSString") << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } - // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex - // because that has corrected for the implicit this parameter, and is zero- - // based. The attribute expects what the user wrote explicitly. - llvm::APSInt Val; - IdxExpr->EvaluateAsInt(Val, S.Context); - - D->addAttr(::new (S.Context) - FormatArgAttr(Attr.getRange(), S.Context, Val.getZExtValue(), - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) FormatArgAttr( + AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex())); } enum FormatAttrKind { @@ -3213,43 +3186,42 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { /// Handle __attribute__((init_priority(priority))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html -static void handleInitPriorityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.getLangOpts().CPlusPlus) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL.getName(); return; } if (S.getCurFunctionOrMethodDecl()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); if (!T->getAs<RecordType>()) { - S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr); - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); + AL.setInvalid(); return; } - Expr *E = Attr.getArgAsExpr(0); + Expr *E = AL.getArgAsExpr(0); uint32_t prioritynum; - if (!checkUInt32Argument(S, Attr, E, prioritynum)) { - Attr.setInvalid(); + if (!checkUInt32Argument(S, AL, E, prioritynum)) { + AL.setInvalid(); return; } if (prioritynum < 101 || prioritynum > 65535) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange() << Attr.getName() << 101 << 65535; - Attr.setInvalid(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_outof_range) + << E->getSourceRange() << AL.getName() << 101 << 65535; + AL.setInvalid(); return; } D->addAttr(::new (S.Context) - InitPriorityAttr(Attr.getRange(), S.Context, prioritynum, - Attr.getAttributeSpellingListIndex())); + InitPriorityAttr(AL.getRange(), S.Context, prioritynum, + AL.getAttributeSpellingListIndex())); } FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, @@ -3275,10 +3247,10 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, /// Handle __attribute__((format(type,idx,firstarg))) attributes based on /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; +static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } @@ -3287,7 +3259,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { bool HasImplicitThisParam = isInstanceMethod(D); unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam; - IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; StringRef Format = II->getName(); if (normalizeName(Format)) { @@ -3302,20 +3274,20 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; if (Kind == InvalidFormat) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << II->getName(); + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << II->getName(); return; } // checks for the 2nd argument - Expr *IdxExpr = Attr.getArgAsExpr(1); + Expr *IdxExpr = AL.getArgAsExpr(1); uint32_t Idx; - if (!checkUInt32Argument(S, Attr, IdxExpr, Idx, 2)) + if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2)) return; if (Idx < 1 || Idx > NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 2 << IdxExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 2 << IdxExpr->getSourceRange(); return; } @@ -3324,7 +3296,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (HasImplicitThisParam) { if (ArgIdx == 0) { - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::err_format_attribute_implicit_this_format_string) << IdxExpr->getSourceRange(); return; @@ -3337,7 +3309,7 @@ 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) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a CFString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; @@ -3346,23 +3318,23 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // FIXME: do we need to check if the type is NSString*? What are the // semantics? if (!isNSStringType(Ty, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "an NSString" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) { - S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + S.Diag(AL.getLoc(), diag::err_format_attribute_not) << "a string type" << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx); return; } // check the 3rd argument - Expr *FirstArgExpr = Attr.getArgAsExpr(2); + Expr *FirstArgExpr = AL.getArgAsExpr(2); uint32_t FirstArg; - if (!checkUInt32Argument(S, Attr, FirstArgExpr, FirstArg, 3)) + if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) return; // check if the function is variadic if the 3rd argument non-zero @@ -3379,43 +3351,42 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { // variable the input is just the current time + the format string. if (Kind == StrftimeFormat) { if (FirstArg != 0) { - S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) + S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) << FirstArgExpr->getSourceRange(); return; } // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << 3 << FirstArgExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << 3 << FirstArgExpr->getSourceRange(); return; } - FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II, + FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II, Idx, FirstArg, - Attr.getAttributeSpellingListIndex()); + AL.getAttributeSpellingListIndex()); if (NewAttr) D->addAttr(NewAttr); } -static void handleTransparentUnionAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Try to find the underlying union declaration. RecordDecl *RD = nullptr; - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); else RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedUnion; return; } if (!RD->isCompleteDefinition()) { if (!RD->isBeingDefined()) - S.Diag(Attr.getLoc(), + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_not_definition); return; } @@ -3423,7 +3394,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); if (Field == FieldEnd) { - S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields); + S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields); return; } @@ -3467,15 +3438,15 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, } RD->addAttr(::new (S.Context) - TransparentUnionAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + TransparentUnionAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is a string literal as the annotation's single // argument. StringRef Str; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Don't duplicate annotations that are already set. @@ -3485,14 +3456,13 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - AnnotateAttr(Attr.getRange(), S.Context, Str, - Attr.getAttributeSpellingListIndex())); + AnnotateAttr(AL.getRange(), S.Context, Str, + AL.getAttributeSpellingListIndex())); } -static void handleAlignValueAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - S.AddAlignValueAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getAttributeSpellingListIndex()); +static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getAttributeSpellingListIndex()); } void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3501,9 +3471,9 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, SourceLocation AttrLoc = AttrRange.getBegin(); QualType T; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) T = TD->getUnderlyingType(); - else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + else if (const auto *VD = dyn_cast<ValueDecl>(D)) T = VD->getType(); else llvm_unreachable("Unknown decl type for align_value"); @@ -3540,42 +3510,32 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); } -static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getName() << 1; return; } - if (Attr.getNumArgs() == 0) { - D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context, - true, nullptr, Attr.getAttributeSpellingListIndex())); + if (AL.getNumArgs() == 0) { + D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context, + true, nullptr, AL.getAttributeSpellingListIndex())); return; } - Expr *E = Attr.getArgAsExpr(0); - if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) { - S.Diag(Attr.getEllipsisLoc(), + Expr *E = AL.getArgAsExpr(0); + if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()) { + S.Diag(AL.getEllipsisLoc(), diag::err_pack_expansion_without_parameter_packs); return; } - if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) + if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) return; - if (E->isValueDependent()) { - if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { - if (!TND->getUnderlyingType()->isDependentType()) { - S.Diag(Attr.getLoc(), diag::err_alignment_dependent_typedef_name) - << E->getSourceRange(); - return; - } - } - } - - S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(), - Attr.isPackExpansion()); + S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(), + AL.isPackExpansion()); } void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, @@ -3599,12 +3559,12 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, int DiagKind = -1; if (isa<ParmVarDecl>(D)) { DiagKind = 0; - } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { if (VD->getStorageClass() == SC_Register) DiagKind = 1; if (VD->isExceptionVariable()) DiagKind = 2; - } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { if (FD->isBitField()) DiagKind = 3; } else if (!isa<TagDecl>(D)) { @@ -3620,7 +3580,18 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - if (E->isTypeDependent() || E->isValueDependent()) { + if (E->isValueDependent()) { + // We can't support a dependent alignment on a non-dependent type, + // because we have no way to model that a type is "alignment-dependent" + // but not dependent in any other way. + if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { + if (!TND->getUnderlyingType()->isDependentType()) { + Diag(AttrLoc, diag::err_alignment_dependent_typedef_name) + << E->getSourceRange(); + return; + } + } + // Save dependent expressions in the AST to be instantiated. AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr); AA->setPackExpansion(IsPackExpansion); @@ -3628,7 +3599,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, return; } - // FIXME: Cache the number on the Attr object? + // FIXME: Cache the number on the AL object? llvm::APSInt Alignment; ExprResult ICE = VerifyIntegerConstantExpression(E, &Alignment, @@ -3666,7 +3637,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); - auto *VD = dyn_cast<VarDecl>(D); + const auto *VD = dyn_cast<VarDecl>(D); if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD && VD->getTLSKind() != VarDecl::TLS_None) { Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) @@ -3683,7 +3654,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, unsigned SpellingListIndex, bool IsPackExpansion) { - // FIXME: Cache the number on the Attr object if non-dependent? + // FIXME: Cache the number on the AL object if non-dependent? // FIXME: Perform checking of type validity AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS, SpellingListIndex); @@ -3695,11 +3666,11 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { assert(D->hasAttrs() && "no attributes on decl"); QualType UnderlyingTy, DiagTy; - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + if (const auto *VD = dyn_cast<ValueDecl>(D)) { UnderlyingTy = DiagTy = VD->getType(); } else { UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D)); - if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + if (const auto *ED = dyn_cast<EnumDecl>(D)) UnderlyingTy = ED->getIntegerType(); } if (DiagTy->isDependentType() || DiagTy->isIncompleteType()) @@ -3819,18 +3790,18 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, /// Despite what would be logical, the mode attribute is a decl attribute, not a /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be /// HImode, not an intermediate pointer. -static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This attribute isn't documented, but glibc uses it. It changes // the width of an int or unsigned int to the specified size. - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIdentifier; return; } - IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident; - S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); + S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex()); } void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, @@ -3876,9 +3847,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } QualType OldTy; - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + else if (const auto *ED = dyn_cast<EnumDecl>(D)) { // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. // Try to get type from enum declaration, default to int. OldTy = ED->getIntegerType(); @@ -3896,7 +3867,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, // Base type can also be a vector type (see PR17453). // Distinguish between base type and base element type. QualType OldElemTy = OldTy; - if (const VectorType *VT = OldTy->getAs<VectorType>()) + if (const auto *VT = OldTy->getAs<VectorType>()) OldElemTy = VT->getElementType(); // GCC allows 'mode' attribute on enumeration types (even incomplete), except @@ -3945,7 +3916,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, if (VectorSize.getBoolValue()) { NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), VectorType::GenericVector); - } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { + } else if (const auto *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { Diag(AttrLoc, diag::err_complex_mode_vector_type); @@ -3964,9 +3935,9 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, } // Install the new type. - if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) + if (auto *TD = dyn_cast<TypedefNameDecl>(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); - else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + else if (auto *ED = dyn_cast<EnumDecl>(D)) ED->setIntegerType(NewTy); else cast<ValueDecl>(D)->setType(NewTy); @@ -3975,10 +3946,10 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } -static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) - NoDebugAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + NoDebugAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, @@ -4010,7 +3981,7 @@ InternalLinkageAttr * Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex) { - if (auto VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { // Attribute applies to Var but not any subclass of it (like ParmVar, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { @@ -4067,71 +4038,70 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } -static void handleAlwaysInlineAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL.getRange(), + AL.getName())) return; if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( - D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Inline); } -static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (MinSizeAttr *MinSize = S.mergeMinSizeAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(MinSize); } -static void handleOptimizeNoneAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr( - D, Attr.getRange(), Attr.getAttributeSpellingListIndex())) + D, AL.getRange(), AL.getAttributeSpellingListIndex())) D->addAttr(Optnone); } -static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); if (!VD->hasGlobalStorage()) { - S.Diag(Attr.getLoc(), diag::err_cuda_nonglobal_constant); + S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant); return; } D->addAttr(::new (S.Context) CUDAConstantAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, Attr.getRange(), - Attr.getName())) +static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL.getRange(), + AL.getName())) return; - auto *VD = cast<VarDecl>(D); + const auto *VD = cast<VarDecl>(D); // extern __shared__ is only allowed on arrays with no length (e.g. // "int x[]"). - if (VD->hasExternalStorage() && !isa<IncompleteArrayType>(VD->getType())) { - S.Diag(Attr.getLoc(), diag::err_cuda_extern_shared) << VD; + if (!S.getLangOpts().CUDARelocatableDeviceCode && VD->hasExternalStorage() && + !isa<IncompleteArrayType>(VD->getType())) { + S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD; return; } if (S.getLangOpts().CUDA && VD->hasLocalStorage() && - S.CUDADiagIfHostCode(Attr.getLoc(), diag::err_cuda_host_shared) + S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) << S.CurrentCUDATarget()) return; D->addAttr(::new (S.Context) CUDASharedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } -static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(), - Attr.getName()) || - checkAttrMutualExclusion<CUDAHostAttr>(S, D, Attr.getRange(), - Attr.getName())) { +static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL.getRange(), + AL.getName()) || + checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL.getRange(), + AL.getName())) { return; } - FunctionDecl *FD = cast<FunctionDecl>(D); + const auto *FD = cast<FunctionDecl>(D); if (!FD->getReturnType()->isVoidType()) { SourceRange RTRange = FD->getReturnTypeSourceRange(); S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return) @@ -4153,88 +4123,88 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) - CUDAGlobalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CUDAGlobalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { - FunctionDecl *Fn = cast<FunctionDecl>(D); +static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *Fn = cast<FunctionDecl>(D); if (!Fn->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); + S.Diag(AL.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } D->addAttr(::new (S.Context) - GNUInlineAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + GNUInlineAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; - // Diagnostic is emitted elsewhere: here we store the (valid) Attr + // Diagnostic is emitted elsewhere: here we store the (valid) AL // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(Attr, CC, /*FD*/nullptr)) + if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr)) return; if (!isa<ObjCMethodDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionOrMethod; return; } - switch (Attr.getKind()) { - case AttributeList::AT_FastCall: + switch (AL.getKind()) { + case ParsedAttr::AT_FastCall: D->addAttr(::new (S.Context) - FastCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + FastCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_StdCall: + case ParsedAttr::AT_StdCall: D->addAttr(::new (S.Context) - StdCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + StdCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_ThisCall: + case ParsedAttr::AT_ThisCall: D->addAttr(::new (S.Context) - ThisCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ThisCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CDecl: + case ParsedAttr::AT_CDecl: D->addAttr(::new (S.Context) - CDeclAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + CDeclAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pascal: + case ParsedAttr::AT_Pascal: D->addAttr(::new (S.Context) - PascalAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + PascalAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SwiftCall: + case ParsedAttr::AT_SwiftCall: D->addAttr(::new (S.Context) - SwiftCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SwiftCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_VectorCall: + case ParsedAttr::AT_VectorCall: D->addAttr(::new (S.Context) - VectorCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + VectorCallAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_MSABI: D->addAttr(::new (S.Context) - MSABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + MSABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: D->addAttr(::new (S.Context) - SysVABIAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + SysVABIAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_RegCall: + case ParsedAttr::AT_RegCall: D->addAttr(::new (S.Context) RegCallAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { PcsAttr::PCSType PCS; switch (CC) { case CC_AAPCS: @@ -4248,37 +4218,37 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) - PcsAttr(Attr.getRange(), S.Context, PCS, - Attr.getAttributeSpellingListIndex())); + PcsAttr(AL.getRange(), S.Context, PCS, + AL.getAttributeSpellingListIndex())); return; } - case AttributeList::AT_IntelOclBicc: + case ParsedAttr::AT_IntelOclBicc: D->addAttr(::new (S.Context) - IntelOclBiccAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + IntelOclBiccAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveMost: + case ParsedAttr::AT_PreserveMost: D->addAttr(::new (S.Context) PreserveMostAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_PreserveAll: + case ParsedAttr::AT_PreserveAll: D->addAttr(::new (S.Context) PreserveAllAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; default: llvm_unreachable("unexpected attribute kind"); } } -static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> DiagnosticIdentifiers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef RuleName; - if (!S.checkStringLiteralArgumentAttr(Attr, I, RuleName, nullptr)) + if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr)) return; // FIXME: Warn if the rule name is unknown. This is tricky because only @@ -4286,11 +4256,11 @@ static void handleSuppressAttr(Sema &S, Decl *D, const AttributeList &Attr) { DiagnosticIdentifiers.push_back(RuleName); } D->addAttr(::new (S.Context) SuppressAttr( - Attr.getRange(), S.Context, DiagnosticIdentifiers.data(), - DiagnosticIdentifiers.size(), Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, DiagnosticIdentifiers.data(), + DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex())); } -bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, +bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, const FunctionDecl *FD) { if (Attrs.isInvalid()) return true; @@ -4300,7 +4270,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, return false; } - unsigned ReqArgs = Attrs.getKind() == AttributeList::AT_Pcs ? 1 : 0; + unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) { Attrs.setInvalid(); return true; @@ -4308,23 +4278,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, // TODO: diagnose uses of these conventions on the wrong target. switch (Attrs.getKind()) { - case AttributeList::AT_CDecl: CC = CC_C; break; - case AttributeList::AT_FastCall: CC = CC_X86FastCall; break; - 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_SwiftCall: CC = CC_Swift; break; - case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; - case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_CDecl: + CC = CC_C; + break; + case ParsedAttr::AT_FastCall: + CC = CC_X86FastCall; + break; + case ParsedAttr::AT_StdCall: + CC = CC_X86StdCall; + break; + case ParsedAttr::AT_ThisCall: + CC = CC_X86ThisCall; + break; + case ParsedAttr::AT_Pascal: + CC = CC_X86Pascal; + break; + case ParsedAttr::AT_SwiftCall: + CC = CC_Swift; + break; + case ParsedAttr::AT_VectorCall: + CC = CC_X86VectorCall; + break; + case ParsedAttr::AT_RegCall: + CC = CC_X86RegCall; + break; + case ParsedAttr::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_Win64; break; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : CC_C; break; - case AttributeList::AT_Pcs: { + case ParsedAttr::AT_Pcs: { StringRef StrRef; if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) { Attrs.setInvalid(); @@ -4342,9 +4328,15 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, Diag(Attrs.getLoc(), diag::err_invalid_pcs); return true; } - case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; - case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break; - case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break; + case ParsedAttr::AT_IntelOclBicc: + CC = CC_IntelOclBicc; + break; + case ParsedAttr::AT_PreserveMost: + CC = CC_PreserveMost; + break; + case ParsedAttr::AT_PreserveAll: + CC = CC_PreserveAll; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -4369,39 +4361,39 @@ bool Sema::CheckCallingConvAttr(const AttributeList &Attrs, CallingConv &CC, } /// Pointer-like types in the default address space. -static bool isValidSwiftContextType(QualType type) { - if (!type->hasPointerRepresentation()) - return type->isDependentType(); - return type->getPointeeType().getAddressSpace() == LangAS::Default; +static bool isValidSwiftContextType(QualType Ty) { + if (!Ty->hasPointerRepresentation()) + return Ty->isDependentType(); + return Ty->getPointeeType().getAddressSpace() == LangAS::Default; } /// Pointers and references in the default address space. -static bool isValidSwiftIndirectResultType(QualType type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftIndirectResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - return type.getAddressSpace() == LangAS::Default; + return Ty.getAddressSpace() == LangAS::Default; } /// Pointers and references to pointers in the default address space. -static bool isValidSwiftErrorResultType(QualType type) { - if (auto ptrType = type->getAs<PointerType>()) { - type = ptrType->getPointeeType(); - } else if (auto refType = type->getAs<ReferenceType>()) { - type = refType->getPointeeType(); +static bool isValidSwiftErrorResultType(QualType Ty) { + if (const auto *PtrType = Ty->getAs<PointerType>()) { + Ty = PtrType->getPointeeType(); + } else if (const auto *RefType = Ty->getAs<ReferenceType>()) { + Ty = RefType->getPointeeType(); } else { - return type->isDependentType(); + return Ty->isDependentType(); } - if (!type.getQualifiers().empty()) + if (!Ty.getQualifiers().empty()) return false; - return isValidSwiftContextType(type); + return isValidSwiftContextType(Ty); } -static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &Attrs, +static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs, ParameterABI Abi) { S.AddParameterABIAttr(Attrs.getRange(), D, Abi, Attrs.getAttributeSpellingListIndex()); @@ -4460,34 +4452,34 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. -bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { - if (Attr.isInvalid()) +bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { + if (AL.isInvalid()) return true; - if (!checkAttributeNumArgs(*this, Attr, 1)) { - Attr.setInvalid(); + if (!checkAttributeNumArgs(*this, AL, 1)) { + AL.setInvalid(); return true; } uint32_t NP; - Expr *NumParamsExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(*this, Attr, NumParamsExpr, NP)) { - Attr.setInvalid(); + Expr *NumParamsExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) { + AL.setInvalid(); return true; } if (Context.getTargetInfo().getRegParmMax() == 0) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform) << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } numParams = NP; if (numParams > Context.getTargetInfo().getRegParmMax()) { - Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) + Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number) << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); - Attr.setInvalid(); + AL.setInvalid(); return true; } @@ -4499,7 +4491,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { // non-nullptr Expr result on success. Otherwise, it returns nullptr // and may output an error. static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, - const CUDALaunchBoundsAttr &Attr, + const CUDALaunchBoundsAttr &AL, const unsigned Idx) { if (S.DiagnoseUnexpandedParameterPack(E)) return nullptr; @@ -4512,7 +4504,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, llvm::APSInt I(64); if (!E->isIntegerConstantExpr(I, S.Context)) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) - << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); return nullptr; } // Make sure we can fit it in 32 bits. @@ -4523,7 +4515,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, } if (I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) - << &Attr << Idx << E->getSourceRange(); + << &AL << Idx << E->getSourceRange(); // We may need to perform implicit conversion of the argument. InitializedEntity Entity = InitializedEntity::InitializeParameter( @@ -4553,253 +4545,232 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); } -static void handleLaunchBoundsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || - !checkAttributeAtMostNumArgs(S, Attr, 2)) +static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1) || + !checkAttributeAtMostNumArgs(S, AL, 2)) return; - S.AddLaunchBoundsAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), - Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr, - Attr.getAttributeSpellingListIndex()); + S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getAttributeSpellingListIndex()); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; - return; - } - - if (!checkAttributeNumArgs(S, Attr, 3)) - return; - - IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident; - - if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << /* arg num = */ 1 << AANT_ArgumentIdentifier; return; } - uint64_t ArgumentIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 2, Attr.getArgAsExpr(1), + ParamIdx ArgumentIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1), ArgumentIdx)) return; - uint64_t TypeTagIdx; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 3, Attr.getArgAsExpr(2), + ParamIdx TypeTagIdx; + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2), TypeTagIdx)) return; - bool IsPointer = (Attr.getName()->getName() == "pointer_with_type_tag"); + bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag"; if (IsPointer) { // Ensure that buffer has a pointer type. - QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); - if (!BufferTy->isPointerType()) { - S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName() << 0; - } + unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex(); + if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) || + !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType()) + S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) + << AL.getName() << 0; } - D->addAttr(::new (S.Context) - ArgumentWithTypeTagAttr(Attr.getRange(), S.Context, ArgumentKind, - ArgumentIdx, TypeTagIdx, IsPointer, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr( + AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx, + TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex())); } static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) - << Attr.getName() << 1 << AANT_ArgumentIdentifier; + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL.getName() << 1 << AANT_ArgumentIdentifier; return; } - if (!checkAttributeNumArgs(S, Attr, 1)) + if (!checkAttributeNumArgs(S, AL, 1)) return; if (!isa<VarDecl>(D)) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedVariable; + S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) + << AL.getName() << ExpectedVariable; return; } - IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident; + IdentifierInfo *PointerKind = AL.getArgAsIdent(0)->Ident; TypeSourceInfo *MatchingCTypeLoc = nullptr; - S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc); + S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc); assert(MatchingCTypeLoc && "no type source info for attribute argument"); D->addAttr(::new (S.Context) - TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind, + TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind, MatchingCTypeLoc, - Attr.getLayoutCompatible(), - Attr.getMustBeNull(), - Attr.getAttributeSpellingListIndex())); + AL.getLayoutCompatible(), + AL.getMustBeNull(), + AL.getAttributeSpellingListIndex())); } -static void handleXRayLogArgsAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - uint64_t ArgCount; +static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + ParamIdx ArgCount; - if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, Attr.getArgAsExpr(0), + if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0), ArgCount, - true /* AllowImplicitThis*/)) + true /* CanIndexImplicitThis */)) return; - // ArgCount isn't a parameter index [0;n), it's a count [1;n] - hence + 1. - D->addAttr(::new (S.Context) - XRayLogArgsAttr(Attr.getRange(), S.Context, ++ArgCount, - Attr.getAttributeSpellingListIndex())); + // ArgCount isn't a parameter index [0;n), it's a count [1;n] + D->addAttr(::new (S.Context) XRayLogArgsAttr( + AL.getRange(), S.Context, ArgCount.getSourceIndex(), + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// -static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType type) { - return type->isDependentType() || - type->isObjCRetainableType(); +static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { + return QT->isDependentType() || QT->isObjCRetainableType(); } -static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isObjCObjectPointerType() || - S.Context.isObjCNSObjectType(type); +static bool isValidSubjectOfNSAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isObjCObjectPointerType() || + S.Context.isObjCNSObjectType(QT); } -static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { - return type->isDependentType() || - type->isPointerType() || - isValidSubjectOfNSAttribute(S, type); +static bool isValidSubjectOfCFAttribute(Sema &S, QualType QT) { + return QT->isDependentType() || QT->isPointerType() || + isValidSubjectOfNSAttribute(S, QT); } -static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), - Attr.getKind() == AttributeList::AT_NSConsumed, +static void handleNSConsumedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + S.AddNSConsumedAttr(AL.getRange(), D, AL.getAttributeSpellingListIndex(), + AL.getKind() == ParsedAttr::AT_NSConsumed, /*template instantiation*/ false); } -void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, - unsigned spellingIndex, bool isNSConsumed, - bool isTemplateInstantiation) { - ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK; +void Sema::AddNSConsumedAttr(SourceRange AttrRange, Decl *D, + unsigned SpellingIndex, bool IsNSConsumed, + bool IsTemplateInstantiation) { + const auto *Param = cast<ParmVarDecl>(D); + bool TypeOK; - if (isNSConsumed) { - typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); - } else { - typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); - } + if (IsNSConsumed) + TypeOK = isValidSubjectOfNSAttribute(*this, Param->getType()); + else + TypeOK = isValidSubjectOfCFAttribute(*this, Param->getType()); - if (!typeOK) { + if (!TypeOK) { // These attributes are normally just advisory, but in ARC, ns_consumed // is significant. Allow non-dependent code to contain inappropriate // attributes even in ARC, but require template instantiations to be // set up correctly. - Diag(D->getLocStart(), - (isTemplateInstantiation && isNSConsumed && - getLangOpts().ObjCAutoRefCount - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type)) - << attrRange - << (isNSConsumed ? "ns_consumed" : "cf_consumed") - << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + Diag(D->getLocStart(), (IsTemplateInstantiation && IsNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << AttrRange << (IsNSConsumed ? "ns_consumed" : "cf_consumed") + << (IsNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); return; } - if (isNSConsumed) - param->addAttr(::new (Context) - NSConsumedAttr(attrRange, Context, spellingIndex)); + if (IsNSConsumed) + D->addAttr(::new (Context) + NSConsumedAttr(AttrRange, Context, SpellingIndex)); else - param->addAttr(::new (Context) - CFConsumedAttr(attrRange, Context, spellingIndex)); + D->addAttr(::new (Context) + CFConsumedAttr(AttrRange, Context, SpellingIndex)); } -bool Sema::checkNSReturnsRetainedReturnType(SourceLocation loc, - QualType type) { - if (isValidSubjectOfNSReturnsRetainedAttribute(type)) +bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { + if (isValidSubjectOfNSReturnsRetainedAttribute(QT)) return false; - Diag(loc, diag::warn_ns_attribute_wrong_return_type) - << "'ns_returns_retained'" << 0 << 0; + Diag(Loc, diag::warn_ns_attribute_wrong_return_type) + << "'ns_returns_retained'" << 0 << 0; return true; } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - QualType returnType; + const ParsedAttr &AL) { + QualType ReturnType; - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) - returnType = MD->getReturnType(); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + ReturnType = MD->getReturnType(); else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (Attr.getKind() == AttributeList::AT_NSReturnsRetained)) + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) return; // ignore: was handled as a type attribute - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - returnType = PD->getType(); - else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - returnType = FD->getReturnType(); - else if (auto *Param = dyn_cast<ParmVarDecl>(D)) { - returnType = Param->getType()->getPointeeType(); - if (returnType.isNull()) { + else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) + ReturnType = PD->getType(); + else if (const auto *FD = dyn_cast<FunctionDecl>(D)) + ReturnType = FD->getReturnType(); + else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + ReturnType = Param->getType()->getPointeeType(); + if (ReturnType.isNull()) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); return; } - } else if (Attr.isUsedAsTypeAttr()) { + } else if (AL.isUsedAsTypeAttr()) { return; } else { AttributeDeclKind ExpectedDeclKind; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionOrMethod; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionMethodOrParameter; break; } S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedDeclKind; + << AL.getRange() << AL.getName() << ExpectedDeclKind; return; } - bool typeOK; - bool cf; - switch (Attr.getKind()) { + bool TypeOK; + bool Cf; + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsRetained: - typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType); - cf = false; + case ParsedAttr::AT_NSReturnsRetained: + TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); + Cf = false; break; - - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - typeOK = isValidSubjectOfNSAttribute(S, returnType); - cf = false; + + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + TypeOK = isValidSubjectOfNSAttribute(S, ReturnType); + Cf = false; break; - case AttributeList::AT_CFReturnsRetained: - case AttributeList::AT_CFReturnsNotRetained: - typeOK = isValidSubjectOfCFAttribute(S, returnType); - cf = true; + case ParsedAttr::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + TypeOK = isValidSubjectOfCFAttribute(S, ReturnType); + Cf = true; break; } - if (!typeOK) { - if (Attr.isUsedAsTypeAttr()) + if (!TypeOK) { + if (AL.isUsedAsTypeAttr()) return; if (isa<ParmVarDecl>(D)) { S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getName() << /*pointer-to-CF*/2 - << Attr.getRange(); + << AL.getName() << /*pointer-to-CF*/2 + << AL.getRange(); } else { // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. enum : unsigned { @@ -4812,40 +4783,40 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, else if (isa<ObjCPropertyDecl>(D)) SubjectKind = Property; S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type) - << Attr.getName() << SubjectKind << cf - << Attr.getRange(); + << AL.getName() << SubjectKind << Cf + << AL.getRange(); } return; } - switch (Attr.getKind()) { + switch (AL.getKind()) { default: llvm_unreachable("invalid ownership attribute"); - case AttributeList::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsAutoreleased: D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsNotRetained: + case ParsedAttr::AT_NSReturnsNotRetained: D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_CFReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: D->addAttr(::new (S.Context) CFReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; - case AttributeList::AT_NSReturnsRetained: + case ParsedAttr::AT_NSReturnsRetained: D->addAttr(::new (S.Context) NSReturnsRetainedAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); return; }; } static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { + const ParsedAttr &Attrs) { const int EP_ObjCMethod = 1; const int EP_ObjCProperty = 2; @@ -4873,116 +4844,91 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, } static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, - const AttributeList &Attrs) { - ObjCMethodDecl *method = cast<ObjCMethodDecl>(D); - - DeclContext *DC = method->getDeclContext(); - if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { + const ParsedAttr &Attrs) { + const auto *Method = cast<ObjCMethodDecl>(D); + + const DeclContext *DC = Method->getDeclContext(); + if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 0; + << Attrs.getName() << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } - if (method->getMethodFamily() == OMF_dealloc) { + if (Method->getMethodFamily() == OMF_dealloc) { S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) - << Attrs.getName() << 1; + << Attrs.getName() << 1; return; } - - method->addAttr(::new (S.Context) - ObjCRequiresSuperAttr(Attrs.getRange(), S.Context, - Attrs.getAttributeSpellingListIndex())); -} - -static void handleCFAuditedTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - D->addAttr(::new (S.Context) - CFAuditedTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); -} - -static void handleCFUnknownTransferAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(), - Attr.getName())) - return; - - D->addAttr(::new (S.Context) - CFUnknownTransferAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ObjCRequiresSuperAttr( + Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex())); } -static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } // Typedefs only allow objc_bridge(id) and have some additional checking. - if (auto TD = dyn_cast<TypedefNameDecl>(D)) { + if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (!Parm->Ident->isStr("id")) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_id) - << Attr.getName(); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) + << AL.getName(); return; } // Only allow 'cv void *'. QualType T = TD->getUnderlyingType(); if (!T->isVoidPointerType()) { - S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); + S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); return; } } D->addAttr(::new (S.Context) - ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { - IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; +static void handleObjCBridgeMutableAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; if (!Parm) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } D->addAttr(::new (S.Context) - ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident, - Attr.getAttributeSpellingListIndex())); + ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident, + AL.getAttributeSpellingListIndex())); } -static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D, - const AttributeList &Attr) { +static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { IdentifierInfo *RelatedClass = - Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : nullptr; + AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr; if (!RelatedClass) { - S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; + S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << AL.getName() << 0; return; } IdentifierInfo *ClassMethod = - Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : nullptr; + AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; IdentifierInfo *InstanceMethod = - Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : nullptr; + AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; D->addAttr(::new (S.Context) - ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass, + ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass, ClassMethod, InstanceMethod, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleObjCDesignatedInitializer(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { ObjCInterfaceDecl *IFace; - if (ObjCCategoryDecl *CatDecl = - dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) + if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) IFace = CatDecl->getClassInterface(); else IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); @@ -4992,29 +4938,28 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D, IFace->setHasDesignatedInitializers(); D->addAttr(::new (S.Context) - ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCDesignatedInitializerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleObjCRuntimeName(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef MetaDataName; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, MetaDataName)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName)) return; D->addAttr(::new (S.Context) - ObjCRuntimeNameAttr(Attr.getRange(), S.Context, + ObjCRuntimeNameAttr(AL.getRange(), S.Context, MetaDataName, - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } // When a user wants to use objc_boxable with a union or struct // but they don't have access to the declaration (legacy/third-party code) // then they can 'enable' this feature with a typedef: // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; -static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { bool notify = false; - RecordDecl *RD = dyn_cast<RecordDecl>(D); + auto *RD = dyn_cast<RecordDecl>(D); if (RD && RD->getDefinition()) { RD = RD->getDefinition(); notify = true; @@ -5022,8 +4967,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { if (RD) { ObjCBoxableAttr *BoxableAttr = ::new (S.Context) - ObjCBoxableAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex()); + ObjCBoxableAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex()); RD->addAttr(BoxableAttr); if (notify) { // we need to notify ASTReader/ASTWriter about @@ -5034,36 +4979,35 @@ static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { } } -static void handleObjCOwnershipAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (hasDeclarator(D)) return; S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) - << Attr.getRange() << Attr.getName() << ExpectedVariable; + << AL.getRange() << AL.getName() << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - ValueDecl *vd = cast<ValueDecl>(D); - QualType type = vd->getType(); + const ParsedAttr &AL) { + const auto *VD = cast<ValueDecl>(D); + QualType QT = VD->getType(); - if (!type->isDependentType() && - !type->isObjCLifetimeType()) { - S.Diag(Attr.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << type; + if (!QT->isDependentType() && + !QT->isObjCLifetimeType()) { + S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) + << QT; return; } - Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); + Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime(); // If we have no lifetime yet, check the lifetime we're presumably // going to infer. - if (lifetime == Qualifiers::OCL_None && !type->isDependentType()) - lifetime = type->getObjCARCImplicitLifetime(); + if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType()) + Lifetime = QT->getObjCARCImplicitLifetime(); - switch (lifetime) { + switch (Lifetime) { case Qualifiers::OCL_None: - assert(type->isDependentType() && + assert(QT->isDependentType() && "didn't infer lifetime for non-dependent type?"); break; @@ -5073,14 +5017,14 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: - S.Diag(Attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless) - << (lifetime == Qualifiers::OCL_Autoreleasing); + S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless) + << (Lifetime == Qualifiers::OCL_Autoreleasing); break; } D->addAttr(::new (S.Context) - ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + ObjCPreciseLifetimeAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5100,16 +5044,16 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex); } -static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } StringRef StrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) return; // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or @@ -5141,162 +5085,158 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { // separating attributes nor of the [ and the ] are in the AST. // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc" // on cfe-dev. - if (Attr.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. - S.Diag(Attr.getLoc(), diag::warn_atl_uuid_deprecated); + if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. + S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(), - Attr.getAttributeSpellingListIndex(), StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(), + AL.getAttributeSpellingListIndex(), StrRef); if (UA) D->addAttr(UA); } -static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { - S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::C; + S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) + << AL.getName() << AttributeLangSupport::C; return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, Attr.getRange(), /*BestCase=*/true, - Attr.getAttributeSpellingListIndex(), - (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); + D, AL.getRange(), /*BestCase=*/true, + AL.getAttributeSpellingListIndex(), + (MSInheritanceAttr::Spelling)AL.getSemanticSpelling()); if (IA) { D->addAttr(IA); S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); } } -static void handleDeclspecThreadAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - VarDecl *VD = cast<VarDecl>(D); +static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const auto *VD = cast<VarDecl>(D); if (!S.Context.getTargetInfo().isTLSSupported()) { - S.Diag(Attr.getLoc(), diag::err_thread_unsupported); + S.Diag(AL.getLoc(), diag::err_thread_unsupported); return; } if (VD->getTSCSpec() != TSCS_unspecified) { - S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable); + S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable); return; } if (VD->hasLocalStorage()) { - S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; + S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)"; return; } - VD->addAttr(::new (S.Context) ThreadAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<StringRef, 4> Tags; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef Tag; - if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + if (!S.checkStringLiteralArgumentAttr(AL, I, Tag)) return; Tags.push_back(Tag); } if (const auto *NS = dyn_cast<NamespaceDecl>(D)) { if (!NS->isInline()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; return; } if (NS->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; return; } - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Tags.push_back(NS->getName()); - } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + } else if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // Store tags sorted and without duplicates. - std::sort(Tags.begin(), Tags.end()); + llvm::sort(Tags.begin(), Tags.end()); Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); D->addAttr(::new (S.Context) - AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), - Attr.getAttributeSpellingListIndex())); + AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(), + AL.getAttributeSpellingListIndex())); } -static void handleARMInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Check the attribute arguments. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << Str << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; return; } - unsigned Index = Attr.getAttributeSpellingListIndex(); + unsigned Index = AL.getAttributeSpellingListIndex(); D->addAttr(::new (S.Context) - ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); + ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index)); } -static void handleMSP430InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeNumArgs(S, Attr, 1)) +static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) return; - if (!Attr.isArgExpr(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + if (!AL.isArgExpr(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL.getName() << AANT_ArgumentIntegerConstant; return; } // FIXME: Check for decl - it should be void ()(void). - Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); llvm::APSInt NumParams(32); if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL.getName() << AANT_ArgumentIntegerConstant << NumParamsExpr->getSourceRange(); return; } unsigned Num = NumParams.getLimitedValue(255); if ((Num & 1) || Num > 30) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << (int)NumParams.getSExtValue() + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << (int)NumParams.getSExtValue() << NumParamsExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - MSP430InterruptAttr(Attr.getLoc(), S.Context, Num, - Attr.getAttributeSpellingListIndex())); + MSP430InterruptAttr(AL.getLoc(), S.Context, Num, + AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleMipsInterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Only one optional argument permitted. - if (Attr.getNumArgs() > 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) - << Attr.getName() << 1; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) + << AL.getName() << 1; return; } StringRef Str; SourceLocation ArgLoc; - if (Attr.getNumArgs() == 0) + if (AL.getNumArgs() == 0) Str = ""; - else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; // Semantic checks for a function with the 'interrupt' attribute for MIPS: @@ -5326,23 +5266,22 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, return; } - if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(), - Attr.getName())) + if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL.getRange(), + AL.getName())) return; MipsInterruptAttr::InterruptType Kind; if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) - << Attr.getName() << "'" + std::string(Str) + "'"; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << "'" + std::string(Str) + "'"; return; } D->addAttr(::new (S.Context) MipsInterruptAttr( - Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); } -static void handleAnyX86InterruptAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Semantic checks for a function with the 'interrupt' attribute. // a) Must be a function. // b) Must have the 'void' return type. @@ -5352,8 +5291,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || CXXMethodDecl::isStaticOverloadedOperator( cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionWithProtoType; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -5403,182 +5342,241 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, return; } D->addAttr(::new (S.Context) AnyX86InterruptAttr( - Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex())); D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'interrupt'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) return; - handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr); + handleSimpleAttribute<AVRInterruptAttr>(S, D, AL); } -static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'signal'" << ExpectedFunction; return; } - if (!checkAttributeNumArgs(S, Attr, 0)) + if (!checkAttributeNumArgs(S, AL, 0)) + return; + + handleSimpleAttribute<AVRSignalAttr>(S, D, AL); +} + + +static void handleRISCVInterruptAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + // Warn about repeated attributes. + if (const auto *A = D->getAttr<RISCVInterruptAttr>()) { + S.Diag(AL.getRange().getBegin(), + diag::warn_riscv_repeated_interrupt_attribute); + S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); + return; + } + + // Check the attribute argument. Argument is optional. + if (!checkAttributeAtMostNumArgs(S, AL, 1)) + return; + + StringRef Str; + SourceLocation ArgLoc; + + // 'machine'is the default interrupt mode. + if (AL.getNumArgs() == 0) + Str = "machine"; + else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + // Semantic checks for a function with the 'interrupt' attribute: + // - Must be a function. + // - Must have no parameters. + // - Must have the 'void' return type. + // - The attribute itself must either have no argument or one of the + // valid interrupt types, see [RISCVInterruptDocs]. + + if (D->getFunctionType() == nullptr) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << ExpectedFunction; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(D->getLocation(), diag::warn_riscv_interrupt_attribute) << 1; + return; + } + + RISCVInterruptAttr::InterruptType Kind; + if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL.getName() << Str << ArgLoc; return; + } - handleSimpleAttribute<AVRSignalAttr>(S, D, Attr); + D->addAttr(::new (S.Context) RISCVInterruptAttr( + AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex())); } -static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Dispatch the interrupt attribute based on the current target. switch (S.Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::msp430: - handleMSP430InterruptAttr(S, D, Attr); + handleMSP430InterruptAttr(S, D, AL); break; case llvm::Triple::mipsel: case llvm::Triple::mips: - handleMipsInterruptAttr(S, D, Attr); + handleMipsInterruptAttr(S, D, AL); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - handleAnyX86InterruptAttr(S, D, Attr); + handleAnyX86InterruptAttr(S, D, AL); break; case llvm::Triple::avr: - handleAVRInterruptAttr(S, D, Attr); + handleAVRInterruptAttr(S, D, AL); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + handleRISCVInterruptAttr(S, D, AL); break; default: - handleARMInterruptAttr(S, D, Attr); + handleARMInterruptAttr(S, D, AL); break; } } static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUFlatWorkGroupSizeAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUFlatWorkGroupSizeAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Min = 0; - Expr *MinExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + Expr *MinExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, MinExpr, Min)) return; uint32_t Max = 0; - if (Attr.getNumArgs() == 2) { - Expr *MaxExpr = Attr.getArgAsExpr(1); - if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + if (AL.getNumArgs() == 2) { + Expr *MaxExpr = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, MaxExpr, Max)) return; } if (Min == 0 && Max != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 0; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 0; return; } if (Max != 0 && Min > Max) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) - << Attr.getName() << 1; + S.Diag(AL.getLoc(), diag::err_attribute_argument_invalid) + << AL.getName() << 1; return; } D->addAttr(::new (S.Context) - AMDGPUWavesPerEUAttr(Attr.getLoc(), S.Context, Min, Max, - Attr.getAttributeSpellingListIndex())); + AMDGPUWavesPerEUAttr(AL.getLoc(), S.Context, Min, Max, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumSGPR = 0; - Expr *NumSGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumSGPRExpr, NumSGPR)) + Expr *NumSGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, NumSGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR, + AL.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t NumVGPR = 0; - Expr *NumVGPRExpr = Attr.getArgAsExpr(0); - if (!checkUInt32Argument(S, Attr, NumVGPRExpr, NumVGPR)) + Expr *NumVGPRExpr = AL.getArgAsExpr(0); + if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, NumVGPR, - Attr.getAttributeSpellingListIndex())); + AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR, + AL.getAttributeSpellingListIndex())); } static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, - const AttributeList& Attr) { + const ParsedAttr &AL) { // If we try to apply it to a function pointer, don't warn, but don't // do anything, either. It doesn't matter anyway, because there's nothing // special about calling a force_align_arg_pointer function. - ValueDecl *VD = dyn_cast<ValueDecl>(D); + const auto *VD = dyn_cast<ValueDecl>(D); if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. - TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); + const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << /* function */0; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunction; return; } D->addAttr(::new (S.Context) - X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + X86ForceAlignArgPointerAttr(AL.getRange(), S.Context, + AL.getAttributeSpellingListIndex())); } -static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t Version; - Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version)) + Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version)) return; // TODO: Investigate what happens with the next major version of MSVC. if (Version != LangOptions::MSVC2015) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) - << Attr.getName() << Version << VersionExpr->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName() << Version << VersionExpr->getSourceRange(); return; } D->addAttr(::new (S.Context) - LayoutVersionAttr(Attr.getRange(), S.Context, Version, - Attr.getAttributeSpellingListIndex())); + LayoutVersionAttr(AL.getRange(), S.Context, Version, + AL.getAttributeSpellingListIndex())); } DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, @@ -5607,7 +5605,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range, return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex); } -static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { +static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa<ClassTemplatePartialSpecializationDecl>(D) && S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) @@ -5615,8 +5613,8 @@ 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 && + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isInlined() && A.getKind() == ParsedAttr::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) @@ -5625,7 +5623,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } } - if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && MD->getParent()->isLambda()) { S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A.getName(); @@ -5634,7 +5632,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } unsigned Index = A.getAttributeSpellingListIndex(); - Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport + Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index); if (NewAttr) @@ -5654,7 +5652,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, D->dropAttr<MSInheritanceAttr>(); } - CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + auto *RD = cast<CXXRecordDecl>(D); if (RD->hasDefinition()) { if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase, SemanticSpelling)) { @@ -5677,7 +5675,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex); } -static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The capability attributes take a single string parameter for the name of // the capability they represent. The lockable attribute does not take any // parameters. However, semantically, both attributes represent the same @@ -5688,8 +5686,8 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { // literal will be considered a "mutex." StringRef N("mutex"); SourceLocation LiteralLoc; - if (Attr.getKind() == AttributeList::AT_Capability && - !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc)) + if (AL.getKind() == ParsedAttr::AT_Capability && + !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc)) return; // Currently, there are only two names allowed for a capability: role and @@ -5697,80 +5695,79 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!N.equals_lower("mutex") && !N.equals_lower("role")) S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; - D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N, + AL.getAttributeSpellingListIndex())); } -static void handleAssertCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context, + D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 1> Args; - if (!checkLockFunAttrCommon(S, D, Attr, Args)) + if (!checkLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { SmallVector<Expr*, 2> Args; - if (!checkTryLockFunAttrCommon(S, D, Attr, Args)) + if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; - D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(), + D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(), S.Context, - Attr.getArgAsExpr(0), + AL.getArgAsExpr(0), Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getAttributeSpellingListIndex())); } static void handleReleaseCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { + const ParsedAttr &AL) { // Check that all arguments are lockable objects. SmallVector<Expr *, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true); D->addAttr(::new (S.Context) ReleaseCapabilityAttr( - Attr.getRange(), S.Context, Args.data(), Args.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Args.data(), Args.size(), + AL.getAttributeSpellingListIndex())); } static void handleRequiresCapabilityAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; // check that all arguments are lockable objects SmallVector<Expr*, 1> Args; - checkAttrArgsAreCapabilityObjs(S, D, Attr, Args); + checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return; RequiresCapabilityAttr *RCA = ::new (S.Context) - RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(), - Args.size(), Attr.getAttributeSpellingListIndex()); + RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(), + Args.size(), AL.getAttributeSpellingListIndex()); D->addAttr(RCA); } -static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (auto *NSD = dyn_cast<NamespaceDecl>(D)) { +static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (const auto *NSD = dyn_cast<NamespaceDecl>(D)) { if (NSD->isAnonymousNamespace()) { - S.Diag(Attr.getLoc(), diag::warn_deprecated_anonymous_namespace); + S.Diag(AL.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. @@ -5780,25 +5777,25 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Handle the cases where the attribute has a text message. StringRef Str, Replacement; - if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && - !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + if (AL.isArgExpr(0) && AL.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(AL, 0, Str)) return; // Only support a single optional message for Declspec and CXX11. - if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) - checkAttributeAtMostNumArgs(S, Attr, 1); - else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && - !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)) + if (AL.isDeclspecAttribute() || AL.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, AL, 1); + else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(AL, 1, Replacement)) return; if (!S.getLangOpts().CPlusPlus14) - if (Attr.isCXX11Attribute() && - !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) - S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); + if (AL.isCXX11Attribute() && + !(AL.hasScope() && AL.getScopeName()->isStr("gnu"))) + S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL.getName(); D->addAttr(::new (S.Context) - DeprecatedAttr(Attr.getRange(), S.Context, Str, Replacement, - Attr.getAttributeSpellingListIndex())); + DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement, + AL.getAttributeSpellingListIndex())); } static bool isGlobalVar(const Decl *D) { @@ -5807,35 +5804,35 @@ static bool isGlobalVar(const Decl *D) { return false; } -static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) +static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeAtLeastNumArgs(S, AL, 1)) return; std::vector<StringRef> Sanitizers; - for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef SanitizerName; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc)) return; if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunctionOrMethod; + << AL.getName() << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); } D->addAttr(::new (S.Context) NoSanitizeAttr( - Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), - Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), + AL.getAttributeSpellingListIndex())); } static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, - const AttributeList &Attr) { - StringRef AttrName = Attr.getName()->getName(); + const ParsedAttr &AL) { + StringRef AttrName = AL.getName()->getName(); normalizeName(AttrName); StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") @@ -5844,77 +5841,78 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << ExpectedFunction; + << AL.getName() << ExpectedFunction; D->addAttr(::new (S.Context) - NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1, - Attr.getAttributeSpellingListIndex())); + NoSanitizeAttr(AL.getRange(), S.Context, &SanitizerName, 1, + AL.getAttributeSpellingListIndex())); } -static void handleInternalLinkageAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (InternalLinkageAttr *Internal = - S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(), - Attr.getAttributeSpellingListIndex())) + S.mergeInternalLinkageAttr(D, AL.getRange(), AL.getName(), + AL.getAttributeSpellingListIndex())) D->addAttr(Internal); } -static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { +static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.OpenCLVersion != 200) - S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version) - << Attr.getName() << "2.0" << 0; + S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) + << AL.getName() << "2.0" << 0; else - S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored) - << Attr.getName() << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL.getName() << "2.0"; } /// 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. -static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr) { +static bool handleCommonAttributeFeatures(Sema &S, Decl *D, + const ParsedAttr &AL) { // Several attributes carry different semantics than the parsing requires, so // those are opted out of the common argument checks. // // We also bail on unknown and ignored attributes because those are handled // as part of the target-specific handling logic. - if (Attr.getKind() == AttributeList::UnknownAttribute) + if (AL.getKind() == ParsedAttr::UnknownAttribute) return false; // Check whether the attribute requires specific language extensions to be // enabled. - if (!Attr.diagnoseLangOpts(S)) + if (!AL.diagnoseLangOpts(S)) return true; // Check whether the attribute appertains to the given subject. - if (!Attr.diagnoseAppertainsTo(S, D)) + if (!AL.diagnoseAppertainsTo(S, D)) return true; - if (Attr.hasCustomParsing()) + if (AL.hasCustomParsing()) return false; - if (Attr.getMinArgs() == Attr.getMaxArgs()) { + if (AL.getMinArgs() == AL.getMaxArgs()) { // If there are no optional arguments, then checking for the argument count // is trivial. - if (!checkAttributeNumArgs(S, Attr, Attr.getMinArgs())) + if (!checkAttributeNumArgs(S, AL, AL.getMinArgs())) return true; } else { // There are optional arguments, so checking is slightly more involved. - if (Attr.getMinArgs() && - !checkAttributeAtLeastNumArgs(S, Attr, Attr.getMinArgs())) + if (AL.getMinArgs() && + !checkAttributeAtLeastNumArgs(S, AL, AL.getMinArgs())) return true; - else if (!Attr.hasVariadicArg() && Attr.getMaxArgs() && - !checkAttributeAtMostNumArgs(S, Attr, Attr.getMaxArgs())) + else if (!AL.hasVariadicArg() && AL.getMaxArgs() && + !checkAttributeAtMostNumArgs(S, AL, AL.getMaxArgs())) return true; } + if (S.CheckAttrTarget(AL)) + return true; + return false; } -static void handleOpenCLAccessAttr(Sema &S, Decl *D, - const AttributeList &Attr) { +static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->isInvalidDecl()) return; // Check if there is only one access qualifier. if (D->hasAttr<OpenCLAccessAttr>()) { - S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers) + S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) << D->getSourceRange(); D->setInvalidDecl(true); return; @@ -5925,12 +5923,12 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe // object. Using the read_write (or __read_write) qualifier with the pipe // qualifier is a compilation error. - if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) { + if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (Attr.getName()->getName().find("read_write") != StringRef::npos) { + if (AL.getName()->getName().find("read_write") != StringRef::npos) { if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { - S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write) - << Attr.getName() << PDecl->getType() << DeclTy->isImageType(); + S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) + << AL.getName() << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); return; } @@ -5938,7 +5936,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, } D->addAttr(::new (S.Context) OpenCLAccessAttr( - Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); } //===----------------------------------------------------------------------===// @@ -5949,633 +5947,659 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, - const AttributeList &Attr, + const ParsedAttr &AL, bool IncludeCXX11Attributes) { - if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute) + if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type // instead. - if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) + if (AL.isCXX11Attribute() && !IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes // which do not apply to the current target architecture are treated as // though they were unknown attributes. - if (Attr.getKind() == AttributeList::UnknownAttribute || - !Attr.existsInTarget(S.Context.getTargetInfo())) { - S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() - ? diag::warn_unhandled_ms_attribute_ignored - : diag::warn_unknown_attribute_ignored) - << Attr.getName(); + if (AL.getKind() == ParsedAttr::UnknownAttribute || + !AL.existsInTarget(S.Context.getTargetInfo())) { + S.Diag(AL.getLoc(), AL.isDeclspecAttribute() + ? diag::warn_unhandled_ms_attribute_ignored + : diag::warn_unknown_attribute_ignored) + << AL.getName(); return; } - if (handleCommonAttributeFeatures(S, scope, D, Attr)) + if (handleCommonAttributeFeatures(S, D, AL)) return; - switch (Attr.getKind()) { + switch (AL.getKind()) { default: - if (!Attr.isStmtAttr()) { + if (!AL.isStmtAttr()) { // Type attributes are handled elsewhere; silently move on. - assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + assert(AL.isTypeAttr() && "Non-type attribute not handled"); break; } - S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl) - << Attr.getName() << D->getLocation(); + S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << AL.getName() << D->getLocation(); break; - case AttributeList::AT_Interrupt: - handleInterruptAttr(S, D, Attr); + case ParsedAttr::AT_Interrupt: + handleInterruptAttr(S, D, AL); break; - case AttributeList::AT_X86ForceAlignArgPointer: - handleX86ForceAlignArgPointerAttr(S, D, Attr); + case ParsedAttr::AT_X86ForceAlignArgPointer: + handleX86ForceAlignArgPointerAttr(S, D, AL); break; - case AttributeList::AT_DLLExport: - case AttributeList::AT_DLLImport: - handleDLLAttr(S, D, Attr); + case ParsedAttr::AT_DLLExport: + case ParsedAttr::AT_DLLImport: + handleDLLAttr(S, D, AL); break; - case AttributeList::AT_Mips16: + case ParsedAttr::AT_Mips16: handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr, - MipsInterruptAttr>(S, D, Attr); + MipsInterruptAttr>(S, D, AL); break; - case AttributeList::AT_NoMips16: - handleSimpleAttribute<NoMips16Attr>(S, D, Attr); + case ParsedAttr::AT_NoMips16: + handleSimpleAttribute<NoMips16Attr>(S, D, AL); break; - case AttributeList::AT_MicroMips: - handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, Attr); + case ParsedAttr::AT_MicroMips: + handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL); break; - case AttributeList::AT_NoMicroMips: - handleSimpleAttribute<NoMicroMipsAttr>(S, D, Attr); + case ParsedAttr::AT_NoMicroMips: + handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL); break; - case AttributeList::AT_MipsLongCall: + case ParsedAttr::AT_MipsLongCall: handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>( - S, D, Attr); + S, D, AL); break; - case AttributeList::AT_MipsShortCall: + case ParsedAttr::AT_MipsShortCall: handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>( - S, D, Attr); + S, D, AL); + break; + case ParsedAttr::AT_AMDGPUFlatWorkGroupSize: + handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL); + break; + case ParsedAttr::AT_AMDGPUWavesPerEU: + handleAMDGPUWavesPerEUAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUFlatWorkGroupSize: - handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumSGPR: + handleAMDGPUNumSGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUWavesPerEU: - handleAMDGPUWavesPerEUAttr(S, D, Attr); + case ParsedAttr::AT_AMDGPUNumVGPR: + handleAMDGPUNumVGPRAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumSGPR: - handleAMDGPUNumSGPRAttr(S, D, Attr); + case ParsedAttr::AT_AVRSignal: + handleAVRSignalAttr(S, D, AL); break; - case AttributeList::AT_AMDGPUNumVGPR: - handleAMDGPUNumVGPRAttr(S, D, Attr); + case ParsedAttr::AT_IBAction: + handleSimpleAttribute<IBActionAttr>(S, D, AL); break; - case AttributeList::AT_AVRSignal: - handleAVRSignalAttr(S, D, Attr); + case ParsedAttr::AT_IBOutlet: + handleIBOutlet(S, D, AL); break; - case AttributeList::AT_IBAction: - handleSimpleAttribute<IBActionAttr>(S, D, Attr); + case ParsedAttr::AT_IBOutletCollection: + handleIBOutletCollection(S, D, AL); break; - case AttributeList::AT_IBOutlet: - handleIBOutlet(S, D, Attr); + case ParsedAttr::AT_IFunc: + handleIFuncAttr(S, D, AL); break; - case AttributeList::AT_IBOutletCollection: - handleIBOutletCollection(S, D, Attr); + case ParsedAttr::AT_Alias: + handleAliasAttr(S, D, AL); break; - case AttributeList::AT_IFunc: - handleIFuncAttr(S, D, Attr); + case ParsedAttr::AT_Aligned: + handleAlignedAttr(S, D, AL); break; - case AttributeList::AT_Alias: - handleAliasAttr(S, D, Attr); + case ParsedAttr::AT_AlignValue: + handleAlignValueAttr(S, D, AL); break; - case AttributeList::AT_Aligned: - handleAlignedAttr(S, D, Attr); + case ParsedAttr::AT_AllocSize: + handleAllocSizeAttr(S, D, AL); break; - case AttributeList::AT_AlignValue: - handleAlignValueAttr(S, D, Attr); + case ParsedAttr::AT_AlwaysInline: + handleAlwaysInlineAttr(S, D, AL); break; - case AttributeList::AT_AllocSize: - handleAllocSizeAttr(S, D, Attr); + case ParsedAttr::AT_Artificial: + handleSimpleAttribute<ArtificialAttr>(S, D, AL); break; - case AttributeList::AT_AlwaysInline: - handleAlwaysInlineAttr(S, D, Attr); + case ParsedAttr::AT_AnalyzerNoReturn: + handleAnalyzerNoReturnAttr(S, D, AL); break; - case AttributeList::AT_AnalyzerNoReturn: - handleAnalyzerNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_TLSModel: + handleTLSModelAttr(S, D, AL); break; - case AttributeList::AT_TLSModel: - handleTLSModelAttr(S, D, Attr); + case ParsedAttr::AT_Annotate: + handleAnnotateAttr(S, D, AL); break; - case AttributeList::AT_Annotate: - handleAnnotateAttr(S, D, Attr); + case ParsedAttr::AT_Availability: + handleAvailabilityAttr(S, D, AL); break; - case AttributeList::AT_Availability: - handleAvailabilityAttr(S, D, Attr); + case ParsedAttr::AT_CarriesDependency: + handleDependencyAttr(S, scope, D, AL); break; - case AttributeList::AT_CarriesDependency: - handleDependencyAttr(S, scope, D, Attr); + case ParsedAttr::AT_CPUDispatch: + case ParsedAttr::AT_CPUSpecific: + handleCPUSpecificAttr(S, D, AL); break; - case AttributeList::AT_Common: - handleCommonAttr(S, D, Attr); + case ParsedAttr::AT_Common: + handleCommonAttr(S, D, AL); break; - case AttributeList::AT_CUDAConstant: - handleConstantAttr(S, D, Attr); + case ParsedAttr::AT_CUDAConstant: + handleConstantAttr(S, D, AL); break; - case AttributeList::AT_PassObjectSize: - handlePassObjectSizeAttr(S, D, Attr); + case ParsedAttr::AT_PassObjectSize: + handlePassObjectSizeAttr(S, D, AL); break; - case AttributeList::AT_Constructor: - handleConstructorAttr(S, D, Attr); + case ParsedAttr::AT_Constructor: + handleConstructorAttr(S, D, AL); break; - case AttributeList::AT_CXX11NoReturn: - handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr); + case ParsedAttr::AT_CXX11NoReturn: + handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL); break; - case AttributeList::AT_Deprecated: - handleDeprecatedAttr(S, D, Attr); + case ParsedAttr::AT_Deprecated: + handleDeprecatedAttr(S, D, AL); break; - case AttributeList::AT_Destructor: - handleDestructorAttr(S, D, Attr); + case ParsedAttr::AT_Destructor: + handleDestructorAttr(S, D, AL); break; - case AttributeList::AT_EnableIf: - handleEnableIfAttr(S, D, Attr); + case ParsedAttr::AT_EnableIf: + handleEnableIfAttr(S, D, AL); break; - case AttributeList::AT_DiagnoseIf: - handleDiagnoseIfAttr(S, D, Attr); + case ParsedAttr::AT_DiagnoseIf: + handleDiagnoseIfAttr(S, D, AL); break; - case AttributeList::AT_ExtVectorType: - handleExtVectorTypeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ExtVectorType: + handleExtVectorTypeAttr(S, D, AL); break; - case AttributeList::AT_ExternalSourceSymbol: - handleExternalSourceSymbolAttr(S, D, Attr); + case ParsedAttr::AT_ExternalSourceSymbol: + handleExternalSourceSymbolAttr(S, D, AL); break; - case AttributeList::AT_MinSize: - handleMinSizeAttr(S, D, Attr); + case ParsedAttr::AT_MinSize: + handleMinSizeAttr(S, D, AL); break; - case AttributeList::AT_OptimizeNone: - handleOptimizeNoneAttr(S, D, Attr); + case ParsedAttr::AT_OptimizeNone: + handleOptimizeNoneAttr(S, D, AL); break; - case AttributeList::AT_FlagEnum: - handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); + case ParsedAttr::AT_FlagEnum: + handleSimpleAttribute<FlagEnumAttr>(S, D, AL); break; - case AttributeList::AT_EnumExtensibility: - handleEnumExtensibilityAttr(S, D, Attr); + case ParsedAttr::AT_EnumExtensibility: + handleEnumExtensibilityAttr(S, D, AL); break; - case AttributeList::AT_Flatten: - handleSimpleAttribute<FlattenAttr>(S, D, Attr); + case ParsedAttr::AT_Flatten: + handleSimpleAttribute<FlattenAttr>(S, D, AL); break; - case AttributeList::AT_Format: - handleFormatAttr(S, D, Attr); + case ParsedAttr::AT_Format: + handleFormatAttr(S, D, AL); break; - case AttributeList::AT_FormatArg: - handleFormatArgAttr(S, D, Attr); + case ParsedAttr::AT_FormatArg: + handleFormatArgAttr(S, D, AL); break; - case AttributeList::AT_CUDAGlobal: - handleGlobalAttr(S, D, Attr); + case ParsedAttr::AT_CUDAGlobal: + handleGlobalAttr(S, D, AL); break; - case AttributeList::AT_CUDADevice: + case ParsedAttr::AT_CUDADevice: handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D, - Attr); + AL); break; - case AttributeList::AT_CUDAHost: - handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, - Attr); + case ParsedAttr::AT_CUDAHost: + handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL); break; - case AttributeList::AT_GNUInline: - handleGNUInlineAttr(S, D, Attr); + case ParsedAttr::AT_GNUInline: + handleGNUInlineAttr(S, D, AL); break; - case AttributeList::AT_CUDALaunchBounds: - handleLaunchBoundsAttr(S, D, Attr); + case ParsedAttr::AT_CUDALaunchBounds: + handleLaunchBoundsAttr(S, D, AL); break; - case AttributeList::AT_Restrict: - handleRestrictAttr(S, D, Attr); + case ParsedAttr::AT_Restrict: + handleRestrictAttr(S, D, AL); break; - case AttributeList::AT_MayAlias: - handleSimpleAttribute<MayAliasAttr>(S, D, Attr); + case ParsedAttr::AT_MayAlias: + handleSimpleAttribute<MayAliasAttr>(S, D, AL); break; - case AttributeList::AT_Mode: - handleModeAttr(S, D, Attr); + case ParsedAttr::AT_Mode: + handleModeAttr(S, D, AL); break; - case AttributeList::AT_NoAlias: - handleSimpleAttribute<NoAliasAttr>(S, D, Attr); + case ParsedAttr::AT_NoAlias: + handleSimpleAttribute<NoAliasAttr>(S, D, AL); break; - case AttributeList::AT_NoCommon: - handleSimpleAttribute<NoCommonAttr>(S, D, Attr); + case ParsedAttr::AT_NoCommon: + handleSimpleAttribute<NoCommonAttr>(S, D, AL); break; - case AttributeList::AT_NoSplitStack: - handleSimpleAttribute<NoSplitStackAttr>(S, D, Attr); + case ParsedAttr::AT_NoSplitStack: + handleSimpleAttribute<NoSplitStackAttr>(S, D, AL); break; - case AttributeList::AT_NonNull: - if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D)) - handleNonNullAttrParameter(S, PVD, Attr); + case ParsedAttr::AT_NonNull: + if (auto *PVD = dyn_cast<ParmVarDecl>(D)) + handleNonNullAttrParameter(S, PVD, AL); else - handleNonNullAttr(S, D, Attr); + handleNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_ReturnsNonNull: + handleReturnsNonNullAttr(S, D, AL); + break; + case ParsedAttr::AT_NoEscape: + handleNoEscapeAttr(S, D, AL); break; - case AttributeList::AT_ReturnsNonNull: - handleReturnsNonNullAttr(S, D, Attr); + case ParsedAttr::AT_AssumeAligned: + handleAssumeAlignedAttr(S, D, AL); break; - case AttributeList::AT_NoEscape: - handleNoEscapeAttr(S, D, Attr); + case ParsedAttr::AT_AllocAlign: + handleAllocAlignAttr(S, D, AL); break; - case AttributeList::AT_AssumeAligned: - handleAssumeAlignedAttr(S, D, Attr); + case ParsedAttr::AT_Overloadable: + handleSimpleAttribute<OverloadableAttr>(S, D, AL); break; - case AttributeList::AT_AllocAlign: - handleAllocAlignAttr(S, D, Attr); + case ParsedAttr::AT_Ownership: + handleOwnershipAttr(S, D, AL); break; - case AttributeList::AT_Overloadable: - handleSimpleAttribute<OverloadableAttr>(S, D, Attr); + case ParsedAttr::AT_Cold: + handleSimpleAttributeWithExclusions<ColdAttr, HotAttr>(S, D, AL); break; - case AttributeList::AT_Ownership: - handleOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_Hot: + handleSimpleAttributeWithExclusions<HotAttr, ColdAttr>(S, D, AL); break; - case AttributeList::AT_Cold: - handleColdAttr(S, D, Attr); + case ParsedAttr::AT_Naked: + handleNakedAttr(S, D, AL); break; - case AttributeList::AT_Hot: - handleHotAttr(S, D, Attr); + case ParsedAttr::AT_NoReturn: + handleNoReturnAttr(S, D, AL); break; - case AttributeList::AT_Naked: - handleNakedAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCfCheck: + handleNoCfCheckAttr(S, D, AL); break; - case AttributeList::AT_NoReturn: - handleNoReturnAttr(S, D, Attr); + case ParsedAttr::AT_NoThrow: + handleSimpleAttribute<NoThrowAttr>(S, D, AL); break; - case AttributeList::AT_NoThrow: - handleSimpleAttribute<NoThrowAttr>(S, D, Attr); + case ParsedAttr::AT_CUDAShared: + handleSharedAttr(S, D, AL); break; - case AttributeList::AT_CUDAShared: - handleSharedAttr(S, D, Attr); + case ParsedAttr::AT_VecReturn: + handleVecReturnAttr(S, D, AL); break; - case AttributeList::AT_VecReturn: - handleVecReturnAttr(S, D, Attr); + case ParsedAttr::AT_ObjCOwnership: + handleObjCOwnershipAttr(S, D, AL); break; - case AttributeList::AT_ObjCOwnership: - handleObjCOwnershipAttr(S, D, Attr); + case ParsedAttr::AT_ObjCPreciseLifetime: + handleObjCPreciseLifetimeAttr(S, D, AL); break; - case AttributeList::AT_ObjCPreciseLifetime: - handleObjCPreciseLifetimeAttr(S, D, Attr); + case ParsedAttr::AT_ObjCReturnsInnerPointer: + handleObjCReturnsInnerPointerAttr(S, D, AL); break; - case AttributeList::AT_ObjCReturnsInnerPointer: - handleObjCReturnsInnerPointerAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresSuper: + handleObjCRequiresSuperAttr(S, D, AL); break; - case AttributeList::AT_ObjCRequiresSuper: - handleObjCRequiresSuperAttr(S, D, Attr); + case ParsedAttr::AT_ObjCBridge: + handleObjCBridgeAttr(S, D, AL); break; - case AttributeList::AT_ObjCBridge: - handleObjCBridgeAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCBridgeMutable: + handleObjCBridgeMutableAttr(S, D, AL); break; - case AttributeList::AT_ObjCBridgeMutable: - handleObjCBridgeMutableAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCBridgeRelated: + handleObjCBridgeRelatedAttr(S, D, AL); break; - case AttributeList::AT_ObjCBridgeRelated: - handleObjCBridgeRelatedAttr(S, scope, D, Attr); + case ParsedAttr::AT_ObjCDesignatedInitializer: + handleObjCDesignatedInitializer(S, D, AL); break; - case AttributeList::AT_ObjCDesignatedInitializer: - handleObjCDesignatedInitializer(S, D, Attr); + case ParsedAttr::AT_ObjCRuntimeName: + handleObjCRuntimeName(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeName: - handleObjCRuntimeName(S, D, Attr); + case ParsedAttr::AT_ObjCRuntimeVisible: + handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRuntimeVisible: - handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCBoxable: + handleObjCBoxable(S, D, AL); break; - case AttributeList::AT_ObjCBoxable: - handleObjCBoxable(S, D, Attr); + case ParsedAttr::AT_CFAuditedTransfer: + handleSimpleAttributeWithExclusions<CFAuditedTransferAttr, + CFUnknownTransferAttr>(S, D, AL); break; - case AttributeList::AT_CFAuditedTransfer: - handleCFAuditedTransferAttr(S, D, Attr); + case ParsedAttr::AT_CFUnknownTransfer: + handleSimpleAttributeWithExclusions<CFUnknownTransferAttr, + CFAuditedTransferAttr>(S, D, AL); break; - case AttributeList::AT_CFUnknownTransfer: - handleCFUnknownTransferAttr(S, D, Attr); + case ParsedAttr::AT_CFConsumed: + case ParsedAttr::AT_NSConsumed: + handleNSConsumedAttr(S, D, AL); break; - case AttributeList::AT_CFConsumed: - case AttributeList::AT_NSConsumed: - handleNSConsumedAttr(S, D, Attr); + case ParsedAttr::AT_NSConsumesSelf: + handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); break; - case AttributeList::AT_NSConsumesSelf: - handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); + case ParsedAttr::AT_NSReturnsAutoreleased: + case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_CFReturnsNotRetained: + case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_CFReturnsRetained: + handleNSReturnsRetainedAttr(S, D, AL); break; - case AttributeList::AT_NSReturnsAutoreleased: - case AttributeList::AT_NSReturnsNotRetained: - case AttributeList::AT_CFReturnsNotRetained: - case AttributeList::AT_NSReturnsRetained: - case AttributeList::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, Attr); + case ParsedAttr::AT_WorkGroupSizeHint: + handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL); break; - case AttributeList::AT_WorkGroupSizeHint: - handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, Attr); + case ParsedAttr::AT_ReqdWorkGroupSize: + handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL); break; - case AttributeList::AT_ReqdWorkGroupSize: - handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr); + case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize: + handleSubGroupSize(S, D, AL); break; - case AttributeList::AT_OpenCLIntelReqdSubGroupSize: - handleSubGroupSize(S, D, Attr); + case ParsedAttr::AT_VecTypeHint: + handleVecTypeHint(S, D, AL); break; - case AttributeList::AT_VecTypeHint: - handleVecTypeHint(S, D, Attr); + case ParsedAttr::AT_RequireConstantInit: + handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL); break; - case AttributeList::AT_RequireConstantInit: - handleSimpleAttribute<RequireConstantInitAttr>(S, D, Attr); + case ParsedAttr::AT_InitPriority: + handleInitPriorityAttr(S, D, AL); break; - case AttributeList::AT_InitPriority: - handleInitPriorityAttr(S, D, Attr); + case ParsedAttr::AT_Packed: + handlePackedAttr(S, D, AL); break; - case AttributeList::AT_Packed: - handlePackedAttr(S, D, Attr); + case ParsedAttr::AT_Section: + handleSectionAttr(S, D, AL); break; - case AttributeList::AT_Section: - handleSectionAttr(S, D, Attr); + case ParsedAttr::AT_CodeSeg: + handleCodeSegAttr(S, D, AL); break; - case AttributeList::AT_Target: - handleTargetAttr(S, D, Attr); + case ParsedAttr::AT_Target: + handleTargetAttr(S, D, AL); break; - case AttributeList::AT_Unavailable: - handleAttrWithMessage<UnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_MinVectorWidth: + handleMinVectorWidthAttr(S, D, AL); break; - case AttributeList::AT_ArcWeakrefUnavailable: - handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, Attr); + case ParsedAttr::AT_Unavailable: + handleAttrWithMessage<UnavailableAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRootClass: - handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); + case ParsedAttr::AT_ArcWeakrefUnavailable: + handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL); break; - case AttributeList::AT_ObjCSubclassingRestricted: - handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCRootClass: + handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; - case AttributeList::AT_ObjCExplicitProtocolImpl: - handleObjCSuppresProtocolAttr(S, D, Attr); + case ParsedAttr::AT_ObjCSubclassingRestricted: + handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); break; - case AttributeList::AT_ObjCRequiresPropertyDefs: - handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); + case ParsedAttr::AT_ObjCExplicitProtocolImpl: + handleObjCSuppresProtocolAttr(S, D, AL); break; - case AttributeList::AT_Unused: - handleUnusedAttr(S, D, Attr); + case ParsedAttr::AT_ObjCRequiresPropertyDefs: + handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL); break; - case AttributeList::AT_ReturnsTwice: - handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); + case ParsedAttr::AT_Unused: + handleUnusedAttr(S, D, AL); break; - case AttributeList::AT_NotTailCalled: - handleNotTailCalledAttr(S, D, Attr); + case ParsedAttr::AT_ReturnsTwice: + handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL); break; - case AttributeList::AT_DisableTailCalls: - handleDisableTailCallsAttr(S, D, Attr); + case ParsedAttr::AT_NotTailCalled: + handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>( + S, D, AL); break; - case AttributeList::AT_Used: - handleUsedAttr(S, D, Attr); + case ParsedAttr::AT_DisableTailCalls: + handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D, + AL); break; - case AttributeList::AT_Visibility: - handleVisibilityAttr(S, D, Attr, false); + case ParsedAttr::AT_Used: + handleSimpleAttribute<UsedAttr>(S, D, AL); break; - case AttributeList::AT_TypeVisibility: - handleVisibilityAttr(S, D, Attr, true); + case ParsedAttr::AT_Visibility: + handleVisibilityAttr(S, D, AL, false); break; - case AttributeList::AT_WarnUnused: - handleSimpleAttribute<WarnUnusedAttr>(S, D, Attr); + case ParsedAttr::AT_TypeVisibility: + handleVisibilityAttr(S, D, AL, true); break; - case AttributeList::AT_WarnUnusedResult: - handleWarnUnusedResult(S, D, Attr); + case ParsedAttr::AT_WarnUnused: + handleSimpleAttribute<WarnUnusedAttr>(S, D, AL); break; - case AttributeList::AT_Weak: - handleSimpleAttribute<WeakAttr>(S, D, Attr); + case ParsedAttr::AT_WarnUnusedResult: + handleWarnUnusedResult(S, D, AL); break; - case AttributeList::AT_WeakRef: - handleWeakRefAttr(S, D, Attr); + case ParsedAttr::AT_Weak: + handleSimpleAttribute<WeakAttr>(S, D, AL); break; - case AttributeList::AT_WeakImport: - handleWeakImportAttr(S, D, Attr); + case ParsedAttr::AT_WeakRef: + handleWeakRefAttr(S, D, AL); break; - case AttributeList::AT_TransparentUnion: - handleTransparentUnionAttr(S, D, Attr); + case ParsedAttr::AT_WeakImport: + handleWeakImportAttr(S, D, AL); break; - case AttributeList::AT_ObjCException: - handleSimpleAttribute<ObjCExceptionAttr>(S, D, Attr); + case ParsedAttr::AT_TransparentUnion: + handleTransparentUnionAttr(S, D, AL); break; - case AttributeList::AT_ObjCMethodFamily: - handleObjCMethodFamilyAttr(S, D, Attr); + case ParsedAttr::AT_ObjCException: + handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL); break; - case AttributeList::AT_ObjCNSObject: - handleObjCNSObject(S, D, Attr); + case ParsedAttr::AT_ObjCMethodFamily: + handleObjCMethodFamilyAttr(S, D, AL); break; - case AttributeList::AT_ObjCIndependentClass: - handleObjCIndependentClass(S, D, Attr); + case ParsedAttr::AT_ObjCNSObject: + handleObjCNSObject(S, D, AL); break; - case AttributeList::AT_Blocks: - handleBlocksAttr(S, D, Attr); + case ParsedAttr::AT_ObjCIndependentClass: + handleObjCIndependentClass(S, D, AL); break; - case AttributeList::AT_Sentinel: - handleSentinelAttr(S, D, Attr); + case ParsedAttr::AT_Blocks: + handleBlocksAttr(S, D, AL); break; - case AttributeList::AT_Const: - handleSimpleAttribute<ConstAttr>(S, D, Attr); + case ParsedAttr::AT_Sentinel: + handleSentinelAttr(S, D, AL); break; - case AttributeList::AT_Pure: - handleSimpleAttribute<PureAttr>(S, D, Attr); + case ParsedAttr::AT_Const: + handleSimpleAttribute<ConstAttr>(S, D, AL); break; - case AttributeList::AT_Cleanup: - handleCleanupAttr(S, D, Attr); + case ParsedAttr::AT_Pure: + handleSimpleAttribute<PureAttr>(S, D, AL); break; - case AttributeList::AT_NoDebug: - handleNoDebugAttr(S, D, Attr); + case ParsedAttr::AT_Cleanup: + handleCleanupAttr(S, D, AL); break; - case AttributeList::AT_NoDuplicate: - handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr); + case ParsedAttr::AT_NoDebug: + handleNoDebugAttr(S, D, AL); break; - case AttributeList::AT_Convergent: - handleSimpleAttribute<ConvergentAttr>(S, D, Attr); + case ParsedAttr::AT_NoDuplicate: + handleSimpleAttribute<NoDuplicateAttr>(S, D, AL); break; - case AttributeList::AT_NoInline: - handleSimpleAttribute<NoInlineAttr>(S, D, Attr); + case ParsedAttr::AT_Convergent: + handleSimpleAttribute<ConvergentAttr>(S, D, AL); break; - case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg. - handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr); + case ParsedAttr::AT_NoInline: + handleSimpleAttribute<NoInlineAttr>(S, D, AL); break; - case AttributeList::AT_StdCall: - case AttributeList::AT_CDecl: - case AttributeList::AT_FastCall: - case AttributeList::AT_ThisCall: - case AttributeList::AT_Pascal: - case AttributeList::AT_RegCall: - case AttributeList::AT_SwiftCall: - case AttributeList::AT_VectorCall: - case AttributeList::AT_MSABI: - case AttributeList::AT_SysVABI: - case AttributeList::AT_Pcs: - case AttributeList::AT_IntelOclBicc: - case AttributeList::AT_PreserveMost: - case AttributeList::AT_PreserveAll: - handleCallConvAttr(S, D, Attr); + case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg. + handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL); break; - case AttributeList::AT_Suppress: - handleSuppressAttr(S, D, Attr); + case ParsedAttr::AT_NoStackProtector: + // Interacts with -fstack-protector options. + handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL); break; - case AttributeList::AT_OpenCLKernel: - handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); + case ParsedAttr::AT_StdCall: + case ParsedAttr::AT_CDecl: + case ParsedAttr::AT_FastCall: + case ParsedAttr::AT_ThisCall: + case ParsedAttr::AT_Pascal: + case ParsedAttr::AT_RegCall: + case ParsedAttr::AT_SwiftCall: + case ParsedAttr::AT_VectorCall: + case ParsedAttr::AT_MSABI: + case ParsedAttr::AT_SysVABI: + case ParsedAttr::AT_Pcs: + case ParsedAttr::AT_IntelOclBicc: + case ParsedAttr::AT_PreserveMost: + case ParsedAttr::AT_PreserveAll: + handleCallConvAttr(S, D, AL); break; - case AttributeList::AT_OpenCLAccess: - handleOpenCLAccessAttr(S, D, Attr); + case ParsedAttr::AT_Suppress: + handleSuppressAttr(S, D, AL); break; - case AttributeList::AT_OpenCLNoSVM: - handleOpenCLNoSVMAttr(S, D, Attr); + case ParsedAttr::AT_OpenCLKernel: + handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL); break; - case AttributeList::AT_SwiftContext: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext); + case ParsedAttr::AT_OpenCLAccess: + handleOpenCLAccessAttr(S, D, AL); break; - case AttributeList::AT_SwiftErrorResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult); + case ParsedAttr::AT_OpenCLNoSVM: + handleOpenCLNoSVMAttr(S, D, AL); break; - case AttributeList::AT_SwiftIndirectResult: - handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult); + case ParsedAttr::AT_SwiftContext: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext); break; - case AttributeList::AT_InternalLinkage: - handleInternalLinkageAttr(S, D, Attr); + case ParsedAttr::AT_SwiftErrorResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult); break; - case AttributeList::AT_LTOVisibilityPublic: - handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr); + case ParsedAttr::AT_SwiftIndirectResult: + handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult); + break; + case ParsedAttr::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, AL); + break; + case ParsedAttr::AT_LTOVisibilityPublic: + handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL); break; // Microsoft attributes: - case AttributeList::AT_EmptyBases: - handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr); + case ParsedAttr::AT_EmptyBases: + handleSimpleAttribute<EmptyBasesAttr>(S, D, AL); + break; + case ParsedAttr::AT_LayoutVersion: + handleLayoutVersion(S, D, AL); break; - case AttributeList::AT_LayoutVersion: - handleLayoutVersion(S, D, Attr); + case ParsedAttr::AT_TrivialABI: + handleSimpleAttribute<TrivialABIAttr>(S, D, AL); break; - case AttributeList::AT_MSNoVTable: - handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); + case ParsedAttr::AT_MSNoVTable: + handleSimpleAttribute<MSNoVTableAttr>(S, D, AL); break; - case AttributeList::AT_MSStruct: - handleSimpleAttribute<MSStructAttr>(S, D, Attr); + case ParsedAttr::AT_MSStruct: + handleSimpleAttribute<MSStructAttr>(S, D, AL); break; - case AttributeList::AT_Uuid: - handleUuidAttr(S, D, Attr); + case ParsedAttr::AT_Uuid: + handleUuidAttr(S, D, AL); break; - case AttributeList::AT_MSInheritance: - handleMSInheritanceAttr(S, D, Attr); + case ParsedAttr::AT_MSInheritance: + handleMSInheritanceAttr(S, D, AL); break; - case AttributeList::AT_SelectAny: - handleSimpleAttribute<SelectAnyAttr>(S, D, Attr); + case ParsedAttr::AT_SelectAny: + handleSimpleAttribute<SelectAnyAttr>(S, D, AL); break; - case AttributeList::AT_Thread: - handleDeclspecThreadAttr(S, D, Attr); + case ParsedAttr::AT_Thread: + handleDeclspecThreadAttr(S, D, AL); break; - case AttributeList::AT_AbiTag: - handleAbiTagAttr(S, D, Attr); + case ParsedAttr::AT_AbiTag: + handleAbiTagAttr(S, D, AL); break; // Thread safety attributes: - case AttributeList::AT_AssertExclusiveLock: - handleAssertExclusiveLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertExclusiveLock: + handleAssertExclusiveLockAttr(S, D, AL); break; - case AttributeList::AT_AssertSharedLock: - handleAssertSharedLockAttr(S, D, Attr); + case ParsedAttr::AT_AssertSharedLock: + handleAssertSharedLockAttr(S, D, AL); break; - case AttributeList::AT_GuardedVar: - handleSimpleAttribute<GuardedVarAttr>(S, D, Attr); + case ParsedAttr::AT_GuardedVar: + handleSimpleAttribute<GuardedVarAttr>(S, D, AL); break; - case AttributeList::AT_PtGuardedVar: - handlePtGuardedVarAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedVar: + handlePtGuardedVarAttr(S, D, AL); break; - case AttributeList::AT_ScopedLockable: - handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr); + case ParsedAttr::AT_ScopedLockable: + handleSimpleAttribute<ScopedLockableAttr>(S, D, AL); break; - case AttributeList::AT_NoSanitize: - handleNoSanitizeAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitize: + handleNoSanitizeAttr(S, D, AL); break; - case AttributeList::AT_NoSanitizeSpecific: - handleNoSanitizeSpecificAttr(S, D, Attr); + case ParsedAttr::AT_NoSanitizeSpecific: + handleNoSanitizeSpecificAttr(S, D, AL); break; - case AttributeList::AT_NoThreadSafetyAnalysis: - handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr); + case ParsedAttr::AT_NoThreadSafetyAnalysis: + handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL); break; - case AttributeList::AT_GuardedBy: - handleGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_GuardedBy: + handleGuardedByAttr(S, D, AL); break; - case AttributeList::AT_PtGuardedBy: - handlePtGuardedByAttr(S, D, Attr); + case ParsedAttr::AT_PtGuardedBy: + handlePtGuardedByAttr(S, D, AL); break; - case AttributeList::AT_ExclusiveTrylockFunction: - handleExclusiveTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_ExclusiveTrylockFunction: + handleExclusiveTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_LockReturned: - handleLockReturnedAttr(S, D, Attr); + case ParsedAttr::AT_LockReturned: + handleLockReturnedAttr(S, D, AL); break; - case AttributeList::AT_LocksExcluded: - handleLocksExcludedAttr(S, D, Attr); + case ParsedAttr::AT_LocksExcluded: + handleLocksExcludedAttr(S, D, AL); break; - case AttributeList::AT_SharedTrylockFunction: - handleSharedTrylockFunctionAttr(S, D, Attr); + case ParsedAttr::AT_SharedTrylockFunction: + handleSharedTrylockFunctionAttr(S, D, AL); break; - case AttributeList::AT_AcquiredBefore: - handleAcquiredBeforeAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredBefore: + handleAcquiredBeforeAttr(S, D, AL); break; - case AttributeList::AT_AcquiredAfter: - handleAcquiredAfterAttr(S, D, Attr); + case ParsedAttr::AT_AcquiredAfter: + handleAcquiredAfterAttr(S, D, AL); break; // Capability analysis attributes. - case AttributeList::AT_Capability: - case AttributeList::AT_Lockable: - handleCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_Capability: + case ParsedAttr::AT_Lockable: + handleCapabilityAttr(S, D, AL); break; - case AttributeList::AT_RequiresCapability: - handleRequiresCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_RequiresCapability: + handleRequiresCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AssertCapability: - handleAssertCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AssertCapability: + handleAssertCapabilityAttr(S, D, AL); break; - case AttributeList::AT_AcquireCapability: - handleAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_AcquireCapability: + handleAcquireCapabilityAttr(S, D, AL); break; - case AttributeList::AT_ReleaseCapability: - handleReleaseCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_ReleaseCapability: + handleReleaseCapabilityAttr(S, D, AL); break; - case AttributeList::AT_TryAcquireCapability: - handleTryAcquireCapabilityAttr(S, D, Attr); + case ParsedAttr::AT_TryAcquireCapability: + handleTryAcquireCapabilityAttr(S, D, AL); break; // Consumed analysis attributes. - case AttributeList::AT_Consumable: - handleConsumableAttr(S, D, Attr); + case ParsedAttr::AT_Consumable: + handleConsumableAttr(S, D, AL); break; - case AttributeList::AT_ConsumableAutoCast: - handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableAutoCast: + handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL); break; - case AttributeList::AT_ConsumableSetOnRead: - handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, Attr); + case ParsedAttr::AT_ConsumableSetOnRead: + handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL); break; - case AttributeList::AT_CallableWhen: - handleCallableWhenAttr(S, D, Attr); + case ParsedAttr::AT_CallableWhen: + handleCallableWhenAttr(S, D, AL); break; - case AttributeList::AT_ParamTypestate: - handleParamTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ParamTypestate: + handleParamTypestateAttr(S, D, AL); break; - case AttributeList::AT_ReturnTypestate: - handleReturnTypestateAttr(S, D, Attr); + case ParsedAttr::AT_ReturnTypestate: + handleReturnTypestateAttr(S, D, AL); break; - case AttributeList::AT_SetTypestate: - handleSetTypestateAttr(S, D, Attr); + case ParsedAttr::AT_SetTypestate: + handleSetTypestateAttr(S, D, AL); break; - case AttributeList::AT_TestTypestate: - handleTestTypestateAttr(S, D, Attr); + case ParsedAttr::AT_TestTypestate: + handleTestTypestateAttr(S, D, AL); break; // Type safety attributes. - case AttributeList::AT_ArgumentWithTypeTag: - handleArgumentWithTypeTagAttr(S, D, Attr); + case ParsedAttr::AT_ArgumentWithTypeTag: + handleArgumentWithTypeTagAttr(S, D, AL); break; - case AttributeList::AT_TypeTagForDatatype: - handleTypeTagForDatatypeAttr(S, D, Attr); + case ParsedAttr::AT_TypeTagForDatatype: + handleTypeTagForDatatypeAttr(S, D, AL); break; - case AttributeList::AT_AnyX86NoCallerSavedRegisters: - handleNoCallerSavedRegsAttr(S, D, Attr); + case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: + handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL); break; - case AttributeList::AT_RenderScriptKernel: - handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); + case ParsedAttr::AT_RenderScriptKernel: + handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL); break; // XRay attributes. - case AttributeList::AT_XRayInstrument: - handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + case ParsedAttr::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL); break; - case AttributeList::AT_XRayLogArgs: - handleXRayLogArgsAttr(S, D, Attr); + case ParsedAttr::AT_XRayLogArgs: + handleXRayLogArgsAttr(S, D, AL); break; } } @@ -6583,18 +6607,21 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, - const AttributeList *AttrList, + const ParsedAttributesView &AttrList, bool IncludeCXX11Attributes) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) - ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes); + if (AttrList.empty()) + return; + + for (const ParsedAttr &AL : AttrList) + ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes); // FIXME: We should be able to handle these cases in TableGen. // GCC accepts // static int a9 __attribute__((weakref)); // but that looks really pointless. We reject it. if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { - Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) - << cast<NamedDecl>(D); + Diag(AttrList.begin()->getLoc(), diag::err_attribute_weakref_without_alias) + << cast<NamedDecl>(D); D->dropAttr<WeakRefAttr>(); return; } @@ -6605,79 +6632,83 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, // 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>()) { + if (const auto *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(); - } else if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) { + } else if (const auto *A = D->getAttr<WorkGroupSizeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) { + } else if (const auto *A = D->getAttr<VecTypeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { - Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; - D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { - 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(); - } 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<OpenCLIntelReqdSubGroupSizeAttr>()) { + } else if (const auto *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); + } else if (!D->hasAttr<CUDAGlobalAttr>()) { + if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } } } } // Helper for delayed processing TransparentUnion attribute. -void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) { - for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext()) - if (Attr->getKind() == AttributeList::AT_TransparentUnion) { - handleTransparentUnionAttr(*this, D, *Attr); +void Sema::ProcessDeclAttributeDelayed(Decl *D, + const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) + if (AL.getKind() == ParsedAttr::AT_TransparentUnion) { + handleTransparentUnionAttr(*this, D, AL); break; } } // Annotation attributes are the only attributes allowed after an access // specifier. -bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, - const AttributeList *AttrList) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - if (l->getKind() == AttributeList::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, *l, l->isCXX11Attribute()); +bool Sema::ProcessAccessDeclAttributeList( + AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) { + for (const ParsedAttr &AL : AttrList) { + if (AL.getKind() == ParsedAttr::AT_Annotate) { + ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute()); } else { - Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec); return true; } } - return false; } /// checkUnusedDeclAttributes - Check a list of attributes to see if it /// contains any decl attributes that we should warn about. -static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { - for ( ; A; A = A->getNext()) { +static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) { + for (const ParsedAttr &AL : A) { // Only warn if the attribute is an unignored, non-type attribute. - if (A->isUsedAsTypeAttr() || A->isInvalid()) continue; - if (A->getKind() == AttributeList::IgnoredAttribute) continue; + if (AL.isUsedAsTypeAttr() || AL.isInvalid()) + continue; + if (AL.getKind() == ParsedAttr::IgnoredAttribute) + continue; - if (A->getKind() == AttributeList::UnknownAttribute) { - S.Diag(A->getLoc(), diag::warn_unknown_attribute_ignored) - << A->getName() << A->getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) { + S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL.getName() << AL.getRange(); } else { - S.Diag(A->getLoc(), diag::warn_attribute_not_on_decl) - << A->getName() << A->getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) + << AL.getName() << AL.getRange(); } } } @@ -6686,7 +6717,7 @@ static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { /// used to build a declaration, complain about any decl attributes /// which might be lying around on it. void Sema::checkUnusedDeclAttributes(Declarator &D) { - ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes().getList()); + ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes()); ::checkUnusedDeclAttributes(*this, D.getAttributes()); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); @@ -6698,7 +6729,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc) { assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND)); NamedDecl *NewD = nullptr; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) { FunctionDecl *NewFD; // FIXME: Missing call to CheckFunctionDeclaration(). // FIXME: Mangling? @@ -6718,7 +6749,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, // Fake up parameter variables; they are declared as if this were // a typedef. QualType FDTy = FD->getType(); - if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) { + if (const auto *FT = FDTy->getAs<FunctionProtoType>()) { SmallVector<ParmVarDecl*, 16> Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); @@ -6727,15 +6758,13 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, } NewFD->setParams(Params); } - } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { + } else if (auto *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getInnerLocStart(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); - if (VD->getQualifier()) { - VarDecl *NewVD = cast<VarDecl>(NewD); - NewVD->setQualifierInfo(VD->getQualifierLoc()); - } + if (VD->getQualifier()) + cast<VarDecl>(NewD)->setQualifierInfo(VD->getQualifierLoc()); } return NewD; } @@ -6771,10 +6800,10 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { LoadExternalWeakUndeclaredIdentifiers(); if (!WeakUndeclaredIdentifiers.empty()) { NamedDecl *ND = nullptr; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (auto *VD = dyn_cast<VarDecl>(D)) if (VD->isExternC()) ND = VD; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (auto *FD = dyn_cast<FunctionDecl>(D)) if (FD->isExternC()) ND = FD; if (ND) { @@ -6795,20 +6824,19 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // Apply decl attributes from the DeclSpec if present. - if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, D, Attrs); + if (!PD.getDeclSpec().getAttributes().empty()) + ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes()); // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: // int *__attr__(x)** D; // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) - if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs, /*IncludeCXX11Attributes=*/false); + ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(), + /*IncludeCXX11Attributes=*/false); // Finally, apply any attributes on the decl itself. - if (const AttributeList *Attrs = PD.getAttributes()) - ProcessDeclAttributeList(S, D, Attrs); + ProcessDeclAttributeList(S, D, PD.getAttributes()); // Apply additional attributes specified by '#pragma clang attribute'. AddPragmaAttributes(S, D); @@ -6817,14 +6845,14 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { /// Is the given declaration allowed to use a forbidden type? /// If so, it'll still be annotated with an attribute that makes it /// illegal to actually use. -static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, +static bool isForbiddenTypeAllowed(Sema &S, Decl *D, const DelayedDiagnostic &diag, UnavailableAttr::ImplicitReason &reason) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && - !isa<FunctionDecl>(decl)) + if (!isa<FieldDecl>(D) && !isa<ObjCPropertyDecl>(D) && + !isa<FunctionDecl>(D)) return false; // Silently accept unsupported uses of __weak in both user and system @@ -6832,7 +6860,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, // -fno-objc-arc files. We do have to take some care against attempts // to define such things; for now, we've only done that for ivars // and properties. - if ((isa<ObjCIvarDecl>(decl) || isa<ObjCPropertyDecl>(decl))) { + if ((isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) { if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled || diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) { reason = UnavailableAttr::IR_ForbiddenWeak; @@ -6841,7 +6869,7 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } // Allow all sorts of things in system headers. - if (S.Context.getSourceManager().isInSystemHeader(decl->getLocation())) { + if (S.Context.getSourceManager().isInSystemHeader(D->getLocation())) { // Currently, all the failures dealt with this way are due to ARC // restrictions. reason = UnavailableAttr::IR_ARCForbiddenType; @@ -6852,30 +6880,29 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, } /// Handle a delayed forbidden-type diagnostic. -static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, - Decl *decl) { - auto reason = UnavailableAttr::IR_None; - if (decl && isForbiddenTypeAllowed(S, decl, diag, reason)) { - assert(reason && "didn't set reason?"); - decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", reason, - diag.Loc)); +static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD, + Decl *D) { + auto Reason = UnavailableAttr::IR_None; + if (D && isForbiddenTypeAllowed(S, D, DD, Reason)) { + assert(Reason && "didn't set reason?"); + D->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", Reason, DD.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(decl)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // FIXME: we may want to suppress diagnostics for all - // kind of forbidden type messages on unavailable functions. + // kind of forbidden type messages on unavailable functions. if (FD->hasAttr<UnavailableAttr>() && - diag.getForbiddenTypeDiagnostic() == - diag::err_arc_array_param_no_ownership) { - diag.Triggered = true; + DD.getForbiddenTypeDiagnostic() == + diag::err_arc_array_param_no_ownership) { + DD.Triggered = true; return; } } - S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) - << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument(); - diag.Triggered = true; + S.Diag(DD.Loc, DD.getForbiddenTypeDiagnostic()) + << DD.getForbiddenTypeOperand() << DD.getForbiddenTypeArgument(); + DD.Triggered = true; } static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, @@ -6918,9 +6945,9 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { // For typedefs, if the typedef declaration appears available look // to the underlying type to see if it is more restrictive. - while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { if (Result == AR_Available) { - if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { + if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); Result = D->getAvailability(Message); continue; @@ -6930,7 +6957,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } // Forward class declarations get their attributes from their definition. - if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); Result = D->getAvailability(Message); @@ -6950,7 +6977,7 @@ ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message) { } -/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in +/// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, @@ -6973,40 +7000,24 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return false; }; - // FIXME: This is a temporary workaround! Some existing Apple headers depends - // on nested declarations in an @interface having the availability of the - // interface when they really shouldn't: they are members of the enclosing - // context, and can referenced from there. - if (S.OriginalLexicalContext && cast<Decl>(S.OriginalLexicalContext) != Ctx) { - auto *OrigCtx = cast<Decl>(S.OriginalLexicalContext); - if (CheckContext(OrigCtx)) - return false; - - // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(OrigCtx)) { - if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(OrigCtx)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - do { if (CheckContext(Ctx)) return false; // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { + // Unless it is "+load" method. + if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) + if (MethodD->isClassMethod() && + MethodD->getSelector().getAsString() == "load") + return true; + + if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) if (CheckContext(Interface)) return false; } // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) + else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) if (CheckContext(Interface)) return false; @@ -7076,6 +7087,45 @@ struct AttributeInsertion { } // end anonymous namespace +/// Tries to parse a string as ObjC method name. +/// +/// \param Name The string to parse. Expected to originate from availability +/// attribute argument. +/// \param SlotNames The vector that will be populated with slot names. In case +/// of unsuccessful parsing can contain invalid data. +/// \returns A number of method parameters if parsing was successful, None +/// otherwise. +static Optional<unsigned> +tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, + const LangOptions &LangOpts) { + // Accept replacements starting with - or + as valid ObjC method names. + if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) + Name = Name.drop_front(1); + if (Name.empty()) + return None; + Name.split(SlotNames, ':'); + unsigned NumParams; + if (Name.back() == ':') { + // Remove an empty string at the end that doesn't represent any slot. + SlotNames.pop_back(); + NumParams = SlotNames.size(); + } else { + if (SlotNames.size() != 1) + // Not a valid method name, just a colon-separated string. + return None; + NumParams = 0; + } + // Verify all slot names are valid. + bool AllowDollar = LangOpts.DollarIdents; + for (StringRef S : SlotNames) { + if (S.empty()) + continue; + if (!isValidIdentifier(S, AllowDollar)) + return None; + } + return NumParams; +} + /// Returns a source location in which it's appropriate to insert a new /// attribute for the given declaration \D. static Optional<AttributeInsertion> @@ -7105,14 +7155,15 @@ createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, /// \param Ctx The context that the reference occurred in /// \param ReferringDecl The exact declaration that was referenced. /// \param OffendingDecl A related decl to \c ReferringDecl that has an -/// availability attribute corrisponding to \c K attached to it. Note that this +/// availability attribute corresponding to \c K attached to it. Note that this /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl /// and OffendingDecl is the EnumDecl. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7134,6 +7185,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) return; + SourceLocation Loc = Locs.front(); + // The declaration can have multiple availability attributes, we are looking // at one of them. const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); @@ -7177,7 +7230,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, << OffendingDecl << /* partial */ 3; if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) if (TD->getDeclName().isEmpty()) { S.Diag(TD->getLocation(), diag::note_decl_unguarded_availability_silence) @@ -7218,8 +7271,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - NoteLocation = Attr->getLocation(); + if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) + NoteLocation = AL->getLocation(); break; case AR_Unavailable: @@ -7230,8 +7283,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto Attr = OffendingDecl->getAttr<UnavailableAttr>()) { - if (Attr->isImplicit() && Attr->getImplicitReason()) { + if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { + if (AL->isImplicit() && AL->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { @@ -7241,7 +7294,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag = diag::err_unavailable_in_arc; }; - switch (Attr->getImplicitReason()) { + switch (AL->getImplicitReason()) { case UnavailableAttr::IR_None: break; case UnavailableAttr::IR_ARCForbiddenType: @@ -7279,37 +7332,55 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, llvm_unreachable("Warning for availability of available declaration?"); } - CharSourceRange UseRange; - StringRef Replacement; + SmallVector<FixItHint, 12> FixIts; if (K == AR_Deprecated) { - if (auto Attr = OffendingDecl->getAttr<DeprecatedAttr>()) - Replacement = Attr->getReplacement(); - if (auto Attr = getAttrForPlatform(S.Context, OffendingDecl)) - Replacement = Attr->getReplacement(); + StringRef Replacement; + if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) + Replacement = AL->getReplacement(); + if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) + Replacement = AL->getReplacement(); + CharSourceRange UseRange; if (!Replacement.empty()) UseRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + if (UseRange.isValid()) { + if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { + Selector Sel = MethodDecl->getSelector(); + SmallVector<StringRef, 12> SelectorSlotNames; + Optional<unsigned> NumParams = tryParseObjCMethodName( + Replacement, SelectorSlotNames, S.getLangOpts()); + if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { + assert(SelectorSlotNames.size() == Locs.size()); + for (unsigned I = 0; I < Locs.size(); ++I) { + if (!Sel.getNameForSlot(I).empty()) { + CharSourceRange NameRange = CharSourceRange::getCharRange( + Locs[I], S.getLocForEndOfToken(Locs[I])); + FixIts.push_back(FixItHint::CreateReplacement( + NameRange, SelectorSlotNames[I])); + } else + FixIts.push_back( + FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); + } + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } } if (!Message.empty()) { - S.Diag(Loc, diag_message) << ReferringDecl << Message - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag) << ReferringDecl << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << ReferringDecl - << (UseRange.isValid() ? - FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } @@ -7325,8 +7396,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), - DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), + DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7387,7 +7459,8 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, - StringRef Message, SourceLocation Loc, + StringRef Message, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { @@ -7395,14 +7468,14 @@ static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { S.DelayedDiagnostics.add( DelayedDiagnostic::makeAvailability( - AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Loc, UnknownObjCClass, ObjCProperty, + Message, Locs, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } @@ -7471,7 +7544,7 @@ public: } }; -/// \brief This class implements -Wunguarded-availability. +/// This class implements -Wunguarded-availability. /// /// This is done with a traversal of the AST of a function that makes reference /// to a partially available declaration. Whenever we encounter an \c if of the @@ -7642,7 +7715,7 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SourceLocation StmtEndLoc = SM.getExpansionRange( (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getLocEnd()) - .second; + .getEnd(); if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) return; @@ -7681,11 +7754,11 @@ bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { if (Range.isInvalid()) return true; - if (const TagType *TT = dyn_cast<TagType>(TyPtr)) { + if (const auto *TT = dyn_cast<TagType>(TyPtr)) { TagDecl *TD = TT->getDecl(); DiagnoseDeclAvailability(TD, Range); - } else if (const TypedefType *TD = dyn_cast<TypedefType>(TyPtr)) { + } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { TypedefNameDecl *D = TD->getDecl(); DiagnoseDeclAvailability(D, Range); @@ -7740,7 +7813,8 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); } -void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, +void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, + ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { @@ -7769,7 +7843,7 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); if (PDeclResult == Result) @@ -7777,6 +7851,6 @@ void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, SourceLocation Loc, } } - EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Loc, + EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 5e24649c71be..4cf3abdf5745 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/ComparisonCategories.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -170,43 +171,40 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, if (EST == EST_None && Method->hasAttr<NoThrowAttr>()) EST = EST_BasicNoexcept; - switch(EST) { + switch (EST) { + case EST_Unparsed: + case EST_Uninstantiated: + case EST_Unevaluated: + llvm_unreachable("should not see unresolved exception specs here"); + // If this function can throw any exceptions, make a note of that. case EST_MSAny: case EST_None: + // FIXME: Whichever we see last of MSAny and None determines our result. + // We should make a consistent, order-independent choice here. ClearExceptions(); ComputedEST = EST; return; + case EST_NoexceptFalse: + ClearExceptions(); + ComputedEST = EST_None; + return; // FIXME: If the call to this decl is using any of its default arguments, we // need to search them for potentially-throwing calls. // If this function has a basic noexcept, it doesn't affect the outcome. case EST_BasicNoexcept: + case EST_NoexceptTrue: return; - // If we're still at noexcept(true) and there's a nothrow() callee, + // If we're still at noexcept(true) and there's a throw() callee, // change to that specification. case EST_DynamicNone: if (ComputedEST == EST_BasicNoexcept) ComputedEST = EST_DynamicNone; return; - // Check out noexcept specs. - case EST_ComputedNoexcept: - { - FunctionProtoType::NoexceptResult NR = - Proto->getNoexceptSpec(Self->Context); - assert(NR != FunctionProtoType::NR_NoNoexcept && - "Must have noexcept result for EST_ComputedNoexcept."); - assert(NR != FunctionProtoType::NR_Dependent && - "Should not generate implicit declarations for dependent cases, " - "and don't know how to handle them anyway."); - // noexcept(false) -> no spec on the new function - if (NR == FunctionProtoType::NR_Throw) { - ClearExceptions(); - ComputedEST = EST_None; - } - // noexcept(true) won't change anything either. - return; - } - default: + case EST_DependentNoexcept: + llvm_unreachable( + "should not generate implicit declarations for dependent cases"); + case EST_Dynamic: break; } assert(EST == EST_Dynamic && "EST case not considered earlier."); @@ -1459,7 +1457,7 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) { DD->setInvalidDecl(); } -/// \brief Merge the exception specifications of two variable declarations. +/// Merge the exception specifications of two variable declarations. /// /// This is called when there's a redeclaration of a VarDecl. The function /// checks if the redeclaration might have an exception specification and @@ -1575,7 +1573,7 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, return true; } -/// \brief Get diagnostic %select index for tag kind for +/// Get diagnostic %select index for tag kind for /// record diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// @@ -2061,27 +2059,39 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { return true; } +/// Get the class that is directly named by the current context. This is the +/// class for which an unqualified-id in this scope could name a constructor +/// or destructor. +/// +/// If the scope specifier denotes a class, this will be that class. +/// If the scope specifier is empty, this will be the class whose +/// member-specification we are currently within. Otherwise, there +/// is no such class. +CXXRecordDecl *Sema::getCurrentClass(Scope *, const CXXScopeSpec *SS) { + assert(getLangOpts().CPlusPlus && "No class names in C!"); + + if (SS && SS->isInvalid()) + return nullptr; + + if (SS && SS->isNotEmpty()) { + DeclContext *DC = computeDeclContext(*SS, true); + return dyn_cast_or_null<CXXRecordDecl>(DC); + } + + return dyn_cast_or_null<CXXRecordDecl>(CurContext); +} + /// isCurrentClassName - Determine whether the identifier II is the /// name of the class type currently being defined. In the case of /// nested classes, this will only return true if II is the name of /// the innermost class. -bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, +bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS) { - assert(getLangOpts().CPlusPlus && "No class names in C!"); - - CXXRecordDecl *CurDecl; - if (SS && SS->isSet() && !SS->isInvalid()) { - DeclContext *DC = computeDeclContext(*SS, true); - CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); - } else - CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); - - if (CurDecl && CurDecl->getIdentifier()) - return &II == CurDecl->getIdentifier(); - return false; + CXXRecordDecl *CurDecl = getCurrentClass(S, SS); + return CurDecl && &II == CurDecl->getIdentifier(); } -/// \brief Determine whether the identifier II is a typo for the name of +/// Determine whether the identifier II is a typo for the name of /// the class type currently being defined. If so, update it to the identifier /// that should have been used. bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) { @@ -2107,7 +2117,7 @@ bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) { return false; } -/// \brief Determine whether the given class is a base class of the given +/// Determine whether the given class is a base class of the given /// class, including looking at dependent bases. static bool findCircularInheritance(const CXXRecordDecl *Class, const CXXRecordDecl *Current) { @@ -2139,7 +2149,7 @@ static bool findCircularInheritance(const CXXRecordDecl *Class, return false; } -/// \brief Check the validity of a C++ base class specifier. +/// Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics /// and returns NULL otherwise. @@ -2233,6 +2243,19 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, CXXRecordDecl *CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); + // Microsoft docs say: + // "If a base-class has a code_seg attribute, derived classes must have the + // same attribute." + const auto *BaseCSA = CXXBaseDecl->getAttr<CodeSegAttr>(); + const auto *DerivedCSA = Class->getAttr<CodeSegAttr>(); + if ((DerivedCSA || BaseCSA) && + (!BaseCSA || !DerivedCSA || BaseCSA->getName() != DerivedCSA->getName())) { + Diag(Class->getLocation(), diag::err_mismatched_code_seg_base); + Diag(CXXBaseDecl->getLocation(), diag::note_base_class_specified_here) + << CXXBaseDecl; + return nullptr; + } + // A class which contains a flexible array member is not suitable for use as a // base class: // - If the layout determines that a base comes before another base, @@ -2290,18 +2313,13 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, // We do not support any C++11 attributes on base-specifiers yet. // Diagnose any attributes we see. - if (!Attributes.empty()) { - for (AttributeList *Attr = Attributes.getList(); Attr; - Attr = Attr->getNext()) { - if (Attr->isInvalid() || - Attr->getKind() == AttributeList::IgnoredAttribute) - continue; - Diag(Attr->getLoc(), - Attr->getKind() == AttributeList::UnknownAttribute - ? diag::warn_unknown_attribute_ignored - : diag::err_base_specifier_attribute) - << Attr->getName(); - } + for (const ParsedAttr &AL : Attributes) { + if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) + continue; + Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute + ? diag::warn_unknown_attribute_ignored + : diag::err_base_specifier_attribute) + << AL.getName(); } TypeSourceInfo *TInfo = nullptr; @@ -2326,7 +2344,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, /// locally, there's no need to abstract the small size parameter. typedef llvm::SmallPtrSet<QualType, 4> IndirectBaseSet; -/// \brief Recursively add the bases of Type. Don't add Type itself. +/// Recursively add the bases of Type. Don't add Type itself. static void NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set, const QualType &Type) @@ -2347,7 +2365,7 @@ NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set, } } -/// \brief Performs the actual work of attaching the given base class +/// Performs the actual work of attaching the given base class /// specifiers to a C++ class. bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, MutableArrayRef<CXXBaseSpecifier *> Bases) { @@ -2404,7 +2422,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, // The Microsoft extension __interface does not permit bases that // are not themselves public interfaces. Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface) - << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName() + << getRecordDiagFromTagKind(RD->getTagKind()) << RD << RD->getSourceRange(); Invalid = true; } @@ -2417,9 +2435,16 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, // Attach the remaining base class specifiers to the derived class. Class->setBases(Bases.data(), NumGoodBases); + // Check that the only base classes that are duplicate are virtual. for (unsigned idx = 0; idx < NumGoodBases; ++idx) { // Check whether this direct base is inaccessible due to ambiguity. QualType BaseType = Bases[idx]->getType(); + + // Skip all dependent types in templates being used as base specifiers. + // Checks below assume that the base specifier is a CXXRecord. + if (BaseType->isDependentType()) + continue; + CanQualType CanonicalBase = Context.getCanonicalType(BaseType) .getUnqualifiedType(); @@ -2459,7 +2484,7 @@ void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl), Bases); } -/// \brief Determine whether the type \p Derived is a C++ class that is +/// Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) { if (!getLangOpts().CPlusPlus) @@ -2486,7 +2511,7 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base) { return DerivedRD->isDerivedFrom(BaseRD); } -/// \brief Determine whether the type \p Derived is a C++ class that is +/// Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths) { @@ -2638,7 +2663,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, } -/// @brief Builds a string representing ambiguous paths from a +/// Builds a string representing ambiguous paths from a /// specific derived class to different subobjects of the same base /// class. /// @@ -2674,10 +2699,9 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. -bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, +bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, - AttributeList *Attrs) { + const ParsedAttributesView &Attrs) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); @@ -2764,7 +2788,7 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { SourceLocation Loc = MD->getLocation(); SourceLocation SpellingLoc = Loc; if (getSourceManager().isMacroArgExpansion(Loc)) - SpellingLoc = getSourceManager().getImmediateExpansionRange(Loc).first; + SpellingLoc = getSourceManager().getImmediateExpansionRange(Loc).getBegin(); SpellingLoc = getSourceManager().getSpellingLoc(SpellingLoc); if (SpellingLoc.isValid() && getSourceManager().isInSystemHeader(SpellingLoc)) return; @@ -2805,10 +2829,13 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } -static AttributeList *getMSPropertyAttr(AttributeList *list) { - for (AttributeList *it = list; it != nullptr; it = it->getNext()) - if (it->isDeclspecPropertyAttribute()) - return it; +static const ParsedAttr *getMSPropertyAttr(const ParsedAttributesView &list) { + ParsedAttributesView::const_iterator Itr = + llvm::find_if(list, [](const ParsedAttr &AL) { + return AL.isDeclspecPropertyAttribute(); + }); + if (Itr != list.end()) + return &*Itr; return nullptr; } @@ -2855,7 +2882,7 @@ void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, if (AS_none != CXXRecordDecl::MergeAccess(P.Access, BaseField->getAccess())) { Diag(Loc, diag::warn_shadow_field) - << FieldName.getAsString() << RD->getName() << Base->getName(); + << FieldName << RD << Base; Diag(BaseField->getLocation(), diag::note_shadow_field); Bases.erase(It); } @@ -2887,8 +2914,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert(!DS.isFriendSpecified()); bool isFunc = D.isDeclarationOfFunction(); - AttributeList *MSPropertyAttr = - getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); + const ParsedAttr *MSPropertyAttr = + getMSPropertyAttr(D.getDeclSpec().getAttributes()); if (cast<CXXRecordDecl>(CurContext)->isInterface()) { // The Microsoft extension __interface only permits public member functions @@ -3044,7 +3071,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // int X::member; // }; if (DeclContext *DC = computeDeclContext(SS, false)) - diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc()); + diagnoseQualifiedDeclaration(SS, DC, Name, D.getIdentifierLoc(), + D.getName().getKind() == + UnqualifiedIdKind::IK_TemplateId); else Diag(D.getIdentifierLoc(), diag::err_member_qualification) << Name << SS.getRange(); @@ -3054,7 +3083,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (MSPropertyAttr) { Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D, - BitWidth, InitStyle, AS, MSPropertyAttr); + BitWidth, InitStyle, AS, *MSPropertyAttr); if (!Member) return nullptr; isInstField = false; @@ -3096,14 +3125,38 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Member->setInvalidDecl(); } + NamedDecl *NonTemplateMember = Member; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) + NonTemplateMember = FunTmpl->getTemplatedDecl(); + else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member)) + NonTemplateMember = VarTmpl->getTemplatedDecl(); + Member->setAccess(AS); // If we have declared a member function template or static data member // template, set the access of the templated declaration as well. - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) - FunTmpl->getTemplatedDecl()->setAccess(AS); - else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member)) - VarTmpl->getTemplatedDecl()->setAccess(AS); + if (NonTemplateMember != Member) + NonTemplateMember->setAccess(AS); + + // C++ [temp.deduct.guide]p3: + // A deduction guide [...] for a member class template [shall be + // declared] with the same access [as the template]. + if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(NonTemplateMember)) { + auto *TD = DG->getDeducedTemplate(); + if (AS != TD->getAccess()) { + Diag(DG->getLocStart(), diag::err_deduction_guide_wrong_access); + Diag(TD->getLocStart(), diag::note_deduction_guide_template_access) + << TD->getAccess(); + const AccessSpecDecl *LastAccessSpec = nullptr; + for (const auto *D : cast<CXXRecordDecl>(CurContext)->decls()) { + if (const auto *AccessSpec = dyn_cast<AccessSpecDecl>(D)) + LastAccessSpec = AccessSpec; + } + assert(LastAccessSpec && "differing access with no access specifier"); + Diag(LastAccessSpec->getLocStart(), diag::note_deduction_guide_access) + << AS; + } + } } if (VS.isOverrideSpecified()) @@ -3544,7 +3597,7 @@ namespace { } } // namespace -/// \brief Enter a new C++ default initializer scope. After calling this, the +/// Enter a new C++ default initializer scope. After calling this, the /// caller must call \ref ActOnFinishCXXInClassMemberInitializer, even if /// parsing or instantiating the initializer failed. void Sema::ActOnStartCXXInClassMemberInitializer() { @@ -3553,7 +3606,7 @@ void Sema::ActOnStartCXXInClassMemberInitializer() { PushFunctionScope(); } -/// \brief This is invoked after parsing an in-class initializer for a +/// This is invoked after parsing an in-class initializer for a /// non-static C++ class member, and after instantiating an in-class initializer /// in a class template. Such actions are deferred until the class is complete. void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, @@ -3581,10 +3634,14 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, ExprResult Init = InitExpr; if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { - InitializedEntity Entity = InitializedEntity::InitializeMember(FD); - InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit - ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) - : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); + InitializedEntity Entity = + InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD); + InitializationKind Kind = + FD->getInClassInitStyle() == ICIS_ListInit + ? InitializationKind::CreateDirectList(InitExpr->getLocStart(), + InitExpr->getLocStart(), + InitExpr->getLocEnd()) + : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); InitializationSequence Seq(*this, Entity, Kind, InitExpr); Init = Seq.Perform(*this, Entity, Kind, InitExpr); if (Init.isInvalid()) { @@ -3607,7 +3664,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, FD->setInClassInitializer(InitExpr); } -/// \brief Find the direct and/or virtual base specifiers that +/// Find the direct and/or virtual base specifiers that /// correspond to the given base type, for use in base initialization /// within a constructor. static bool FindBaseInitializer(Sema &SemaRef, @@ -3651,7 +3708,7 @@ static bool FindBaseInitializer(Sema &SemaRef, return DirectBaseSpec || VirtualBaseSpec; } -/// \brief Handle a C++ member initializer using braced-init-list syntax. +/// Handle a C++ member initializer using braced-init-list syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, @@ -3667,7 +3724,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, EllipsisLoc); } -/// \brief Handle a C++ member initializer using parentheses syntax. +/// Handle a C++ member initializer using parentheses syntax. MemInitResult Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, @@ -3710,7 +3767,7 @@ private: } -/// \brief Handle a C++ member initializer. +/// Handle a C++ member initializer. MemInitResult Sema::BuildMemInitializer(Decl *ConstructorD, Scope *S, @@ -3889,53 +3946,6 @@ Sema::BuildMemInitializer(Decl *ConstructorD, return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, EllipsisLoc); } -/// Checks a member initializer expression for cases where reference (or -/// pointer) members are bound to by-value parameters (or their addresses). -static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, - Expr *Init, - SourceLocation IdLoc) { - QualType MemberTy = Member->getType(); - - // We only handle pointers and references currently. - // FIXME: Would this be relevant for ObjC object pointers? Or block pointers? - if (!MemberTy->isReferenceType() && !MemberTy->isPointerType()) - return; - - const bool IsPointer = MemberTy->isPointerType(); - if (IsPointer) { - if (const UnaryOperator *Op - = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) { - // The only case we're worried about with pointers requires taking the - // address. - if (Op->getOpcode() != UO_AddrOf) - return; - - Init = Op->getSubExpr(); - } else { - // We only handle address-of expression initializers for pointers. - return; - } - } - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { - // We only warn when referring to a non-reference parameter declaration. - const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl()); - if (!Parameter || Parameter->getType()->isReferenceType()) - return; - - S.Diag(Init->getExprLoc(), - IsPointer ? diag::warn_init_ptr_member_to_parameter_addr - : diag::warn_bind_ref_member_to_parameter) - << Member << Parameter << Init->getSourceRange(); - } else { - // Other initializers are fine. - return; - } - - S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) - << (unsigned)IsPointer; -} - MemInitResult Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { @@ -3979,9 +3989,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, : InitializedEntity::InitializeMember(IndirectMember, nullptr); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(IdLoc) - : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList( + IdLoc, Init->getLocStart(), Init->getLocEnd()) + : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, @@ -3989,8 +4000,6 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, if (MemberInit.isInvalid()) return true; - CheckForDanglingReferenceOrPointer(*this, Member, MemberInit.get(), IdLoc); - // C++11 [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. @@ -4033,9 +4042,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( QualType(ClassDecl->getTypeForDecl(), 0)); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(NameLoc) - : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList( + NameLoc, Init->getLocStart(), Init->getLocEnd()) + : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, Args, nullptr); @@ -4167,9 +4177,9 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitializedEntity BaseEntity = InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = - InitList ? InitializationKind::CreateDirectList(BaseLoc) - : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), - InitRange.getEnd()); + InitList ? InitializationKind::CreateDirectList(BaseLoc) + : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), + InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, nullptr); if (BaseInit.isInvalid()) @@ -4321,7 +4331,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, QualType ParamType = Param->getType().getNonReferenceType(); // Suppress copying zero-width bitfields. - if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0) + if (Field->isZeroLengthBitField(SemaRef.Context)) return false; Expr *MemberExprBase = @@ -4536,7 +4546,7 @@ struct BaseAndFieldInfo { return !FieldRD->hasInClassInitializer(); } - /// \brief Determine whether the given field is, or is within, a union member + /// Determine whether the given field is, or is within, a union member /// that is inactive (because there was an initializer given for a different /// member of the union, or because the union was not initialized at all). bool isWithinInactiveUnionMember(FieldDecl *Field, @@ -4554,7 +4564,7 @@ struct BaseAndFieldInfo { }; } -/// \brief Determine whether the given type is an incomplete or zero-lenfgth +/// Determine whether the given type is an incomplete or zero-lenfgth /// array type. static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { if (T->isIncompleteArrayType()) @@ -4601,6 +4611,10 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field); if (DIE.isInvalid()) return true; + + auto Entity = InitializedEntity::InitializeMember(Field, nullptr, true); + SemaRef.checkInitializerLifetime(Entity, DIE.get()); + CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) @@ -5464,7 +5478,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, } } -static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { +static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); if (!ClassAttr) return; @@ -5479,6 +5493,14 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { return; for (Decl *Member : Class->decls()) { + // Defined static variables that are members of an exported base + // class must be marked export too. + auto *VD = dyn_cast<VarDecl>(Member); + if (VD && Member->getAttr<DLLExportAttr>() && + VD->getStorageClass() == SC_Static && + TSK == TSK_ImplicitInstantiation) + S.MarkVariableReferenced(VD->getLocation(), VD); + auto *MD = dyn_cast<CXXMethodDecl>(Member); if (!MD) continue; @@ -5506,7 +5528,7 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) { S.MarkFunctionReferenced(Class->getLocation(), MD); if (Trap.hasErrorOccurred()) { S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) - << Class->getName() << !S.getLangOpts().CPlusPlus11; + << Class << !S.getLangOpts().CPlusPlus11; break; } @@ -5556,7 +5578,17 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, } } -/// \brief Check class-level dllimport/dllexport attribute. +void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) { + // Mark any compiler-generated routines with the implicit code_seg attribute. + for (auto *Method : Class->methods()) { + if (Method->isUserProvided()) + continue; + if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true)) + Method->addAttr(A); + } +} + +/// Check class-level dllimport/dllexport attribute. void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); @@ -5606,6 +5638,13 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // The class is either imported or exported. const bool ClassExported = ClassAttr->getKind() == attr::DLLExport; + // Check if this was a dllimport attribute propagated from a derived class to + // a base class template specialization. We don't apply these attributes to + // static data members. + const bool PropagatedImport = + !ClassExported && + cast<DLLImportAttr>(ClassAttr)->wasPropagatedToBaseTemplate(); + TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); // Ignore explicit dllexport on explicit class template instantiation declarations. @@ -5657,6 +5696,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { } } + // Don't apply dllimport attributes to static data members of class template + // instantiations when the attribute is propagated from a derived class. + if (VD && PropagatedImport) + continue; + if (!cast<NamedDecl>(Member)->isExternallyVisible()) continue; @@ -5665,6 +5709,21 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { cast<InheritableAttr>(ClassAttr->clone(getASTContext())); NewAttr->setInherited(true); Member->addAttr(NewAttr); + + if (MD) { + // Propagate DLLAttr to friend re-declarations of MD that have already + // been constructed. + for (FunctionDecl *FD = MD->getMostRecentDecl(); FD; + FD = FD->getPreviousDecl()) { + if (FD->getFriendObjectKind() == Decl::FOK_None) + continue; + assert(!getDLLAttr(FD) && + "friend re-decl should not already have a DLLAttr"); + NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext())); + NewAttr->setInherited(true); + FD->addAttr(NewAttr); + } + } } } @@ -5672,7 +5731,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { DelayedDllExportClasses.push_back(Class); } -/// \brief Perform propagation of DLL attributes from a derived class to a +/// Perform propagation of DLL attributes from a derived class to a /// templated base class for MS compatibility. void Sema::propagateDLLAttrToBaseClassTemplate( CXXRecordDecl *Class, Attr *ClassAttr, @@ -5694,6 +5753,11 @@ void Sema::propagateDLLAttrToBaseClassTemplate( NewAttr->setInherited(true); BaseTemplateSpec->addAttr(NewAttr); + // If this was an import, mark that we propagated it from a derived class to + // a base class template specialization. + if (auto *ImportAttr = dyn_cast<DLLImportAttr>(NewAttr)) + ImportAttr->setPropagatedToBaseTemplate(); + // If the template is already instantiated, checkDLLAttributeRedeclaration() // needs to be run again to work see the new attribute. Otherwise this will // get run whenever the template is instantiated. @@ -5756,10 +5820,74 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, /// Determine whether a type is permitted to be passed or returned in /// registers, per C++ [class.temporary]p3. -static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { +static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, + TargetInfo::CallingConvKind CCK) { if (D->isDependentType() || D->isInvalidDecl()) return false; + // Clang <= 4 used the pre-C++11 rule, which ignores move operations. + // The PS4 platform ABI follows the behavior of Clang 3.2. + if (CCK == TargetInfo::CCK_ClangABI4OrPS4) + return !D->hasNonTrivialDestructorForCall() && + !D->hasNonTrivialCopyConstructorForCall(); + + if (CCK == TargetInfo::CCK_MicrosoftWin64) { + bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; + bool DtorIsTrivialForCall = false; + + // If a class has at least one non-deleted, trivial copy constructor, it + // is passed according to the C ABI. Otherwise, it is passed indirectly. + // + // Note: This permits classes with non-trivial copy or move ctors to be + // passed in registers, so long as they *also* have a trivial copy ctor, + // which is non-conforming. + if (D->needsImplicitCopyConstructor()) { + if (!D->defaultedCopyConstructorIsDeleted()) { + if (D->hasTrivialCopyConstructor()) + CopyCtorIsTrivial = true; + if (D->hasTrivialCopyConstructorForCall()) + CopyCtorIsTrivialForCall = true; + } + } else { + for (const CXXConstructorDecl *CD : D->ctors()) { + if (CD->isCopyConstructor() && !CD->isDeleted()) { + if (CD->isTrivial()) + CopyCtorIsTrivial = true; + if (CD->isTrivialForCall()) + CopyCtorIsTrivialForCall = true; + } + } + } + + if (D->needsImplicitDestructor()) { + if (!D->defaultedDestructorIsDeleted() && + D->hasTrivialDestructorForCall()) + DtorIsTrivialForCall = true; + } else if (const auto *DD = D->getDestructor()) { + if (!DD->isDeleted() && DD->isTrivialForCall()) + DtorIsTrivialForCall = true; + } + + // If the copy ctor and dtor are both trivial-for-calls, pass direct. + if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall) + return true; + + // If a class has a destructor, we'd really like to pass it indirectly + // because it allows us to elide copies. Unfortunately, MSVC makes that + // impossible for small types, which it will pass in a single register or + // stack slot. Most objects with dtors are large-ish, so handle that early. + // We can't call out all large objects as being indirect because there are + // multiple x64 calling conventions and the C++ ABI code shouldn't dictate + // how we pass large POD types. + + // Note: This permits small classes with nontrivial destructors to be + // passed in registers, which is non-conforming. + if (CopyCtorIsTrivial && + S.getASTContext().getTypeSize(D->getTypeForDecl()) <= 64) + return true; + return false; + } + // Per C++ [class.temporary]p3, the relevant condition is: // each copy constructor, move constructor, and destructor of X is // either trivial or deleted, and X has at least one non-deleted copy @@ -5768,20 +5896,20 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { if (D->needsImplicitCopyConstructor() && !D->defaultedCopyConstructorIsDeleted()) { - if (!D->hasTrivialCopyConstructor()) + if (!D->hasTrivialCopyConstructorForCall()) return false; HasNonDeletedCopyOrMove = true; } if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() && !D->defaultedMoveConstructorIsDeleted()) { - if (!D->hasTrivialMoveConstructor()) + if (!D->hasTrivialMoveConstructorForCall()) return false; HasNonDeletedCopyOrMove = true; } if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() && - !D->hasTrivialDestructor()) + !D->hasTrivialDestructorForCall()) return false; for (const CXXMethodDecl *MD : D->methods()) { @@ -5794,14 +5922,14 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { else if (!isa<CXXDestructorDecl>(MD)) continue; - if (!MD->isTrivial()) + if (!MD->isTrivialForCall()) return false; } return HasNonDeletedCopyOrMove; } -/// \brief Perform semantic checks on a class definition that has been +/// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { @@ -5851,10 +5979,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { DeclContext::lookup_result R = Record->lookup(Record->getDeclName()); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = *I; - if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) || + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (((isa<FieldDecl>(D) || isa<UnresolvedUsingValueDecl>(D)) && + Record->hasUserDeclaredConstructor()) || isa<IndirectFieldDecl>(D)) { - Diag(D->getLocation(), diag::err_member_name_of_class) + Diag((*I)->getLocation(), diag::err_member_name_of_class) << D->getDeclName(); break; } @@ -5878,6 +6007,17 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + // See if trivial_abi has to be dropped. + if (Record->hasAttr<TrivialABIAttr>()) + checkIllFormedTrivialABIStruct(*Record); + + // Set HasTrivialSpecialMemberForCall if the record has attribute + // "trivial_abi". + bool HasTrivialABI = Record->hasAttr<TrivialABIAttr>(); + + if (HasTrivialABI) + Record->setHasTrivialSpecialMemberForCall(); + bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; if (!Record->isDependentType()) { @@ -5900,12 +6040,23 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!M->isImplicit() && !M->isUserProvided()) { if (CSM != CXXInvalid) { M->setTrivial(SpecialMemberIsTrivial(M, CSM)); - // Inform the class that we've finished declaring this member. Record->finishedDefaultedOrDeletedMember(M); + M->setTrivialForCall( + HasTrivialABI || + SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI)); + Record->setTrivialForCallFlags(M); } } + // Set triviality for the purpose of calls if this is a user-provided + // copy/move constructor or destructor. + if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor || + CSM == CXXDestructor) && M->isUserProvided()) { + M->setTrivialForCall(HasTrivialABI); + Record->setTrivialForCallFlags(M); + } + if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() && M->hasAttr<DLLExportAttr>()) { if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && @@ -5945,8 +6096,35 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } checkClassLevelDLLAttribute(Record); + checkClassLevelCodeSegAttribute(Record); - Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record)); + bool ClangABICompat4 = + Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4; + TargetInfo::CallingConvKind CCK = + Context.getTargetInfo().getCallingConvKind(ClangABICompat4); + bool CanPass = canPassInRegisters(*this, Record, CCK); + + // Do not change ArgPassingRestrictions if it has already been set to + // APK_CanNeverPassInRegs. + if (Record->getArgPassingRestrictions() != RecordDecl::APK_CanNeverPassInRegs) + Record->setArgPassingRestrictions(CanPass + ? RecordDecl::APK_CanPassInRegs + : RecordDecl::APK_CannotPassInRegs); + + // If canPassInRegisters returns true despite the record having a non-trivial + // destructor, the record is destructed in the callee. This happens only when + // the record or one of its subobjects has a field annotated with trivial_abi + // or a field qualified with ObjC __strong/__weak. + if (Context.getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee()) + Record->setParamDestroyedInCallee(true); + else if (Record->hasNonTrivialDestructor()) + Record->setParamDestroyedInCallee(CanPass); + + if (getLangOpts().ForceEmitVTables) { + // If we want to emit all the vtables, we need to mark it as used. This + // is especially required for cases like vtable assumption loads. + MarkVTableUsed(Record->getInnerLocStart(), Record); + } } /// Look up the special member function that would be called by a special @@ -7017,9 +7195,14 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, /// /// If \p Selected is not \c NULL, \c *Selected will be filled in with the /// member that was most likely to be intended to be trivial, if any. +/// +/// If \p ForCall is true, look at CXXRecord::HasTrivialSpecialMembersForCall to +/// determine whether the special member is trivial. static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM, unsigned Quals, - bool ConstRHS, CXXMethodDecl **Selected) { + bool ConstRHS, + Sema::TrivialABIHandling TAH, + CXXMethodDecl **Selected) { if (Selected) *Selected = nullptr; @@ -7060,7 +7243,9 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // C++11 [class.dtor]p5: // A destructor is trivial if: // - all the direct [subobjects] have trivial destructors - if (RD->hasTrivialDestructor()) + if (RD->hasTrivialDestructor() || + (TAH == Sema::TAH_ConsiderTrivialABI && + RD->hasTrivialDestructorForCall())) return true; if (Selected) { @@ -7075,7 +7260,9 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // C++11 [class.copy]p12: // A copy constructor is trivial if: // - the constructor selected to copy each direct [subobject] is trivial - if (RD->hasTrivialCopyConstructor()) { + if (RD->hasTrivialCopyConstructor() || + (TAH == Sema::TAH_ConsiderTrivialABI && + RD->hasTrivialCopyConstructorForCall())) { if (Quals == Qualifiers::Const) // We must either select the trivial copy constructor or reach an // ambiguity; no need to actually perform overload resolution. @@ -7128,6 +7315,10 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // not supposed to! if (Selected) *Selected = SMOR.getMethod(); + + if (TAH == Sema::TAH_ConsiderTrivialABI && + (CSM == Sema::CXXCopyConstructor || CSM == Sema::CXXMoveConstructor)) + return SMOR.getMethod()->isTrivialForCall(); return SMOR.getMethod()->isTrivial(); } @@ -7166,14 +7357,14 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, QualType SubType, bool ConstRHS, Sema::CXXSpecialMember CSM, TrivialSubobjectKind Kind, - bool Diagnose) { + Sema::TrivialABIHandling TAH, bool Diagnose) { CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl(); if (!SubRD) return true; CXXMethodDecl *Selected; if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(), - ConstRHS, Diagnose ? &Selected : nullptr)) + ConstRHS, TAH, Diagnose ? &Selected : nullptr)) return true; if (Diagnose) { @@ -7203,7 +7394,8 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, << Kind << SubType.getUnqualifiedType() << CSM; // Explain why the defaulted or deleted special member isn't trivial. - S.SpecialMemberIsTrivial(Selected, CSM, Diagnose); + S.SpecialMemberIsTrivial(Selected, CSM, Sema::TAH_IgnoreTrivialABI, + Diagnose); } } @@ -7214,7 +7406,9 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, /// trivial. static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM, - bool ConstArg, bool Diagnose) { + bool ConstArg, + Sema::TrivialABIHandling TAH, + bool Diagnose) { for (const auto *FI : RD->fields()) { if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) continue; @@ -7224,7 +7418,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // Pretend anonymous struct or union members are members of this class. if (FI->isAnonymousStructOrUnion()) { if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(), - CSM, ConstArg, Diagnose)) + CSM, ConstArg, TAH, Diagnose)) return false; continue; } @@ -7252,7 +7446,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, bool ConstRHS = ConstArg && !FI->isMutable(); if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, ConstRHS, - CSM, TSK_Field, Diagnose)) + CSM, TSK_Field, TAH, Diagnose)) return false; } @@ -7266,14 +7460,15 @@ void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { bool ConstArg = (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment); checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, ConstArg, CSM, - TSK_CompleteObject, /*Diagnose*/true); + TSK_CompleteObject, TAH_IgnoreTrivialABI, + /*Diagnose*/true); } /// Determine whether a defaulted or deleted special member function is trivial, /// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12, /// C++11 [class.copy]p25, and C++11 [class.dtor]p5. bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, - bool Diagnose) { + TrivialABIHandling TAH, bool Diagnose) { assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough"); CXXRecordDecl *RD = MD->getParent(); @@ -7350,7 +7545,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // destructors] for (const auto &BI : RD->bases()) if (!checkTrivialSubobjectCall(*this, BI.getLocStart(), BI.getType(), - ConstArg, CSM, TSK_BaseClass, Diagnose)) + ConstArg, CSM, TSK_BaseClass, TAH, Diagnose)) return false; // C++11 [class.ctor]p5, C++11 [class.dtor]p5: @@ -7365,7 +7560,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // -- for all of the non-static data members of its class that are of class // type (or array thereof), each such class has a trivial [default // constructor or destructor] - if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose)) + if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, TAH, Diagnose)) return false; // C++11 [class.dtor]p5: @@ -7477,7 +7672,7 @@ public: }; } // end anonymous namespace -/// \brief Add the most overriden methods from MD to Methods +/// Add the most overriden methods from MD to Methods static void AddMostOverridenMethods(const CXXMethodDecl *MD, llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { if (MD->size_overridden_methods() == 0) @@ -7487,7 +7682,7 @@ static void AddMostOverridenMethods(const CXXMethodDecl *MD, AddMostOverridenMethods(O, Methods); } -/// \brief Check if a method overloads virtual methods in a base class without +/// Check if a method overloads virtual methods in a base class without /// overriding any. void Sema::FindHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl<CXXMethodDecl*> &OverloadedMethods) { @@ -7528,7 +7723,7 @@ void Sema::NoteHiddenVirtualMethods(CXXMethodDecl *MD, } } -/// \brief Diagnose methods which overload virtual methods in a base class +/// Diagnose methods which overload virtual methods in a base class /// without overriding any. void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) { if (MD->isInvalidDecl()) @@ -7547,22 +7742,64 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) { } } -void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, - Decl *TagDecl, - SourceLocation LBrac, - SourceLocation RBrac, - AttributeList *AttrList) { +void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { + auto PrintDiagAndRemoveAttr = [&]() { + // No diagnostics if this is a template instantiation. + if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) + Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), + diag::ext_cannot_use_trivial_abi) << &RD; + RD.dropAttr<TrivialABIAttr>(); + }; + + // Ill-formed if the struct has virtual functions. + if (RD.isPolymorphic()) { + PrintDiagAndRemoveAttr(); + return; + } + + for (const auto &B : RD.bases()) { + // Ill-formed if the base class is non-trivial for the purpose of calls or a + // virtual base. + if ((!B.getType()->isDependentType() && + !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) || + B.isVirtual()) { + PrintDiagAndRemoveAttr(); + return; + } + } + + for (const auto *FD : RD.fields()) { + // Ill-formed if the field is an ObjectiveC pointer or of a type that is + // non-trivial for the purpose of calls. + QualType FT = FD->getType(); + if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { + PrintDiagAndRemoveAttr(); + return; + } + + if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>()) + if (!RT->isDependentType() && + !cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) { + PrintDiagAndRemoveAttr(); + return; + } + } +} + +void Sema::ActOnFinishCXXMemberSpecification( + Scope *S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, + SourceLocation RBrac, const ParsedAttributesView &AttrList) { if (!TagDecl) return; AdjustDeclIfTemplate(TagDecl); - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - if (l->getKind() != AttributeList::AT_Visibility) + for (const ParsedAttr &AL : AttrList) { + if (AL.getKind() != ParsedAttr::AT_Visibility) continue; - l->setInvalid(); - Diag(l->getLoc(), diag::warn_attribute_after_definition_ignored) << - l->getName(); + AL.setInvalid(); + Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) + << AL.getName(); } ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( @@ -7570,7 +7807,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, reinterpret_cast<Decl**>(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); - CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl)); + CheckCompletedCXXClass(cast<CXXRecordDecl>(TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -8108,7 +8345,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId, &ConvTSI); - if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { + const DeclSpec &DS = D.getDeclSpec(); + if (DS.hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: // @@ -8118,9 +8356,18 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // // The return type will be changed later anyway. Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) - << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(DS.getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); + } else if (DS.getTypeQualifiers() && !D.isInvalidType()) { + // It's also plausible that the user writes type qualifiers in the wrong + // place, such as: + // struct S { const operator int(); }; + // FIXME: we could provide a fixit to move the qualifiers onto the + // conversion type. + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) + << SourceRange(D.getIdentifierLoc()) << 0; + D.setInvalidType(); } const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); @@ -8233,12 +8480,12 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. - if (D.getDeclSpec().isExplicitSpecified()) - Diag(D.getDeclSpec().getExplicitSpecLoc(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_explicit_conversion_functions : - diag::ext_explicit_conversion_functions) - << SourceRange(D.getDeclSpec().getExplicitSpecLoc()); + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_explicit_conversion_functions + : diag::ext_explicit_conversion_functions) + << SourceRange(DS.getExplicitSpecLoc()); } /// ActOnConversionDeclarator - Called by ActOnDeclarator to complete @@ -8437,7 +8684,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, // Namespace Handling //===----------------------------------------------------------------------===// -/// \brief Diagnose a mismatch in 'inline' qualifiers when a namespace is +/// Diagnose a mismatch in 'inline' qualifiers when a namespace is /// reopened. static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, SourceLocation Loc, @@ -8479,14 +8726,10 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. -Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, - SourceLocation InlineLoc, - SourceLocation NamespaceLoc, - SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation LBrace, - AttributeList *AttrList, - UsingDirectiveDecl *&UD) { +Decl *Sema::ActOnStartNamespaceDef( + Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc, + SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace, + const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) { SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; // For anonymous namespace, take the location of the left brace. SourceLocation Loc = II ? IdentLoc : LBrace; @@ -8673,7 +8916,137 @@ NamespaceDecl *Sema::lookupStdExperimentalNamespace() { return StdExperimentalNamespaceCache; } -/// \brief Retrieve the special "std" namespace, which may require us to +namespace { + +enum UnsupportedSTLSelect { + USS_InvalidMember, + USS_MissingMember, + USS_NonTrivial, + USS_Other +}; + +struct InvalidSTLDiagnoser { + Sema &S; + SourceLocation Loc; + QualType TyForDiags; + + QualType operator()(UnsupportedSTLSelect Sel = USS_Other, StringRef Name = "", + const VarDecl *VD = nullptr) { + { + auto D = S.Diag(Loc, diag::err_std_compare_type_not_supported) + << TyForDiags << ((int)Sel); + if (Sel == USS_InvalidMember || Sel == USS_MissingMember) { + assert(!Name.empty()); + D << Name; + } + } + if (Sel == USS_InvalidMember) { + S.Diag(VD->getLocation(), diag::note_var_declared_here) + << VD << VD->getSourceRange(); + } + return QualType(); + } +}; +} // namespace + +QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, + SourceLocation Loc) { + assert(getLangOpts().CPlusPlus && + "Looking for comparison category type outside of C++."); + + // Check if we've already successfully checked the comparison category type + // before. If so, skip checking it again. + ComparisonCategoryInfo *Info = Context.CompCategories.lookupInfo(Kind); + if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) + return Info->getType(); + + // If lookup failed + if (!Info) { + std::string NameForDiags = "std::"; + NameForDiags += ComparisonCategories::getCategoryString(Kind); + Diag(Loc, diag::err_implied_comparison_category_type_not_found) + << NameForDiags; + return QualType(); + } + + assert(Info->Kind == Kind); + assert(Info->Record); + + // Update the Record decl in case we encountered a forward declaration on our + // first pass. FIXME: This is a bit of a hack. + if (Info->Record->hasDefinition()) + Info->Record = Info->Record->getDefinition(); + + // Use an elaborated type for diagnostics which has a name containing the + // prepended 'std' namespace but not any inline namespace names. + QualType TyForDiags = [&]() { + auto *NNS = + NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()); + return Context.getElaboratedType(ETK_None, NNS, Info->getType()); + }(); + + if (RequireCompleteType(Loc, TyForDiags, diag::err_incomplete_type)) + return QualType(); + + InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags}; + + if (!Info->Record->isTriviallyCopyable()) + return UnsupportedSTLError(USS_NonTrivial); + + for (const CXXBaseSpecifier &BaseSpec : Info->Record->bases()) { + CXXRecordDecl *Base = BaseSpec.getType()->getAsCXXRecordDecl(); + // Tolerate empty base classes. + if (Base->isEmpty()) + continue; + // Reject STL implementations which have at least one non-empty base. + return UnsupportedSTLError(); + } + + // Check that the STL has implemented the types using a single integer field. + // This expectation allows better codegen for builtin operators. We require: + // (1) The class has exactly one field. + // (2) The field is an integral or enumeration type. + auto FIt = Info->Record->field_begin(), FEnd = Info->Record->field_end(); + if (std::distance(FIt, FEnd) != 1 || + !FIt->getType()->isIntegralOrEnumerationType()) { + return UnsupportedSTLError(); + } + + // Build each of the require values and store them in Info. + for (ComparisonCategoryResult CCR : + ComparisonCategories::getPossibleResultsForType(Kind)) { + StringRef MemName = ComparisonCategories::getResultString(CCR); + ComparisonCategoryInfo::ValueInfo *ValInfo = Info->lookupValueInfo(CCR); + + if (!ValInfo) + return UnsupportedSTLError(USS_MissingMember, MemName); + + VarDecl *VD = ValInfo->VD; + assert(VD && "should not be null!"); + + // Attempt to diagnose reasons why the STL definition of this type + // might be foobar, including it failing to be a constant expression. + // TODO Handle more ways the lookup or result can be invalid. + if (!VD->isStaticDataMember() || !VD->isConstexpr() || !VD->hasInit() || + !VD->checkInitIsICE()) + return UnsupportedSTLError(USS_InvalidMember, MemName, VD); + + // Attempt to evaluate the var decl as a constant expression and extract + // the value of its first field as a ICE. If this fails, the STL + // implementation is not supported. + if (!ValInfo->hasValidIntValue()) + return UnsupportedSTLError(); + + MarkVariableReferenced(Loc, VD); + } + + // We've successfully built the required types and expressions. Update + // the cache and return the newly cached value. + FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)] = true; + return Info->getType(); +} + +/// Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { @@ -8816,7 +9189,7 @@ bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { return isStdInitializerList(ArgType, nullptr); } -/// \brief Determine whether a using statement is in a context where it will be +/// Determine whether a using statement is in a context where it will be /// apply in all contexts. static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { switch (CurContext->getDeclKind()) { @@ -8871,13 +9244,11 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, return false; } -Decl *Sema::ActOnUsingDirective(Scope *S, - SourceLocation UsingLoc, - SourceLocation NamespcLoc, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *NamespcName, - AttributeList *AttrList) { +Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, + SourceLocation NamespcLoc, CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + const ParsedAttributesView &AttrList) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(NamespcName && "Invalid NamespcName."); assert(IdentLoc.isValid() && "Invalid NamespceName location."); @@ -8932,7 +9303,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, // Find enclosing context containing both using-directive and // nominated namespace. - DeclContext *CommonAncestor = cast<DeclContext>(NS); + DeclContext *CommonAncestor = NS; while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) CommonAncestor = CommonAncestor->getParent(); @@ -8969,15 +9340,12 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { S->PushUsingDirective(UDir); } - -Decl *Sema::ActOnUsingDeclaration(Scope *S, - AccessSpecifier AS, +Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - SourceLocation TypenameLoc, - CXXScopeSpec &SS, + SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, SourceLocation EllipsisLoc, - AttributeList *AttrList) { + const ParsedAttributesView &AttrList) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); if (SS.isEmpty()) { @@ -9056,7 +9424,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, return UD; } -/// \brief Determine whether a using declaration considers the given +/// Determine whether a using declaration considers the given /// declarations as "equivalent", e.g., if they are redeclarations of /// the same entity or are both typedefs of the same type. static bool @@ -9149,6 +9517,19 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D)) continue; + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { + // C++ [class.mem]p19: + // If T is the name of a class, then [every named member other than + // a non-static data member] shall have a name different from T + if (RD->isInjectedClassName() && !isa<FieldDecl>(Target) && + !isa<IndirectFieldDecl>(Target) && + !isa<UnresolvedUsingValueDecl>(Target) && + DiagnoseClassNameShadow( + CurContext, + DeclarationNameInfo(Using->getDeclName(), Using->getLocation()))) + return true; + } + if (IsEquivalentForUsingDecl(Context, D, Target)) { if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I)) PrevShadow = Shadow; @@ -9421,15 +9802,11 @@ private: /// \param IsInstantiation - Whether this call arises from an /// instantiation of an unresolved using declaration. We treat /// the lookup differently for these declarations. -NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, - SourceLocation UsingLoc, - bool HasTypenameKeyword, - SourceLocation TypenameLoc, - CXXScopeSpec &SS, - DeclarationNameInfo NameInfo, - SourceLocation EllipsisLoc, - AttributeList *AttrList, - bool IsInstantiation) { +NamedDecl *Sema::BuildUsingDeclaration( + Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, + DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, + const ParsedAttributesView &AttrList, bool IsInstantiation) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); @@ -9995,14 +10372,11 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } -Decl *Sema::ActOnAliasDeclaration(Scope *S, - AccessSpecifier AS, +Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, MultiTemplateParamsArg TemplateParamLists, - SourceLocation UsingLoc, - UnqualifiedId &Name, - AttributeList *AttrList, - TypeResult Type, - Decl *DeclFromDeclSpec) { + SourceLocation UsingLoc, UnqualifiedId &Name, + const ParsedAttributesView &AttrList, + TypeResult Type, Decl *DeclFromDeclSpec) { // Skip up to the relevant declaration scope. while (S->isTemplateParamScope()) S = S->getParent(); @@ -10378,7 +10752,7 @@ struct DeclaringSpecialMember { } } - /// \brief Are we already trying to declare this special member? + /// Are we already trying to declare this special member? bool isAlreadyBeingDeclared() const { return WasAlreadyBeingDeclared; } @@ -10720,6 +11094,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // We don't need to use SpecialMemberIsTrivial here; triviality for // destructors is easy to compute. Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); + Destructor->setTrivialForCall(ClassDecl->hasAttr<TrivialABIAttr>() || + ClassDecl->hasTrivialDestructorForCall()); // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; @@ -10784,7 +11160,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } -/// \brief Perform any semantic analysis which needs to be delayed until all +/// Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { // If the context is an invalid C++ class, just suppress these checks. @@ -10804,12 +11180,12 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { void Sema::referenceDLLExportedClassMethods() { if (!DelayedDllExportClasses.empty()) { - // Calling ReferenceDllExportedMethods might cause the current function to + // Calling ReferenceDllExportedMembers might cause the current function to // be called again, so use a local copy of DelayedDllExportClasses. SmallVector<CXXRecordDecl *, 4> WorkList; std::swap(DelayedDllExportClasses, WorkList); for (CXXRecordDecl *Class : WorkList) - ReferenceDllExportedMethods(*this, Class); + ReferenceDllExportedMembers(*this, Class); } } @@ -10843,7 +11219,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, } namespace { -/// \brief An abstract base class for all helper classes used in building the +/// An abstract base class for all helper classes used in building the // copy/move operators. These classes serve as factory functions and help us // avoid using the same Expr* in the AST twice. class ExprBuilder { @@ -10990,11 +11366,11 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, Expr *From = FromB.build(S, Loc); From = new (S.Context) UnaryOperator(From, UO_AddrOf, S.Context.getPointerType(From->getType()), - VK_RValue, OK_Ordinary, Loc); + VK_RValue, OK_Ordinary, Loc, false); Expr *To = ToB.build(S, Loc); To = new (S.Context) UnaryOperator(To, UO_AddrOf, S.Context.getPointerType(To->getType()), - VK_RValue, OK_Ordinary, Loc); + VK_RValue, OK_Ordinary, Loc, false); const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = @@ -11028,7 +11404,7 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, return Call.getAs<Stmt>(); } -/// \brief Builds a statement that copies/moves the given entity from \p From to +/// Builds a statement that copies/moves the given entity from \p From to /// \c To. /// /// This routine is used to copy/move the members of a class with an @@ -11233,10 +11609,12 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, BO_NE, S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc, FPOptions()); - // Create the pre-increment of the iteration variable. - Expr *Increment - = new (S.Context) UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, - SizeType, VK_LValue, OK_Ordinary, Loc); + // Create the pre-increment of the iteration variable. We can determine + // whether the increment will overflow based on the value of the array + // bound. + Expr *Increment = new (S.Context) + UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType, + VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue()); // Construct the loop that copies all elements of this array. return S.ActOnForStmt( @@ -11525,7 +11903,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } // Suppress assigning zero-width bitfields. - if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + if (Field->isZeroLengthBitField(Context)) continue; QualType FieldType = Field->getType().getNonReferenceType(); @@ -11892,7 +12270,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } // Suppress assigning zero-width bitfields. - if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) + if (Field->isZeroLengthBitField(Context)) continue; QualType FieldType = Field->getType().getNonReferenceType(); @@ -12021,9 +12399,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setParams(FromParam); CopyConstructor->setTrivial( - ClassDecl->needsOverloadResolutionForCopyConstructor() - ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) - : ClassDecl->hasTrivialCopyConstructor()); + ClassDecl->needsOverloadResolutionForCopyConstructor() + ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) + : ClassDecl->hasTrivialCopyConstructor()); + + CopyConstructor->setTrivialForCall( + ClassDecl->hasAttr<TrivialABIAttr>() || + (ClassDecl->needsOverloadResolutionForCopyConstructor() + ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor, + TAH_ConsiderTrivialABI) + : ClassDecl->hasTrivialCopyConstructorForCall())); // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -12144,9 +12529,16 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setParams(FromParam); MoveConstructor->setTrivial( - ClassDecl->needsOverloadResolutionForMoveConstructor() - ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) - : ClassDecl->hasTrivialMoveConstructor()); + ClassDecl->needsOverloadResolutionForMoveConstructor() + ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) + : ClassDecl->hasTrivialMoveConstructor()); + + MoveConstructor->setTrivialForCall( + ClassDecl->hasAttr<TrivialABIAttr>() || + (ClassDecl->needsOverloadResolutionForMoveConstructor() + ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor, + TAH_ConsiderTrivialABI) + : ClassDecl->hasTrivialMoveConstructorForCall())); // Note that we have declared this constructor. ++ASTContext::NumImplicitMoveConstructorsDeclared; @@ -12321,7 +12713,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( } } -/// \brief Determine whether the given list arguments contains exactly one +/// Determine whether the given list arguments contains exactly one /// "real" (non-default) argument. static bool hasOneRealArgument(MultiExprArg Args) { switch (Args.size()) { @@ -12532,7 +12924,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { Diag(VD->getLocation(), diag::warn_global_destructor); } -/// \brief Given a constructor and the set of arguments provided for the +/// Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. /// @@ -12599,6 +12991,13 @@ CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, return false; } +static QualType +RemoveAddressSpaceFromPtr(Sema &SemaRef, const PointerType *PtrTy) { + QualType QTy = PtrTy->getPointeeType(); + QTy = SemaRef.Context.removeAddrSpaceQualType(QTy); + return SemaRef.Context.getPointerType(QTy); +} + static inline bool CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, CanQualType ExpectedResultType, @@ -12614,6 +13013,13 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, diag::err_operator_new_delete_dependent_result_type) << FnDecl->getDeclName() << ExpectedResultType; + // OpenCL C++: the operator is valid on any address space. + if (SemaRef.getLangOpts().OpenCLCPlusPlus) { + if (auto *PtrTy = ResultType->getAs<PointerType>()) { + ResultType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy); + } + } + // Check that the result type is what we expect. if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) return SemaRef.Diag(FnDecl->getLocation(), @@ -12639,6 +13045,13 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, << FnDecl->getDeclName() << ExpectedFirstParamType; // Check that the first parameter type is what we expect. + if (SemaRef.getLangOpts().OpenCLCPlusPlus) { + // OpenCL C++: the operator is valid on any address space. + if (auto *PtrTy = + FnDecl->getParamDecl(0)->getType()->getAs<PointerType>()) { + FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy); + } + } if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != ExpectedFirstParamType) return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) @@ -12948,6 +13361,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { ParamType->isSpecificBuiltinType(BuiltinType::LongDouble) || Context.hasSameType(ParamType, Context.CharTy) || Context.hasSameType(ParamType, Context.WideCharTy) || + Context.hasSameType(ParamType, Context.Char8Ty) || Context.hasSameType(ParamType, Context.Char16Ty) || Context.hasSameType(ParamType, Context.Char32Ty)) { } else if (const PointerType *Ptr = ParamType->getAs<PointerType>()) { @@ -13008,10 +13422,12 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { } QualType InnerType = PointeeType.getUnqualifiedType(); - // Only const char *, const wchar_t*, const char16_t*, and const char32_t* - // are allowed as the first parameter to a two-parameter function + // Only const char *, const wchar_t*, const char8_t*, const char16_t*, and + // const char32_t* are allowed as the first parameter to a two-parameter + // function if (!(Context.hasSameType(InnerType, Context.CharTy) || Context.hasSameType(InnerType, Context.WideCharTy) || + Context.hasSameType(InnerType, Context.Char8Ty) || Context.hasSameType(InnerType, Context.Char16Ty) || Context.hasSameType(InnerType, Context.Char32Ty))) { Diag((*Param)->getSourceRange().getBegin(), @@ -13118,19 +13534,18 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, } Decl *Sema::ActOnEmptyDeclaration(Scope *S, - AttributeList *AttrList, + const ParsedAttributesView &AttrList, SourceLocation SemiLoc) { Decl *ED = EmptyDecl::Create(Context, CurContext, SemiLoc); // Attribute declarations appertain to empty declaration so we handle // them here. - if (AttrList) - ProcessDeclAttributeList(S, ED, AttrList); + ProcessDeclAttributeList(S, ED, AttrList); CurContext->addDecl(ED); return ED; } -/// \brief Perform semantic analysis for the variable declaration that +/// Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. VarDecl *Sema::BuildExceptionDeclaration(Scope *S, @@ -13386,7 +13801,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, return Decl; } -/// \brief Perform semantic analysis of the given friend type declaration. +/// Perform semantic analysis of the given friend type declaration. /// /// \returns A friend declaration that. FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, @@ -13463,10 +13878,9 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, /// templated. Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, - CXXScopeSpec &SS, - IdentifierInfo *Name, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, + const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); @@ -13579,7 +13993,6 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, return Friend; } - /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// @@ -14151,6 +14564,16 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, } } + // Virtual overrides must have the same code_seg. + const auto *OldCSA = Old->getAttr<CodeSegAttr>(); + const auto *NewCSA = New->getAttr<CodeSegAttr>(); + if ((NewCSA || OldCSA) && + (!OldCSA || !NewCSA || NewCSA->getName() != OldCSA->getName())) { + Diag(New->getLocation(), diag::err_mismatched_code_seg_override); + Diag(Old->getLocation(), diag::note_previous_declaration); + return true; + } + CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv(); // If the calling conventions match, everything is fine @@ -14277,7 +14700,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return false; } -/// \brief Mark the given method pure. +/// Mark the given method pure. /// /// \param Method the method to be marked pure. /// @@ -14307,7 +14730,7 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) { Diag(D->getLocation(), diag::err_illegal_initializer); } -/// \brief Determine whether the given declaration is a global variable or +/// Determine whether the given declaration is a global variable or /// static data member. static bool isNonlocalVariable(const Decl *D) { if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D)) @@ -14414,7 +14837,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // Try to insert this class into the map. LoadExternalVTableUses(); - Class = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + Class = Class->getCanonicalDecl(); std::pair<llvm::DenseMap<CXXRecordDecl *, bool>::iterator, bool> Pos = VTablesUsed.insert(std::make_pair(Class, DefinitionRequired)); if (!Pos.second) { @@ -14526,7 +14949,7 @@ bool Sema::DefineUsedVTables() { // vtable for this class is required. DefinedAnything = true; MarkVirtualMembersReferenced(Loc, Class); - CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl()); + CXXRecordDecl *Canonical = Class->getCanonicalDecl(); if (VTablesUsed[Canonical]) Consumer.HandleVTable(Class); @@ -14649,9 +15072,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { static void DelegatingCycleHelper(CXXConstructorDecl* Ctor, - llvm::SmallSet<CXXConstructorDecl*, 4> &Valid, - llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid, - llvm::SmallSet<CXXConstructorDecl*, 4> &Current, + llvm::SmallPtrSet<CXXConstructorDecl*, 4> &Valid, + llvm::SmallPtrSet<CXXConstructorDecl*, 4> &Invalid, + llvm::SmallPtrSet<CXXConstructorDecl*, 4> &Current, Sema &S) { if (Ctor->isInvalidDecl()) return; @@ -14713,7 +15136,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor, void Sema::CheckDelegatingCtorCycles() { - llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; + llvm::SmallPtrSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; for (DelegatingCtorDeclsType::iterator I = DelegatingCtorDecls.begin(ExternalSource), @@ -14721,14 +15144,12 @@ void Sema::CheckDelegatingCtorCycles() { I != E; ++I) DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); - for (llvm::SmallSet<CXXConstructorDecl *, 4>::iterator CI = Invalid.begin(), - CE = Invalid.end(); - CI != CE; ++CI) + for (auto CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) (*CI)->setInvalidDecl(); } namespace { - /// \brief AST visitor that finds references to the 'this' expression. + /// AST visitor that finds references to the 'this' expression. class FindCXXThisExpr : public RecursiveASTVisitor<FindCXXThisExpr> { Sema &S; @@ -14798,7 +15219,9 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { case EST_None: break; - case EST_ComputedNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; LLVM_FALLTHROUGH; @@ -14895,31 +15318,17 @@ void Sema::checkExceptionSpecification( return; } - if (EST == EST_ComputedNoexcept) { - // If an error occurred, there's no expression here. - if (NoexceptExpr) { - assert((NoexceptExpr->isTypeDependent() || - NoexceptExpr->getType()->getCanonicalTypeUnqualified() == - Context.BoolTy) && - "Parser should have made sure that the expression is boolean"); - if (IsTopLevel && NoexceptExpr && - DiagnoseUnexpandedParameterPack(NoexceptExpr)) { - ESI.Type = EST_BasicNoexcept; - return; - } - - if (!NoexceptExpr->isValueDependent()) { - ExprResult Result = VerifyIntegerConstantExpression( - NoexceptExpr, nullptr, diag::err_noexcept_needs_constant_expression, - /*AllowFold*/ false); - if (Result.isInvalid()) { - ESI.Type = EST_BasicNoexcept; - return; - } - NoexceptExpr = Result.get(); - } - ESI.NoexceptExpr = NoexceptExpr; + if (isComputedNoexcept(EST)) { + assert((NoexceptExpr->isTypeDependent() || + NoexceptExpr->getType()->getCanonicalTypeUnqualified() == + Context.BoolTy) && + "Parser should have made sure that the expression is boolean"); + if (IsTopLevel && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + ESI.Type = EST_BasicNoexcept; + return; } + + ESI.NoexceptExpr = NoexceptExpr; return; } } @@ -14964,11 +15373,11 @@ void Sema::actOnDelayedExceptionSpecification(Decl *MethodD, /// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. /// MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, - SourceLocation DeclStart, - Declarator &D, Expr *BitWidth, + SourceLocation DeclStart, Declarator &D, + Expr *BitWidth, InClassInitStyle InitStyle, AccessSpecifier AS, - AttributeList *MSPropertyAttr) { + const ParsedAttr &MSPropertyAttr) { IdentifierInfo *II = D.getIdentifier(); if (!II) { Diag(DeclStart, diag::err_anonymous_property); @@ -15031,7 +15440,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, PrevDecl = nullptr; SourceLocation TSSL = D.getLocStart(); - const AttributeList::PropertyData &Data = MSPropertyAttr->getPropertyData(); + const ParsedAttr::PropertyData &Data = MSPropertyAttr.getPropertyData(); MSPropertyDecl *NewPD = MSPropertyDecl::Create( Context, Record, Loc, II, T, TInfo, TSSL, Data.GetterId, Data.SetterId); ProcessDeclAttributes(TUScope, NewPD, D); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index ff3c07e938a8..e1b033ea8282 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -156,23 +156,23 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, Diag(Overridden->getLocation(), diag::note_related_result_type_overridden); } - if (getLangOpts().ObjCAutoRefCount) { - Diags.setSeverity(diag::warn_nsreturns_retained_attribute_mismatch, - diag::Severity::Error, SourceLocation()); - Diags.setSeverity(diag::warn_nsconsumed_attribute_mismatch, - diag::Severity::Error, SourceLocation()); - } if ((NewMethod->hasAttr<NSReturnsRetainedAttr>() != Overridden->hasAttr<NSReturnsRetainedAttr>())) { Diag(NewMethod->getLocation(), - diag::warn_nsreturns_retained_attribute_mismatch) << 1; + getLangOpts().ObjCAutoRefCount + ? diag::err_nsreturns_retained_attribute_mismatch + : diag::warn_nsreturns_retained_attribute_mismatch) + << 1; Diag(Overridden->getLocation(), diag::note_previous_decl) << "method"; } if ((NewMethod->hasAttr<NSReturnsNotRetainedAttr>() != Overridden->hasAttr<NSReturnsNotRetainedAttr>())) { Diag(NewMethod->getLocation(), - diag::warn_nsreturns_retained_attribute_mismatch) << 0; + getLangOpts().ObjCAutoRefCount + ? diag::err_nsreturns_retained_attribute_mismatch + : diag::warn_nsreturns_retained_attribute_mismatch) + << 0; Diag(Overridden->getLocation(), diag::note_previous_decl) << "method"; } @@ -185,7 +185,10 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, ParmVarDecl *newDecl = (*ni); if (newDecl->hasAttr<NSConsumedAttr>() != oldDecl->hasAttr<NSConsumedAttr>()) { - Diag(newDecl->getLocation(), diag::warn_nsconsumed_attribute_mismatch); + Diag(newDecl->getLocation(), + getLangOpts().ObjCAutoRefCount + ? diag::err_nsconsumed_attribute_mismatch + : diag::warn_nsconsumed_attribute_mismatch); Diag(oldDecl->getLocation(), diag::note_previous_decl) << "parameter"; } @@ -199,7 +202,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, } } -/// \brief Check a method declaration for compatibility with the Objective-C +/// Check a method declaration for compatibility with the Objective-C /// ARC conventions. bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { ObjCMethodFamily family = method->getMethodFamily(); @@ -263,12 +266,20 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, const NamedDecl *ND, if (!ND) return; bool IsCategory = false; - AvailabilityResult Availability = ND->getAvailability(); + StringRef RealizedPlatform; + AvailabilityResult Availability = ND->getAvailability( + /*Message=*/nullptr, /*EnclosingVersion=*/VersionTuple(), + &RealizedPlatform); if (Availability != AR_Deprecated) { if (isa<ObjCMethodDecl>(ND)) { if (Availability != AR_Unavailable) return; - // Warn about implementing unavailable methods. + if (RealizedPlatform.empty()) + RealizedPlatform = S.Context.getTargetInfo().getPlatformName(); + // Warn about implementing unavailable methods, unless the unavailable + // is for an app extension. + if (RealizedPlatform.endswith("_app_extension")) + return; S.Diag(ImplLoc, diag::warn_unavailable_def); S.Diag(ND->getLocation(), diag::note_method_declared_at) << ND->getDeclName(); @@ -338,6 +349,13 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { if (!MDecl) return; + QualType ResultType = MDecl->getReturnType(); + if (!ResultType->isDependentType() && !ResultType->isVoidType() && + !MDecl->isInvalidDecl() && + RequireCompleteType(MDecl->getLocation(), ResultType, + diag::err_func_def_incomplete_result)) + MDecl->setInvalidDecl(); + // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); PushFunctionScope(); @@ -930,16 +948,14 @@ static bool checkTypeParamListConsistency(Sema &S, return false; } -Decl *Sema:: -ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - ObjCTypeParamList *typeParamList, - IdentifierInfo *SuperName, SourceLocation SuperLoc, - ArrayRef<ParsedType> SuperTypeArgs, - SourceRange SuperTypeArgsRange, - Decl * const *ProtoRefs, unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, AttributeList *AttrList) { +Decl *Sema::ActOnStartClassInterface( + Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList) { assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. @@ -1024,9 +1040,8 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IDecl->setInvalidDecl(); } } - - if (AttrList) - ProcessDeclAttributeList(TUScope, IDecl, AttrList); + + ProcessDeclAttributeList(TUScope, IDecl, AttrList); AddPragmaAttributes(TUScope, IDecl); PushOnScopeChains(IDecl, TUScope); @@ -1165,15 +1180,11 @@ bool Sema::CheckForwardProtocolDeclarationForCircularDependency( return res; } -Decl * -Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, - SourceLocation ProtocolLoc, - Decl * const *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList) { +Decl *Sema::ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, + SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList) { bool err = false; // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); @@ -1192,6 +1203,11 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, ProtocolLoc, AtProtoInterfaceLoc, /*PrevDecl=*/nullptr); + + // If we are using modules, add the decl to the context in order to + // serialize something meaningful. + if (getLangOpts().Modules) + PushOnScopeChains(PDecl, TUScope); PDecl->startDefinition(); } else { if (PrevDecl) { @@ -1211,9 +1227,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, PushOnScopeChains(PDecl, TUScope); PDecl->startDefinition(); } - - if (AttrList) - ProcessDeclAttributeList(TUScope, PDecl, AttrList); + + ProcessDeclAttributeList(TUScope, PDecl, AttrList); AddPragmaAttributes(TUScope, PDecl); // Merge attributes from previous declarations. @@ -1544,14 +1559,12 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( // add the '*'. if (type->getAs<ObjCInterfaceType>()) { SourceLocation starLoc = getLocForEndOfToken(loc); - ParsedAttributes parsedAttrs(attrFactory); D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, SourceLocation(), SourceLocation(), SourceLocation(), SourceLocation(), SourceLocation()), - parsedAttrs, starLoc); // Diagnose the missing '*'. @@ -1729,7 +1742,7 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, Sema::DeclGroupPtrTy Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, ArrayRef<IdentifierLocPair> IdentList, - AttributeList *attrList) { + const ParsedAttributesView &attrList) { SmallVector<Decl *, 8> DeclsInGroup; for (const IdentifierLocPair &IdentPair : IdentList) { IdentifierInfo *Ident = IdentPair.first; @@ -1742,9 +1755,8 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, PushOnScopeChains(PDecl, TUScope); CheckObjCDeclScope(PDecl); - - if (attrList) - ProcessDeclAttributeList(TUScope, PDecl, attrList); + + ProcessDeclAttributeList(TUScope, PDecl, attrList); AddPragmaAttributes(TUScope, PDecl); if (PrevDecl) @@ -1756,17 +1768,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, return BuildDeclaratorGroup(DeclsInGroup); } -Decl *Sema:: -ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, - SourceLocation CategoryLoc, - Decl * const *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList) { +Decl *Sema::ActOnStartCategoryInterface( + SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, + IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + Decl *const *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, + const ParsedAttributesView &AttrList) { ObjCCategoryDecl *CDecl; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); @@ -1832,6 +1840,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); + // Process the attributes before looking at protocols to ensure that the + // availability attribute is attached to the category to provide availability + // checking for protocol uses. + ProcessDeclAttributeList(TUScope, CDecl, AttrList); + AddPragmaAttributes(TUScope, CDecl); + if (NumProtoRefs) { diagnoseUseOfProtocols(*this, CDecl, (ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs, ProtoLocs); @@ -1843,10 +1857,6 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, NumProtoRefs, Context); } - if (AttrList) - ProcessDeclAttributeList(TUScope, CDecl, AttrList); - AddPragmaAttributes(TUScope, CDecl); - CheckObjCDeclScope(CDecl); return ActOnObjCContainerStartDefinition(CDecl); } @@ -2162,17 +2172,9 @@ static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc, unsigned DiagID, NamedDecl *NeededFor = nullptr) { // No point warning no definition of method which is 'unavailable'. - switch (method->getAvailability()) { - case AR_Available: - case AR_Deprecated: - break; - - // Don't warn about unavailable or not-yet-introduced methods. - case AR_NotYetIntroduced: - case AR_Unavailable: + if (method->getAvailability() == AR_Unavailable) return; - } - + // FIXME: For now ignore 'IncompleteImpl'. // Previously we grouped all unimplemented methods under a single // warning, but some users strongly voiced that they would prefer @@ -2717,7 +2719,7 @@ static void CheckProtocolMethodDefs(Sema &S, // This is because method will be implemented in the primary class // or one of its super class implementation. - // Ugly, but necessary. Method declared in protcol might have + // Ugly, but necessary. Method declared in protocol might have // have been synthesized due to a property declared in the class which // uses the protocol. if (ObjCMethodDecl *MethodInClass = @@ -3345,7 +3347,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, Previous->setNext(new (Mem) ObjCMethodList(Method)); } -/// \brief Read the contents of the method pool for a given selector from +/// Read the contents of the method pool for a given selector from /// external storage. void Sema::ReadMethodPool(Selector Sel) { assert(ExternalSource && "We need an external AST source"); @@ -3427,7 +3429,7 @@ static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method, MethodInterface->isSuperClassOf(BoundInterface) || BoundInterface->isSuperClassOf(MethodInterface); } - llvm_unreachable("unknow method context"); + llvm_unreachable("unknown method context"); } /// We first select the type of the method: Instance or Factory, then collect @@ -3859,9 +3861,9 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, assert(AtEnd.isValid() && "Invalid location for '@end'"); - ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); - Decl *ClassDecl = cast<Decl>(OCD); - + auto *OCD = cast<ObjCContainerDecl>(CurContext); + Decl *ClassDecl = OCD; + bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) || isa<ObjCProtocolDecl>(ClassDecl); @@ -4084,7 +4086,7 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { return (Decl::ObjCDeclQualifier) (unsigned) PQTVal; } -/// \brief Check whether the declared result type of the given Objective-C +/// Check whether the declared result type of the given Objective-C /// method declaration is compatible with the method's class. /// static Sema::ResultTypeCompatibilityKind @@ -4130,7 +4132,7 @@ class OverrideSearch { public: Sema &S; ObjCMethodDecl *Method; - llvm::SmallPtrSet<ObjCMethodDecl*, 4> Overridden; + llvm::SmallSetVector<ObjCMethodDecl*, 4> Overridden; bool Recursive; public: @@ -4167,7 +4169,7 @@ public: } } - typedef llvm::SmallPtrSetImpl<ObjCMethodDecl*>::iterator iterator; + typedef decltype(Overridden)::iterator iterator; iterator begin() const { return Overridden.begin(); } iterator end() const { return Overridden.end(); } @@ -4335,10 +4337,6 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, // Then merge the declarations. mergeObjCMethodDecls(ObjCMethod, overridden); - } - - for (ObjCMethodDecl *overridden : overrides) { - CheckObjCMethodOverride(ObjCMethod, overridden); if (ObjCMethod->isImplicit() && overridden->isImplicit()) continue; // Conflicting properties are detected elsewhere. @@ -4502,25 +4500,21 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef, } Decl *Sema::ActOnMethodDeclaration( - Scope *S, - SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, - ObjCDeclSpec &ReturnQT, ParsedType ReturnType, - ArrayRef<SourceLocation> SelectorLocs, - Selector Sel, + Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, + tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). - ObjCArgInfo *ArgInfo, - DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args - AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, + ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, + unsigned CNumArgs, // c-style args + const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic, bool MethodDefinition) { // Make sure we can establish a context for the method. if (!CurContext->isObjCContainer()) { Diag(MethodLoc, diag::err_missing_method_context); return nullptr; } - ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); - Decl *ClassDecl = cast<Decl>(OCD); + Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext); QualType resultDeclType; bool HasRelatedResultType = false; @@ -4621,8 +4615,7 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethod->setObjCDeclQualifier( CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); - if (AttrList) - ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); + ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); AddPragmaAttributes(TUScope, ObjCMethod); // Add the method now. @@ -4726,6 +4719,17 @@ Decl *Sema::ActOnMethodDeclaration( Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) checkObjCMethodX86VectorTypes(*this, ObjCMethod); + // + load method cannot have availability attributes. It get called on + // startup, so it has to have the availability of the deployment target. + if (const auto *attr = ObjCMethod->getAttr<AvailabilityAttr>()) { + if (ObjCMethod->isClassMethod() && + ObjCMethod->getSelector().getAsString() == "load") { + Diag(attr->getLocation(), diag::warn_availability_on_static_initializer) + << 0; + ObjCMethod->dropAttr<AvailabilityAttr>(); + } + } + ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; @@ -4769,7 +4773,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, Context.DeepCollectObjCIvars(Class, true, Ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. for (unsigned i = 0; i < Ivars.size(); i++) { - const FieldDecl* ID = cast<FieldDecl>(Ivars[i]); + const FieldDecl* ID = Ivars[i]; RecordDecl *Record = dyn_cast<RecordDecl>(TagD); Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, /*FIXME: StartL=*/ID->getLocation(), @@ -4784,13 +4788,13 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, D != Decls.end(); ++D) { FieldDecl *FD = cast<FieldDecl>(*D); if (getLangOpts().CPlusPlus) - PushOnScopeChains(cast<FieldDecl>(FD), S); + PushOnScopeChains(FD, S); else if (RecordDecl *Record = dyn_cast<RecordDecl>(TagD)) Record->addDecl(FD); } } -/// \brief Build a type-check a new Objective-C exception variable declaration. +/// Build a type-check a new Objective-C exception variable declaration. VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, SourceLocation StartLoc, SourceLocation IdLoc, @@ -4811,12 +4815,17 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, // Don't do any further checking. } else if (T->isDependentType()) { // Okay: we don't know what this type will instantiate to. - } else if (!T->isObjCObjectPointerType()) { - Invalid = true; - Diag(IdLoc ,diag::err_catch_param_not_objc_type); } else if (T->isObjCQualifiedIdType()) { Invalid = true; Diag(IdLoc, diag::err_illegal_qualifiers_on_catch_parm); + } else if (T->isObjCIdType()) { + // Okay: we don't know what this type will instantiate to. + } else if (!T->isObjCObjectPointerType()) { + Invalid = true; + Diag(IdLoc, diag::err_catch_param_not_objc_type); + } else if (!T->getAs<ObjCObjectPointerType>()->getInterfaceType()) { + Invalid = true; + Diag(IdLoc, diag::err_catch_param_not_objc_type); } VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index 67d1b02d1fca..df5bc9b82b96 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -76,6 +76,29 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { .Default(false); } +ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, + Expr *NoexceptExpr, + ExceptionSpecificationType &EST) { + // FIXME: This is bogus, a noexcept expression is not a condition. + ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); + if (Converted.isInvalid()) + return Converted; + + if (Converted.get()->isValueDependent()) { + EST = EST_DependentNoexcept; + return Converted; + } + + llvm::APSInt Result; + Converted = VerifyIntegerConstantExpression( + Converted.get(), &Result, + diag::err_noexcept_needs_constant_expression, + /*AllowFold*/ false); + if (!Converted.isInvalid()) + EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; + return Converted; +} + /// 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. @@ -203,8 +226,8 @@ Sema::UpdateExceptionSpec(FunctionDecl *FD, if (auto *Listener = getASTMutationListener()) Listener->ResolvedExceptionSpec(FD); - for (auto *Redecl : FD->redecls()) - Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); + for (FunctionDecl *Redecl : FD->redecls()) + Context.adjustExceptionSpec(Redecl, ESI); } static bool CheckEquivalentExceptionSpecImpl( @@ -309,13 +332,19 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { + // FIXME: What if the exceptions are described in terms of the old + // prototype's parameters? ESI.Exceptions = OldProto->exceptions(); } - if (ESI.Type == EST_ComputedNoexcept) { - // For computed noexcept, we can't just take the expression from the old - // prototype. It likely contains references to the old prototype's - // parameters. + if (ESI.Type == EST_NoexceptFalse) + ESI.Type = EST_None; + if (ESI.Type == EST_NoexceptTrue) + ESI.Type = EST_BasicNoexcept; + + // For dependent noexcept, we can't just take the expression from the old + // prototype. It likely contains references to the old prototype's parameters. + if (ESI.Type == EST_DependentNoexcept) { New->setInvalidDecl(); } else { // Update the type of the function with the appropriate exception @@ -325,12 +354,12 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->getExtProtoInfo().withExceptionSpec(ESI))); } - if (getLangOpts().MicrosoftExt && ESI.Type != EST_ComputedNoexcept) { + if (getLangOpts().MicrosoftExt && ESI.Type != EST_DependentNoexcept) { // Allow missing exception specifications in redeclarations as an extension. DiagID = diag::ext_ms_missing_exception_specification; ReturnValueOnError = false; } else if (New->isReplaceableGlobalAllocationFunction() && - ESI.Type != EST_ComputedNoexcept) { + ESI.Type != EST_DependentNoexcept) { // Allow missing exception specifications in redeclarations as an extension, // when declaring a replaceable global allocation function. DiagID = diag::ext_missing_exception_specification; @@ -367,7 +396,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { OS << "noexcept"; break; - case EST_ComputedNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: OS << "noexcept("; assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); @@ -478,63 +509,62 @@ static bool CheckEquivalentExceptionSpecImpl( !isUnresolvedExceptionSpec(NewEST) && "Shouldn't see unknown exception specifications here"); - // Shortcut the case where both have no spec. - if (OldEST == EST_None && NewEST == EST_None) - return false; + CanThrowResult OldCanThrow = Old->canThrow(); + CanThrowResult NewCanThrow = New->canThrow(); - FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(S.Context); - FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(S.Context); - if (OldNR == FunctionProtoType::NR_BadNoexcept || - NewNR == FunctionProtoType::NR_BadNoexcept) + // Any non-throwing specifications are compatible. + if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot) return false; - // Dependent noexcept specifiers are compatible with each other, but nothing - // else. - // One noexcept is compatible with another if the argument is the same - if (OldNR == NewNR && - OldNR != FunctionProtoType::NR_NoNoexcept && - NewNR != FunctionProtoType::NR_NoNoexcept) - return false; - if (OldNR != NewNR && - OldNR != FunctionProtoType::NR_NoNoexcept && - NewNR != FunctionProtoType::NR_NoNoexcept) { - S.Diag(NewLoc, DiagID); - if (NoteID.getDiagID() != 0 && OldLoc.isValid()) - S.Diag(OldLoc, NoteID); - return true; + // Any throws-anything specifications are usually compatible. + if (OldCanThrow == CT_Can && OldEST != EST_Dynamic && + NewCanThrow == CT_Can && NewEST != EST_Dynamic) { + // The exception is that the absence of an exception specification only + // matches noexcept(false) for functions, as described above. + if (!AllowNoexceptAllMatchWithNoSpec && + ((OldEST == EST_None && NewEST == EST_NoexceptFalse) || + (OldEST == EST_NoexceptFalse && NewEST == EST_None))) { + // This is the disallowed case. + } else { + return false; + } } - // The MS extension throw(...) is compatible with itself. - if (OldEST == EST_MSAny && NewEST == EST_MSAny) - return false; - - // It's also compatible with no spec. - if ((OldEST == EST_None && NewEST == EST_MSAny) || - (OldEST == EST_MSAny && NewEST == EST_None)) - return false; + // C++14 [except.spec]p3: + // Two exception-specifications are compatible if [...] both have the form + // noexcept(constant-expression) and the constant-expressions are equivalent + if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) { + llvm::FoldingSetNodeID OldFSN, NewFSN; + Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true); + New->getNoexceptExpr()->Profile(NewFSN, S.Context, true); + if (OldFSN == NewFSN) + return false; + } - // It's also compatible with noexcept(false). - if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw) - return false; - if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw) - return false; + // Dynamic exception specifications with the same set of adjusted types + // are compatible. + if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) { + bool Success = true; + // Both have a dynamic exception spec. Collect the first set, then compare + // to the second. + llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; + for (const auto &I : Old->exceptions()) + OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); + + for (const auto &I : New->exceptions()) { + CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); + if (OldTypes.count(TypePtr)) + NewTypes.insert(TypePtr); + else { + Success = false; + break; + } + } - // As described above, noexcept(false) matches no spec only for functions. - if (AllowNoexceptAllMatchWithNoSpec) { - if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw) - return false; - if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw) + if (Success && OldTypes.size() == NewTypes.size()) return false; } - // Any non-throwing specifications are compatible. - bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow || - OldEST == EST_DynamicNone; - bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow || - NewEST == EST_DynamicNone; - if (OldNonThrowing && NewNonThrowing) - return false; - // As a special compatibility feature, under C++0x we accept no spec and // throw(std::bad_alloc) as equivalent for operator new and operator new[]. // This is because the implicit declaration changed, but old code would break. @@ -560,54 +590,24 @@ static bool CheckEquivalentExceptionSpecImpl( } } - // At this point, the only remaining valid case is two matching dynamic - // specifications. We return here unless both specifications are dynamic. - if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) { - if (MissingExceptionSpecification && Old->hasExceptionSpec() && - !New->hasExceptionSpec()) { - // The old type has an exception specification of some sort, but - // the new type does not. - *MissingExceptionSpecification = true; - - if (MissingEmptyExceptionSpecification && OldNonThrowing) { - // The old type has a throw() or noexcept(true) exception specification - // and the new type has no exception specification, and the caller asked - // to handle this itself. - *MissingEmptyExceptionSpecification = true; - } - - return true; + // If the caller wants to handle the case that the new function is + // incompatible due to a missing exception specification, let it. + if (MissingExceptionSpecification && OldEST != EST_None && + NewEST == EST_None) { + // The old type has an exception specification of some sort, but + // the new type does not. + *MissingExceptionSpecification = true; + + if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) { + // The old type has a throw() or noexcept(true) exception specification + // and the new type has no exception specification, and the caller asked + // to handle this itself. + *MissingEmptyExceptionSpecification = true; } - S.Diag(NewLoc, DiagID); - if (NoteID.getDiagID() != 0 && OldLoc.isValid()) - S.Diag(OldLoc, NoteID); return true; } - assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic && - "Exception compatibility logic error: non-dynamic spec slipped through."); - - bool Success = true; - // Both have a dynamic exception spec. Collect the first set, then compare - // to the second. - llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; - for (const auto &I : Old->exceptions()) - OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); - - for (const auto &I : New->exceptions()) { - CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); - if (OldTypes.count(TypePtr)) - NewTypes.insert(TypePtr); - else - Success = false; - } - - Success = Success && OldTypes.size() == NewTypes.size(); - - if (Success) { - return false; - } S.Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0 && OldLoc.isValid()) S.Diag(OldLoc, NoteID); @@ -626,6 +626,90 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, New, NewLoc); } +bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { + // [except.handle]p3: + // A handler is a match for an exception object of type E if: + + // HandlerType must be ExceptionType or derived from it, or pointer or + // reference to such types. + const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>(); + if (RefTy) + HandlerType = RefTy->getPointeeType(); + + // -- the handler is of type cv T or cv T& and E and T are the same type + if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType)) + return true; + + // FIXME: ObjC pointer types? + if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) { + if (RefTy && (!HandlerType.isConstQualified() || + HandlerType.isVolatileQualified())) + return false; + + // -- the handler is of type cv T or const T& where T is a pointer or + // pointer to member type and E is std::nullptr_t + if (ExceptionType->isNullPtrType()) + return true; + + // -- the handler is of type cv T or const T& where T is a pointer or + // pointer to member type and E is a pointer or pointer to member type + // that can be converted to T by one or more of + // -- a qualification conversion + // -- a function pointer conversion + bool LifetimeConv; + QualType Result; + // FIXME: Should we treat the exception as catchable if a lifetime + // conversion is required? + if (IsQualificationConversion(ExceptionType, HandlerType, false, + LifetimeConv) || + IsFunctionConversion(ExceptionType, HandlerType, Result)) + return true; + + // -- a standard pointer conversion [...] + if (!ExceptionType->isPointerType() || !HandlerType->isPointerType()) + return false; + + // Handle the "qualification conversion" portion. + Qualifiers EQuals, HQuals; + ExceptionType = Context.getUnqualifiedArrayType( + ExceptionType->getPointeeType(), EQuals); + HandlerType = Context.getUnqualifiedArrayType( + HandlerType->getPointeeType(), HQuals); + if (!HQuals.compatiblyIncludes(EQuals)) + return false; + + if (HandlerType->isVoidType() && ExceptionType->isObjectType()) + return true; + + // The only remaining case is a derived-to-base conversion. + } + + // -- the handler is of type cg T or cv T& and T is an unambiguous public + // base class of E + if (!ExceptionType->isRecordType() || !HandlerType->isRecordType()) + return false; + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) || + Paths.isAmbiguous(Context.getCanonicalType(HandlerType))) + return false; + + // Do this check from a context without privileges. + switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType, + Paths.front(), + /*Diagnostic*/ 0, + /*ForceCheck*/ true, + /*ForceUnprivileged*/ true)) { + case AR_accessible: return true; + case AR_inaccessible: return false; + case AR_dependent: + llvm_unreachable("access check dependent for unprivileged context"); + case AR_delayed: + llvm_unreachable("access check delayed in non-declaration"); + } + llvm_unreachable("unexpected access check result"); +} + /// CheckExceptionSpecSubset - Check whether the second function type's /// exception specification is a subset (or equivalent) of the first function /// type. This is used by override and pointer assignment checks. @@ -656,62 +740,32 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, return false; ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); - - // If superset contains everything, we're done. - if (SuperEST == EST_None || SuperEST == EST_MSAny) - return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, - Subset, SubLoc); - - // If there are dependent noexcept specs, assume everything is fine. Unlike - // with the equivalency check, this is safe in this case, because we don't - // want to merge declarations. Checks after instantiation will catch any - // omissions we make here. - // We also shortcut checking if a noexcept expression was bad. - - FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context); - if (SuperNR == FunctionProtoType::NR_BadNoexcept || - SuperNR == FunctionProtoType::NR_Dependent) - return false; - - // Another case of the superset containing everything. - if (SuperNR == FunctionProtoType::NR_Throw) - return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, - Subset, SubLoc); - ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); - assert(!isUnresolvedExceptionSpec(SuperEST) && !isUnresolvedExceptionSpec(SubEST) && "Shouldn't see unknown exception specifications here"); - // It does not. If the subset contains everything, we've failed. - if (SubEST == EST_None || SubEST == EST_MSAny) { - Diag(SubLoc, DiagID); - if (NoteID.getDiagID() != 0) - Diag(SuperLoc, NoteID); - return true; - } - - FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context); - if (SubNR == FunctionProtoType::NR_BadNoexcept || - SubNR == FunctionProtoType::NR_Dependent) + // If there are dependent noexcept specs, assume everything is fine. Unlike + // with the equivalency check, this is safe in this case, because we don't + // want to merge declarations. Checks after instantiation will catch any + // omissions we make here. + if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept) return false; - // Another case of the subset containing everything. - if (SubNR == FunctionProtoType::NR_Throw) { - Diag(SubLoc, DiagID); - if (NoteID.getDiagID() != 0) - Diag(SuperLoc, NoteID); - return true; - } + CanThrowResult SuperCanThrow = Superset->canThrow(); + CanThrowResult SubCanThrow = Subset->canThrow(); - // If the subset contains nothing, we're done. - if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) + // If the superset contains everything or the subset contains nothing, we're + // done. + if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) || + SubCanThrow == CT_Cannot) return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, Subset, SubLoc); - // Otherwise, if the superset contains nothing, we've failed. - if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { + // If the subset contains everything or the superset contains nothing, we've + // failed. + if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || + SuperCanThrow == CT_Cannot) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); @@ -722,75 +776,23 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, "Exception spec subset: non-dynamic case slipped through."); // Neither contains everything or nothing. Do a proper comparison. - for (const auto &SubI : Subset->exceptions()) { - // Take one type from the subset. - QualType CanonicalSubT = Context.getCanonicalType(SubI); - // Unwrap pointers and references so that we can do checks within a class - // hierarchy. Don't unwrap member pointers; they don't have hierarchy - // conversions on the pointee. - bool SubIsPointer = false; - if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) - CanonicalSubT = RefTy->getPointeeType(); - if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { - CanonicalSubT = PtrTy->getPointeeType(); - SubIsPointer = true; - } - bool SubIsClass = CanonicalSubT->isRecordType(); - CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); + for (QualType SubI : Subset->exceptions()) { + if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>()) + SubI = RefTy->getPointeeType(); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - - bool Contained = false; // Make sure it's in the superset. - for (const auto &SuperI : Superset->exceptions()) { - QualType CanonicalSuperT = Context.getCanonicalType(SuperI); - // SubT must be SuperT or derived from it, or pointer or reference to - // such types. - if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) - CanonicalSuperT = RefTy->getPointeeType(); - if (SubIsPointer) { - if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) - CanonicalSuperT = PtrTy->getPointeeType(); - else { - continue; - } - } - CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); - // If the types are the same, move on to the next type in the subset. - if (CanonicalSubT == CanonicalSuperT) { + bool Contained = false; + for (QualType SuperI : Superset->exceptions()) { + // [except.spec]p5: + // the target entity shall allow at least the exceptions allowed by the + // source + // + // We interpret this as meaning that a handler for some target type would + // catch an exception of each source type. + if (handlerCanCatch(SuperI, SubI)) { Contained = true; break; } - - // Otherwise we need to check the inheritance. - if (!SubIsClass || !CanonicalSuperT->isRecordType()) - continue; - - Paths.clear(); - if (!IsDerivedFrom(SubLoc, CanonicalSubT, CanonicalSuperT, Paths)) - continue; - - if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) - continue; - - // Do this check from a context without privileges. - switch (CheckBaseClassAccess(SourceLocation(), - CanonicalSuperT, CanonicalSubT, - Paths.front(), - /*Diagnostic*/ 0, - /*ForceCheck*/ true, - /*ForceUnprivileged*/ true)) { - case AR_accessible: break; - case AR_inaccessible: continue; - case AR_dependent: - llvm_unreachable("access check dependent for unprivileged context"); - case AR_delayed: - llvm_unreachable("access check delayed in non-declaration"); - } - - Contained = true; - break; } if (!Contained) { Diag(SubLoc, DiagID); @@ -994,7 +996,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { if (!FT) return CT_Can; - return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; + return FT->canThrow(); } static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { @@ -1262,6 +1264,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ImaginaryLiteralClass: case Expr::ImplicitValueInitExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::ObjCEncodeExprClass: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index a6e43765e106..60abd718e228 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -37,6 +37,7 @@ #include "clang/Sema/Designator.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -47,7 +48,7 @@ using namespace clang; using namespace sema; -/// \brief Determine whether the use of this declaration is valid, without +/// Determine whether the use of this declaration is valid, without /// emitting diagnostics. bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) { // See if this is an auto-typed variable whose initializer we are parsing. @@ -88,7 +89,7 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { } } -/// \brief Emit a note explaining that this function is deleted. +/// Emit a note explaining that this function is deleted. void Sema::NoteDeletedFunction(FunctionDecl *Decl) { assert(Decl->isDeleted()); @@ -116,7 +117,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) { << Decl << true; } -/// \brief Determine whether a FunctionDecl was ever declared with an +/// Determine whether a FunctionDecl was ever declared with an /// explicit storage class. static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { for (auto I : D->redecls()) { @@ -126,7 +127,7 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { return false; } -/// \brief Check whether we're in an extern inline function and referring to a +/// Check whether we're in an extern inline function and referring to a /// variable or function with internal linkage (C11 6.7.4p3). /// /// This is only a warning because we used to silently accept this code, but @@ -189,7 +190,7 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { } } -/// \brief Determine whether the use of this declaration is valid, and +/// Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. /// /// This routine diagnoses various problems with referencing @@ -201,10 +202,11 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// -bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, +bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks) { + SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -288,7 +290,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } - DiagnoseAvailabilityOfDecl(D, Loc, UnknownObjCClass, ObjCPropertyAccess, + DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, AvoidPartialAvailabilityChecks); DiagnoseUnusedOfDecl(*this, D, Loc); @@ -298,7 +300,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return false; } -/// \brief Retrieve the message suffix that should be added to a +/// Retrieve the message suffix that should be added to a /// diagnostic complaining about the given function being deleted or /// unavailable. std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { @@ -776,6 +778,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { return VAK_Valid; } + if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) + return VAK_Invalid; + if (Ty.isCXX98PODType(Context)) return VAK_Valid; @@ -837,7 +842,10 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { break; case VAK_Invalid: - if (Ty->isObjCObjectType()) + if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) + Diag(E->getLocStart(), + diag::err_cannot_pass_non_trivial_c_struct_to_vararg) << Ty << CT; + else if (Ty->isObjCObjectType()) DiagRuntimeBehavior( E->getLocStart(), nullptr, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) @@ -909,7 +917,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return E; } -/// \brief Converts an integer to complex float type. Helper function of +/// Converts an integer to complex float type. Helper function of /// UsualArithmeticConversions() /// /// \return false if the integer expression is an integer type and is @@ -934,7 +942,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, return false; } -/// \brief Handle arithmetic conversion with complex types. Helper function of +/// Handle arithmetic conversion with complex types. Helper function of /// UsualArithmeticConversions() static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, @@ -990,7 +998,7 @@ static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, return ResultType; } -/// \brief Handle arithmetic conversion from integer to float. Helper function +/// Handle arithmetic conversion from integer to float. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, ExprResult &IntExpr, @@ -1021,7 +1029,7 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, return result; } -/// \brief Handle arithmethic conversion with floating point types. Helper +/// Handle arithmethic conversion with floating point types. Helper /// function of UsualArithmeticConversions() static QualType handleFloatConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, @@ -1059,7 +1067,7 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS, /*convertFloat=*/!IsCompAssign); } -/// \brief Diagnose attempts to convert between __float128 and long double if +/// Diagnose attempts to convert between __float128 and long double if /// there is no support for such conversion. Helper function of /// UsualArithmeticConversions(). static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, @@ -1092,13 +1100,12 @@ static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && RHSElemType == S.Context.Float128Ty); - /* We've handled the situation where __float128 and long double have the same - representation. The only other allowable conversion is if long double is - really just double. - */ + // We've handled the situation where __float128 and long double have the same + // representation. We allow all conversions for all possible long double types + // except PPC's double double. return Float128AndLongDouble && - (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != - &llvm::APFloat::IEEEdouble()); + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == + &llvm::APFloat::PPCDoubleDouble()); } typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); @@ -1116,7 +1123,7 @@ ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) { } } -/// \brief Handle integer arithmetic conversions. Helper function of +/// Handle integer arithmetic conversions. Helper function of /// UsualArithmeticConversions() template <PerformCastFn doLHSCast, PerformCastFn doRHSCast> static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, @@ -1167,7 +1174,7 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, } } -/// \brief Handle conversions with GCC complex int extension. Helper function +/// Handle conversions with GCC complex int extension. Helper function /// of UsualArithmeticConversions() static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, @@ -1529,6 +1536,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { CharTy = Context.getWideCharType(); Kind = StringLiteral::Wide; } else if (Literal.isUTF8()) { + if (getLangOpts().Char8) + CharTy = Context.Char8Ty; Kind = StringLiteral::UTF8; } else if (Literal.isUTF16()) { CharTy = Context.Char16Ty; @@ -1545,17 +1554,14 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings) CharTyConst.addConst(); + CharTyConst = Context.adjustStringLiteralBaseType(CharTyConst); + // Get an array type for the string, according to C99 6.4.5. This includes // the nul terminator character as well as the string length for pascal // strings. - QualType StrTy = Context.getConstantArrayType(CharTyConst, - llvm::APInt(32, Literal.GetNumStringChars()+1), - ArrayType::Normal, 0); - - // OpenCL v1.1 s6.5.3: a string literal is in the constant address space. - if (getLangOpts().OpenCL) { - StrTy = Context.getAddrSpaceQualType(StrTy, LangAS::opencl_constant); - } + QualType StrTy = Context.getConstantArrayType( + CharTyConst, llvm::APInt(32, Literal.GetNumStringChars() + 1), + ArrayType::Normal, 0); // Pass &StringTokLocs[0], StringTokLocs.size() to factory! StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), @@ -1674,9 +1680,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclRefReferenced(E); if (getLangOpts().ObjCWeak && isa<VarDecl>(D) && - Ty.getObjCLifetime() == Qualifiers::OCL_Weak && + Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart())) - recordUseOfEvaluatedWeak(E); + getCurFunction()->recordUseOfWeak(E); FieldDecl *FD = dyn_cast<FieldDecl>(D); if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) @@ -2074,16 +2080,17 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) ? LookupObjCImplicitSelfParam : LookupOrdinaryName); - if (TemplateArgs) { + if (TemplateKWLoc.isValid() || TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the // lookup to determine that it was a template name in the first place. If // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. bool MemberOfUnknownSpecialization; - LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, - MemberOfUnknownSpecialization); - + if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization, TemplateKWLoc)) + return ExprError(); + if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, @@ -2149,6 +2156,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, if (SS.isValid()) CCC->setTypoNNS(SS.getScopeRep()); } + // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for + // a template name, but we happen to have always already looked up the name + // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? std::move(CCC) : std::move(DefaultValidator), nullptr, None, &TE)) { @@ -2426,8 +2436,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, IV->getLocation(), SelfExpr.get(), true, true); if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) - recordUseOfEvaluatedWeak(Result); + if (!isUnevaluatedContext() && + !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) + getCurFunction()->recordUseOfWeak(Result); } if (getLangOpts().ObjCAutoRefCount) { if (CurContext->isClosure()) @@ -2471,7 +2482,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return ExprResult((Expr *)nullptr); } -/// \brief Cast a base object to a member's actual type. +/// Cast a base object to a member's actual type. /// /// Logically this happens in three phases: /// @@ -2717,12 +2728,23 @@ static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { return false; } +// Certain multiversion types should be treated as overloaded even when there is +// only one result. +static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) { + assert(R.isSingleResult() && "Expected only a single result"); + const auto *FD = dyn_cast<FunctionDecl>(R.getFoundDecl()); + return FD && + (FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion()); +} + 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>()) + if (!NeedsADL && R.isSingleResult() && + !R.getAsSingle<FunctionTemplateDecl>() && + !ShouldLookupResultBeMultiVersionOverload(R)) return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), R.getRepresentativeDecl(), nullptr, AcceptInvalidDecl); @@ -2730,7 +2752,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We only need to check the declaration if there's exactly one // result, because in the overloaded case the results can only be // functions and function templates. - if (R.isSingleResult() && + if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) && CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) return ExprError(); @@ -2753,7 +2775,7 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, ValueDecl *var, DeclContext *DC); -/// \brief Complete semantic analysis for a reference to the given declaration. +/// 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, @@ -2769,9 +2791,7 @@ ExprResult Sema::BuildDeclarationNameExpr( if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { // Specifically diagnose references to class templates that are missing // a template argument list. - Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0) - << Template << SS.getRange(); - Diag(Template->getLocation(), diag::note_template_decl_here); + diagnoseMissingTemplateArguments(TemplateName(Template), Loc); return ExprError(); } @@ -3034,8 +3054,9 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, unsigned Length = Str.length(); llvm::APInt LengthI(32, Length + 1); - if (IT == PredefinedExpr::LFunction) { - ResTy = Context.WideCharTy.withConst(); + if (IT == PredefinedExpr::LFunction || IT == PredefinedExpr::LFuncSig) { + ResTy = + Context.adjustStringLiteralBaseType(Context.WideCharTy.withConst()); SmallString<32> RawChars; ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), Str, RawChars); @@ -3044,7 +3065,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, /*Pascal*/ false, ResTy, Loc); } else { - ResTy = Context.CharTy.withConst(); + ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, @@ -3064,7 +3085,8 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break; case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS] case tok::kw___FUNCSIG__: IT = PredefinedExpr::FuncSig; break; // [MS] - case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break; + case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break; // [MS] + case tok::kw_L__FUNCSIG__: IT = PredefinedExpr::LFuncSig; break; // [MS] case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break; } @@ -3086,6 +3108,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { QualType Ty; if (Literal.isWide()) Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++. + else if (Literal.isUTF8() && getLangOpts().Char8) + Ty = Context.Char8Ty; // u8'x' -> char8_t when it exists. else if (Literal.isUTF16()) Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11. else if (Literal.isUTF32()) @@ -3281,8 +3305,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // operator "" X ("n") unsigned Length = Literal.getUDSuffixOffset(); QualType StrTy = Context.getConstantArrayType( - Context.CharTy.withConst(), llvm::APInt(32, Length + 1), - ArrayType::Normal, 0); + Context.adjustStringLiteralBaseType(Context.CharTy.withConst()), + llvm::APInt(32, Length + 1), ArrayType::Normal, 0); Expr *Lit = StringLiteral::Create( Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); @@ -3314,7 +3338,52 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Expr *Res; - if (Literal.isFloatingLiteral()) { + if (Literal.isFixedPointLiteral()) { + QualType Ty; + + if (Literal.isAccum) { + if (Literal.isHalf) { + Ty = Context.ShortAccumTy; + } else if (Literal.isLong) { + Ty = Context.LongAccumTy; + } else { + Ty = Context.AccumTy; + } + } else if (Literal.isFract) { + if (Literal.isHalf) { + Ty = Context.ShortFractTy; + } else if (Literal.isLong) { + Ty = Context.LongFractTy; + } else { + Ty = Context.FractTy; + } + } + + if (Literal.isUnsigned) Ty = Context.getCorrespondingUnsignedType(Ty); + + bool isSigned = !Literal.isUnsigned; + unsigned scale = Context.getFixedPointScale(Ty); + unsigned ibits = Context.getFixedPointIBits(Ty); + unsigned bit_width = Context.getTypeInfo(Ty).Width; + + llvm::APInt Val(bit_width, 0, isSigned); + bool Overflowed = Literal.GetFixedPointValue(Val, scale); + + // Do not use bit_width since some types may have padding like _Fract or + // unsigned _Accums if PaddingOnUnsignedFixedPoint is set. + auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width); + if (Literal.isFract && Val == MaxVal + 1) + // Clause 6.4.4 - The value of a constant shall be in the range of + // representable values for its type, with exception for constants of a + // fract type with a value of exactly 1; such a constant shall denote + // the maximal value for the type. + --Val; + else if (Val.ugt(MaxVal) || Overflowed) + Diag(Tok.getLocation(), diag::err_too_large_for_fixed_point); + + Res = FixedPointLiteral::CreateFromRawInt(Context, Val, Ty, + Tok.getLocation(), scale); + } else if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ if (getOpenCLOptions().isEnabled("cl_khr_fp16")) @@ -3554,7 +3623,7 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, return false; } -/// \brief Check whether E is a pointer from a decayed array type (the decayed +/// Check whether E is a pointer from a decayed array type (the decayed /// pointer type is equal to T) and emit a warning if it is. static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, Expr *E) { @@ -3572,7 +3641,7 @@ static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, << ICE->getSubExpr()->getType(); } -/// \brief Check the constraints on expression operands to unary type expression +/// Check the constraints on expression operands to unary type expression /// and type traits. /// /// Completes any types necessary and validates the constraints on the operand @@ -3656,7 +3725,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return false; } -/// \brief Check the constraints on operands to unary expression and type +/// Check the constraints on operands to unary expression and type /// traits. /// /// This will complete any types necessary, and validate the various constraints @@ -3910,7 +3979,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, } while (!T.isNull() && T->isVariablyModifiedType()); } -/// \brief Build a sizeof or alignof expression given a type operand. +/// Build a sizeof or alignof expression given a type operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, @@ -3954,7 +4023,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); } -/// \brief Build a sizeof or alignof expression given an expression +/// Build a sizeof or alignof expression given an expression /// operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, @@ -4072,7 +4141,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, return BuildUnaryOp(S, OpLoc, Opc, Input); } -/// \brief Diagnose if arithmetic on the given ObjC pointer is illegal. +/// Diagnose if arithmetic on the given ObjC pointer is illegal. /// /// \return true on error static bool checkArithmeticOnObjCPointer(Sema &S, @@ -4328,10 +4397,13 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // Per C++ core issue 1213, the result is an xvalue if either operand is // a non-lvalue array, and an lvalue otherwise. - if (getLangOpts().CPlusPlus11 && - ((LHSExp->getType()->isArrayType() && !LHSExp->isLValue()) || - (RHSExp->getType()->isArrayType() && !RHSExp->isLValue()))) - VK = VK_XValue; + if (getLangOpts().CPlusPlus11) { + for (auto *Op : {LHSExp, RHSExp}) { + Op = Op->IgnoreImplicit(); + if (Op->getType()->isArrayType() && !Op->isLValue()) + VK = VK_XValue; + } + } // Perform default conversions. if (!LHSExp->getType()->getAs<VectorType>()) { @@ -4392,12 +4464,24 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) { BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; + // We apply C++ DR1213 to vector subscripting too. + if (getLangOpts().CPlusPlus11 && LHSExp->getValueKind() == VK_RValue) { + ExprResult Materialized = TemporaryMaterializationConversion(LHSExp); + if (Materialized.isInvalid()) + return ExprError(); + LHSExp = Materialized.get(); + } VK = LHSExp->getValueKind(); if (VK != VK_RValue) OK = OK_VectorComponent; - // FIXME: need to deal with const... ResultType = VTy->getElementType(); + QualType BaseType = BaseExpr->getType(); + Qualifiers BaseQuals = BaseType.getQualifiers(); + Qualifiers MemberQuals = ResultType.getQualifiers(); + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + ResultType = Context.getQualifiedType(ResultType, Combined); } else if (LHSTy->isArrayType()) { // If we see an array that wasn't promoted by // DefaultFunctionArrayLvalueConversion, it must be an array that @@ -4831,6 +4915,10 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, (!Param || !Param->hasAttr<CFConsumedAttr>())) CFAudited = true; + if (Proto->getExtParameterInfo(i).isNoEscape()) + if (auto *BE = dyn_cast<BlockExpr>(Arg->IgnoreParenNoopCasts(Context))) + BE->getBlockDecl()->setDoesNotEscape(); + InitializedEntity Entity = Param ? InitializedEntity::InitializeParameter(Context, Param, ProtoArgType) @@ -5496,7 +5584,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // CUDA: Kernel calls must be to global functions if (FDecl && !FDecl->hasAttr<CUDAGlobalAttr>()) return ExprError(Diag(LParenLoc,diag::err_kern_call_not_global_function) - << FDecl->getName() << Fn->getSourceRange()); + << FDecl << Fn->getSourceRange()); // CUDA: Kernel function must have 'void' return type if (!FuncT->getReturnType()->isVoidType()) @@ -5506,7 +5594,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // CUDA: Calls to global functions must be configured if (FDecl && FDecl->hasAttr<CUDAGlobalAttr>()) return ExprError(Diag(LParenLoc, diag::err_global_call_not_config) - << FDecl->getName() << Fn->getSourceRange()); + << FDecl << Fn->getSourceRange()); } } @@ -5705,7 +5793,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, } // Semantic analysis for initializers is done by ActOnDeclarator() and - // CheckInitializer() - it requires knowledge of the object being intialized. + // CheckInitializer() - it requires knowledge of the object being initialized. InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc); @@ -6239,7 +6327,7 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L, return expr; } -/// \brief Emit a specialized diagnostic when one expression is a null pointer +/// Emit a specialized diagnostic when one expression is a null pointer /// constant and the other is not a pointer. Returns true if a diagnostic is /// emitted. bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, @@ -6280,7 +6368,7 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, return true; } -/// \brief Return false if the condition expression is valid, true otherwise. +/// Return false if the condition expression is valid, true otherwise. static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { QualType CondTy = Cond->getType(); @@ -6299,7 +6387,7 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { return true; } -/// \brief Handle when one or both operands are void type. +/// Handle when one or both operands are void type. static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, ExprResult &RHS) { Expr *LHSExpr = LHS.get(); @@ -6316,7 +6404,7 @@ static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, return S.Context.VoidTy; } -/// \brief Return false if the NullExpr can be promoted to PointerTy, +/// Return false if the NullExpr can be promoted to PointerTy, /// true otherwise. static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, QualType PointerTy) { @@ -6329,7 +6417,7 @@ static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, return false; } -/// \brief Checks compatibility between two pointers and return the resulting +/// Checks compatibility between two pointers and return the resulting /// type. static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, @@ -6463,7 +6551,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return ResultTy; } -/// \brief Return the resulting type when the operands are both block pointers. +/// Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, @@ -6488,7 +6576,7 @@ static QualType checkConditionalBlockPointerCompatibility(Sema &S, return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); } -/// \brief Return the resulting type when the operands are both pointers. +/// Return the resulting type when the operands are both pointers. static QualType checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, @@ -6527,7 +6615,7 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); } -/// \brief Return false if the first expression is not an integer and the second +/// Return false if the first expression is not an integer and the second /// expression is not a pointer, true otherwise. static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, Expr* PointerExpr, SourceLocation Loc, @@ -6547,7 +6635,7 @@ static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, return true; } -/// \brief Simple conversion between integer and floating point types. +/// Simple conversion between integer and floating point types. /// /// Used when handling the OpenCL conditional operator where the /// condition is a vector while the other operands are scalar. @@ -6602,7 +6690,7 @@ static QualType OpenCLArithmeticConversions(Sema &S, ExprResult &LHS, (S, LHS, RHS, LHSType, RHSType, /*IsCompAssign = */ false); } -/// \brief Convert scalar operands to a vector that matches the +/// Convert scalar operands to a vector that matches the /// condition in length. /// /// Used when handling the OpenCL conditional operator where the @@ -6647,7 +6735,7 @@ OpenCLConvertScalarsToVectors(Sema &S, ExprResult &LHS, ExprResult &RHS, return VectorTy; } -/// \brief Return false if this is a valid OpenCL condition vector +/// Return false if this is a valid OpenCL condition vector static bool checkOpenCLConditionVector(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { // OpenCL v1.1 s6.11.6 says the elements of the vector must be of @@ -6662,7 +6750,7 @@ static bool checkOpenCLConditionVector(Sema &S, Expr *Cond, return true; } -/// \brief Return false if the vector condition type and the vector +/// Return false if the vector condition type and the vector /// result type are compatible. /// /// OpenCL v1.1 s6.11.6 requires that both vector types have the same @@ -6692,7 +6780,7 @@ static bool checkVectorResult(Sema &S, QualType CondTy, QualType VecResTy, return false; } -/// \brief Return the resulting type for the conditional operator in +/// Return the resulting type for the conditional operator in /// OpenCL (aka "ternary selection operator", OpenCL v1.1 /// s6.3.i) when the condition is a vector type. static QualType @@ -6727,7 +6815,7 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc); } -/// \brief Return true if the Expr is block type +/// Return true if the Expr is block type static bool checkBlockType(Sema &S, const Expr *E) { if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { QualType Ty = CE->getCallee()->getType(); @@ -7050,6 +7138,10 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, E = E->IgnoreImpCasts(); E = E->IgnoreConversionOperator(); E = E->IgnoreImpCasts(); + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { + E = MTE->GetTemporaryExpr(); + E = E->IgnoreImpCasts(); + } // Built-in binary operator. if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) { @@ -7097,6 +7189,8 @@ static bool ExprLooksBoolean(Expr *E) { return OP->getOpcode() == UO_LNot; if (E->getType()->isPointerType()) return true; + // FIXME: What about overloaded operator calls returning "unspecified boolean + // type"s (commonly pointer-to-members)? return false; } @@ -7848,7 +7942,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } -/// \brief Constructs a transparent union from an expression that is +/// Constructs a transparent union from an expression that is /// used to initialize the transparent union. static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult, QualType UnionType, @@ -8015,7 +8109,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, if (Diagnose && isa<ObjCProtocolExpr>(PRE)) { ObjCProtocolDecl *PDecl = cast<ObjCProtocolExpr>(PRE)->getProtocol(); if (PDecl && !PDecl->hasDefinition()) { - Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl->getName(); + Diag(PRE->getExprLoc(), diag::warn_atprotocol_protocol) << PDecl; Diag(PDecl->getLocation(), diag::note_entity_declared_at) << PDecl; } } @@ -8054,18 +8148,57 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, RHS = E; return Compatible; } - + if (ConvertRHS) RHS = ImpCastExprToType(E, Ty, Kind); } return result; } +namespace { +/// The original operand to an operator, prior to the application of the usual +/// arithmetic conversions and converting the arguments of a builtin operator +/// candidate. +struct OriginalOperand { + explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) { + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op)) + Op = MTE->GetTemporaryExpr(); + if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op)) + Op = BTE->getSubExpr(); + if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) { + Orig = ICE->getSubExprAsWritten(); + Conversion = ICE->getConversionFunction(); + } + } + + QualType getType() const { return Orig->getType(); } + + Expr *Orig; + NamedDecl *Conversion; +}; +} + QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS) { + OriginalOperand OrigLHS(LHS.get()), OrigRHS(RHS.get()); + Diag(Loc, diag::err_typecheck_invalid_operands) - << LHS.get()->getType() << RHS.get()->getType() + << OrigLHS.getType() << OrigRHS.getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + + // If a user-defined conversion was applied to either of the operands prior + // to applying the built-in operator rules, tell the user about it. + if (OrigLHS.Conversion) { + Diag(OrigLHS.Conversion->getLocation(), + diag::note_typecheck_invalid_operands_converted) + << 0 << LHS.get()->getType(); + } + if (OrigRHS.Conversion) { + Diag(OrigRHS.Conversion->getLocation(), + diag::note_typecheck_invalid_operands_converted) + << 1 << RHS.get()->getType(); + } + return QualType(); } @@ -8216,7 +8349,7 @@ static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int, QualType IntTy = Int->get()->getType().getUnqualifiedType(); // Determine if the integer constant can be expressed as a floating point - // number of the appropiate type. + // number of the appropriate type. llvm::APSInt Result; bool CstInt = Int->get()->EvaluateAsInt(Result, S.Context); uint64_t Bits = 0; @@ -8594,7 +8727,7 @@ QualType Sema::CheckRemainderOperands( return compType; } -/// \brief Diagnose invalid arithmetic on two void pointers. +/// Diagnose invalid arithmetic on two void pointers. static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, Expr *LHSExpr, Expr *RHSExpr) { S.Diag(Loc, S.getLangOpts().CPlusPlus @@ -8604,7 +8737,7 @@ static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, << RHSExpr->getSourceRange(); } -/// \brief Diagnose invalid arithmetic on a void pointer. +/// Diagnose invalid arithmetic on a void pointer. static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, Expr *Pointer) { S.Diag(Loc, S.getLangOpts().CPlusPlus @@ -8613,7 +8746,7 @@ static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, << 0 /* one pointer */ << Pointer->getSourceRange(); } -/// \brief Diagnose invalid arithmetic on a null pointer. +/// Diagnose invalid arithmetic on a null pointer. /// /// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n' /// idiom, which we recognize as a GNU extension. @@ -8628,7 +8761,7 @@ static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc, << S.getLangOpts().CPlusPlus << Pointer->getSourceRange(); } -/// \brief Diagnose invalid arithmetic on two function pointers. +/// Diagnose invalid arithmetic on two function pointers. static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS) { assert(LHS->getType()->isAnyPointerType()); @@ -8644,7 +8777,7 @@ static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, << LHS->getSourceRange() << RHS->getSourceRange(); } -/// \brief Diagnose invalid arithmetic on a function pointer. +/// Diagnose invalid arithmetic on a function pointer. static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, Expr *Pointer) { assert(Pointer->getType()->isAnyPointerType()); @@ -8656,7 +8789,7 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, << Pointer->getSourceRange(); } -/// \brief Emit error if Operand is incomplete pointer type +/// Emit error if Operand is incomplete pointer type /// /// \returns True if pointer has incomplete type static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, @@ -8672,7 +8805,7 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, PointeeTy, Operand->getSourceRange()); } -/// \brief Check the validity of an arithmetic pointer operand. +/// Check the validity of an arithmetic pointer operand. /// /// If the operand has pointer type, this code will check for pointer types /// which are invalid in arithmetic operations. These will be diagnosed @@ -8703,7 +8836,7 @@ static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, return true; } -/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer +/// Check the validity of a binary arithmetic operation w.r.t. pointer /// operands. /// /// This routine will diagnose any invalid arithmetic on pointer operands much @@ -8805,7 +8938,7 @@ static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc, Self.Diag(OpLoc, diag::note_string_plus_scalar_silence); } -/// \brief Emit a warning when adding a char literal to a string. +/// Emit a warning when adding a char literal to a string. static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { const Expr *StringRefExpr = LHSExpr; @@ -8856,7 +8989,7 @@ static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc, } } -/// \brief Emit error when two pointers are incompatible. +/// Emit error when two pointers are incompatible. static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc, Expr *LHSExpr, Expr *RHSExpr) { assert(LHSExpr->getType()->isAnyPointerType()); @@ -9154,7 +9287,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange(); } -/// \brief Return the resulting type when a vector is shifted +/// Return the resulting type when a vector is shifted /// by a scalar or vector shift amount. static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { @@ -9300,16 +9433,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, return LHSType; } -static bool IsWithinTemplateSpecialization(Decl *D) { - if (DeclContext *DC = D->getDeclContext()) { - if (isa<ClassTemplateSpecializationDecl>(DC)) - return true; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) - return FD->isFunctionTemplateSpecialization(); - } - return false; -} - /// If two different enums are compared, raise a warning. static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS) { @@ -9339,7 +9462,7 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, << LHS->getSourceRange() << RHS->getSourceRange(); } -/// \brief Diagnose bad pointer comparisons. +/// Diagnose bad pointer comparisons. static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, bool IsError) { @@ -9349,7 +9472,7 @@ static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } -/// \brief Returns false if the pointers are converted to a composite type, +/// Returns false if the pointers are converted to a composite type, /// true otherwise. static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS) { @@ -9587,137 +9710,368 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS, // Get the decl for a simple expression: a reference to a variable, // an implicit C++ field reference, or an implicit ObjC ivar reference. static ValueDecl *getCompareDecl(Expr *E) { - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) return DR->getDecl(); - if (ObjCIvarRefExpr* Ivar = dyn_cast<ObjCIvarRefExpr>(E)) { + if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) { if (Ivar->isFreeIvar()) return Ivar->getDecl(); } - if (MemberExpr* Mem = dyn_cast<MemberExpr>(E)) { + if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) { if (Mem->isImplicitAccess()) return Mem->getMemberDecl(); } return nullptr; } -// C99 6.5.8, C++ [expr.rel] -QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, BinaryOperatorKind Opc, - bool IsRelational) { - checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true); +/// Diagnose some forms of syntactically-obvious tautological comparison. +static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, + Expr *LHS, Expr *RHS, + BinaryOperatorKind Opc) { + Expr *LHSStripped = LHS->IgnoreParenImpCasts(); + Expr *RHSStripped = RHS->IgnoreParenImpCasts(); + + QualType LHSType = LHS->getType(); + QualType RHSType = RHS->getType(); + if (LHSType->hasFloatingRepresentation() || + (LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) || + LHS->getLocStart().isMacroID() || RHS->getLocStart().isMacroID() || + S.inTemplateInstantiation()) + return; - // Handle vector comparisons separately. - if (LHS.get()->getType()->isVectorType() || - RHS.get()->getType()->isVectorType()) - return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational); + // Comparisons between two array types are ill-formed for operator<=>, so + // we shouldn't emit any additional warnings about it. + if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType()) + return; + + // For non-floating point types, check for self-comparisons of the form + // x == x, x != x, x < x, etc. These always evaluate to a constant, and + // often indicate logic errors in the program. + // + // NOTE: Don't warn about comparison expressions resulting from macro + // expansion. Also don't warn about comparisons which are only self + // comparisons within a template instantiation. The warnings should catch + // obvious cases in the definition of the template anyways. The idea is to + // warn when the typed comparison operator will always evaluate to the same + // result. + ValueDecl *DL = getCompareDecl(LHSStripped); + ValueDecl *DR = getCompareDecl(RHSStripped); + if (DL && DR && declaresSameEntity(DL, DR)) { + StringRef Result; + switch (Opc) { + case BO_EQ: case BO_LE: case BO_GE: + Result = "true"; + break; + case BO_NE: case BO_LT: case BO_GT: + Result = "false"; + break; + case BO_Cmp: + Result = "'std::strong_ordering::equal'"; + break; + default: + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 0 /*self-comparison*/ << !Result.empty() + << Result); + } else if (DL && DR && + DL->getType()->isArrayType() && DR->getType()->isArrayType() && + !DL->isWeak() && !DR->isWeak()) { + // What is it always going to evaluate to? + StringRef Result; + switch(Opc) { + case BO_EQ: // e.g. array1 == array2 + Result = "false"; + break; + case BO_NE: // e.g. array1 != array2 + Result = "true"; + break; + default: // e.g. array1 <= array2 + // The best we can say is 'a constant' + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 1 /*array comparison*/ + << !Result.empty() << Result); + } + + if (isa<CastExpr>(LHSStripped)) + LHSStripped = LHSStripped->IgnoreParenCasts(); + if (isa<CastExpr>(RHSStripped)) + RHSStripped = RHSStripped->IgnoreParenCasts(); + + // Warn about comparisons against a string constant (unless the other + // operand is null); the user probably wants strcmp. + Expr *LiteralString = nullptr; + Expr *LiteralStringStripped = nullptr; + if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && + !RHSStripped->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNull)) { + LiteralString = LHS; + LiteralStringStripped = LHSStripped; + } else if ((isa<StringLiteral>(RHSStripped) || + isa<ObjCEncodeExpr>(RHSStripped)) && + !LHSStripped->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNull)) { + LiteralString = RHS; + LiteralStringStripped = RHSStripped; + } + + if (LiteralString) { + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_stringcompare) + << isa<ObjCEncodeExpr>(LiteralStringStripped) + << LiteralString->getSourceRange()); + } +} + +static ImplicitConversionKind castKindToImplicitConversionKind(CastKind CK) { + switch (CK) { + default: { +#ifndef NDEBUG + llvm::errs() << "unhandled cast kind: " << CastExpr::getCastKindName(CK) + << "\n"; +#endif + llvm_unreachable("unhandled cast kind"); + } + case CK_UserDefinedConversion: + return ICK_Identity; + case CK_LValueToRValue: + return ICK_Lvalue_To_Rvalue; + case CK_ArrayToPointerDecay: + return ICK_Array_To_Pointer; + case CK_FunctionToPointerDecay: + return ICK_Function_To_Pointer; + case CK_IntegralCast: + return ICK_Integral_Conversion; + case CK_FloatingCast: + return ICK_Floating_Conversion; + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + return ICK_Floating_Integral; + case CK_IntegralComplexCast: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralComplexToFloatingComplex: + return ICK_Complex_Conversion; + case CK_FloatingComplexToReal: + case CK_FloatingRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralRealToComplex: + return ICK_Complex_Real; + } +} + +static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, + QualType FromType, + SourceLocation Loc) { + // Check for a narrowing implicit conversion. + StandardConversionSequence SCS; + SCS.setAsIdentityConversion(); + SCS.setToType(0, FromType); + SCS.setToType(1, ToType); + if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + SCS.Second = castKindToImplicitConversionKind(ICE->getCastKind()); + + APValue PreNarrowingValue; + QualType PreNarrowingType; + switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue, + PreNarrowingType, + /*IgnoreFloatToIntegralConversion*/ true)) { + case NK_Dependent_Narrowing: + // Implicit conversion to a narrower type, but the expression is + // value-dependent so we can't tell whether it's actually narrowing. + case NK_Not_Narrowing: + return false; + + case NK_Constant_Narrowing: + // Implicit conversion to a narrower type, and the value is not a constant + // expression. + S.Diag(E->getLocStart(), diag::err_spaceship_argument_narrowing) + << /*Constant*/ 1 + << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << ToType; + return true; + + case NK_Variable_Narrowing: + // Implicit conversion to a narrower type, and the value is not a constant + // expression. + case NK_Type_Narrowing: + S.Diag(E->getLocStart(), diag::err_spaceship_argument_narrowing) + << /*Constant*/ 0 << FromType << ToType; + // TODO: It's not a constant expression, but what if the user intended it + // to be? Can we produce notes to help them figure out why it isn't? + return true; + } + llvm_unreachable("unhandled case in switch"); +} + +static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, + ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc) { + using CCT = ComparisonCategoryType; QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); + // Dig out the original argument type and expression before implicit casts + // were applied. These are the types/expressions we need to check the + // [expr.spaceship] requirements against. + ExprResult LHSStripped = LHS.get()->IgnoreParenImpCasts(); + ExprResult RHSStripped = RHS.get()->IgnoreParenImpCasts(); + QualType LHSStrippedType = LHSStripped.get()->getType(); + QualType RHSStrippedType = RHSStripped.get()->getType(); + + // C++2a [expr.spaceship]p3: If one of the operands is of type bool and the + // other is not, the program is ill-formed. + if (LHSStrippedType->isBooleanType() != RHSStrippedType->isBooleanType()) { + S.InvalidOperands(Loc, LHSStripped, RHSStripped); + return QualType(); + } - Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts(); - Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts(); + int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() + + RHSStrippedType->isEnumeralType(); + if (NumEnumArgs == 1) { + bool LHSIsEnum = LHSStrippedType->isEnumeralType(); + QualType OtherTy = LHSIsEnum ? RHSStrippedType : LHSStrippedType; + if (OtherTy->hasFloatingRepresentation()) { + S.InvalidOperands(Loc, LHSStripped, RHSStripped); + return QualType(); + } + } + if (NumEnumArgs == 2) { + // C++2a [expr.spaceship]p5: If both operands have the same enumeration + // type E, the operator yields the result of converting the operands + // to the underlying type of E and applying <=> to the converted operands. + if (!S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { + S.InvalidOperands(Loc, LHS, RHS); + return QualType(); + } + QualType IntType = + LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType(); + assert(IntType->isArithmeticType()); - checkEnumComparison(*this, Loc, LHS.get(), RHS.get()); - diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we + // promote the boolean type, and all other promotable integer types, to + // avoid this. + if (IntType->isPromotableIntegerType()) + IntType = S.Context.getPromotedIntegerType(IntType); - if (!LHSType->hasFloatingRepresentation() && - !(LHSType->isBlockPointerType() && IsRelational) && - !LHS.get()->getLocStart().isMacroID() && - !RHS.get()->getLocStart().isMacroID() && - !inTemplateInstantiation()) { - // For non-floating point types, check for self-comparisons of the form - // x == x, x != x, x < x, etc. These always evaluate to a constant, and - // often indicate logic errors in the program. - // - // NOTE: Don't warn about comparison expressions resulting from macro - // expansion. Also don't warn about comparisons which are only self - // comparisons within a template specialization. The warnings should catch - // obvious cases in the definition of the template anyways. The idea is to - // warn when the typed comparison operator will always evaluate to the same - // result. - ValueDecl *DL = getCompareDecl(LHSStripped); - ValueDecl *DR = getCompareDecl(RHSStripped); - if (DL && DR && DL == DR && !IsWithinTemplateSpecialization(DL)) { - DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always) - << 0 // self- - << (Opc == BO_EQ - || Opc == BO_LE - || Opc == BO_GE)); - } else if (DL && DR && LHSType->isArrayType() && RHSType->isArrayType() && - !DL->getType()->isReferenceType() && - !DR->getType()->isReferenceType()) { - // what is it always going to eval to? - char always_evals_to; - switch(Opc) { - case BO_EQ: // e.g. array1 == array2 - always_evals_to = 0; // false - break; - case BO_NE: // e.g. array1 != array2 - always_evals_to = 1; // true - break; - default: - // best we can say is 'a constant' - always_evals_to = 2; // e.g. array1 <= array2 - break; - } - DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always) - << 1 // array - << always_evals_to); - } + LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast); + RHS = S.ImpCastExprToType(RHS.get(), IntType, CK_IntegralCast); + LHSType = RHSType = IntType; + } + + // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the + // usual arithmetic conversions are applied to the operands. + QualType Type = S.UsualArithmeticConversions(LHS, RHS); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); + if (Type.isNull()) + return S.InvalidOperands(Loc, LHS, RHS); + assert(Type->isArithmeticType() || Type->isEnumeralType()); + + bool HasNarrowing = checkThreeWayNarrowingConversion( + S, Type, LHS.get(), LHSType, LHS.get()->getLocStart()); + HasNarrowing |= checkThreeWayNarrowingConversion( + S, Type, RHS.get(), RHSType, RHS.get()->getLocStart()); + if (HasNarrowing) + return QualType(); - if (isa<CastExpr>(LHSStripped)) - LHSStripped = LHSStripped->IgnoreParenCasts(); - if (isa<CastExpr>(RHSStripped)) - RHSStripped = RHSStripped->IgnoreParenCasts(); + assert(!Type.isNull() && "composite type for <=> has not been set"); - // Warn about comparisons against a string constant (unless the other - // operand is null), the user probably wants strcmp. - Expr *literalString = nullptr; - Expr *literalStringStripped = nullptr; - if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && - !RHSStripped->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - literalString = LHS.get(); - literalStringStripped = LHSStripped; - } else if ((isa<StringLiteral>(RHSStripped) || - isa<ObjCEncodeExpr>(RHSStripped)) && - !LHSStripped->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { - literalString = RHS.get(); - literalStringStripped = RHSStripped; + auto TypeKind = [&]() { + if (const ComplexType *CT = Type->getAs<ComplexType>()) { + if (CT->getElementType()->hasFloatingRepresentation()) + return CCT::WeakEquality; + return CCT::StrongEquality; } + if (Type->isIntegralOrEnumerationType()) + return CCT::StrongOrdering; + if (Type->hasFloatingRepresentation()) + return CCT::PartialOrdering; + llvm_unreachable("other types are unimplemented"); + }(); - if (literalString) { - DiagRuntimeBehavior(Loc, nullptr, - PDiag(diag::warn_stringcompare) - << isa<ObjCEncodeExpr>(literalStringStripped) - << literalString->getSourceRange()); - } - } + return S.CheckComparisonCategoryType(TypeKind, Loc); +} + +static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, + ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc) { + if (Opc == BO_Cmp) + return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc); // C99 6.5.8p3 / C99 6.5.9p4 - UsualArithmeticConversions(LHS, RHS); + QualType Type = S.UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); + if (Type.isNull()) + return S.InvalidOperands(Loc, LHS, RHS); + assert(Type->isArithmeticType() || Type->isEnumeralType()); - LHSType = LHS.get()->getType(); - RHSType = RHS.get()->getType(); + checkEnumComparison(S, Loc, LHS.get(), RHS.get()); + + if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc)) + return S.InvalidOperands(Loc, LHS, RHS); + + // Check for comparisons of floating point operands using != and ==. + if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc)) + S.CheckFloatComparison(Loc, LHS.get(), RHS.get()); // The result of comparisons is 'bool' in C++, 'int' in C. - QualType ResultTy = Context.getLogicalOperationType(); + return S.Context.getLogicalOperationType(); +} - if (IsRelational) { - if (LHSType->isRealType() && RHSType->isRealType()) - return ResultTy; - } else { - // Check for comparisons of floating point operands using != and ==. - if (LHSType->hasFloatingRepresentation()) - CheckFloatComparison(Loc, LHS.get(), RHS.get()); +// C99 6.5.8, C++ [expr.rel] +QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc) { + bool IsRelational = BinaryOperator::isRelationalOp(Opc); + bool IsThreeWay = Opc == BO_Cmp; + auto IsAnyPointerType = [](ExprResult E) { + QualType Ty = E.get()->getType(); + return Ty->isPointerType() || Ty->isMemberPointerType(); + }; - if (LHSType->isArithmeticType() && RHSType->isArithmeticType()) - return ResultTy; + // C++2a [expr.spaceship]p6: If at least one of the operands is of pointer + // type, array-to-pointer, ..., conversions are performed on both operands to + // bring them to their composite type. + // Otherwise, all comparisons expect an rvalue, so convert to rvalue before + // any type-related checks. + if (!IsThreeWay || IsAnyPointerType(LHS) || IsAnyPointerType(RHS)) { + LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + } else { + LHS = DefaultLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + RHS = DefaultLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); } + checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true); + + // Handle vector comparisons separately. + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorCompareOperands(LHS, RHS, Loc, Opc); + + diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); + + QualType LHSType = LHS.get()->getType(); + QualType RHSType = RHS.get()->getType(); + if ((LHSType->isArithmeticType() || LHSType->isEnumeralType()) && + (RHSType->isArithmeticType() || RHSType->isEnumeralType())) + return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); + const Expr::NullPointerConstantKind LHSNullKind = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); const Expr::NullPointerConstantKind RHSNullKind = @@ -9725,6 +10079,44 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, bool LHSIsNull = LHSNullKind != Expr::NPCK_NotNull; bool RHSIsNull = RHSNullKind != Expr::NPCK_NotNull; + auto computeResultTy = [&]() { + if (Opc != BO_Cmp) + return Context.getLogicalOperationType(); + assert(getLangOpts().CPlusPlus); + assert(Context.hasSameType(LHS.get()->getType(), RHS.get()->getType())); + + QualType CompositeTy = LHS.get()->getType(); + assert(!CompositeTy->isReferenceType()); + + auto buildResultTy = [&](ComparisonCategoryType Kind) { + return CheckComparisonCategoryType(Kind, Loc); + }; + + // C++2a [expr.spaceship]p7: If the composite pointer type is a function + // pointer type, a pointer-to-member type, or std::nullptr_t, the + // result is of type std::strong_equality + if (CompositeTy->isFunctionPointerType() || + CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType()) + // FIXME: consider making the function pointer case produce + // strong_ordering not strong_equality, per P0946R0-Jax18 discussion + // and direction polls + return buildResultTy(ComparisonCategoryType::StrongEquality); + + // C++2a [expr.spaceship]p8: If the composite pointer type is an object + // pointer type, p <=> q is of type std::strong_ordering. + if (CompositeTy->isPointerType()) { + // P0946R0: Comparisons between a null pointer constant and an object + // pointer result in std::strong_equality + if (LHSIsNull != RHSIsNull) + return buildResultTy(ComparisonCategoryType::StrongEquality); + return buildResultTy(ComparisonCategoryType::StrongOrdering); + } + // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed. + // TODO: Extend support for operator<=> to ObjC types. + return InvalidOperands(Loc, LHS, RHS); + }; + + if (!IsRelational && LHSIsNull != RHSIsNull) { bool IsEquality = Opc == BO_EQ; if (RHSIsNull) @@ -9752,29 +10144,30 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // conformance with the C++ standard. diagnoseFunctionPointerToVoidComparison( *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext()); - + if (isSFINAEContext()) return QualType(); - + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); - return ResultTy; + return computeResultTy(); } // C++ [expr.eq]p2: // If at least one operand is a pointer [...] bring them to their // composite pointer type. + // C++ [expr.spaceship]p6 + // If at least one of the operands is of pointer type, [...] bring them + // to their composite pointer type. // C++ [expr.rel]p2: // If both operands are pointers, [...] bring them to their composite // pointer type. if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= (IsRelational ? 2 : 1) && - (!LangOpts.ObjCAutoRefCount || - !(LHSType->isObjCObjectPointerType() || - RHSType->isObjCObjectPointerType()))) { + (!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() || + RHSType->isObjCObjectPointerType()))) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); - else - return ResultTy; + return computeResultTy(); } } else if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 @@ -9825,7 +10218,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, else RHS = ImpCastExprToType(RHS.get(), LHSType, Kind); } - return ResultTy; + return computeResultTy(); } if (getLangOpts().CPlusPlus) { @@ -9835,11 +10228,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (!IsRelational && LHSIsNull && RHSIsNull) { if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (RHSType->isNullPtrType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } } @@ -9848,12 +10241,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (!IsRelational && RHSType->isNullPtrType() && (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (!IsRelational && LHSType->isNullPtrType() && (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (IsRelational && @@ -9876,7 +10269,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); else LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } } } @@ -9889,15 +10282,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); else - return ResultTy; + return computeResultTy(); } - - // Handle scoped enumeration types specifically, since they don't promote - // to integers. - if (LHS.get()->getType()->isEnumeralType() && - Context.hasSameUnqualifiedType(LHS.get()->getType(), - RHS.get()->getType())) - return ResultTy; } // Handle block pointer types. @@ -9913,7 +10299,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange(); } RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); - return ResultTy; + return computeResultTy(); } // Allow block pointers to be compared with null pointer constants. @@ -9937,7 +10323,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, RHS = ImpCastExprToType(RHS.get(), LHSType, LHSType->isPointerType() ? CK_BitCast : CK_AnyPointerToBlockPointerCast); - return ResultTy; + return computeResultTy(); } if (LHSType->isObjCObjectPointerType() || @@ -9970,7 +10356,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, RHS = ImpCastExprToType(E, LHSType, LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } - return ResultTy; + return computeResultTy(); } if (LHSType->isObjCObjectPointerType() && RHSType->isObjCObjectPointerType()) { @@ -9984,7 +10370,20 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast); else RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); - return ResultTy; + return computeResultTy(); + } + + if (!IsRelational && LHSType->isBlockPointerType() && + RHSType->isBlockCompatibleObjCPointerType(Context)) { + LHS = ImpCastExprToType(LHS.get(), RHSType, + CK_BlockPointerToObjCPointerCast); + return computeResultTy(); + } else if (!IsRelational && + LHSType->isBlockCompatibleObjCPointerType(Context) && + RHSType->isBlockPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, + CK_BlockPointerToObjCPointerCast); + return computeResultTy(); } } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || @@ -10024,30 +10423,30 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, else RHS = ImpCastExprToType(RHS.get(), LHSType, RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); - return ResultTy; + return computeResultTy(); } // Handle block pointers. if (!IsRelational && RHSIsNull && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (!IsRelational && LHSIsNull && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (getLangOpts().OpenCLVersion >= 200) { if (LHSIsNull && RHSType->isQueueT()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } if (LHSType->isQueueT() && RHSIsNull) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return ResultTy; + return computeResultTy(); } } @@ -10101,7 +10500,7 @@ QualType Sema::GetSignedVectorType(QualType V) { /// types. QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, - bool IsRelational) { + BinaryOperatorKind Opc) { // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, @@ -10121,22 +10520,12 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. - if (!LHSType->hasFloatingRepresentation() && !inTemplateInstantiation()) { - if (DeclRefExpr* DRL - = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParenImpCasts())) - if (DeclRefExpr* DRR - = dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParenImpCasts())) - if (DRL->getDecl() == DRR->getDecl()) - DiagRuntimeBehavior(Loc, nullptr, - PDiag(diag::warn_comparison_always) - << 0 // self- - << 2 // "a constant" - ); - } + diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); // Check for comparisons of floating point operands using != and ==. - if (!IsRelational && LHSType->hasFloatingRepresentation()) { - assert (RHS.get()->getType()->hasFloatingRepresentation()); + if (BinaryOperator::isEqualityOp(Opc) && + LHSType->hasFloatingRepresentation()) { + assert(RHS.get()->getType()->hasFloatingRepresentation()); CheckFloatComparison(Loc, LHS.get(), RHS.get()); } @@ -10418,8 +10807,16 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, // Static fields do not inherit constness from parents. break; } - break; - } // End MemberExpr + break; // End MemberExpr + } else if (const ArraySubscriptExpr *ASE = + dyn_cast<ArraySubscriptExpr>(E)) { + E = ASE->getBase()->IgnoreParenImpCasts(); + continue; + } else if (const ExtVectorElementExpr *EVE = + dyn_cast<ExtVectorElementExpr>(E)) { + E = EVE->getBase()->IgnoreParenImpCasts(); + continue; + } break; } @@ -10660,12 +11057,34 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr, SourceLocation Loc, Sema &Sema) { + if (Sema.inTemplateInstantiation()) + return; + if (Sema.isUnevaluatedContext()) + return; + if (Loc.isInvalid() || Loc.isMacroID()) + return; + if (LHSExpr->getExprLoc().isMacroID() || RHSExpr->getExprLoc().isMacroID()) + return; + // C / C++ fields MemberExpr *ML = dyn_cast<MemberExpr>(LHSExpr); MemberExpr *MR = dyn_cast<MemberExpr>(RHSExpr); - if (ML && MR && ML->getMemberDecl() == MR->getMemberDecl()) { - if (isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase())) - Sema.Diag(Loc, diag::warn_identity_field_assign) << 0; + if (ML && MR) { + if (!(isa<CXXThisExpr>(ML->getBase()) && isa<CXXThisExpr>(MR->getBase()))) + return; + const ValueDecl *LHSDecl = + cast<ValueDecl>(ML->getMemberDecl()->getCanonicalDecl()); + const ValueDecl *RHSDecl = + cast<ValueDecl>(MR->getMemberDecl()->getCanonicalDecl()); + if (LHSDecl != RHSDecl) + return; + if (LHSDecl->getType().isVolatileQualified()) + return; + if (const ReferenceType *RefTy = LHSDecl->getType()->getAs<ReferenceType>()) + if (RefTy->getPointeeType().isVolatileQualified()) + return; + + Sema.Diag(Loc, diag::warn_identity_field_assign) << 0; } // Objective-C instance variables @@ -11046,7 +11465,7 @@ namespace { AO_No_Error = 4 }; } -/// \brief Diagnose invalid operand for address of operations. +/// Diagnose invalid operand for address of operations. /// /// \param Type The type of operand which cannot have its address taken. static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, @@ -11419,12 +11838,13 @@ static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( } /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. -/// This warning is only emitted for builtin assignment operations. It is also -/// suppressed in the event of macro expansions. +/// This warning suppressed in the event of macro expansions. static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, - SourceLocation OpLoc) { + SourceLocation OpLoc, bool IsBuiltin) { if (S.inTemplateInstantiation()) return; + if (S.isUnevaluatedContext()) + return; if (OpLoc.isInvalid() || OpLoc.isMacroID()) return; LHSExpr = LHSExpr->IgnoreParenImpCasts(); @@ -11447,9 +11867,10 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, if (RefTy->getPointeeType().isVolatileQualified()) return; - S.Diag(OpLoc, diag::warn_self_assignment) - << LHSDeclRef->getType() - << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); + S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin + : diag::warn_self_assignment_overloaded) + << LHSDeclRef->getType() << LHSExpr->getSourceRange() + << RHSExpr->getSourceRange(); } /// Check if a bitwise-& is performed on an Objective-C pointer. This @@ -11584,8 +12005,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, // C++11 5.17p9: // The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning // of x = {} is x = T(). - InitializationKind Kind = - InitializationKind::CreateDirectList(RHSExpr->getLocStart()); + InitializationKind Kind = InitializationKind::CreateDirectList( + RHSExpr->getLocStart(), RHSExpr->getLocStart(), RHSExpr->getLocEnd()); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr); @@ -11642,7 +12063,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, OK = LHS.get()->getObjectKind(); } if (!ResultTy.isNull()) { - DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); + DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); } RecordModifiableNonNullParam(*this, LHS.get()); @@ -11678,19 +12099,17 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_GE: case BO_GT: ConvertHalfVec = true; - ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); break; case BO_EQ: case BO_NE: ConvertHalfVec = true; - ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); break; case BO_Cmp: - // FIXME: Implement proper semantic checking of '<=>'. ConvertHalfVec = true; - ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); - if (!ResultTy.isNull()) - ResultTy = Context.VoidTy; + ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); + assert(ResultTy.isNull() || ResultTy->getAsCXXRecordDecl()); break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); @@ -11740,7 +12159,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_AndAssign: case BO_OrAssign: // fallthrough - DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); + DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); LLVM_FALLTHROUGH; case BO_XorAssign: CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); @@ -11858,7 +12277,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, ParensRange); } -/// \brief It accepts a '&&' expr that is inside a '||' one. +/// It accepts a '&&' expr that is inside a '||' one. /// Emit a diagnostic together with a fixit hint that wraps the '&&' expression /// in parentheses. static void @@ -11873,7 +12292,7 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, Bop->getSourceRange()); } -/// \brief Returns true if the given expression can be evaluated as a constant +/// Returns true if the given expression can be evaluated as a constant /// 'true'. static bool EvaluatesAsTrue(Sema &S, Expr *E) { bool Res; @@ -11881,7 +12300,7 @@ static bool EvaluatesAsTrue(Sema &S, Expr *E) { E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res; } -/// \brief Returns true if the given expression can be evaluated as a constant +/// Returns true if the given expression can be evaluated as a constant /// 'false'. static bool EvaluatesAsFalse(Sema &S, Expr *E) { bool Res; @@ -11889,7 +12308,7 @@ static bool EvaluatesAsFalse(Sema &S, Expr *E) { E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res; } -/// \brief Look for '&&' in the left hand of a '||' expr. +/// Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) { @@ -11911,7 +12330,7 @@ static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, } } -/// \brief Look for '&&' in the right hand of a '||' expr. +/// Look for '&&' in the right hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) { @@ -11926,7 +12345,7 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, } } -/// \brief Look for bitwise op in the left or right hand of a bitwise op with +/// Look for bitwise op in the left or right hand of a bitwise op with /// lower precedence and emit a diagnostic together with a fixit hint that wraps /// the '&' expression in parentheses. static void DiagnoseBitwiseOpInBitwiseOp(Sema &S, BinaryOperatorKind Opc, @@ -12039,6 +12458,21 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHS, Expr *RHS) { + switch (Opc) { + case BO_Assign: + case BO_DivAssign: + case BO_RemAssign: + case BO_SubAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); + CheckIdentityFieldAssignment(LHS, RHS, OpLoc, S); + break; + default: + break; + } + // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of @@ -12161,6 +12595,16 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } +static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { + if (T.isNull() || T->isDependentType()) + return false; + + if (!T->isPromotableIntegerType()) + return true; + + return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); +} + ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr) { @@ -12168,6 +12612,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; + bool CanOverflow = false; + bool ConvertHalfVec = false; if (getLangOpts().OpenCL) { QualType Ty = InputExpr->getType(); @@ -12193,6 +12639,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Opc == UO_PostInc, Opc == UO_PreInc || Opc == UO_PreDec); + CanOverflow = isOverflowingIntegerType(Context, resultType); break; case UO_AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); @@ -12206,6 +12653,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } case UO_Plus: case UO_Minus: + CanOverflow = Opc == UO_Minus && + isOverflowingIntegerType(Context, Input.get()->getType()); Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); // Unary plus and minus require promoting an operand of half vector to a @@ -12242,6 +12691,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); + if (resultType->isDependentType()) break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. @@ -12338,7 +12788,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, OK = Input.get()->getObjectKind(); break; case UO_Coawait: - // It's unnessesary to represent the pass-through operator co_await in the + // It's unnecessary to represent the pass-through operator co_await in the // AST; just return the input expression instead. assert(!Input.get()->getType()->isDependentType() && "the co_await expression must be non-dependant before " @@ -12356,17 +12806,17 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, CheckArrayAccess(Input.get()); auto *UO = new (Context) - UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc); + UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow); // Convert the result back to a half vector. if (ConvertHalfVec) return convertVector(UO, Context.HalfTy, *this); return UO; } -/// \brief Determine whether the given expression is a qualified member +/// Determine whether the given expression is a qualified member /// access expression, of a form that could be turned into a pointer to member /// with the address-of operator. -static bool isQualifiedMemberAccess(Expr *E) { +bool Sema::isQualifiedMemberAccess(Expr *E) { if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { if (!DRE->getQualifier()) return false; @@ -12549,11 +12999,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, LastExpr = rebuiltLastStmt; } else { LastExpr = PerformCopyInitialization( - InitializedEntity::InitializeResult(LPLoc, - Ty, - false), - SourceLocation(), - LastExpr); + InitializedEntity::InitializeStmtExprResult(LPLoc, Ty), + SourceLocation(), LastExpr); } if (LastExpr.isInvalid()) @@ -12784,7 +13231,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, CondExpr = CondICE.get(); CondIsTrue = condEval.getZExtValue(); - // If the condition is > zero, then the AST type is the same as the LSHExpr. + // If the condition is > zero, then the AST type is the same as the LHSExpr. Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr; resType = ActiveExpr->getType(); @@ -12990,7 +13437,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // Set the captured variables on the block. // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo! SmallVector<BlockDecl::Capture, 4> Captures; - for (CapturingScopeInfo::Capture &Cap : BSI->Captures) { + for (Capture &Cap : BSI->Captures) { if (Cap.isThisCapture()) continue; BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(), @@ -13070,7 +13517,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, for (const auto &CI : Result->getBlockDecl()->captures()) { const VarDecl *var = CI.getVariable(); if (var->getType().isDestructedType() != QualType::DK_none) { - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); break; } } @@ -13336,7 +13783,6 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::err_typecheck_incompatible_address_space; break; - } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) { DiagKind = diag::err_typecheck_incompatible_ownership; break; @@ -13460,7 +13906,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (DiagKind == diag::warn_incompatible_qualified_id && PDecl && IFace && !IFace->hasDefinition()) Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id) - << IFace->getName() << PDecl->getName(); + << IFace << PDecl; if (SecondType == Context.OverloadTy) NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression, @@ -13701,22 +14147,22 @@ ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { } void -Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl, - bool IsDecltype) { +Sema::PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, + ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, - LambdaContextDecl, IsDecltype); + LambdaContextDecl, ExprContext); Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); } void -Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - ReuseLambdaContextDecl_t, - bool IsDecltype) { +Sema::PushExpressionEvaluationContext( + ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, + ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl; - PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype); + PushExpressionEvaluationContext(NewContext, ClosureContextDecl, ExprContext); } void Sema::PopExpressionEvaluationContext() { @@ -13724,30 +14170,30 @@ void Sema::PopExpressionEvaluationContext() { unsigned NumTypos = Rec.NumTypos; if (!Rec.Lambdas.empty()) { - if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { + using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind; + if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument || Rec.isUnevaluated() || + (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17)) { unsigned D; if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). D = diag::err_lambda_unevaluated_operand; - } else { + } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17) { // C++1y [expr.const]p2: // A conditional-expression e is a core constant expression unless the // evaluation of e, following the rules of the abstract machine, would // evaluate [...] a lambda-expression. D = diag::err_lambda_in_constant_expression; - } + } else if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument) { + // C++17 [expr.prim.lamda]p2: + // A lambda-expression shall not appear [...] in a template-argument. + D = diag::err_lambda_in_invalid_context; + } else + llvm_unreachable("Couldn't infer lambda error message."); - // C++1z allows lambda expressions as core constant expressions. - // FIXME: In C++1z, reinstate the restrictions on lambda expressions (CWG - // 1607) from appearing within template-arguments and array-bounds that - // are part of function-signatures. Be mindful that P0315 (Lambdas in - // unevaluated contexts) might lift some of these restrictions in a - // future version. - if (!Rec.isConstantEvaluated() || !getLangOpts().CPlusPlus17) - for (const auto *L : Rec.Lambdas) - Diag(L->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. @@ -13806,13 +14252,13 @@ static bool isEvaluatableContext(Sema &SemaRef) { switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::ExpressionEvaluationContext::Unevaluated: case Sema::ExpressionEvaluationContext::UnevaluatedAbstract: - case Sema::ExpressionEvaluationContext::DiscardedStatement: // Expressions in this context are never evaluated. return false; case Sema::ExpressionEvaluationContext::UnevaluatedList: case Sema::ExpressionEvaluationContext::ConstantEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: + case Sema::ExpressionEvaluationContext::DiscardedStatement: // Expressions in this context could be evaluated. return true; @@ -13856,7 +14302,7 @@ static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) { (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided())); } -/// \brief Mark a function referenced, and check whether it is odr-used +/// 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, bool MightBeOdrUse) { @@ -14089,7 +14535,7 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec // Similarly to mutable captures in lambda, all the OpenMP captures by copy // are mutable in the sense that user can change their value - they are // private instances of the captured declarations. - const CapturingScopeInfo::Capture &Cap = CSI->getCapture(Var); + const Capture &Cap = CSI->getCapture(Var); if (Cap.isCopyCapture() && !(isa<LambdaScopeInfo>(CSI) && cast<LambdaScopeInfo>(CSI)->Mutable) && !(isa<CapturedRegionScopeInfo>(CSI) && @@ -14242,30 +14688,6 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); - { - auto AddAutoreleaseNote = - S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing); - // Provide a fix-it for the '__autoreleasing' keyword at the - // appropriate location in the variable's type. - if (const auto *TSI = Var->getTypeSourceInfo()) { - PointerTypeLoc PTL = - TSI->getTypeLoc().getAsAdjusted<PointerTypeLoc>(); - if (PTL) { - SourceLocation Loc = PTL.getPointeeLoc().getEndLoc(); - Loc = Lexer::getLocForEndOfToken(Loc, 0, S.getSourceManager(), - S.getLangOpts()); - if (Loc.isValid()) { - StringRef CharAtLoc = Lexer::getSourceText( - CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(1)), - S.getSourceManager(), S.getLangOpts()); - AddAutoreleaseNote << FixItHint::CreateInsertion( - Loc, CharAtLoc.empty() || !isWhitespace(CharAtLoc[0]) - ? " __autoreleasing " - : " __autoreleasing"); - } - } - } - } S.Diag(VarLoc, diag::note_declare_parameter_strong); } } @@ -14273,7 +14695,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); if (HasBlocksAttr || CaptureType->isReferenceType() || - (S.getLangOpts().OpenMP && S.IsOpenMPCapturedDecl(Var))) { + (S.getLangOpts().OpenMP && S.isOpenMPCapturedDecl(Var))) { // Block capture by reference does not change the capture or // declaration reference types. ByRef = true; @@ -14333,7 +14755,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, } -/// \brief Capture the given variable in the captured region. +/// Capture the given variable in the captured region. static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, @@ -14346,14 +14768,14 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { - if (S.IsOpenMPCapturedDecl(Var)) { + if (S.isOpenMPCapturedDecl(Var)) { bool HasConst = DeclRefType.isConstQualified(); DeclRefType = DeclRefType.getUnqualifiedType(); // Don't lose diagnostics about assignments to const. if (HasConst) DeclRefType.addConst(); } - ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel); + ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel); } if (ByRef) @@ -14393,7 +14815,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, return true; } -/// \brief Create a field within the lambda class for the variable +/// Create a field within the lambda class for the variable /// being captured. static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, QualType FieldType, QualType DeclRefType, @@ -14411,7 +14833,7 @@ static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, Lambda->addDecl(Field); } -/// \brief Capture the given variable in the lambda. +/// Capture the given variable in the lambda. static bool captureInLambda(LambdaScopeInfo *LSI, VarDecl *Var, SourceLocation Loc, @@ -14545,7 +14967,7 @@ bool Sema::tryCaptureVariable( // Capture global variables if it is required to use private copy of this // variable. bool IsGlobal = !Var->hasLocalStorage(); - if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var))) + if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var))) return true; Var = Var->getCanonicalDecl(); @@ -14910,7 +15332,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, // A reference initialized by a constant expression can never be // odr-used, so simply ignore it. if (!Var->getType()->isReferenceType() || - (SemaRef.LangOpts.OpenMP && SemaRef.IsOpenMPCapturedDecl(Var))) + (SemaRef.LangOpts.OpenMP && SemaRef.isOpenMPCapturedDecl(Var))) SemaRef.MaybeODRUseExprs.insert(E); } else if (OdrUseContext) { MarkVarDeclODRUsed(Var, Loc, SemaRef, @@ -14945,7 +15367,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, } } -/// \brief Mark a variable referenced, and check whether it is odr-used +/// Mark a variable referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be /// used directly for normal expressions referring to VarDecl. void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { @@ -14986,7 +15408,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } -/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. +/// Perform reference-marking and odr-use handling for a DeclRefExpr. void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even @@ -14999,7 +15421,7 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } -/// \brief Perform reference-marking and odr-use handling for a MemberExpr. +/// Perform reference-marking and odr-use handling for a MemberExpr. void Sema::MarkMemberReferenced(MemberExpr *E) { // C++11 [basic.def.odr]p2: // A non-overloaded function whose name appears as a potentially-evaluated @@ -15018,7 +15440,7 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse); } -/// \brief Perform marking for a reference to an arbitrary declaration. It +/// Perform marking for a reference to an arbitrary declaration. It /// marks the declaration referenced, and performs odr-use checking for /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. @@ -15081,7 +15503,7 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { } namespace { - /// \brief Helper class that marks all of the declarations referenced by + /// Helper class that marks all of the declarations referenced by /// potentially-evaluated subexpressions as "referenced". class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> { Sema &S; @@ -15154,7 +15576,7 @@ namespace { }; } -/// \brief Mark any declarations that appear within this expression or any +/// Mark any declarations that appear within this expression or any /// potentially-evaluated subexpressions as "referenced". /// /// \param SkipLocalVariables If true, don't mark local variables as @@ -15164,7 +15586,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E, EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E); } -/// \brief Emit a diagnostic that describes an effect on the run-time behavior +/// Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// /// This routine emits the given diagnostic when the code currently being @@ -15230,7 +15652,8 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, // If we're inside a decltype's expression, don't check for a valid return // type or construct temporaries until we know whether this is the last call. - if (ExprEvalContexts.back().IsDecltype) { + if (ExprEvalContexts.back().ExprContext == + ExpressionEvaluationContextRecord::EK_Decltype) { ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE); return false; } @@ -15321,7 +15744,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { << FixItHint::CreateReplacement(Loc, "=="); } -/// \brief Redundant parentheses over an equality comparison can indicate +/// Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { // Don't warn if the parens came from a macro. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index 89055aecd4b6..a1168fa34d56 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Implements semantic analysis for C++ expressions. +/// Implements semantic analysis for C++ expressions. /// //===----------------------------------------------------------------------===// @@ -42,7 +42,7 @@ using namespace clang; using namespace sema; -/// \brief Handle the result of the special case name lookup for inheriting +/// Handle the result of the special case name lookup for inheriting /// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as /// constructor names in member using declarations, even if 'X' is not the /// name of the corresponding type. @@ -80,6 +80,50 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } +ParsedType Sema::getConstructorName(IdentifierInfo &II, + SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + bool EnteringContext) { + CXXRecordDecl *CurClass = getCurrentClass(S, &SS); + assert(CurClass && &II == CurClass->getIdentifier() && + "not a constructor name"); + + // When naming a constructor as a member of a dependent context (eg, in a + // friend declaration or an inherited constructor declaration), form an + // unresolved "typename" type. + if (CurClass->isDependentContext() && !EnteringContext) { + QualType T = Context.getDependentNameType(ETK_None, SS.getScopeRep(), &II); + return ParsedType::make(T); + } + + if (SS.isNotEmpty() && RequireCompleteDeclContext(SS, CurClass)) + return ParsedType(); + + // Find the injected-class-name declaration. Note that we make no attempt to + // diagnose cases where the injected-class-name is shadowed: the only + // declaration that can validly shadow the injected-class-name is a + // non-static data member, and if the class contains both a non-static data + // member and a constructor then it is ill-formed (we check that in + // CheckCompletedCXXClass). + CXXRecordDecl *InjectedClassName = nullptr; + for (NamedDecl *ND : CurClass->lookup(&II)) { + auto *RD = dyn_cast<CXXRecordDecl>(ND); + if (RD && RD->isInjectedClassName()) { + InjectedClassName = RD; + break; + } + } + if (!InjectedClassName && CurClass->isInvalidDecl()) + return ParsedType(); + assert(InjectedClassName && "couldn't find injected class name"); + + QualType T = Context.getTypeDeclType(InjectedClassName); + DiagnoseUseOfDecl(InjectedClassName, NameLoc); + MarkAnyDeclReferenced(NameLoc, InjectedClassName, /*OdrUse=*/false); + + return ParsedType::make(T); +} + ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, @@ -383,7 +427,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, llvm_unreachable("unknown nested name specifier kind"); } -/// \brief Build a C++ typeid expression with a type operand. +/// Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, @@ -408,7 +452,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceRange(TypeidLoc, RParenLoc)); } -/// \brief Build a C++ typeid expression with an expression operand. +/// Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, @@ -480,6 +524,12 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // OpenCL C++ 1.0 s2.9: typeid is not supported. + if (getLangOpts().OpenCLCPlusPlus) { + return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) + << "typeid"); + } + // Find the std::type_info type. if (!getStdNamespace()) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -560,7 +610,7 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, } } -/// \brief Build a Microsoft __uuidof expression with a type operand. +/// Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, @@ -580,7 +630,7 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceRange(TypeidLoc, RParenLoc)); } -/// \brief Build a Microsoft __uuidof expression with an expression operand. +/// Build a Microsoft __uuidof expression with an expression operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, @@ -695,7 +745,11 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(OpLoc)) + !getSourceManager().isInSystemHeader(OpLoc) && + (!getLangOpts().OpenMPIsDevice || + !getLangOpts().OpenMPHostCXXExceptions || + isInOpenMPTargetExecutionDirective() || + isInOpenMPDeclareTargetContext())) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; // Exceptions aren't allowed in CUDA device code. @@ -728,7 +782,7 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, // exception object const VarDecl *NRVOVariable = nullptr; if (IsThrownVarInScope) - NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false); + NRVOVariable = getCopyElisionCandidate(QualType(), Ex, CES_Strict); InitializedEntity Entity = InitializedEntity::InitializeException( OpLoc, ExceptionObjectTy, @@ -1114,8 +1168,9 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); - const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? - *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; + const int MaxFunctionScopesIndex = FunctionScopeIndexToStopAt + ? *FunctionScopeIndexToStopAt + : FunctionScopes.size() - 1; // Check that we can capture the *enclosing object* (referred to by '*this') // by the capturing-entity/closure (lambda/block/etc) at @@ -1141,7 +1196,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, unsigned NumCapturingClosures = 0; - for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { + for (int idx = MaxFunctionScopesIndex; idx >= 0; idx--) { if (CapturingScopeInfo *CSI = dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) { if (CSI->CXXThisCaptureIndex != 0) { @@ -1196,8 +1251,8 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. QualType ThisTy = getCurrentThisType(); - for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; - --idx, --NumCapturingClosures) { + for (int idx = MaxFunctionScopesIndex; NumCapturingClosures; + --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = nullptr; @@ -1244,11 +1299,16 @@ bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { return Class && Class->isBeingDefined(); } +/// Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg exprs, - SourceLocation RParenLoc) { + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { if (!TypeRep) return ExprError(); @@ -1257,7 +1317,8 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); - auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); + auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs, + RParenOrBraceLoc, ListInitialization); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without // checking for embedded typos. @@ -1267,38 +1328,40 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, return Result; } -/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. -/// Can be interpreted either as function-style casting ("int(x)") -/// or class type construction ("ClassType(x,y,z)") -/// or creation of a value-initialized type ("int()"). ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, - SourceLocation RParenLoc) { + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { - return CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs, - RParenLoc); + // FIXME: CXXUnresolvedConstructExpr does not model list-initialization + // directly. We work around this by dropping the locations of the braces. + SourceRange Locs = ListInitialization + ? SourceRange() + : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); + return CXXUnresolvedConstructExpr::Create(Context, TInfo, Locs.getBegin(), + Exprs, Locs.getEnd()); } - bool ListInitialization = LParenLoc.isInvalid(); assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && "List initialization must have initializer list as expression."); - SourceRange FullRange = SourceRange(TyBeginLoc, - ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); + SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization - ? InitializationKind::CreateDirectList(TyBeginLoc) - : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, - RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + ? InitializationKind::CreateDirectList( + TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) + : InitializationKind::CreateDirect(TyBeginLoc, LParenOrBraceLoc, + RParenOrBraceLoc) + : InitializationKind::CreateValue(TyBeginLoc, LParenOrBraceLoc, + RParenOrBraceLoc); // C++1z [expr.type.conv]p1: // If the type is a placeholder for a deduced class type, [...perform class @@ -1319,7 +1382,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, if (Exprs.size() == 1 && !ListInitialization && !isa<InitListExpr>(Exprs[0])) { Expr *Arg = Exprs[0]; - return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc); + return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg, + RParenOrBraceLoc); } // For an expression of the form T(), T shall not be an array type. @@ -1367,15 +1431,18 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // CXXTemporaryObjectExpr. It's also weird that the functional cast // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); + SourceRange Locs = ListInitialization + ? SourceRange() + : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); Result = CXXFunctionalCastExpr::Create( - Context, ResultType, Expr::getValueKindForType(Ty), TInfo, - CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc); + Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp, + Result.get(), /*Path=*/nullptr, Locs.getBegin(), Locs.getEnd()); } return Result; } -/// \brief Determine whether the given function is a non-placement +/// Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) @@ -1430,7 +1497,7 @@ namespace { CUDAPref = S.IdentifyCUDAPreference(Caller, FD); } - operator bool() const { return FD; } + explicit operator bool() const { return FD; } bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { @@ -1543,7 +1610,7 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, return Best && Best.HasSizeT; } -/// \brief Parsed a C++ 'new' expression (C++ 5.3.4). +/// Parsed a C++ 'new' expression (C++ 5.3.4). /// /// E.g.: /// @code new (memory) int[size][4] @endcode @@ -1593,9 +1660,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (Expr *NumElts = (Expr *)Array.NumElts) { if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { 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. + // 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. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); assert(IntWidth && "Builtin type of size 0?"); llvm::APSInt Value(IntWidth); @@ -1728,7 +1795,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. : initStyle == CXXNewExpr::ListInit - ? InitializationKind::CreateDirectList(TypeRange.getBegin()) + ? InitializationKind::CreateDirectList(TypeRange.getBegin(), + Initializer->getLocStart(), + Initializer->getLocEnd()) : InitializationKind::CreateDirect(TypeRange.getBegin(), DirectInitRange.getBegin(), DirectInitRange.getEnd()); @@ -1795,13 +1864,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); - if (initStyle == CXXNewExpr::ListInit && - isStdInitializerList(AllocType, nullptr)) { - Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(), - diag::warn_dangling_std_initializer_list) - << /*at end of FE*/0 << Inits[0]->getSourceRange(); - } - // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && @@ -1831,7 +1893,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), - AA_Converting); + AA_Converting); if (!ConvertedSize.isInvalid() && ArraySize->getType()->getAs<RecordType>()) @@ -1960,11 +2022,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, bool PassAlignment = getLangOpts().AlignedAllocation && Alignment > NewAlignment; + AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), - UseGlobal, AllocType, ArraySize, PassAlignment, + Scope, Scope, AllocType, ArraySize, PassAlignment, PlacementArgs, OperatorNew, OperatorDelete)) return ExprError(); @@ -2099,7 +2162,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, Range, DirectInitRange); } -/// \brief Checks that a type is suitable as the allocated type +/// Checks that a type is suitable as the allocated type /// in a new-expression. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R) { @@ -2120,7 +2183,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - else if (AllocType.getAddressSpace() != LangAS::Default) + else if (AllocType.getAddressSpace() != LangAS::Default && + !getLangOpts().OpenCLCPlusPlus) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); @@ -2137,12 +2201,10 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, return false; } -static bool -resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range, - SmallVectorImpl<Expr *> &Args, bool &PassAlignment, - FunctionDecl *&Operator, - OverloadCandidateSet *AlignedCandidates = nullptr, - Expr *AlignArg = nullptr) { +static bool resolveAllocationOverload( + Sema &S, LookupResult &R, SourceRange Range, SmallVectorImpl<Expr *> &Args, + bool &PassAlignment, FunctionDecl *&Operator, + OverloadCandidateSet *AlignedCandidates, Expr *AlignArg, bool Diagnose) { OverloadCandidateSet Candidates(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); @@ -2188,7 +2250,8 @@ resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range, AlignArg = Args[1]; Args.erase(Args.begin() + 1); return resolveAllocationOverload(S, R, Range, Args, PassAlignment, - Operator, &Candidates, AlignArg); + Operator, &Candidates, AlignArg, + Diagnose); } // MSVC will fall back on trying to find a matching global operator new @@ -2204,67 +2267,72 @@ resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range, S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); // FIXME: This will give bad diagnostics pointing at the wrong functions. return resolveAllocationOverload(S, R, Range, Args, PassAlignment, - Operator, nullptr); + Operator, /*Candidates=*/nullptr, + /*AlignArg=*/nullptr, Diagnose); } - S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) - << R.getLookupName() << Range; - - // If we have aligned candidates, only note the align_val_t candidates - // from AlignedCandidates and the non-align_val_t candidates from - // Candidates. - if (AlignedCandidates) { - auto IsAligned = [](OverloadCandidate &C) { - return C.Function->getNumParams() > 1 && - C.Function->getParamDecl(1)->getType()->isAlignValT(); - }; - auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; - - // This was an overaligned allocation, so list the aligned candidates - // first. - Args.insert(Args.begin() + 1, AlignArg); - AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", - R.getNameLoc(), IsAligned); - Args.erase(Args.begin() + 1); - Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), - IsUnaligned); - } else { - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + if (Diagnose) { + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + + // If we have aligned candidates, only note the align_val_t candidates + // from AlignedCandidates and the non-align_val_t candidates from + // Candidates. + if (AlignedCandidates) { + auto IsAligned = [](OverloadCandidate &C) { + return C.Function->getNumParams() > 1 && + C.Function->getParamDecl(1)->getType()->isAlignValT(); + }; + auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; + + // This was an overaligned allocation, so list the aligned candidates + // first. + Args.insert(Args.begin() + 1, AlignArg); + AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", + R.getNameLoc(), IsAligned); + Args.erase(Args.begin() + 1); + Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), + IsUnaligned); + } else { + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + } } return true; case OR_Ambiguous: - S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) - << R.getLookupName() << Range; - Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + if (Diagnose) { + S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + } return true; case OR_Deleted: { - S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << R.getLookupName() - << S.getDeletedOrUnavailableSuffix(Best->Function) - << Range; - Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + if (Diagnose) { + S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() << R.getLookupName() + << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + } return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } - -/// FindAllocationFunctions - Finds the overloads of operator new and delete -/// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, - bool UseGlobal, QualType AllocType, - bool IsArray, bool &PassAlignment, - MultiExprArg PlaceArgs, + AllocationFunctionScope NewScope, + AllocationFunctionScope DeleteScope, + QualType AllocType, bool IsArray, + bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, - FunctionDecl *&OperatorDelete) { + FunctionDecl *&OperatorDelete, + bool Diagnose) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 - // 1) If UseGlobal is true, only look in the global scope. Else, also look - // in the scope of the allocated class. + // 1) If looking in AFS_Global scope for allocation functions, only look in + // the global scope. Else, if AFS_Class, only look in the scope of the + // allocated class. If AFS_Both, look in both. // 2) If an array size is given, look for operator new[], else look for // operator new. // 3) The first argument is always size_t. Append the arguments from the @@ -2314,7 +2382,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // function's name is looked up in the global scope. Otherwise, if the // allocated type is a class type T or array thereof, the allocation // function's name is looked up in the scope of T. - if (AllocElemType->isRecordType() && !UseGlobal) + if (AllocElemType->isRecordType() && NewScope != AFS_Global) LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl()); // We can see ambiguity here if the allocation function is found in @@ -2325,8 +2393,17 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // If this lookup fails to find the name, or if the allocated type is not // a class type, the allocation function's name is looked up in the // global scope. - if (R.empty()) + if (R.empty()) { + if (NewScope == AFS_Class) + return true; + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + } + + if (getLangOpts().OpenCLCPlusPlus && R.empty()) { + Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new"; + return true; + } assert(!R.empty() && "implicitly declared allocation functions not found"); assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); @@ -2335,7 +2412,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, R.suppressDiagnostics(); if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment, - OperatorNew)) + OperatorNew, /*Candidates=*/nullptr, + /*AlignArg=*/nullptr, Diagnose)) return true; } @@ -2362,7 +2440,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // the allocated type is not a class type or array thereof, the // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); - if (AllocElemType->isRecordType() && !UseGlobal) { + if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) { CXXRecordDecl *RD = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl()); LookupQualifiedName(FoundDelete, RD); @@ -2372,6 +2450,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool FoundGlobalDelete = FoundDelete.empty(); if (FoundDelete.empty()) { + if (DeleteScope == AFS_Class) + return true; + DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); } @@ -2559,6 +2640,11 @@ void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; + // OpenCL C++ 1.0 s2.9: the implicitly declared new and delete operators + // are not supported. + if (getLangOpts().OpenCLCPlusPlus) + return; + // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are // implicitly declared in global scope in each translation unit of a @@ -2845,7 +2931,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, } namespace { -/// \brief Checks whether delete-expression, and new-expression used for +/// Checks whether delete-expression, and new-expression used for /// initializing deletee have the same array form. class MismatchingNewDeleteDetector { public: @@ -2868,7 +2954,7 @@ public: : Field(nullptr), IsArrayForm(false), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} - /// \brief Checks whether pointee of a delete-expression is initialized with + /// Checks whether pointee of a delete-expression is initialized with /// matching form of new-expression. /// /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the @@ -2879,7 +2965,7 @@ public: /// couldn't be analyzed. If at least one constructor initializes the member /// with matching type of new, the return value is \c NoMismatch. MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); - /// \brief Analyzes a class member. + /// Analyzes a class member. /// \param Field Class member to analyze. /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. @@ -2892,13 +2978,13 @@ public: private: const bool EndOfTU; - /// \brief Indicates that there is at least one constructor without body. + /// Indicates that there is at least one constructor without body. bool HasUndefinedConstructors; - /// \brief Returns \c CXXNewExpr from given initialization expression. + /// Returns \c CXXNewExpr from given initialization expression. /// \param E Expression used for initializing pointee in delete-expression. /// E can be a single-element \c InitListExpr consisting of new-expression. const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); - /// \brief Returns whether member is initialized with mismatching form of + /// Returns whether member is initialized with mismatching form of /// \c new either by the member initializer or in-class initialization. /// /// If bodies of all constructors are not visible at the end of translation @@ -2906,7 +2992,7 @@ private: /// form of \c new, mismatch cannot be proven, and this function will return /// \c NoMismatch. MismatchResult analyzeMemberExpr(const MemberExpr *ME); - /// \brief Returns whether variable is initialized with mismatching form of + /// Returns whether variable is initialized with mismatching form of /// \c new. /// /// If variable is initialized with matching form of \c new or variable is not @@ -2914,7 +3000,7 @@ private: /// If variable is initialized with mismatching form of \c new, returns false. /// \param D Variable to analyze. bool hasMatchingVarInit(const DeclRefExpr *D); - /// \brief Checks whether the constructor initializes pointee with mismatching + /// Checks whether the constructor initializes pointee with mismatching /// form of \c new. /// /// Returns true, if member is initialized with matching form of \c new in @@ -2923,7 +3009,7 @@ private: /// constructor isn't defined at the point where delete-expression is seen, or /// member isn't initialized by the constructor. bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); - /// \brief Checks whether member is initialized with matching form of + /// Checks whether member is initialized with matching form of /// \c new in member initializer list. bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); /// Checks whether member is initialized with mismatching form of \c new by @@ -3192,7 +3278,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); - if (Pointee.getAddressSpace() != LangAS::Default) + if (Pointee.getAddressSpace() != LangAS::Default && + !getLangOpts().OpenCLCPlusPlus) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() @@ -3267,6 +3354,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } if (!OperatorDelete) { + if (getLangOpts().OpenCLCPlusPlus) { + Diag(StartLoc, diag::err_openclcxx_not_supported) << "default delete"; + return ExprError(); + } + bool IsComplete = isCompleteType(StartLoc, Pointee); bool CanProvideSize = IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize || @@ -3322,6 +3414,128 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return Result; } +static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, + bool IsDelete, + FunctionDecl *&Operator) { + + DeclarationName NewName = S.Context.DeclarationNames.getCXXOperatorName( + IsDelete ? OO_Delete : OO_New); + + LookupResult R(S, NewName, TheCall->getLocStart(), Sema::LookupOrdinaryName); + S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); + assert(!R.empty() && "implicitly declared allocation functions not found"); + assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); + + // We do our own custom access checks below. + R.suppressDiagnostics(); + + SmallVector<Expr *, 8> Args(TheCall->arg_begin(), TheCall->arg_end()); + OverloadCandidateSet Candidates(R.getNameLoc(), + OverloadCandidateSet::CSK_Normal); + for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end(); + FnOvl != FnOvlEnd; ++FnOvl) { + // Even member operator new/delete are implicitly treated as + // static, so don't use AddMemberCandidate. + NamedDecl *D = (*FnOvl)->getUnderlyingDecl(); + + if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { + S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), + /*ExplicitTemplateArgs=*/nullptr, Args, + Candidates, + /*SuppressUserConversions=*/false); + continue; + } + + FunctionDecl *Fn = cast<FunctionDecl>(D); + S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, + /*SuppressUserConversions=*/false); + } + + SourceRange Range = TheCall->getSourceRange(); + + // Do the resolution. + OverloadCandidateSet::iterator Best; + switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { + case OR_Success: { + // Got one! + FunctionDecl *FnDecl = Best->Function; + assert(R.getNamingClass() == nullptr && + "class members should not be considered"); + + if (!FnDecl->isReplaceableGlobalAllocationFunction()) { + S.Diag(R.getNameLoc(), diag::err_builtin_operator_new_delete_not_usual) + << (IsDelete ? 1 : 0) << Range; + S.Diag(FnDecl->getLocation(), diag::note_non_usual_function_declared_here) + << R.getLookupName() << FnDecl->getSourceRange(); + return true; + } + + Operator = FnDecl; + return false; + } + + case OR_No_Viable_Function: + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + + case OR_Ambiguous: + S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + return true; + + case OR_Deleted: { + S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() << R.getLookupName() + << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + } + } + llvm_unreachable("Unreachable, bad result from BestViableFunction"); +} + +ExprResult +Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete) { + CallExpr *TheCall = cast<CallExpr>(TheCallResult.get()); + if (!getLangOpts().CPlusPlus) { + Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) + << (IsDelete ? "__builtin_operator_delete" : "__builtin_operator_new") + << "C++"; + return ExprError(); + } + // CodeGen assumes it can find the global new and delete to call, + // so ensure that they are declared. + DeclareGlobalNewDelete(); + + FunctionDecl *OperatorNewOrDelete = nullptr; + if (resolveBuiltinNewDeleteOverload(*this, TheCall, IsDelete, + OperatorNewOrDelete)) + return ExprError(); + assert(OperatorNewOrDelete && "should be found"); + + TheCall->setType(OperatorNewOrDelete->getReturnType()); + for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { + QualType ParamTy = OperatorNewOrDelete->getParamDecl(i)->getType(); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, ParamTy, false); + ExprResult Arg = PerformCopyInitialization( + Entity, TheCall->getArg(i)->getLocStart(), TheCall->getArg(i)); + if (Arg.isInvalid()) + return ExprError(); + TheCall->setArg(i, Arg.get()); + } + auto Callee = dyn_cast<ImplicitCastExpr>(TheCall->getCallee()); + assert(Callee && Callee->getCastKind() == CK_BuiltinFnToFnPtr && + "Callee expected to be implicit cast to a builtin function pointer"); + Callee->setType(OperatorNewOrDelete->getType()); + + return TheCallResult; +} + void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, @@ -3378,7 +3592,7 @@ Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar, CK == ConditionKind::ConstexprIf); } -/// \brief Check the use of the given variable as a C++ condition in an if, +/// Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, @@ -3548,6 +3762,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, CheckedConversionKind CCK) { + // C++ [over.match.oper]p7: [...] operands of class type are converted [...] + if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType()) + return From; + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, @@ -3607,6 +3825,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From = CastArg.get(); + // C++ [over.match.oper]p7: + // [...] the second standard conversion sequence of a user-defined + // conversion sequence is not applied. + if (CCK == CCK_ForBuiltinOverloadedOp) + return From; + return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, CCK); } @@ -4070,14 +4294,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. - if (CCK == CCK_ImplicitConversion) + if (!isCast(CCK)) diagnoseNullableToNonnullConversion(ToType, InitialFromType, From->getLocStart()); return From; } -/// \brief Check the completeness of a type in a unary type trait. +/// Check the completeness of a type in a unary type trait. /// /// If the particular type trait requires a complete type, tries to complete /// it. If completing the type fails, a diagnostic is emitted and false @@ -4227,7 +4451,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); - if (!CPT || !CPT->isNothrow(C)) + if (!CPT || !CPT->isNothrow()) return false; } } @@ -4475,7 +4699,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, const FunctionProtoType *CPT = Destructor->getType()->getAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); - if (!CPT || !CPT->isNothrow(C)) + if (!CPT || !CPT->isNothrow()) return false; } } @@ -4568,7 +4792,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->isNothrow(C) || CPT->getNumParams() > 1) + if (!CPT->isNothrow() || CPT->getNumParams() > 1) return false; } } @@ -4607,7 +4831,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->isNothrow(C) || CPT->getNumParams() > 0) + if (!CPT->isNothrow() || CPT->getNumParams() > 0) return false; } } @@ -4645,11 +4869,14 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); - if (Kind <= BTT_Last) + // Evaluate BTT_ReferenceBindsToTemporary alongside the IsConstructible + // traits to avoid duplication. + if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary) return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), Args[1]->getType(), RParenLoc); switch (Kind) { + case clang::BTT_ReferenceBindsToTemporary: case clang::TT_IsConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { @@ -4726,6 +4953,13 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (Kind == clang::TT_IsConstructible) return true; + if (Kind == clang::BTT_ReferenceBindsToTemporary) { + if (!T->isReferenceType()) + return false; + + return !Init.isDirectReferenceBinding(); + } + if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; @@ -5231,8 +5465,9 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, case RQ_LValue: if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { - // C++2a allows functions with ref-qualifier & if they are also 'const'. - if (Proto->isConst()) + // C++2a allows functions with ref-qualifier & if their cv-qualifier-seq + // is (exactly) 'const'. + if (Proto->isConst() && !Proto->isVolatile()) Diag(Loc, getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : diag::ext_pointer_to_const_ref_member_on_rvalue); @@ -5269,7 +5504,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, return Result; } -/// \brief Try to convert a type to another according to C++11 5.16p3. +/// Try to convert a type to another according to C++11 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be @@ -5294,7 +5529,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // constraint that in the conversion the reference must bind directly to // an lvalue. // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be - // implicitly conveted to the type "rvalue reference to R2", subject to + // implicitly converted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. if (To->isLValue() || To->isXValue()) { QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) @@ -5363,7 +5598,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, return false; } -/// \brief Try to find a common type for two according to C++0x 5.16p5. +/// Try to find a common type for two according to C++0x 5.16p5. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, overload resolution is used to find a @@ -5425,7 +5660,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS return true; } -/// \brief Perform an "extended" implicit conversion as returned by +/// Perform an "extended" implicit conversion as returned by /// TryClassUnification. static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); @@ -5441,7 +5676,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { return false; } -/// \brief Check the operands of ?: under C++ semantics. +/// Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) @@ -5745,27 +5980,23 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, if (EST2 == EST_None) return ESI2; if (EST1 == EST_MSAny) return ESI1; if (EST2 == EST_MSAny) return ESI2; + if (EST1 == EST_NoexceptFalse) return ESI1; + if (EST2 == EST_NoexceptFalse) return ESI2; // If either of them is non-throwing, the result is the other. if (EST1 == EST_DynamicNone) return ESI2; if (EST2 == EST_DynamicNone) return ESI1; if (EST1 == EST_BasicNoexcept) return ESI2; if (EST2 == EST_BasicNoexcept) return ESI1; + if (EST1 == EST_NoexceptTrue) return ESI2; + if (EST2 == EST_NoexceptTrue) return ESI1; - // If either of them is a non-value-dependent computed noexcept, that - // determines the result. - if (EST2 == EST_ComputedNoexcept && ESI2.NoexceptExpr && - !ESI2.NoexceptExpr->isValueDependent()) - return !ESI2.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI2 : ESI1; - if (EST1 == EST_ComputedNoexcept && ESI1.NoexceptExpr && - !ESI1.NoexceptExpr->isValueDependent()) - return !ESI1.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI1 : ESI2; // If we're left with value-dependent computed noexcept expressions, we're // stuck. Before C++17, we can just drop the exception specification entirely, // since it's not actually part of the canonical type. And this should never // happen in C++17, because it would mean we were computing the composite // pointer type of dependent types, which should never happen. - if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { + if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { assert(!S.getLangOpts().CPlusPlus17 && "computing composite pointer type of dependent types"); return FunctionProtoType::ExceptionSpecInfo(); @@ -5778,7 +6009,9 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: - case EST_ComputedNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: llvm_unreachable("handled above"); case EST_Dynamic: { @@ -5805,7 +6038,7 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, llvm_unreachable("invalid ExceptionSpecificationType"); } -/// \brief Find a merged pointer type and convert the two expressions to it. +/// Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 /// and @p E2 according to C++1z 5p14. It converts both expressions to this @@ -6195,7 +6428,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (RD->isInvalidDecl() || RD->isDependentContext()) return E; - bool IsDecltype = ExprEvalContexts.back().IsDecltype; + bool IsDecltype = ExprEvalContexts.back().ExprContext == + ExpressionEvaluationContextRecord::EK_Decltype; CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD); if (Destructor) { @@ -6277,7 +6511,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { /// are omitted for the 'topmost' call in the decltype expression. If the /// topmost call bound a temporary, strip that temporary off the expression. ExprResult Sema::ActOnDecltypeExpression(Expr *E) { - assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression"); + assert(ExprEvalContexts.back().ExprContext == + ExpressionEvaluationContextRecord::EK_Decltype && + "not in a decltype expression"); // C++11 [expr.call]p11: // If a function call is a prvalue of object type, @@ -6319,7 +6555,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { TopBind = nullptr; // Disable the special decltype handling now. - ExprEvalContexts.back().IsDecltype = false; + ExprEvalContexts.back().ExprContext = + ExpressionEvaluationContextRecord::EK_Other; // In MS mode, don't perform any extra checking of call return types within a // decltype expression. @@ -6572,7 +6809,7 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, return false; } -/// \brief Check if it's ok to try and recover dot pseudo destructor calls on +/// Check if it's ok to try and recover dot pseudo destructor calls on /// pointer objects. static bool canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, @@ -6877,10 +7114,17 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates) { + // Convert the expression to match the conversion function's implicit object + // parameter. + ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr, + FoundDecl, Method); + if (Exp.isInvalid()) + return true; + if (Method->getParent()->isLambda() && Method->getConversionType()->isBlockPointerType()) { // This is a lambda coversion to block pointer; check if the argument - // is a LambdaExpr. + // was a LambdaExpr. Expr *SubE = E; CastExpr *CE = dyn_cast<CastExpr>(SubE); if (CE && CE->getCastKind() == CK_NoOp) @@ -6897,22 +7141,16 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); - ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(), - E->getExprLoc(), - Method, E); + ExprResult BlockExp = BuildBlockForLambdaConversion( + Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); - if (Exp.isInvalid()) - Diag(E->getExprLoc(), diag::note_lambda_to_block_conv); - return Exp; + if (BlockExp.isInvalid()) + Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); + return BlockExp; } } - ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr, - FoundDecl, Method); - if (Exp.isInvalid()) - return true; - MemberExpr *ME = new (Context) MemberExpr( Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(), Context.BoundMemberTy, VK_RValue, OK_Ordinary); @@ -7123,7 +7361,7 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, return !IsVariableAConstantExpression(Var, Context); } -/// \brief Check if the current lambda has any potential captures +/// Check if the current lambda has any potential captures /// that must be captured by any of its enclosing lambdas that are ready to /// capture. If there is a lambda that can capture a nested /// potential-capture, go ahead and do so. Also, check to see if any @@ -7146,9 +7384,6 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); - ArrayRef<const FunctionScopeInfo *> FunctionScopesArrayRef( - S.FunctionScopes.data(), S.FunctionScopes.size()); - // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. @@ -7177,7 +7412,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( // capture the variable in that lambda (and all its enclosing lambdas). if (const Optional<unsigned> Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( - FunctionScopesArrayRef, Var, S)) { + S.FunctionScopes, Var, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S, &FunctionScopeIndexOfCapturableLambda); @@ -7213,7 +7448,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( // 'this' in that lambda (and all its enclosing lambdas). if (const Optional<unsigned> Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( - FunctionScopesArrayRef, /*0 is 'this'*/ nullptr, S)) { + S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation, /*Explicit*/ false, /*BuildAndDiagnose*/ true, @@ -7306,13 +7541,12 @@ class TransformTypos : public TreeTransform<TransformTypos> { llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache; llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution; - /// \brief Emit diagnostics for all of the TypoExprs encountered. + /// 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); + for (TypoExpr *TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); if (State.DiagHandler) { TypoCorrection TC = State.Consumer->getCurrentCorrection(); @@ -7333,7 +7567,7 @@ class TransformTypos : public TreeTransform<TransformTypos> { } } - /// \brief If corrections for the first TypoExpr have been exhausted for a + /// 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 @@ -7504,12 +7738,8 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && (E->isTypeDependent() || E->isValueDependent() || E->isInstantiationDependent())) { - auto TyposInContext = ExprEvalContexts.back().NumTypos; - assert(TyposInContext < ~0U && "Recursive call of CorrectDelayedTyposInExpr"); - ExprEvalContexts.back().NumTypos = ~0U; auto TyposResolved = DelayedTypos.size(); auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); - ExprEvalContexts.back().NumTypos = TyposInContext; TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index f57f79e62efe..3a8fee862c91 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp @@ -640,6 +640,7 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, const RecordType *RTy, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, bool HasTemplateArgs, + SourceLocation TemplateKWLoc, TypoExpr *&TE) { SourceRange BaseRange = BaseExpr ? BaseExpr->getSourceRange() : SourceRange(); RecordDecl *RDecl = RTy->getDecl(); @@ -649,13 +650,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, BaseRange)) return true; - if (HasTemplateArgs) { + if (HasTemplateArgs || TemplateKWLoc.isValid()) { // LookupTemplateName doesn't expect these both to exist simultaneously. QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); bool MOUS; - SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS); - return false; + return SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS, + TemplateKWLoc); } DeclContext *DC = RDecl; @@ -733,7 +734,8 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult &BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs); + Decl *ObjCImpDecl, bool HasTemplateArgs, + SourceLocation TemplateKWLoc); ExprResult Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, @@ -759,9 +761,9 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, TypoExpr *TE = nullptr; QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); - if (LookupMemberExprInRecord(*this, R, nullptr, - RecordTy->getAs<RecordType>(), OpLoc, IsArrow, - SS, TemplateArgs != nullptr, TE)) + if (LookupMemberExprInRecord( + *this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow, + SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) return ExprError(); if (TE) return TE; @@ -769,10 +771,10 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, // Explicit member accesses. } else { ExprResult BaseResult = Base; - ExprResult Result = LookupMemberExpr( - *this, R, BaseResult, IsArrow, OpLoc, SS, - ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr, - TemplateArgs != nullptr); + ExprResult Result = + LookupMemberExpr(*this, R, BaseResult, IsArrow, OpLoc, SS, + ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr, + TemplateArgs != nullptr, TemplateKWLoc); if (BaseResult.isInvalid()) return ExprError(); @@ -802,16 +804,13 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, Expr *baseObjectExpr, SourceLocation opLoc) { // First, build the expression that refers to the base object. - - bool baseObjectIsPointer = false; - Qualifiers baseQuals; - + // Case 1: the base of the indirect field is not a field. VarDecl *baseVariable = indirectField->getVarDecl(); CXXScopeSpec EmptySS; if (baseVariable) { assert(baseVariable->getType()->isRecordType()); - + // In principle we could have a member access expression that // accesses an anonymous struct/union that's a static member of // the base object's class. However, under the current standard, @@ -824,68 +823,37 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, ExprResult result = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); if (result.isInvalid()) return ExprError(); - - baseObjectExpr = result.get(); - baseObjectIsPointer = false; - baseQuals = baseObjectExpr->getType().getQualifiers(); - - // Case 2: the base of the indirect field is a field and the user - // wrote a member expression. - } else if (baseObjectExpr) { - // The caller provided the base object expression. Determine - // whether its a pointer and whether it adds any qualifiers to the - // anonymous struct/union fields we're looking into. - QualType objectType = baseObjectExpr->getType(); - - if (const PointerType *ptr = objectType->getAs<PointerType>()) { - baseObjectIsPointer = true; - objectType = ptr->getPointeeType(); - } else { - baseObjectIsPointer = false; - } - baseQuals = objectType.getQualifiers(); - - // Case 3: the base of the indirect field is a field and we should - // build an implicit member access. - } else { - // We've found a member of an anonymous struct/union that is - // inside a non-anonymous struct/union, so in a well-formed - // program our base object expression is "this". - QualType ThisTy = getCurrentThisType(); - if (ThisTy.isNull()) { - Diag(loc, diag::err_invalid_member_use_in_static_method) - << indirectField->getDeclName(); - return ExprError(); - } - - // Our base object expression is "this". - CheckCXXThisCapture(loc); - baseObjectExpr - = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); - baseObjectIsPointer = true; - baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); + + baseObjectExpr = result.get(); } - + + assert((baseVariable || baseObjectExpr) && + "referencing anonymous struct/union without a base variable or " + "expression"); + // Build the implicit member references to the field of the // anonymous struct/union. Expr *result = baseObjectExpr; IndirectFieldDecl::chain_iterator FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); - - // Build the first member access in the chain with full information. + + // Case 2: the base of the indirect field is a field and the user + // wrote a member expression. if (!baseVariable) { FieldDecl *field = cast<FieldDecl>(*FI); - + + bool baseObjectIsPointer = baseObjectExpr->getType()->isPointerType(); + // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - result = BuildFieldReferenceExpr(result, baseObjectIsPointer, - SourceLocation(), EmptySS, field, - foundDecl, memberNameInfo).get(); + // Build the first member access in the chain with full information. + result = + BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), + SS, field, foundDecl, memberNameInfo) + .get(); if (!result) return ExprError(); - - // FIXME: check qualified member access } // In all cases, we should now skip the first declaration in the chain. @@ -922,7 +890,7 @@ BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow, NameInfo.getLoc()); } -/// \brief Build a MemberExpr AST node. +/// Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr( Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -937,7 +905,7 @@ static MemberExpr *BuildMemberExpr( return E; } -/// \brief Determine if the given scope is within a function-try-block handler. +/// Determine if the given scope is within a function-try-block handler. static bool IsInFnTryBlockHandler(const Scope *S) { // Walk the scope stack until finding a FnTryCatchScope, or leave the // function scope. If a FnTryCatchScope is found, check whether the TryScope @@ -954,16 +922,12 @@ getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs, const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc) { - if (!TemplateArgs) { - S.Diag(MemberNameInfo.getBeginLoc(), diag::err_template_decl_ref) - << /*Variable template*/ 1 << MemberNameInfo.getName() - << MemberNameInfo.getSourceRange(); - - S.Diag(VarTempl->getLocation(), diag::note_template_decl_here); - + S.diagnoseMissingTemplateArguments(TemplateName(VarTempl), + MemberNameInfo.getBeginLoc()); return nullptr; } + DeclResult VDecl = S.CheckVarTemplateId( VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs); if (VDecl.isInvalid()) @@ -1264,7 +1228,8 @@ Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) { static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, ExprResult &BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, - Decl *ObjCImpDecl, bool HasTemplateArgs) { + Decl *ObjCImpDecl, bool HasTemplateArgs, + SourceLocation TemplateKWLoc) { assert(BaseExpr.get() && "no base expression"); // Perform default conversions. @@ -1314,8 +1279,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { TypoExpr *TE = nullptr; - if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, - OpLoc, IsArrow, SS, HasTemplateArgs, TE)) + if (LookupMemberExprInRecord(S, R, BaseExpr.get(), RTy, OpLoc, IsArrow, SS, + HasTemplateArgs, TemplateKWLoc, TE)) return ExprError(); // Returning valid-but-null is how we indicate to the caller that @@ -1353,7 +1318,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, OpLoc, S.Context.getObjCClassType()); if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); goto fail; } @@ -1479,8 +1444,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, IsArrow); if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc)) - S.recordUseOfEvaluatedWeak(Result); + if (!S.isUnevaluatedContext() && + !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc)) + S.getCurFunction()->recordUseOfWeak(Result); } return Result; @@ -1524,9 +1490,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, } if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { - // Check the use of this method. - if (S.DiagnoseUseOfDecl(OMD, MemberLoc)) - return ExprError(); Selector SetterSel = SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(), S.PP.getSelectorTable(), @@ -1546,7 +1509,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // use the 'id' redefinition in this case. if (IsArrow && ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); return ExprError(S.Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); @@ -1559,7 +1522,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (!MD) { if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); goto fail; } @@ -1567,6 +1530,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Also must look for a getter name which uses property syntax. Selector Sel = S.PP.getSelectorTable().getNullarySelector(Member); ObjCInterfaceDecl *IFace = MD->getClassInterface(); + if (!IFace) + goto fail; + ObjCMethodDecl *Getter; if ((Getter = IFace->lookupClassMethod(Sel))) { // Check the use of this method. @@ -1598,7 +1564,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (ShouldTryAgainWithRedefinitionType(S, BaseExpr)) return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); return ExprError(S.Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); @@ -1623,10 +1589,14 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, else VK = BaseExpr.get()->getValueKind(); } + QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc, Member, MemberLoc); if (ret.isNull()) return ExprError(); + Qualifiers BaseQ = + S.Context.getCanonicalType(BaseExpr.get()->getType()).getQualifiers(); + ret = S.Context.getQualifiedType(ret, BaseQ); return new (S.Context) ExtVectorElementExpr(ret, VK, BaseExpr.get(), *Member, MemberLoc); @@ -1639,7 +1609,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, BaseExpr = S.ImpCastExprToType( BaseExpr.get(), S.Context.getObjCSelRedefinitionType(), CK_BitCast); return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } // Failure cases. @@ -1662,7 +1632,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Recurse as an -> access. IsArrow = true; return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } } @@ -1676,7 +1646,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, return ExprError(); BaseExpr = S.DefaultFunctionArrayConversion(BaseExpr.get()); return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl, HasTemplateArgs); + ObjCImpDecl, HasTemplateArgs, TemplateKWLoc); } S.Diag(OpLoc, diag::err_typecheck_member_reference_struct_union) @@ -1805,7 +1775,7 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, if (getLangOpts().OpenMP && IsArrow && !CurContext->isDependentContext() && isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) { - if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) { + if (auto *PrivateCopy = isOpenMPCapturedDecl(Field)) { return getOpenMPCapturedExpr(PrivateCopy, VK, OK, MemberNameInfo.getLoc()); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index cd0c2c47ae4c..bf0ffeba06b2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -141,7 +141,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){ return new (Context) ObjCStringLiteral(S, Ty, AtLoc); } -/// \brief Emits an error if the given method does not exist, or if the return +/// Emits an error if the given method does not exist, or if the return /// type is not an Objective-C object. static bool validateBoxingMethod(Sema &S, SourceLocation Loc, const ObjCInterfaceDecl *Class, @@ -165,7 +165,7 @@ static bool validateBoxingMethod(Sema &S, SourceLocation Loc, return true; } -/// \brief Maps ObjCLiteralKind to NSClassIdKindKind +/// Maps ObjCLiteralKind to NSClassIdKindKind static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind( Sema::ObjCLiteralKind LiteralKind) { switch (LiteralKind) { @@ -189,7 +189,7 @@ static NSAPI::NSClassIdKindKind ClassKindFromLiteralKind( llvm_unreachable("LiteralKind can't be converted into a ClassKind"); } -/// \brief Validates ObjCInterfaceDecl availability. +/// Validates ObjCInterfaceDecl availability. /// ObjCInterfaceDecl, used to create ObjC literals, should be defined /// if clang not in a debugger mode. static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl, @@ -211,7 +211,7 @@ static bool ValidateObjCLiteralInterfaceDecl(Sema &S, ObjCInterfaceDecl *Decl, return true; } -/// \brief Looks up ObjCInterfaceDecl of a given NSClassIdKindKind. +/// Looks up ObjCInterfaceDecl of a given NSClassIdKindKind. /// Used to create ObjC literals, such as NSDictionary (@{}), /// NSArray (@[]) and Boxed Expressions (@()) static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S, @@ -236,7 +236,7 @@ static ObjCInterfaceDecl *LookupObjCInterfaceDeclForLiteral(Sema &S, return ID; } -/// \brief Retrieve the NSNumber factory method that should be used to create +/// Retrieve the NSNumber factory method that should be used to create /// an Objective-C literal for the given type. static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, QualType NumberType, @@ -379,7 +379,7 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, return BuildObjCNumericLiteral(AtLoc, Inner.get()); } -/// \brief Check that the given expression is a valid element of an Objective-C +/// Check that the given expression is a valid element of an Objective-C /// collection literal. static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, QualType T, @@ -1357,6 +1357,11 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, if (isClassMessage) return resultType; + // There is nothing left to do if the result type cannot have a nullability + // specifier. + if (!resultType->canHaveNullability()) + return resultType; + // Map the nullability of the result into a table index. unsigned receiverNullabilityIdx = 0; if (auto nullability = ReceiverType->getNullability(Context)) @@ -1613,6 +1618,11 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, ParmVarDecl *param = Method->parameters()[i]; assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + if (param->hasAttr<NoEscapeAttr>()) + if (auto *BE = dyn_cast<BlockExpr>( + argExpr->IgnoreParenNoopCasts(Context))) + BE->getBlockDecl()->setDoesNotEscape(); + // Strip the unbridged-cast placeholder expression off unless it's // a consumed argument. if (argExpr->hasPlaceholderType(BuiltinType::ARCUnbridgedCast) && @@ -2319,7 +2329,7 @@ static void checkFoundationAPI(Sema &S, SourceLocation Loc, } } -/// \brief Diagnose use of %s directive in an NSString which is being passed +/// Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, @@ -2358,7 +2368,7 @@ DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, } } -/// \brief Build an Objective-C class message expression. +/// Build an Objective-C class message expression. /// /// This routine takes care of both normal class messages and /// class messages to the superclass. @@ -2403,11 +2413,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } - SourceLocation SelLoc; + ArrayRef<SourceLocation> SelectorSlotLocs; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelLoc = SelectorLocs.front(); + SelectorSlotLocs = SelectorLocs; else - SelLoc = Loc; + SelectorSlotLocs = Loc; + SourceLocation SelLoc = SelectorSlotLocs.front(); if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything @@ -2432,7 +2443,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(Class && "We don't know which class we're messaging?"); // objc++ diagnoses during typename annotation. if (!getLangOpts().CPlusPlus) - (void)DiagnoseUseOfDecl(Class, SelLoc); + (void)DiagnoseUseOfDecl(Class, SelectorSlotLocs); // Find the method we are messaging. if (!Method) { SourceRange TypeRange @@ -2457,7 +2468,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!Method) Method = Class->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } @@ -2581,7 +2592,7 @@ static bool isMethodDeclaredInRootProtocol(Sema &S, const ObjCMethodDecl *M) { return false; } -/// \brief Build an Objective-C instance message expression. +/// Build an Objective-C instance message expression. /// /// This routine takes care of both normal instance messages and /// instance messages to the superclass instance. @@ -2627,11 +2638,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); SourceRange RecRange = SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange(); - SourceLocation SelLoc; + ArrayRef<SourceLocation> SelectorSlotLocs; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) - SelLoc = SelectorLocs.front(); + SelectorSlotLocs = SelectorLocs; else - SelLoc = Loc; + SelectorSlotLocs = Loc; + SourceLocation SelLoc = SelectorSlotLocs.front(); if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) @@ -2743,7 +2755,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), receiverIsIdLike, Methods)) - DiagnoseUseOfDecl(Method, SelLoc); + DiagnoseUseOfDecl(Method, SelectorSlotLocs); } } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2775,7 +2787,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); } - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } if (!Method) { @@ -2792,7 +2804,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // to select a better one. Method = Methods[0]; - // If we find an instance method, emit waring. + // If we find an instance method, emit warning. if (Method->isInstanceMethod()) { if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { @@ -2822,7 +2834,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); - if (Method && DiagnoseUseOfDecl(Method, SelLoc)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs)) return ExprError(); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { @@ -2897,7 +2909,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } } - if (Method && DiagnoseUseOfDecl(Method, SelLoc, forwardClass)) + if (Method && DiagnoseUseOfDecl(Method, SelectorSlotLocs, forwardClass)) return ExprError(); } else { // Reject other random receiver types (e.g. structs). @@ -3491,6 +3503,7 @@ static void addFixitForObjCARCConversion(Sema &S, // We handle C-style and implicit casts here. switch (CCK) { case Sema::CCK_ImplicitConversion: + case Sema::CCK_ForBuiltinOverloadedOp: case Sema::CCK_CStyleCast: case Sema::CCK_OtherCast: break; @@ -3644,11 +3657,13 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, SourceLocation afterLParen = S.getLocForEndOfToken(castRange.getBegin()); SourceLocation noteLoc = afterLParen.isValid() ? afterLParen : loc; + unsigned convKindForDiag = Sema::isCast(CCK) ? 0 : 1; + // Bridge from an ARC type to a CF type. if (castACTC == ACTC_retainable && isAnyRetainable(exprACTC)) { S.Diag(loc, diag::err_arc_cast_requires_bridge) - << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit + << convKindForDiag << 2 // of C pointer type << castExprType << unsigned(castType->isBlockPointerType()) // to ObjC|block type @@ -3690,7 +3705,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) { bool br = S.isKnownName("CFBridgingRetain"); S.Diag(loc, diag::err_arc_cast_requires_bridge) - << unsigned(CCK == Sema::CCK_ImplicitConversion) // cast|implicit + << convKindForDiag << unsigned(castExprType->isBlockPointerType()) // of ObjC|block type << castExprType << 2 // to C pointer type @@ -3727,7 +3742,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, } S.Diag(loc, diag::err_arc_mismatched_cast) - << (CCK != Sema::CCK_ImplicitConversion) + << !convKindForDiag << srcKind << castExprType << castType << castRange << castExpr->getSourceRange(); } @@ -4180,7 +4195,7 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType, if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) return ACR_okay; if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && - CCK != CCK_ImplicitConversion) + isCast(CCK)) return ACR_okay; switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) { @@ -4205,8 +4220,7 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType, // If this is a non-implicit cast from id or block type to a // CoreFoundation type, delay complaining in case the cast is used // in an acceptable context. - if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && - CCK != CCK_ImplicitConversion) + if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC) && isCast(CCK)) return ACR_unbridged; // Issue a diagnostic about a missing @-sign when implicit casting a cstring @@ -4276,9 +4290,9 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { assert(uo->getOpcode() == UO_Extension); Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); - return new (Context) UnaryOperator(sub, UO_Extension, sub->getType(), - sub->getValueKind(), sub->getObjectKind(), - uo->getOperatorLoc()); + return new (Context) + UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(), + sub->getObjectKind(), uo->getOperatorLoc(), false); } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { assert(!gse->isResultDependent()); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index df64a33954fa..3ee5ec4a4929 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" @@ -32,7 +33,7 @@ using namespace clang; // Sema Initialization Checking //===----------------------------------------------------------------------===// -/// \brief Check whether T is compatible with a wide character type (wchar_t, +/// Check whether T is compatible with a wide character type (wchar_t, /// char16_t or char32_t). static bool IsWideCharCompatible(QualType T, ASTContext &Context) { if (Context.typesAreCompatible(Context.getWideCharType(), T)) @@ -49,10 +50,12 @@ enum StringInitFailureKind { SIF_NarrowStringIntoWideChar, SIF_WideStringIntoChar, SIF_IncompatWideStringIntoWideChar, + SIF_UTF8StringIntoPlainChar, + SIF_PlainStringIntoUTF8Char, SIF_Other }; -/// \brief Check whether the array of type AT can be initialized by the Init +/// Check whether the array of type AT can be initialized by the Init /// expression by means of string initialization. Returns SIF_None if so, /// otherwise returns a StringInitFailureKind that describes why the /// initialization would not work. @@ -77,12 +80,21 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); switch (SL->getKind()) { - case StringLiteral::Ascii: case StringLiteral::UTF8: + // char8_t array can be initialized with a UTF-8 string. + if (ElemTy->isChar8Type()) + return SIF_None; + LLVM_FALLTHROUGH; + case StringLiteral::Ascii: // char array can be initialized with a narrow string. // Only allow char x[] = "foo"; not char x[] = L"foo"; if (ElemTy->isCharType()) - return SIF_None; + return (SL->getKind() == StringLiteral::UTF8 && + Context.getLangOpts().Char8) + ? SIF_UTF8StringIntoPlainChar + : SIF_None; + if (ElemTy->isChar8Type()) + return SIF_PlainStringIntoUTF8Char; if (IsWideCharCompatible(ElemTy, Context)) return SIF_NarrowStringIntoWideChar; return SIF_Other; @@ -94,7 +106,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, case StringLiteral::UTF16: if (Context.typesAreCompatible(Context.Char16Ty, ElemTy)) return SIF_None; - if (ElemTy->isCharType()) + if (ElemTy->isCharType() || ElemTy->isChar8Type()) return SIF_WideStringIntoChar; if (IsWideCharCompatible(ElemTy, Context)) return SIF_IncompatWideStringIntoWideChar; @@ -102,7 +114,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, case StringLiteral::UTF32: if (Context.typesAreCompatible(Context.Char32Ty, ElemTy)) return SIF_None; - if (ElemTy->isCharType()) + if (ElemTy->isCharType() || ElemTy->isChar8Type()) return SIF_WideStringIntoChar; if (IsWideCharCompatible(ElemTy, Context)) return SIF_IncompatWideStringIntoWideChar; @@ -110,7 +122,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, case StringLiteral::Wide: if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy)) return SIF_None; - if (ElemTy->isCharType()) + if (ElemTy->isCharType() || ElemTy->isChar8Type()) return SIF_WideStringIntoChar; if (IsWideCharCompatible(ElemTy, Context)) return SIF_IncompatWideStringIntoWideChar; @@ -206,7 +218,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, namespace { -/// @brief Semantic checking for initializer lists. +/// Semantic checking for initializer lists. /// /// The InitListChecker class contains a set of routines that each /// handle the initialization of a certain kind of entity, e.g., @@ -366,7 +378,7 @@ public: bool TreatUnavailableAsInvalid); bool HadError() { return hadError; } - // @brief Retrieves the fully-structured initializer list used for + // Retrieves the fully-structured initializer list used for // semantic analysis and code generation. InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } }; @@ -561,6 +573,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, hadError = true; return; } + SemaRef.checkInitializerLifetime(MemberEntity, DIE.get()); if (Init < NumInits) ILE->setInit(Init, DIE.get()); else { @@ -740,6 +753,9 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, ElementEntity.getKind() == InitializedEntity::EK_VectorElement) ElementEntity.setElementIndex(Init); + if (Init >= NumInits && ILE->hasArrayFiller()) + return; + Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr); if (!InitExpr && Init < NumInits && ILE->hasArrayFiller()) ILE->setInit(Init, ILE->getArrayFiller()); @@ -1005,6 +1021,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_Binding: + case InitializedEntity::EK_StmtExprResult: llvm_unreachable("unexpected braced scalar init"); } @@ -2014,7 +2031,7 @@ void InitListChecker::CheckStructUnionTypes( StructuredList, StructuredIndex); } -/// \brief Expand a field designator that refers to a member of an +/// Expand a field designator that refers to a member of an /// anonymous struct or union into a series of field designators that /// refers to the field within the appropriate subobject. /// @@ -2078,7 +2095,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { } // end anonymous namespace -/// @brief Check the well-formedness of a C99 designated initializer. +/// Check the well-formedness of a C99 designated initializer. /// /// Determines whether the designated initializer @p DIE, which /// resides at the given @p Index within the initializer list @p @@ -2985,6 +3002,7 @@ DeclarationName InitializedEntity::getName() const { return DeclarationName(Capture.VarID); case EK_Result: + case EK_StmtExprResult: case EK_Exception: case EK_New: case EK_Temporary: @@ -3015,6 +3033,7 @@ ValueDecl *InitializedEntity::getDecl() const { return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1); case EK_Result: + case EK_StmtExprResult: case EK_Exception: case EK_New: case EK_Temporary: @@ -3040,6 +3059,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Exception: return LocAndNRVO.NRVO; + case EK_StmtExprResult: case EK_Variable: case EK_Parameter: case EK_Parameter_CF_Audited: @@ -3075,6 +3095,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { case EK_Parameter_CF_Audited: OS << "CF audited function Parameter"; break; case EK_Result: OS << "Result"; break; + case EK_StmtExprResult: OS << "StmtExprResult"; break; case EK_Exception: OS << "Exception"; break; case EK_Member: OS << "Member"; break; case EK_Binding: OS << "Binding"; break; @@ -3185,6 +3206,8 @@ bool InitializationSequence::isAmbiguous() const { case FK_NarrowStringIntoWideCharArray: case FK_WideStringIntoCharArray: case FK_IncompatWideStringIntoWideChar: + case FK_PlainStringIntoUTF8Char: + case FK_UTF8StringIntoPlainChar: case FK_AddressOfOverloadFailed: // FIXME: Could do better case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToBitfield: @@ -3517,7 +3540,8 @@ static void MaybeProduceObjCObject(Sema &S, /// retainable type, then returns need to immediately retain the /// object. If an autorelease is required, it will be done at the /// last instant. - } else if (Entity.getKind() == InitializedEntity::EK_Result) { + } else if (Entity.getKind() == InitializedEntity::EK_Result || + Entity.getKind() == InitializedEntity::EK_StmtExprResult) { if (!Entity.getType()->isObjCRetainableType()) return; @@ -3532,7 +3556,7 @@ static void TryListInitialization(Sema &S, InitializationSequence &Sequence, bool TreatUnavailableAsInvalid); -/// \brief When initializing from init list via constructor, handle +/// When initializing from init list via constructor, handle /// initialization of an object of type std::initializer_list<T>. /// /// \return true if we have handled initialization of an object of type @@ -3558,8 +3582,8 @@ static bool TryInitializerListConstruction(Sema &S, clang::ArrayType::Normal, 0); InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(ArrayType); - InitializationKind Kind = - InitializationKind::CreateDirectList(List->getExprLoc()); + InitializationKind Kind = InitializationKind::CreateDirectList( + List->getExprLoc(), List->getLocStart(), List->getLocEnd()); TryListInitialization(S, HiddenArray, Kind, List, Sequence, TreatUnavailableAsInvalid); if (Sequence) @@ -3693,7 +3717,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, return CandidateSet.BestViableFunction(S, DeclLoc, Best); } -/// \brief Attempt initialization by constructor (C++ [dcl.init]), which +/// Attempt initialization by constructor (C++ [dcl.init]), which /// enumerates the constructors of the initialized entity and performs overload /// resolution to select the best. /// \param DestType The destination class type. @@ -3910,7 +3934,7 @@ static void TryValueInitialization(Sema &S, InitializationSequence &Sequence, InitListExpr *InitList = nullptr); -/// \brief Attempt list initialization of a reference. +/// Attempt list initialization of a reference. static void TryReferenceListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -3984,7 +4008,7 @@ static void TryReferenceListInitialization(Sema &S, } } -/// \brief Attempt list initialization (C++0x [dcl.init.list]) +/// Attempt list initialization (C++0x [dcl.init.list]) static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4179,7 +4203,7 @@ static void TryListInitialization(Sema &S, Sequence.AddListInitializationStep(DestType); } -/// \brief Try a reference initialization that involves calling a conversion +/// Try a reference initialization that involves calling a conversion /// function. static OverloadingResult TryRefInitWithConversionFunction( Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4208,9 +4232,11 @@ static OverloadingResult TryRefInitWithConversionFunction( OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); - // Determine whether we are allowed to call explicit constructors or - // explicit conversion operators. - bool AllowExplicit = Kind.AllowExplicit(); + // Determine whether we are allowed to call explicit conversion operators. + // Note that none of [over.match.copy], [over.match.conv], nor + // [over.match.ref] permit an explicit constructor to be chosen when + // initializing a reference, not even for direct-initialization. + bool AllowExplicitCtors = false; bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding(); const RecordType *T1RecordType = nullptr; @@ -4226,7 +4252,7 @@ static OverloadingResult TryRefInitWithConversionFunction( continue; if (!Info.Constructor->isInvalidDecl() && - Info.Constructor->isConvertingConstructor(AllowExplicit)) { + Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) { if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, @@ -4369,7 +4395,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, const InitializedEntity &Entity, Expr *CurInitExpr); -/// \brief Attempt reference initialization (C++0x [dcl.init.ref]) +/// Attempt reference initialization (C++0x [dcl.init.ref]) static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4396,13 +4422,13 @@ static void TryReferenceInitialization(Sema &S, } /// Determine whether an expression is a non-referenceable glvalue (one to -/// which a reference can never bind). Attemting to bind a reference to +/// which a reference can never bind). Attempting to bind a reference to /// such a glvalue will always create a temporary. static bool isNonReferenceableGLValue(Expr *E) { return E->refersToBitField() || E->refersToVectorElement(); } -/// \brief Reference initialization without resolving overloaded functions. +/// Reference initialization without resolving overloaded functions. static void TryReferenceInitializationCore(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4662,7 +4688,7 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); } -/// \brief Attempt character array initialization from a string literal +/// Attempt character array initialization from a string literal /// (C++ [dcl.init.string], C99 6.7.8). static void TryStringLiteralInitialization(Sema &S, const InitializedEntity &Entity, @@ -4672,7 +4698,7 @@ static void TryStringLiteralInitialization(Sema &S, Sequence.AddStringInitStep(Entity.getType()); } -/// \brief Attempt value initialization (C++ [dcl.init]p7). +/// Attempt value initialization (C++ [dcl.init]p7). static void TryValueInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4750,7 +4776,7 @@ static void TryValueInitialization(Sema &S, Sequence.AddZeroInitializationStep(Entity.getType()); } -/// \brief Attempt default initialization (C++ [dcl.init]p6). +/// Attempt default initialization (C++ [dcl.init]p6). static void TryDefaultInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4789,7 +4815,7 @@ static void TryDefaultInitialization(Sema &S, } } -/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), +/// Attempt a user-defined conversion between two types (C++ [dcl.init]), /// which enumerates all conversion functions and performs overload resolution /// to select the best. static void TryUserDefinedConversion(Sema &S, @@ -5068,7 +5094,7 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) { << src->getSourceRange(); } -/// \brief Determine whether we have compatible array types for the +/// Determine whether we have compatible array types for the /// purposes of GNU by-copy array initialization. static bool hasCompatibleArrayTypes(ASTContext &Context, const ArrayType *Dest, const ArrayType *Source) { @@ -5362,6 +5388,12 @@ void InitializationSequence::InitializeFrom(Sema &S, case SIF_IncompatWideStringIntoWideChar: SetFailed(FK_IncompatWideStringIntoWideChar); return; + case SIF_PlainStringIntoUTF8Char: + SetFailed(FK_PlainStringIntoUTF8Char); + return; + case SIF_UTF8StringIntoPlainChar: + SetFailed(FK_UTF8StringIntoPlainChar); + return; case SIF_Other: break; } @@ -5607,6 +5639,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited; case InitializedEntity::EK_Result: + case InitializedEntity::EK_StmtExprResult: // FIXME: Not quite right. return Sema::AA_Returning; case InitializedEntity::EK_Temporary: @@ -5629,13 +5662,14 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { llvm_unreachable("Invalid EntityKind!"); } -/// \brief Whether we should bind a created object as a temporary when +/// Whether we should bind a created object as a temporary when /// initializing the given entity. static bool shouldBindAsTemporary(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: case InitializedEntity::EK_Result: + case InitializedEntity::EK_StmtExprResult: case InitializedEntity::EK_New: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: @@ -5660,11 +5694,12 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } -/// \brief Whether the given entity, when initialized with an object +/// Whether the given entity, when initialized with an object /// created for that initialization, requires destruction. static bool shouldDestroyEntity(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_Result: + case InitializedEntity::EK_StmtExprResult: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: @@ -5691,11 +5726,12 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } -/// \brief Get the location at which initialization diagnostics should appear. +/// Get the location at which initialization diagnostics should appear. static SourceLocation getInitializationLoc(const InitializedEntity &Entity, Expr *Initializer) { switch (Entity.getKind()) { case InitializedEntity::EK_Result: + case InitializedEntity::EK_StmtExprResult: return Entity.getReturnLoc(); case InitializedEntity::EK_Exception: @@ -5727,7 +5763,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, llvm_unreachable("missed an InitializedEntity kind?"); } -/// \brief Make a (potentially elidable) temporary copy of the object +/// Make a (potentially elidable) temporary copy of the object /// provided by the given initializer by calling the appropriate copy /// constructor. /// @@ -5892,7 +5928,7 @@ static ExprResult CopyObject(Sema &S, return CurInit; } -/// \brief Check whether elidable copy construction for binding a reference to +/// Check whether elidable copy construction for binding a reference to /// a temporary would have succeeded if we were building in C++98 mode, for /// -Wc++98-compat. static void CheckCXX98CompatAccessibleCopy(Sema &S, @@ -6056,10 +6092,7 @@ PerformConstructorInitialization(Sema &S, TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) TSInfo = S.Context.getTrivialTypeSourceInfo(Entity.getType(), Loc); - SourceRange ParenOrBraceRange = - (Kind.getKind() == InitializationKind::IK_DirectList) - ? SourceRange(LBraceLoc, RBraceLoc) - : Kind.getParenRange(); + SourceRange ParenOrBraceRange = Kind.getParenOrBraceRange(); if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>( Step.Function.FoundDecl.getDecl())) { @@ -6093,7 +6126,7 @@ PerformConstructorInitialization(Sema &S, if (IsListInitialization) ParenOrBraceRange = SourceRange(LBraceLoc, RBraceLoc); else if (Kind.getKind() == InitializationKind::IK_Direct) - ParenOrBraceRange = Kind.getParenRange(); + ParenOrBraceRange = Kind.getParenOrBraceRange(); // If the entity allows NRVO, mark the construction as elidable // unconditionally. @@ -6134,90 +6167,96 @@ PerformConstructorInitialization(Sema &S, return CurInit; } -/// Determine whether the specified InitializedEntity definitely has a lifetime -/// longer than the current full-expression. Conservatively returns false if -/// it's unclear. -static bool -InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { - const InitializedEntity *Top = &Entity; - while (Top->getParent()) - Top = Top->getParent(); - - switch (Top->getKind()) { - case InitializedEntity::EK_Variable: - case InitializedEntity::EK_Result: - case InitializedEntity::EK_Exception: - case InitializedEntity::EK_Member: - case InitializedEntity::EK_Binding: - case InitializedEntity::EK_New: - case InitializedEntity::EK_Base: - case InitializedEntity::EK_Delegating: - return true; - - case InitializedEntity::EK_ArrayElement: - case InitializedEntity::EK_VectorElement: - case InitializedEntity::EK_BlockElement: - case InitializedEntity::EK_LambdaToBlockConversionBlockElement: - case InitializedEntity::EK_ComplexElement: - // Could not determine what the full initialization is. Assume it might not - // outlive the full-expression. - return false; - - case InitializedEntity::EK_Parameter: - case InitializedEntity::EK_Parameter_CF_Audited: - case InitializedEntity::EK_Temporary: - case InitializedEntity::EK_LambdaCapture: - case InitializedEntity::EK_CompoundLiteralInit: - case InitializedEntity::EK_RelatedResult: - // The entity being initialized might not outlive the full-expression. - return false; - } - - llvm_unreachable("unknown entity kind"); +namespace { +enum LifetimeKind { + /// The lifetime of a temporary bound to this entity ends at the end of the + /// full-expression, and that's (probably) fine. + LK_FullExpression, + + /// The lifetime of a temporary bound to this entity is extended to the + /// lifeitme of the entity itself. + LK_Extended, + + /// The lifetime of a temporary bound to this entity probably ends too soon, + /// because the entity is allocated in a new-expression. + LK_New, + + /// The lifetime of a temporary bound to this entity ends too soon, because + /// the entity is a return object. + LK_Return, + + /// The lifetime of a temporary bound to this entity ends too soon, because + /// the entity is the result of a statement expression. + LK_StmtExprResult, + + /// This is a mem-initializer: if it would extend a temporary (other than via + /// a default member initializer), the program is ill-formed. + LK_MemInitializer, +}; +using LifetimeResult = + llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>; } /// Determine the declaration which an initialized entity ultimately refers to, /// for the purpose of lifetime-extending a temporary bound to a reference in /// the initialization of \p Entity. -static const InitializedEntity *getEntityForTemporaryLifetimeExtension( +static LifetimeResult getEntityLifetime( const InitializedEntity *Entity, - const InitializedEntity *FallbackDecl = nullptr) { + const InitializedEntity *InitField = nullptr) { // C++11 [class.temporary]p5: switch (Entity->getKind()) { case InitializedEntity::EK_Variable: // The temporary [...] persists for the lifetime of the reference - return Entity; + return {Entity, LK_Extended}; case InitializedEntity::EK_Member: // For subobjects, we look at the complete object. if (Entity->getParent()) - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), - Entity); + return getEntityLifetime(Entity->getParent(), Entity); // except: - // -- A temporary bound to a reference member in a constructor's - // ctor-initializer persists until the constructor exits. - return Entity; + // C++17 [class.base.init]p8: + // A temporary expression bound to a reference member in a + // mem-initializer is ill-formed. + // C++17 [class.base.init]p11: + // A temporary expression bound to a reference member from a + // default member initializer is ill-formed. + // + // The context of p11 and its example suggest that it's only the use of a + // default member initializer from a constructor that makes the program + // ill-formed, not its mere existence, and that it can even be used by + // aggregate initialization. + return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended + : LK_MemInitializer}; case InitializedEntity::EK_Binding: // Per [dcl.decomp]p3, the binding is treated as a variable of reference // type. - return Entity; + return {Entity, LK_Extended}; case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: // -- A temporary bound to a reference parameter in a function call // persists until the completion of the full-expression containing // the call. + return {nullptr, LK_FullExpression}; + case InitializedEntity::EK_Result: // -- The lifetime of a temporary bound to the returned value in a // function return statement is not extended; the temporary is // destroyed at the end of the full-expression in the return statement. + return {nullptr, LK_Return}; + + case InitializedEntity::EK_StmtExprResult: + // FIXME: Should we lifetime-extend through the result of a statement + // expression? + return {nullptr, LK_StmtExprResult}; + case InitializedEntity::EK_New: // -- A temporary bound to a reference in a new-initializer persists // until the completion of the full-expression containing the // new-initializer. - return nullptr; + return {nullptr, LK_New}; case InitializedEntity::EK_Temporary: case InitializedEntity::EK_CompoundLiteralInit: @@ -6225,56 +6264,122 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension( // We don't yet know the storage duration of the surrounding temporary. // Assume it's got full-expression duration for now, it will patch up our // storage duration if that's not correct. - return nullptr; + return {nullptr, LK_FullExpression}; case InitializedEntity::EK_ArrayElement: // For subobjects, we look at the complete object. - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), - FallbackDecl); + return getEntityLifetime(Entity->getParent(), InitField); case InitializedEntity::EK_Base: // For subobjects, we look at the complete object. if (Entity->getParent()) - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), - Entity); - LLVM_FALLTHROUGH; + return getEntityLifetime(Entity->getParent(), InitField); + return {InitField, LK_MemInitializer}; + case InitializedEntity::EK_Delegating: // We can reach this case for aggregate initialization in a constructor: // struct A { int &&r; }; // struct B : A { B() : A{0} {} }; - // In this case, use the innermost field decl as the context. - return FallbackDecl; + // In this case, use the outermost field decl as the context. + return {InitField, LK_MemInitializer}; case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_LambdaCapture: - case InitializedEntity::EK_Exception: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: - return nullptr; + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_Exception: + // FIXME: Can we diagnose lifetime problems with exceptions? + return {nullptr, LK_FullExpression}; } llvm_unreachable("unknown entity kind"); } -static void performLifetimeExtension(Expr *Init, - const InitializedEntity *ExtendingEntity); +namespace { +enum ReferenceKind { + /// Lifetime would be extended by a reference binding to a temporary. + RK_ReferenceBinding, + /// Lifetime would be extended by a std::initializer_list object binding to + /// its backing array. + RK_StdInitializerList, +}; + +/// A temporary or local variable. This will be one of: +/// * A MaterializeTemporaryExpr. +/// * A DeclRefExpr whose declaration is a local. +/// * An AddrLabelExpr. +/// * A BlockExpr for a block with captures. +using Local = Expr*; + +/// Expressions we stepped over when looking for the local state. Any steps +/// that would inhibit lifetime extension or take us out of subexpressions of +/// the initializer are included. +struct IndirectLocalPathEntry { + enum EntryKind { + DefaultInit, + AddressOf, + VarInit, + LValToRVal, + } Kind; + Expr *E; + Decl *D = nullptr; + IndirectLocalPathEntry() {} + IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {} + IndirectLocalPathEntry(EntryKind K, Expr *E, Decl *D) : Kind(K), E(E), D(D) {} +}; + +using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>; + +struct RevertToOldSizeRAII { + IndirectLocalPath &Path; + unsigned OldSize = Path.size(); + RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {} + ~RevertToOldSizeRAII() { Path.resize(OldSize); } +}; + +using LocalVisitor = llvm::function_ref<bool(IndirectLocalPath &Path, Local L, + ReferenceKind RK)>; +} + +static bool isVarOnPath(IndirectLocalPath &Path, VarDecl *VD) { + for (auto E : Path) + if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD) + return true; + return false; +} + +static bool pathContainsInit(IndirectLocalPath &Path) { + return std::any_of(Path.begin(), Path.end(), [=](IndirectLocalPathEntry E) { + return E.Kind == IndirectLocalPathEntry::DefaultInit || + E.Kind == IndirectLocalPathEntry::VarInit; + }); +} + +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, + Expr *Init, LocalVisitor Visit, + bool RevisitSubinits); + +/// Visit the locals that would be reachable through a reference bound to the +/// glvalue expression \c Init. +static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, + Expr *Init, ReferenceKind RK, + LocalVisitor Visit) { + RevertToOldSizeRAII RAII(Path); -/// Update a glvalue expression that is used as the initializer of a reference -/// to note that its lifetime is extended. -/// \return \c true if any temporary had its lifetime extended. -static bool -performReferenceExtension(Expr *Init, - const InitializedEntity *ExtendingEntity) { // Walk past any constructs which we can lifetime-extend across. Expr *Old; do { Old = Init; + if (auto *EWC = dyn_cast<ExprWithCleanups>(Init)) + Init = EWC->getSubExpr(); + if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) { - // This is just redundant braces around an initializer. Step over it. + // If this is just redundant braces around an initializer, step over it. + if (ILE->isTransparent()) Init = ILE->getInit(0); - } } // Step over any subobject adjustments; we may have a materialized @@ -6288,43 +6393,134 @@ performReferenceExtension(Expr *Init, Init = CE->getSubExpr(); // Per the current approach for DR1299, look through array element access - // when performing lifetime extension. - if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) + // on array glvalues when performing lifetime extension. + if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) { Init = ASE->getBase(); + auto *ICE = dyn_cast<ImplicitCastExpr>(Init); + if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay) + Init = ICE->getSubExpr(); + else + // We can't lifetime extend through this but we might still find some + // retained temporaries. + return visitLocalsRetainedByInitializer(Path, Init, Visit, true); + } + + // Step into CXXDefaultInitExprs so we can diagnose cases where a + // constructor inherits one as an implicit mem-initializer. + if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) { + Path.push_back( + {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); + Init = DIE->getExpr(); + } } while (Init != Old); - if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) { - // Update the storage duration of the materialized temporary. - // FIXME: Rebuild the expression instead of mutating it. - ME->setExtendingDecl(ExtendingEntity->getDecl(), - ExtendingEntity->allocateManglingNumber()); - performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingEntity); - return true; + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) { + if (Visit(Path, Local(MTE), RK)) + visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit, + true); + } + + switch (Init->getStmtClass()) { + case Stmt::DeclRefExprClass: { + // If we find the name of a local non-reference parameter, we could have a + // lifetime problem. + auto *DRE = cast<DeclRefExpr>(Init); + auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (VD && VD->hasLocalStorage() && + !DRE->refersToEnclosingVariableOrCapture()) { + if (!VD->getType()->isReferenceType()) { + Visit(Path, Local(DRE), RK); + } else if (isa<ParmVarDecl>(DRE->getDecl())) { + // The lifetime of a reference parameter is unknown; assume it's OK + // for now. + break; + } else if (VD->getInit() && !isVarOnPath(Path, VD)) { + Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); + visitLocalsRetainedByReferenceBinding(Path, VD->getInit(), + RK_ReferenceBinding, Visit); + } + } + break; } - return false; + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + const UnaryOperator *U = cast<UnaryOperator>(Init); + if (U->getOpcode() == UO_Deref) + visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true); + break; + } + + case Stmt::OMPArraySectionExprClass: { + visitLocalsRetainedByInitializer( + Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true); + break; + } + + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryConditionalOperatorClass: { + auto *C = cast<AbstractConditionalOperator>(Init); + if (!C->getTrueExpr()->getType()->isVoidType()) + visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit); + if (!C->getFalseExpr()->getType()->isVoidType()) + visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit); + break; + } + + // FIXME: Visit the left-hand side of an -> or ->*. + + default: + break; + } } -/// Update a prvalue expression that is going to be materialized as a -/// lifetime-extended temporary. -static void performLifetimeExtension(Expr *Init, - const InitializedEntity *ExtendingEntity) { +/// Visit the locals that would be reachable through an object initialized by +/// the prvalue expression \c Init. +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, + Expr *Init, LocalVisitor Visit, + bool RevisitSubinits) { + RevertToOldSizeRAII RAII(Path); + + // Step into CXXDefaultInitExprs so we can diagnose cases where a + // constructor inherits one as an implicit mem-initializer. + if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) { + Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); + Init = DIE->getExpr(); + } + + if (auto *EWC = dyn_cast<ExprWithCleanups>(Init)) + Init = EWC->getSubExpr(); + // Dig out the expression which constructs the extended temporary. Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments()); if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init)) Init = BTE->getSubExpr(); - if (CXXStdInitializerListExpr *ILE = - dyn_cast<CXXStdInitializerListExpr>(Init)) { - performReferenceExtension(ILE->getSubExpr(), ExtendingEntity); - return; - } + // C++17 [dcl.init.list]p6: + // initializing an initializer_list object from the array extends the + // lifetime of the array exactly like binding a reference to a temporary. + if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init)) + return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(), + RK_StdInitializerList, Visit); if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + // We already visited the elements of this initializer list while + // performing the initialization. Don't visit them again unless we've + // changed the lifetime of the initialized entity. + if (!RevisitSubinits) + return; + + if (ILE->isTransparent()) + return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit, + RevisitSubinits); + if (ILE->getType()->isArrayType()) { for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) - performLifetimeExtension(ILE->getInit(I), ExtendingEntity); + visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit, + RevisitSubinits); return; } @@ -6336,7 +6532,8 @@ static void performLifetimeExtension(Expr *Init, // bound to temporaries, those temporaries are also lifetime-extended. if (RD->isUnion() && ILE->getInitializedFieldInUnion() && ILE->getInitializedFieldInUnion()->getType()->isReferenceType()) - performReferenceExtension(ILE->getInit(0), ExtendingEntity); + visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0), + RK_ReferenceBinding, Visit); else { unsigned Index = 0; for (const auto *I : RD->fields()) { @@ -6346,51 +6543,365 @@ static void performLifetimeExtension(Expr *Init, continue; Expr *SubInit = ILE->getInit(Index); if (I->getType()->isReferenceType()) - performReferenceExtension(SubInit, ExtendingEntity); - else if (isa<InitListExpr>(SubInit) || - isa<CXXStdInitializerListExpr>(SubInit)) - // This may be either aggregate-initialization of a member or - // initialization of a std::initializer_list object. Either way, + visitLocalsRetainedByReferenceBinding(Path, SubInit, + RK_ReferenceBinding, Visit); + else + // This might be either aggregate-initialization of a member or + // initialization of a std::initializer_list object. Regardless, // we should recursively lifetime-extend that initializer. - performLifetimeExtension(SubInit, ExtendingEntity); + visitLocalsRetainedByInitializer(Path, SubInit, Visit, + RevisitSubinits); ++Index; } } } + return; } -} -static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity, - const Expr *Init, bool IsInitializerList, - const ValueDecl *ExtendingDecl) { - // Warn if a field lifetime-extends a temporary. - if (isa<FieldDecl>(ExtendingDecl)) { - if (IsInitializerList) { - S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list) - << /*at end of constructor*/true; + // Step over value-preserving rvalue casts. + while (auto *CE = dyn_cast<CastExpr>(Init)) { + switch (CE->getCastKind()) { + case CK_LValueToRValue: + // If we can match the lvalue to a const object, we can look at its + // initializer. + Path.push_back({IndirectLocalPathEntry::LValToRVal, CE}); + return visitLocalsRetainedByReferenceBinding( + Path, Init, RK_ReferenceBinding, + [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool { + if (auto *DRE = dyn_cast<DeclRefExpr>(L)) { + auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (VD && VD->getType().isConstQualified() && VD->getInit()) { + Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); + visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true); + } + } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) { + if (MTE->getType().isConstQualified()) + visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), + Visit, true); + } + return false; + }); + + // We assume that objects can be retained by pointers cast to integers, + // but not if the integer is cast to floating-point type or to _Complex. + // We assume that casts to 'bool' do not preserve enough information to + // retain a local object. + case CK_NoOp: + case CK_BitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_AddressSpaceConversion: + break; + + case CK_ArrayToPointerDecay: + // Model array-to-pointer decay as taking the address of the array + // lvalue. + Path.push_back({IndirectLocalPathEntry::AddressOf, CE}); + return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(), + RK_ReferenceBinding, Visit); + + default: return; } - bool IsSubobjectMember = false; - for (const InitializedEntity *Ent = Entity.getParent(); Ent; - Ent = Ent->getParent()) { - if (Ent->getKind() != InitializedEntity::EK_Base) { - IsSubobjectMember = true; + Init = CE->getSubExpr(); + } + + Init = Init->IgnoreParens(); + switch (Init->getStmtClass()) { + case Stmt::UnaryOperatorClass: { + auto *UO = cast<UnaryOperator>(Init); + // If the initializer is the address of a local, we could have a lifetime + // problem. + if (UO->getOpcode() == UO_AddrOf) { + // If this is &rvalue, then it's ill-formed and we have already diagnosed + // it. Don't produce a redundant warning about the lifetime of the + // temporary. + if (isa<MaterializeTemporaryExpr>(UO->getSubExpr())) + return; + + Path.push_back({IndirectLocalPathEntry::AddressOf, UO}); + visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(), + RK_ReferenceBinding, Visit); + } + break; + } + + case Stmt::BinaryOperatorClass: { + // Handle pointer arithmetic. + auto *BO = cast<BinaryOperator>(Init); + BinaryOperatorKind BOK = BO->getOpcode(); + if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub)) + break; + + if (BO->getLHS()->getType()->isPointerType()) + visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true); + else if (BO->getRHS()->getType()->isPointerType()) + visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true); + break; + } + + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryConditionalOperatorClass: { + auto *C = cast<AbstractConditionalOperator>(Init); + // In C++, we can have a throw-expression operand, which has 'void' type + // and isn't interesting from a lifetime perspective. + if (!C->getTrueExpr()->getType()->isVoidType()) + visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true); + if (!C->getFalseExpr()->getType()->isVoidType()) + visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true); + break; + } + + case Stmt::BlockExprClass: + if (cast<BlockExpr>(Init)->getBlockDecl()->hasCaptures()) { + // This is a local block, whose lifetime is that of the function. + Visit(Path, Local(cast<BlockExpr>(Init)), RK_ReferenceBinding); + } + break; + + case Stmt::AddrLabelExprClass: + // We want to warn if the address of a label would escape the function. + Visit(Path, Local(cast<AddrLabelExpr>(Init)), RK_ReferenceBinding); + break; + + default: + break; + } +} + +/// Determine whether this is an indirect path to a temporary that we are +/// supposed to lifetime-extend along (but don't). +static bool shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { + for (auto Elem : Path) { + if (Elem.Kind != IndirectLocalPathEntry::DefaultInit) + return false; + } + return true; +} + +/// Find the range for the first interesting entry in the path at or after I. +static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, + Expr *E) { + for (unsigned N = Path.size(); I != N; ++I) { + switch (Path[I].Kind) { + case IndirectLocalPathEntry::AddressOf: + case IndirectLocalPathEntry::LValToRVal: + // These exist primarily to mark the path as not permitting or + // supporting lifetime extension. + break; + + case IndirectLocalPathEntry::DefaultInit: + case IndirectLocalPathEntry::VarInit: + return Path[I].E->getSourceRange(); + } + } + return E->getSourceRange(); +} + +void Sema::checkInitializerLifetime(const InitializedEntity &Entity, + Expr *Init) { + LifetimeResult LR = getEntityLifetime(&Entity); + LifetimeKind LK = LR.getInt(); + const InitializedEntity *ExtendingEntity = LR.getPointer(); + + // If this entity doesn't have an interesting lifetime, don't bother looking + // for temporaries within its initializer. + if (LK == LK_FullExpression) + return; + + auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L, + ReferenceKind RK) -> bool { + SourceRange DiagRange = nextPathEntryRange(Path, 0, L); + SourceLocation DiagLoc = DiagRange.getBegin(); + + switch (LK) { + case LK_FullExpression: + llvm_unreachable("already handled this"); + + case LK_Extended: { + auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L); + if (!MTE) { + // The initialized entity has lifetime beyond the full-expression, + // and the local entity does too, so don't warn. + // + // FIXME: We should consider warning if a static / thread storage + // duration variable retains an automatic storage duration local. + return false; + } + + // Lifetime-extend the temporary. + if (Path.empty()) { + // Update the storage duration of the materialized temporary. + // FIXME: Rebuild the expression instead of mutating it. + MTE->setExtendingDecl(ExtendingEntity->getDecl(), + ExtendingEntity->allocateManglingNumber()); + // Also visit the temporaries lifetime-extended by this initializer. + return true; + } + + if (shouldLifetimeExtendThroughPath(Path)) { + // We're supposed to lifetime-extend the temporary along this path (per + // the resolution of DR1815), but we don't support that yet. + // + // FIXME: Properly handle this situation. Perhaps the easiest approach + // would be to clone the initializer expression on each use that would + // lifetime extend its temporaries. + Diag(DiagLoc, diag::warn_unsupported_lifetime_extension) + << RK << DiagRange; + } else { + // If the path goes through the initialization of a variable or field, + // it can't possibly reach a temporary created in this full-expression. + // We will have already diagnosed any problems with the initializer. + if (pathContainsInit(Path)) + return false; + + Diag(DiagLoc, diag::warn_dangling_variable) + << RK << !Entity.getParent() << ExtendingEntity->getDecl() + << Init->isGLValue() << DiagRange; + } + break; + } + + case LK_MemInitializer: { + if (isa<MaterializeTemporaryExpr>(L)) { + // Under C++ DR1696, if a mem-initializer (or a default member + // initializer used by the absence of one) would lifetime-extend a + // temporary, the program is ill-formed. + if (auto *ExtendingDecl = + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { + bool IsSubobjectMember = ExtendingEntity != &Entity; + Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) + ? diag::err_dangling_member + : diag::warn_dangling_member) + << ExtendingDecl << IsSubobjectMember << RK << DiagRange; + // Don't bother adding a note pointing to the field if we're inside + // its default member initializer; our primary diagnostic points to + // the same place in that case. + if (Path.empty() || + Path.back().Kind != IndirectLocalPathEntry::DefaultInit) { + Diag(ExtendingDecl->getLocation(), + diag::note_lifetime_extending_member_declared_here) + << RK << IsSubobjectMember; + } + } else { + // We have a mem-initializer but no particular field within it; this + // is either a base class or a delegating initializer directly + // initializing the base-class from something that doesn't live long + // enough. + // + // FIXME: Warn on this. + return false; + } + } else { + // Paths via a default initializer can only occur during error recovery + // (there's no other way that a default initializer can refer to a + // local). Don't produce a bogus warning on those cases. + if (pathContainsInit(Path)) + return false; + + auto *DRE = dyn_cast<DeclRefExpr>(L); + auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr; + if (!VD) { + // A member was initialized to a local block. + // FIXME: Warn on this. + return false; + } + + if (auto *Member = + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { + bool IsPointer = Member->getType()->isAnyPointerType(); + Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr + : diag::warn_bind_ref_member_to_parameter) + << Member << VD << isa<ParmVarDecl>(VD) << DiagRange; + Diag(Member->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << (unsigned)IsPointer; + } + } + break; + } + + case LK_New: + if (isa<MaterializeTemporaryExpr>(L)) { + Diag(DiagLoc, RK == RK_ReferenceBinding + ? diag::warn_new_dangling_reference + : diag::warn_new_dangling_initializer_list) + << !Entity.getParent() << DiagRange; + } else { + // We can't determine if the allocation outlives the local declaration. + return false; + } + break; + + case LK_Return: + case LK_StmtExprResult: + if (auto *DRE = dyn_cast<DeclRefExpr>(L)) { + // We can't determine if the local variable outlives the statement + // expression. + if (LK == LK_StmtExprResult) + return false; + Diag(DiagLoc, diag::warn_ret_stack_addr_ref) + << Entity.getType()->isReferenceType() << DRE->getDecl() + << isa<ParmVarDecl>(DRE->getDecl()) << DiagRange; + } else if (isa<BlockExpr>(L)) { + Diag(DiagLoc, diag::err_ret_local_block) << DiagRange; + } else if (isa<AddrLabelExpr>(L)) { + Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange; + } else { + Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) + << Entity.getType()->isReferenceType() << DiagRange; + } + break; + } + + for (unsigned I = 0; I != Path.size(); ++I) { + auto Elem = Path[I]; + + switch (Elem.Kind) { + case IndirectLocalPathEntry::AddressOf: + case IndirectLocalPathEntry::LValToRVal: + // These exist primarily to mark the path as not permitting or + // supporting lifetime extension. + break; + + case IndirectLocalPathEntry::DefaultInit: { + auto *FD = cast<FieldDecl>(Elem.D); + Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer) + << FD << nextPathEntryRange(Path, I + 1, L); + break; + } + + case IndirectLocalPathEntry::VarInit: + const VarDecl *VD = cast<VarDecl>(Elem.D); + Diag(VD->getLocation(), diag::note_local_var_initializer) + << VD->getType()->isReferenceType() << VD->getDeclName() + << nextPathEntryRange(Path, I + 1, L); break; } } - S.Diag(Init->getExprLoc(), - diag::warn_bind_ref_member_to_temporary) - << ExtendingDecl << Init->getSourceRange() - << IsSubobjectMember << IsInitializerList; - if (IsSubobjectMember) - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_subobject_of_member_declared_here); - else - S.Diag(ExtendingDecl->getLocation(), - diag::note_ref_or_ptr_member_declared_here) - << /*is pointer*/false; - } + + // We didn't lifetime-extend, so don't go any further; we don't need more + // warnings or errors on inner temporaries within this one's initializer. + return false; + }; + + llvm::SmallVector<IndirectLocalPathEntry, 8> Path; + if (Init->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding, + TemporaryVisitor); + else + visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false); } static void DiagnoseNarrowingInInitList(Sema &S, @@ -6427,13 +6938,7 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr, // Find the std::move call and get the argument. const CallExpr *CE = dyn_cast<CallExpr>(InitExpr->IgnoreParens()); - if (!CE || CE->getNumArgs() != 1) - return; - - const FunctionDecl *MoveFunction = CE->getDirectCallee(); - if (!MoveFunction || !MoveFunction->isInStdNamespace() || - !MoveFunction->getIdentifier() || - !MoveFunction->getIdentifier()->isStr("move")) + if (!CE || !CE->isCallToStdMove()) return; const Expr *Arg = CE->getArg(0)->IgnoreImplicit(); @@ -6490,7 +6995,7 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr, // macro only if it is at the beginning of the macro. while (ArgLoc.isMacroID() && S.getSourceManager().isAtStartOfImmediateMacroExpansion(ArgLoc)) { - ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).first; + ArgLoc = S.getSourceManager().getImmediateExpansionRange(ArgLoc).getBegin(); } if (LParen.isMacroID()) @@ -6619,7 +7124,7 @@ InitializationSequence::Perform(Sema &S, if (Kind.getKind() == InitializationKind::IK_Direct && !Kind.isExplicitCast()) { // Rebuild the ParenListExpr. - SourceRange ParenRange = Kind.getParenRange(); + SourceRange ParenRange = Kind.getParenOrBraceRange(); return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(), Args); } @@ -6658,20 +7163,6 @@ InitializationSequence::Perform(Sema &S, return ExprError(); } - // Diagnose cases where we initialize a pointer to an array temporary, and the - // pointer obviously outlives the temporary. - if (Args.size() == 1 && Args[0]->getType()->isArrayType() && - Entity.getType()->isPointerType() && - InitializedEntityOutlivesFullExpression(Entity)) { - const Expr *Init = Args[0]->skipRValueSubobjectAdjustments(); - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) - Init = MTE->GetTemporaryExpr(); - Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context); - if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary) - S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay) - << Init->getSourceRange(); - } - QualType DestType = Entity.getType().getNonReferenceType(); // FIXME: Ugly hack around the fact that Entity.getType() is not // the same as Entity.getDecl()->getType() in cases involving type merging, @@ -6822,16 +7313,6 @@ InitializationSequence::Perform(Sema &S, } } - // Even though we didn't materialize a temporary, the binding may still - // extend the lifetime of a temporary. This happens if we bind a reference - // to the result of a cast to reference type. - if (const InitializedEntity *ExtendingEntity = - getEntityForTemporaryLifetimeExtension(&Entity)) - if (performReferenceExtension(CurInit.get(), ExtendingEntity)) - warnOnLifetimeExtension(S, Entity, CurInit.get(), - /*IsInitializerList=*/false, - ExtendingEntity->getDecl()); - CheckForNullPointerDereference(S, CurInit.get()); break; @@ -6846,23 +7327,13 @@ InitializationSequence::Perform(Sema &S, // Materialize the temporary into memory. MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr( Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType()); - - // Maybe lifetime-extend the temporary's subobjects to match the - // entity's lifetime. - if (const InitializedEntity *ExtendingEntity = - getEntityForTemporaryLifetimeExtension(&Entity)) - if (performReferenceExtension(MTE, ExtendingEntity)) - warnOnLifetimeExtension(S, Entity, CurInit.get(), - /*IsInitializerList=*/false, - ExtendingEntity->getDecl()); + CurInit = MTE; // If we're extending this temporary to automatic storage duration -- we // need to register its cleanup during the full-expression's cleanups. if (MTE->getStorageDuration() == SD_Automatic && MTE->getType().isDestructedType()) S.Cleanup.setExprNeedsCleanups(true); - - CurInit = MTE; break; } @@ -6935,16 +7406,6 @@ InitializationSequence::Perform(Sema &S, if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) return ExprError(); - // FIXME: Should we move this initialization into a separate - // derived-to-base conversion? I believe the answer is "no", because - // we don't want to turn off access control here for c-style casts. - CurInit = S.PerformObjectArgumentInitialization(CurInit.get(), - /*Qualifier=*/nullptr, - FoundFn, Conversion); - if (CurInit.isInvalid()) - return ExprError(); - - // Build the actual call to the conversion function. CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion, HadMultipleCandidates); if (CurInit.isInvalid()) @@ -7139,14 +7600,17 @@ InitializationSequence::Perform(Sema &S, bool IsStdInitListInit = Step->Kind == SK_StdInitializerListConstructorCall; Expr *Source = CurInit.get(); + SourceRange Range = Kind.hasParenOrBraceRange() + ? Kind.getParenOrBraceRange() + : SourceRange(); CurInit = PerformConstructorInitialization( S, UseTemporary ? TempEntity : Entity, Kind, Source ? MultiExprArg(Source) : Args, *Step, ConstructorInitRequiresZeroInit, /*IsListInitialization*/ IsStdInitListInit, /*IsStdInitListInitialization*/ IsStdInitListInit, - /*LBraceLoc*/ SourceLocation(), - /*RBraceLoc*/ SourceLocation()); + /*LBraceLoc*/ Range.getBegin(), + /*RBraceLoc*/ Range.getEnd()); break; } @@ -7302,15 +7766,6 @@ InitializationSequence::Perform(Sema &S, CurInit.get()->getType(), CurInit.get(), /*BoundToLvalueReference=*/false); - // Maybe lifetime-extend the array temporary's subobjects to match the - // entity's lifetime. - if (const InitializedEntity *ExtendingEntity = - getEntityForTemporaryLifetimeExtension(&Entity)) - if (performReferenceExtension(MTE, ExtendingEntity)) - warnOnLifetimeExtension(S, Entity, CurInit.get(), - /*IsInitializerList=*/true, - ExtendingEntity->getDecl()); - // Wrap it in a construction of a std::initializer_list<T>. CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE); @@ -7432,6 +7887,11 @@ InitializationSequence::Perform(Sema &S, } } + // Check whether the initializer has a shorter lifetime than the initialized + // entity, and if not, either lifetime-extend or warn as appropriate. + if (auto *Init = CurInit.get()) + S.checkInitializerLifetime(Entity, Init); + // Diagnose non-fatal problems with the completed initialization. if (Entity.getKind() == InitializedEntity::EK_Member && cast<FieldDecl>(Entity.getDecl())->isBitField()) @@ -7549,6 +8009,19 @@ bool InitializationSequence::Diagnose(Sema &S, if (!Failed()) return false; + // When we want to diagnose only one element of a braced-init-list, + // we need to factor it out. + Expr *OnlyArg; + if (Args.size() == 1) { + auto *List = dyn_cast<InitListExpr>(Args[0]); + if (List && List->getNumInits() == 1) + OnlyArg = List->getInit(0); + else + OnlyArg = Args[0]; + } + else + OnlyArg = nullptr; + QualType DestType = Entity.getType(); switch (Failure) { case FK_TooManyInitsForReference: @@ -7591,6 +8064,17 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_array_init_incompat_wide_string_into_wchar); break; + case FK_PlainStringIntoUTF8Char: + S.Diag(Kind.getLocation(), + diag::err_array_init_plain_string_into_char8_t); + S.Diag(Args.front()->getLocStart(), + diag::note_array_init_plain_string_into_char8_t) + << FixItHint::CreateInsertion(Args.front()->getLocStart(), "u8"); + break; + case FK_UTF8StringIntoPlainChar: + S.Diag(Kind.getLocation(), + diag::err_array_init_utf8_string_into_char); + break; case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: S.Diag(Kind.getLocation(), @@ -7598,7 +8082,7 @@ bool InitializationSequence::Diagnose(Sema &S, ? diag::err_array_init_different_type : diag::err_array_init_non_constant_array)) << DestType.getNonReferenceType() - << Args[0]->getType() + << OnlyArg->getType() << Args[0]->getSourceRange(); break; @@ -7609,7 +8093,7 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_AddressOfOverloadFailed: { DeclAccessPair Found; - S.ResolveAddressOfOverloadedFunction(Args[0], + S.ResolveAddressOfOverloadedFunction(OnlyArg, DestType.getNonReferenceType(), true, Found); @@ -7617,9 +8101,9 @@ bool InitializationSequence::Diagnose(Sema &S, } case FK_AddressOfUnaddressableFunction: { - auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(Args[0])->getDecl()); + auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(OnlyArg)->getDecl()); S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, - Args[0]->getLocStart()); + OnlyArg->getLocStart()); break; } @@ -7629,11 +8113,11 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: if (Failure == FK_UserConversionOverloadFailed) S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) - << Args[0]->getType() << DestType + << OnlyArg->getType() << DestType << Args[0]->getSourceRange(); else S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous) - << DestType << Args[0]->getType() + << DestType << OnlyArg->getType() << Args[0]->getSourceRange(); FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); @@ -7643,10 +8127,10 @@ bool InitializationSequence::Diagnose(Sema &S, if (!S.RequireCompleteType(Kind.getLocation(), DestType.getNonReferenceType(), diag::err_typecheck_nonviable_condition_incomplete, - Args[0]->getType(), Args[0]->getSourceRange())) + OnlyArg->getType(), Args[0]->getSourceRange())) S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << (Entity.getKind() == InitializedEntity::EK_Result) - << Args[0]->getType() << Args[0]->getSourceRange() + << OnlyArg->getType() << Args[0]->getSourceRange() << DestType.getNonReferenceType(); FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); @@ -7654,7 +8138,7 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) - << Args[0]->getType() << DestType.getNonReferenceType() + << OnlyArg->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; OverloadingResult Ovl @@ -7690,7 +8174,7 @@ bool InitializationSequence::Diagnose(Sema &S, : diag::err_lvalue_reference_bind_to_unrelated) << DestType.getNonReferenceType().isVolatileQualified() << DestType.getNonReferenceType() - << Args[0]->getType() + << OnlyArg->getType() << Args[0]->getSourceRange(); break; @@ -7715,12 +8199,12 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) - << DestType.getNonReferenceType() << Args[0]->getType() + << DestType.getNonReferenceType() << OnlyArg->getType() << Args[0]->getSourceRange(); break; case FK_ReferenceInitDropsQualifiers: { - QualType SourceType = Args[0]->getType(); + QualType SourceType = OnlyArg->getType(); QualType NonRefType = DestType.getNonReferenceType(); Qualifiers DroppedQualifiers = SourceType.getQualifiers() - NonRefType.getQualifiers(); @@ -7736,18 +8220,18 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ReferenceInitFailed: S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) << DestType.getNonReferenceType() - << Args[0]->isLValue() - << Args[0]->getType() + << OnlyArg->isLValue() + << OnlyArg->getType() << Args[0]->getSourceRange(); emitBadConversionNotes(S, Entity, Args[0]); break; case FK_ConversionFailed: { - QualType FromType = Args[0]->getType(); + QualType FromType = OnlyArg->getType(); PartialDiagnostic PDiag = S.PDiag(diag::err_init_conversion_failed) << (int)Entity.getKind() << DestType - << Args[0]->isLValue() + << OnlyArg->isLValue() << FromType << Args[0]->getSourceRange(); S.HandleFunctionTypeMismatch(PDiag, FromType, DestType); @@ -8000,6 +8484,14 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "incompatible wide string into wide char array"; break; + case FK_PlainStringIntoUTF8Char: + OS << "plain string literal into char8_t array"; + break; + + case FK_UTF8StringIntoPlainChar: + OS << "u8 string literal into char array"; + break; + case FK_ArrayTypeMismatch: OS << "array type mismatch"; break; @@ -8290,6 +8782,11 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } +static bool NarrowingErrs(const LangOptions &L) { + return L.CPlusPlus11 && + (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015)); +} + static void DiagnoseNarrowingInInitList(Sema &S, const ImplicitConversionSequence &ICS, QualType PreNarrowingType, @@ -8323,35 +8820,34 @@ static void DiagnoseNarrowingInInitList(Sema &S, // This was a floating-to-integer conversion, which is always considered a // narrowing conversion even if the value is a constant and can be // represented exactly as an integer. - S.Diag(PostInit->getLocStart(), - (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) - ? diag::warn_init_list_type_narrowing - : diag::ext_init_list_type_narrowing) - << PostInit->getSourceRange() - << PreNarrowingType.getLocalUnqualifiedType() - << EntityType.getLocalUnqualifiedType(); + S.Diag(PostInit->getLocStart(), NarrowingErrs(S.getLangOpts()) + ? diag::ext_init_list_type_narrowing + : diag::warn_init_list_type_narrowing) + << PostInit->getSourceRange() + << PreNarrowingType.getLocalUnqualifiedType() + << EntityType.getLocalUnqualifiedType(); break; case NK_Constant_Narrowing: // A constant value was narrowed. S.Diag(PostInit->getLocStart(), - (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) - ? diag::warn_init_list_constant_narrowing - : diag::ext_init_list_constant_narrowing) - << PostInit->getSourceRange() - << ConstantValue.getAsString(S.getASTContext(), ConstantType) - << EntityType.getLocalUnqualifiedType(); + NarrowingErrs(S.getLangOpts()) + ? diag::ext_init_list_constant_narrowing + : diag::warn_init_list_constant_narrowing) + << PostInit->getSourceRange() + << ConstantValue.getAsString(S.getASTContext(), ConstantType) + << EntityType.getLocalUnqualifiedType(); break; case NK_Variable_Narrowing: // A variable's value may have been narrowed. S.Diag(PostInit->getLocStart(), - (S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11) - ? diag::warn_init_list_variable_narrowing - : diag::ext_init_list_variable_narrowing) - << PostInit->getSourceRange() - << PreNarrowingType.getLocalUnqualifiedType() - << EntityType.getLocalUnqualifiedType(); + NarrowingErrs(S.getLangOpts()) + ? diag::ext_init_list_variable_narrowing + : diag::warn_init_list_variable_narrowing) + << PostInit->getSourceRange() + << PreNarrowingType.getLocalUnqualifiedType() + << EntityType.getLocalUnqualifiedType(); break; } @@ -8624,6 +9120,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Expr *E = ListInit->getInit(0); auto *RD = E->getType()->getAsCXXRecordDecl(); if (!isa<InitListExpr>(E) && RD && + isCompleteType(Kind.getLocation(), E->getType()) && isOrIsDerivedFromSpecializationOf(RD, Template)) TryListConstructors = false; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp index 19d2de719728..a42b2e827e9b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp @@ -24,7 +24,7 @@ using namespace clang; using namespace sema; -/// \brief Examines the FunctionScopeInfo stack to determine the nearest +/// Examines the FunctionScopeInfo stack to determine the nearest /// enclosing lambda (to the current lambda) that is 'capture-ready' for /// the variable referenced in the current lambda (i.e. \p VarToCapture). /// If successful, returns the index into Sema's FunctionScopeInfo stack @@ -135,7 +135,7 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda( return NoLambdaIsCaptureReady; } -/// \brief Examines the FunctionScopeInfo stack to determine the nearest +/// Examines the FunctionScopeInfo stack to determine the nearest /// enclosing lambda (to the current lambda) that is 'capture-capable' for /// the variable referenced in the current lambda (i.e. \p VarToCapture). /// If successful, returns the index into Sema's FunctionScopeInfo stack @@ -263,7 +263,7 @@ CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, return Class; } -/// \brief Determine whether the given context is or is enclosed in an inline +/// Determine whether the given context is or is enclosed in an inline /// function. static bool isInInlineFunction(const DeclContext *DC) { while (!DC->isFileContext()) { @@ -692,9 +692,7 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { } // Third case: only one return statement. Don't bother doing extra work! - SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(), - E = CSI.Returns.end(); - if (I+1 == E) + if (CSI.Returns.size() == 1) return; // General case: many return statements. @@ -703,15 +701,22 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { // We require the return types to strictly match here. // Note that we've already done the required promotions as part of // processing the return statement. - for (; I != E; ++I) { - const ReturnStmt *RS = *I; + for (const ReturnStmt *RS : CSI.Returns) { const Expr *RetE = RS->getRetValue(); QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy).getUnqualifiedType(); if (Context.getCanonicalFunctionResultType(ReturnType) == - Context.getCanonicalFunctionResultType(CSI.ReturnType)) + Context.getCanonicalFunctionResultType(CSI.ReturnType)) { + // Use the return type with the strictest possible nullability annotation. + auto RetTyNullability = ReturnType->getNullability(Ctx); + auto BlockNullability = CSI.ReturnType->getNullability(Ctx); + if (BlockNullability && + (!RetTyNullability || + hasWeakerNullability(*RetTyNullability, *BlockNullability))) + CSI.ReturnType = ReturnType; continue; + } // FIXME: This is a poor diagnostic for ReturnStmts without expressions. // TODO: It's possible that the *first* return is the divergent one. @@ -904,6 +909,14 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, ParamInfo.getDeclSpec().isConstexprSpecified()); if (ExplicitParams) CheckCXXDefaultArguments(Method); + + // This represents the function body for the lambda function, check if we + // have to apply optnone due to a pragma. + AddRangeBasedOptnone(Method); + + // code_seg attribute on lambda apply to the method. + if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true)) + Method->addAttr(A); // Attributes on the lambda apply to the method. ProcessDeclAttributes(CurScope, Method, ParamInfo); @@ -984,6 +997,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true, /*FunctionScopeIndexToStopAtPtr*/ nullptr, C->Kind == LCK_StarThis); + if (!LSI->Captures.empty()) + LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange; continue; } @@ -1130,6 +1145,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, TryCapture_ExplicitByVal; tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc); } + if (!LSI->Captures.empty()) + LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange; } finishLambdaExplicitCaptures(LSI); @@ -1161,7 +1178,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, Class->setInvalidDecl(); SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), - SourceLocation(), nullptr); + SourceLocation(), ParsedAttributesView()); CheckCompletedCXXClass(Class); PopFunctionScopeInfo(); @@ -1185,7 +1202,7 @@ QualType Sema::getLambdaConversionFunctionResultType( CallOpProto->getParamTypes(), InvokerExtInfo); } -/// \brief Add a lambda's conversion to function pointer, as described in +/// Add a lambda's conversion to function pointer, as described in /// C++11 [expr.prim.lambda]p6. static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, @@ -1354,7 +1371,7 @@ static void addFunctionPointerConversion(Sema &S, Class->addDecl(Invoke); } -/// \brief Add a lambda's conversion to block pointer. +/// Add a lambda's conversion to block pointer. static void addBlockPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, @@ -1388,8 +1405,9 @@ static void addBlockPointerConversion(Sema &S, Class->addDecl(Conversion); } -static ExprResult performLambdaVarCaptureInitialization( - Sema &S, const LambdaScopeInfo::Capture &Capture, FieldDecl *Field) { +static ExprResult performLambdaVarCaptureInitialization(Sema &S, + const Capture &Capture, + FieldDecl *Field) { assert(Capture.isVariableCapture() && "not a variable capture"); auto *Var = Capture.getVariable(); @@ -1443,7 +1461,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) { llvm_unreachable("Unknown implicit capture style"); } -bool Sema::CaptureHasSideEffects(const LambdaScopeInfo::Capture &From) { +bool Sema::CaptureHasSideEffects(const Capture &From) { if (!From.isVLATypeCapture()) { Expr *Init = From.getInitExpr(); if (Init && Init->HasSideEffects(Context)) @@ -1468,12 +1486,13 @@ bool Sema::CaptureHasSideEffects(const LambdaScopeInfo::Capture &From) { return false; } -void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) { +bool Sema::DiagnoseUnusedLambdaCapture(SourceRange CaptureRange, + const Capture &From) { if (CaptureHasSideEffects(From)) - return; + return false; if (From.isVLATypeCapture()) - return; + return false; auto diag = Diag(From.getLocation(), diag::warn_unused_lambda_capture); if (From.isThisCapture()) @@ -1481,6 +1500,8 @@ void Sema::DiagnoseUnusedLambdaCapture(const LambdaScopeInfo::Capture &From) { else diag << From.getVariable(); diag << From.isNonODRUsed(); + diag << FixItHint::CreateRemoval(CaptureRange); + return true; } ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, @@ -1522,22 +1543,64 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // Translate captures. auto CurField = Class->field_begin(); + // True if the current capture has a used capture or default before it. + bool CurHasPreviousCapture = CaptureDefault != LCD_None; + SourceLocation PrevCaptureLoc = CurHasPreviousCapture ? + CaptureDefaultLoc : IntroducerRange.getBegin(); + for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) { - const LambdaScopeInfo::Capture &From = LSI->Captures[I]; + const Capture &From = LSI->Captures[I]; + assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; + // Use source ranges of explicit captures for fixits where available. + SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I]; + // Warn about unused explicit captures. + bool IsCaptureUsed = true; if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) { // Initialized captures that are non-ODR used may not be eliminated. bool NonODRUsedInitCapture = IsGenericLambda && From.isNonODRUsed() && From.getInitExpr(); - if (!NonODRUsedInitCapture) - DiagnoseUnusedLambdaCapture(From); + if (!NonODRUsedInitCapture) { + bool IsLast = (I + 1) == LSI->NumExplicitCaptures; + SourceRange FixItRange; + if (CaptureRange.isValid()) { + if (!CurHasPreviousCapture && !IsLast) { + // If there are no captures preceding this capture, remove the + // following comma. + FixItRange = SourceRange(CaptureRange.getBegin(), + getLocForEndOfToken(CaptureRange.getEnd())); + } else { + // Otherwise, remove the comma since the last used capture. + FixItRange = SourceRange(getLocForEndOfToken(PrevCaptureLoc), + CaptureRange.getEnd()); + } + } + + IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From); + } + } + + if (CaptureRange.isValid()) { + CurHasPreviousCapture |= IsCaptureUsed; + PrevCaptureLoc = CaptureRange.getEnd(); } // Handle 'this' capture. if (From.isThisCapture()) { + // Capturing 'this' implicitly with a default of '[=]' is deprecated, + // because it results in a reference capture. Don't warn prior to + // C++2a; there's nothing that can be done about it before then. + if (getLangOpts().CPlusPlus2a && IsImplicit && + CaptureDefault == LCD_ByCopy) { + Diag(From.getLocation(), diag::warn_deprecated_this_capture); + Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture) + << FixItHint::CreateInsertion( + getLocForEndOfToken(CaptureDefaultLoc), ", this"); + } + Captures.push_back( LambdaCapture(From.getLocation(), IsImplicit, From.isCopyCapture() ? LCK_StarThis : LCK_This)); @@ -1587,7 +1650,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // Finalize the lambda class. SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), - SourceLocation(), nullptr); + SourceLocation(), ParsedAttributesView()); CheckCompletedCXXClass(Class); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index a9db973851df..2732112c00b6 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -187,7 +187,7 @@ namespace { } void done() { - std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); + llvm::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); } typedef ListTy::const_iterator const_iterator; @@ -356,7 +356,7 @@ static DeclContext *getContextForScopeMatching(Decl *D) { return D->getDeclContext()->getRedeclContext(); } -/// \brief Determine whether \p D is a better lookup result than \p Existing, +/// Determine whether \p D is a better lookup result than \p Existing, /// given that they declare the same entity. static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, NamedDecl *D, NamedDecl *Existing) { @@ -669,7 +669,7 @@ LLVM_DUMP_METHOD void LookupResult::dump() { D->dump(); } -/// \brief Lookup a builtin function, when name lookup would otherwise +/// Lookup a builtin function, when name lookup would otherwise /// fail. static bool LookupBuiltin(Sema &S, LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); @@ -713,7 +713,7 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { return false; } -/// \brief Determine whether we can declare a special member function within +/// Determine whether we can declare a special member function within /// the class at this point. static bool CanDeclareSpecialMemberFunction(const CXXRecordDecl *Class) { // We need to have a definition for the class. @@ -755,7 +755,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { DeclareImplicitDestructor(Class); } -/// \brief Determine whether this is the name of an implicitly-declared +/// Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { @@ -773,7 +773,7 @@ static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { return false; } -/// \brief If there are any implicit member functions with the given name +/// If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, @@ -1354,7 +1354,7 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND) { makeMergedDefinitionVisible(Param); } -/// \brief Find the module in which the given declaration was defined. +/// Find the module in which the given declaration was defined. static Module *getDefiningModule(Sema &S, Decl *Entity) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Entity)) { // If this function was instantiated from a template, the defining module is @@ -1452,6 +1452,8 @@ template<typename Filter> static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules, Filter F) { + bool HasFilteredRedecls = false; + for (auto *Redecl : D->redecls()) { auto *R = cast<NamedDecl>(Redecl); if (!F(R)) @@ -1460,6 +1462,8 @@ static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D, if (S.isVisible(R)) return true; + HasFilteredRedecls = true; + if (Modules) { Modules->push_back(R->getOwningModule()); const auto &Merged = S.Context.getModulesWithMergedDefinition(R); @@ -1467,7 +1471,11 @@ static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D, } } - return false; + // Only return false if there is at least one redecl that is not filtered out. + if (HasFilteredRedecls) + return false; + + return true; } bool Sema::hasVisibleExplicitSpecialization( @@ -1497,11 +1505,9 @@ bool Sema::hasVisibleMemberSpecialization( // class definition? return D->getLexicalDeclContext()->isFileContext(); }); - - return false; } -/// \brief Determine whether a declaration is visible to name lookup. +/// Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current /// lookup context, taking into account the current template instantiation @@ -1648,7 +1654,7 @@ bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { return New->isExternallyDeclarable(); } -/// \brief Retrieve the visible declaration corresponding to D, if any. +/// Retrieve the visible declaration corresponding to D, if any. /// /// This routine determines whether the declaration D is visible in the current /// module, with the current imports. If not, it checks whether any @@ -1656,7 +1662,8 @@ bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) { /// /// \returns D, or a visible previous declaration of D, whichever is more recent /// and visible. If no declaration of D is visible, returns null. -static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { +static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D, + unsigned IDNS) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); for (auto RD : D->redecls()) { @@ -1668,7 +1675,8 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { // FIXME: This is wrong in the case where the previous declaration is not // visible in the same scope as D. This needs to be done much more // carefully. - if (LookupResult::isVisible(SemaRef, ND)) + if (ND->isInIdentifierNamespace(IDNS) && + LookupResult::isVisible(SemaRef, ND)) return ND; } @@ -1693,17 +1701,18 @@ NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { auto *Key = ND->getCanonicalDecl(); if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key)) return Acceptable; - auto *Acceptable = - isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key); + auto *Acceptable = isVisible(getSema(), Key) + ? Key + : findAcceptableDecl(getSema(), Key, IDNS); if (Acceptable) getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable)); return Acceptable; } - return findAcceptableDecl(getSema(), D); + return findAcceptableDecl(getSema(), D, IDNS); } -/// @brief Perform unqualified name lookup starting from a given +/// Perform unqualified name lookup starting from a given /// scope. /// /// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is @@ -1841,7 +1850,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { return (ExternalSource && ExternalSource->LookupUnqualified(R, S)); } -/// @brief Perform qualified name lookup in the namespaces nominated by +/// Perform qualified name lookup in the namespaces nominated by /// using directives by the given context. /// /// C++98 [namespace.qual]p2: @@ -1947,7 +1956,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, return Found; } -/// \brief Callback that looks for any member of a class with the given name. +/// Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); @@ -1956,7 +1965,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, return !Path.Decls.empty(); } -/// \brief Determine whether the given set of member declarations contains only +/// Determine whether the given set of member declarations contains only /// static members, nested types, and enumerators. template<typename InputIterator> static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { @@ -1988,7 +1997,7 @@ static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { return false; } -/// \brief Perform qualified name lookup into a given context. +/// Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find /// names when the context of those names is explicit specified, e.g., @@ -2212,7 +2221,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, return true; } -/// \brief Performs qualified name lookup or special type of lookup for +/// 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 @@ -2237,7 +2246,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, return LookupQualifiedName(R, LookupCtx); } -/// @brief Performs name lookup for a name that was parsed in the +/// Performs name lookup for a name that was parsed in the /// source code, and may contain a C++ scope specifier. /// /// This routine is a convenience routine meant to be called from @@ -2291,7 +2300,7 @@ 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 +/// Perform qualified name lookup into all base classes of the given /// class. /// /// \param R captures both the lookup criteria and any lookup results found. @@ -2309,7 +2318,7 @@ bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { CXXRecordDecl *RD = cast<CXXRecordDecl>( BaseSpec.getType()->castAs<RecordType>()->getDecl()); LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); - Result.setBaseObjectType(Context.getRecordType(Class)); + Result.setBaseObjectType(Context.getRecordType(Class)); LookupQualifiedName(Result, RD); // Copy the lookup results into the target, merging the base's access into @@ -2329,7 +2338,7 @@ bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { return !R.empty(); } -/// \brief Produce a diagnostic describing the ambiguity that resulted +/// Produce a diagnostic describing the ambiguity that resulted /// from name lookup. /// /// \param Result The result of the ambiguous lookup to be diagnosed. @@ -2445,7 +2454,7 @@ static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, Namespaces.insert(Ctx->getPrimaryContext()); } -// \brief Add the associated classes and namespaces for argument-dependent +// Add the associated classes and namespaces for argument-dependent // lookup that involves a template argument (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, @@ -2495,7 +2504,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } } -// \brief Add the associated classes and namespaces for +// Add the associated classes and namespaces for // argument-dependent lookup with an argument of class type // (C++ [basic.lookup.koenig]p2). static void @@ -2590,7 +2599,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } } -// \brief Add the associated classes and namespaces for +// Add the associated classes and namespaces for // argument-dependent lookup with an argument of type T // (C++ [basic.lookup.koenig]p2). static void @@ -2754,7 +2763,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { } } -/// \brief Find the associated classes and namespaces for +/// Find the associated classes and namespaces for /// argument-dependent lookup for a call with the given set of /// arguments. /// @@ -2821,7 +2830,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, return R.getAsSingle<NamedDecl>(); } -/// \brief Find the protocol with the given name, if any. +/// Find the protocol with the given name, if any. ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl) { @@ -3048,7 +3057,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, return *Result; } -/// \brief Look up the default constructor for the given class. +/// Look up the default constructor for the given class. CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { SpecialMemberOverloadResult Result = LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, @@ -3057,7 +3066,7 @@ CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { return cast_or_null<CXXConstructorDecl>(Result.getMethod()); } -/// \brief Look up the copying constructor for the given class. +/// Look up the copying constructor for the given class. CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && @@ -3069,7 +3078,7 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, return cast_or_null<CXXConstructorDecl>(Result.getMethod()); } -/// \brief Look up the moving constructor for the given class. +/// Look up the moving constructor for the given class. CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals) { SpecialMemberOverloadResult Result = @@ -3079,7 +3088,7 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, return cast_or_null<CXXConstructorDecl>(Result.getMethod()); } -/// \brief Look up the constructors for the given class. +/// Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Class)) { @@ -3096,7 +3105,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { return Class->lookup(Name); } -/// \brief Look up the copying assignment operator for the given class. +/// Look up the copying assignment operator for the given class. CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals) { @@ -3113,7 +3122,7 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, return Result.getMethod(); } -/// \brief Look up the moving assignment operator for the given class. +/// Look up the moving assignment operator for the given class. CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, @@ -3129,7 +3138,7 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, return Result.getMethod(); } -/// \brief Look for the destructor of the given class. +/// Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). @@ -3329,6 +3338,23 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, // lookup (11.4). DeclContext::lookup_result R = NS->lookup(Name); for (auto *D : R) { + auto *Underlying = D; + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) + Underlying = USD->getTargetDecl(); + + if (!isa<FunctionDecl>(Underlying) && + !isa<FunctionTemplateDecl>(Underlying)) + continue; + + if (!isVisible(D)) { + D = findAcceptableDecl( + *this, D, (Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend)); + if (!D) + continue; + if (auto *USD = dyn_cast<UsingShadowDecl>(D)) + Underlying = USD->getTargetDecl(); + } + // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) { @@ -3350,22 +3376,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, continue; } - auto *Underlying = D; - if (auto *USD = dyn_cast<UsingShadowDecl>(D)) - Underlying = USD->getTargetDecl(); - - if (!isa<FunctionDecl>(Underlying) && - !isa<FunctionTemplateDecl>(Underlying)) - continue; - - if (!isVisible(D)) { - D = findAcceptableDecl(*this, D); - if (!D) - continue; - if (auto *USD = dyn_cast<UsingShadowDecl>(D)) - Underlying = USD->getTargetDecl(); - } - // FIXME: Preserve D as the FoundDecl. Result.insert(Underlying); } @@ -3385,26 +3395,26 @@ class ShadowContextRAII; class VisibleDeclsRecord { public: - /// \brief An entry in the shadow map, which is optimized to store a + /// An entry in the shadow map, which is optimized to store a /// single declaration (the common case) but can also store a list /// of declarations. typedef llvm::TinyPtrVector<NamedDecl*> ShadowMapEntry; private: - /// \brief A mapping from declaration names to the declarations that have + /// A mapping from declaration names to the declarations that have /// this name within a particular scope. typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap; - /// \brief A list of shadow maps, which is used to model name hiding. + /// A list of shadow maps, which is used to model name hiding. std::list<ShadowMap> ShadowMaps; - /// \brief The declaration contexts we have already visited. + /// The declaration contexts we have already visited. llvm::SmallPtrSet<DeclContext *, 8> VisitedContexts; friend class ShadowContextRAII; public: - /// \brief Determine whether we have already visited this context + /// 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).second; @@ -3414,20 +3424,20 @@ public: return VisitedContexts.count(Ctx); } - /// \brief Determine whether the given declaration is hidden in the + /// Determine whether the given declaration is hidden in the /// current scope. /// /// \returns the declaration that hides the given declaration, or /// NULL if no such declaration exists. NamedDecl *checkHidden(NamedDecl *ND); - /// \brief Add a declaration to the current shadow map. + /// Add a declaration to the current shadow map. void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].push_back(ND); } }; -/// \brief RAII object that records when we've entered a shadow context. +/// RAII object that records when we've entered a shadow context. class ShadowContextRAII { VisibleDeclsRecord &Visible; @@ -3494,7 +3504,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited, - bool IncludeDependentBases = false) { + bool IncludeDependentBases, + bool LoadExternal) { if (!Ctx) return; @@ -3502,6 +3513,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (Visited.visitedContext(Ctx->getPrimaryContext())) return; + Consumer.EnteredContext(Ctx); + // Outside C++, lookup results for the TU live on identifiers. if (isa<TranslationUnitDecl>(Ctx) && !Result.getSema().getLangOpts().CPlusPlus) { @@ -3509,11 +3522,12 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, auto &Idents = S.Context.Idents; // Ensure all external identifiers are in the identifier table. - if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { - std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); - for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) - Idents.get(Name); - } + if (LoadExternal) + if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) { + std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); + for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next()) + Idents.get(Name); + } // Walk all lookup results in the TU for each identifier. for (const auto &Ident : Idents) { @@ -3535,8 +3549,13 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); + // We sometimes skip loading namespace-level results (they tend to be huge). + bool Load = LoadExternal || + !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx)); // Enumerate all of the results in this context. - for (DeclContextLookupResult R : Ctx->lookups()) { + for (DeclContextLookupResult R : + Load ? Ctx->lookups() + : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { for (auto *D : R) { if (auto *ND = Result.getAcceptableDecl(D)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); @@ -3553,7 +3572,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, continue; LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited, - IncludeDependentBases); + IncludeDependentBases, LoadExternal); } } @@ -3610,7 +3629,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(RD, Result, QualifiedNameLookup, true, Consumer, - Visited, IncludeDependentBases); + Visited, IncludeDependentBases, LoadExternal); } } @@ -3619,22 +3638,23 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse categories. for (auto *Cat : IFace->visible_categories()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, - Consumer, Visited); + LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, + Visited, IncludeDependentBases, LoadExternal); } // Traverse protocols. for (auto *I : IFace->all_referenced_protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, LoadExternal); } // Traverse the superclass. if (IFace->getSuperClass()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, - true, Consumer, Visited); + true, Consumer, Visited, IncludeDependentBases, + LoadExternal); } // If there is an implementation, traverse it. We do this to find @@ -3642,26 +3662,28 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getImplementation(), Result, - QualifiedNameLookup, InBaseClass, Consumer, Visited); + QualifiedNameLookup, InBaseClass, Consumer, Visited, + IncludeDependentBases, LoadExternal); } } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { for (auto *I : Protocol->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, LoadExternal); } } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { for (auto *I : Category->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, - Visited); + Visited, IncludeDependentBases, LoadExternal); } // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Category->getImplementation(), Result, - QualifiedNameLookup, true, Consumer, Visited); + QualifiedNameLookup, true, Consumer, Visited, + IncludeDependentBases, LoadExternal); } } } @@ -3669,7 +3691,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, static void LookupVisibleDecls(Scope *S, LookupResult &Result, UnqualUsingDirectiveSet &UDirs, VisibleDeclConsumer &Consumer, - VisibleDeclsRecord &Visited) { + VisibleDeclsRecord &Visited, + bool LoadExternal) { if (!S) return; @@ -3708,7 +3731,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, LoadExternal); } } @@ -3722,7 +3746,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, LoadExternal); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation @@ -3736,7 +3761,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, LoadExternal); } if (Entity) { @@ -3745,17 +3771,19 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity)) LookupVisibleDecls(const_cast<DeclContext *>(UUE.getNominatedNamespace()), Result, /*QualifiedNameLookup=*/false, - /*InBaseClass=*/false, Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited, + /*IncludeDependentBases=*/false, LoadExternal); } // Lookup names in the parent scope. ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited); + LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited, + LoadExternal); } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, - bool IncludeGlobalScope) { + bool IncludeGlobalScope, bool LoadExternal) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; @@ -3776,13 +3804,13 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); + ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, LoadExternal); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope, - bool IncludeDependentBases) { + bool IncludeDependentBases, bool LoadExternal) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; @@ -3791,7 +3819,7 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited, - IncludeDependentBases); + IncludeDependentBases, LoadExternal); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. @@ -3846,7 +3874,7 @@ static void LookupPotentialTypoResult(Sema &SemaRef, bool isObjCIvarLookup, bool FindHidden); -/// \brief Check whether the declarations found for a typo correction are +/// Check whether the declarations found for a typo correction are /// visible. Set the correction's RequiresImport flag to true if none of the /// declarations are visible, false otherwise. static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { @@ -3865,17 +3893,13 @@ static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { bool AnyVisibleDecls = !NewDecls.empty(); for (/**/; DI != DE; ++DI) { - NamedDecl *VisibleDecl = *DI; - if (!LookupResult::isVisible(SemaRef, *DI)) - VisibleDecl = findAcceptableDecl(SemaRef, *DI); - - if (VisibleDecl) { + if (LookupResult::isVisible(SemaRef, *DI)) { if (!AnyVisibleDecls) { // Found a visible decl, discard all hidden ones. AnyVisibleDecls = true; NewDecls.clear(); } - NewDecls.push_back(VisibleDecl); + NewDecls.push_back(*DI); } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate()) NewDecls.push_back(*DI); } @@ -3945,8 +3969,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, // Only consider visible declarations and declarations from modules with // names that exactly match. - if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo && - !findAcceptableDecl(SemaRef, ND)) + if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo) return; FoundName(Name->getName()); @@ -4337,7 +4360,7 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( DistanceMap[NumSpecifiers].push_back(SI); } -/// \brief Perform name lookup for a possible result for typo correction. +/// Perform name lookup for a possible result for typo correction. static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, IdentifierInfo *Name, @@ -4391,7 +4414,7 @@ static void LookupPotentialTypoResult(Sema &SemaRef, } } -/// \brief Add keywords to the consumer as possible typo corrections. +/// Add keywords to the consumer as possible typo corrections. static void AddKeywordsToConsumer(Sema &SemaRef, TypoCorrectionConsumer &Consumer, Scope *S, CorrectionCandidateCallback &CCC, @@ -4442,7 +4465,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef, } } - if (SemaRef.getLangOpts().GNUMode) + if (SemaRef.getLangOpts().GNUKeywords) Consumer.addKeywordResult("typeof"); } else if (CCC.WantFunctionLikeCasts) { static const char *const CastableTypeSpecs[] = { @@ -4512,7 +4535,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef, if (S && S->getContinueParent()) Consumer.addKeywordResult("continue"); - if (!SemaRef.getCurFunction()->SwitchStack.empty()) { + if (SemaRef.getCurFunction() && + !SemaRef.getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult("case"); Consumer.addKeywordResult("default"); } @@ -4681,7 +4705,7 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer( return Consumer; } -/// \brief Try to "correct" a typo in the source code by finding +/// 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. /// @@ -4810,7 +4834,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure && !SecondBestTC); } -/// \brief Try to "correct" a typo in the source code by finding +/// 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. /// @@ -4966,6 +4990,8 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { // determine if it is a pointer or reference to a function. If so, // check against the number of arguments expected for the pointee. QualType ValType = cast<ValueDecl>(ND)->getType(); + if (ValType.isNull()) + continue; if (ValType->isAnyPointerType() || ValType->isReferenceType()) ValType = ValType->getPointeeType(); if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>()) @@ -5047,7 +5073,7 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, Recover); } -/// \brief Get a "quoted.h" or <angled.h> include path to use in a diagnostic +/// Get a "quoted.h" or <angled.h> include path to use in a diagnostic /// suggesting the addition of a #include of the specified file. static std::string getIncludeStringForHeader(Preprocessor &PP, const FileEntry *E) { @@ -5126,7 +5152,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); } -/// \brief Diagnose a successfully-corrected typo. Separated from the correction +/// Diagnose a successfully-corrected typo. Separated from the correction /// itself to allow external validation of the result, etc. /// /// \param Correction The result of performing typo correction. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index ea5b1da46f32..2983ec51f49e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -104,7 +104,7 @@ static void checkPropertyDeclWithOwnership(Sema &S, << propertyLifetime; } -/// \brief Check this Objective-C property against a property declared in the +/// Check this Objective-C property against a property declared in the /// given protocol. static void CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, @@ -618,7 +618,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, TInfo = Context.getTrivialTypeSourceInfo(T, TLoc); } - DeclContext *DC = cast<DeclContext>(CDecl); + DeclContext *DC = CDecl; ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), PropertyId, AtLoc, @@ -897,14 +897,24 @@ SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc, : HasUnexpectedAttribute; Mismatches.push_back({Prop, Kind, AttributeName}); }; - if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr, + // The ownership might be incompatible unless the property has no explicit + // ownership. + bool HasOwnership = (Attr & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_unsafe_unretained | + ObjCPropertyDecl::OBJC_PR_weak)) != 0; + if (HasOwnership && + isIncompatiblePropertyAttribute(OriginalAttributes, Attr, ObjCPropertyDecl::OBJC_PR_copy)) { Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_copy, "copy"); continue; } - if (areIncompatiblePropertyAttributes( - OriginalAttributes, Attr, ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong)) { + if (HasOwnership && areIncompatiblePropertyAttributes( + OriginalAttributes, Attr, + ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_strong)) { Diag(OriginalAttributes & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong), "retain (or strong)"); @@ -1819,7 +1829,7 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl, return false; } -/// \brief Default synthesizes all properties which must be synthesized +/// Default synthesizes all properties which must be synthesized /// in class's \@implementation. void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, ObjCInterfaceDecl *IDecl, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index 24b58e8fd12b..e1a4c420d402 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements semantic analysis for OpenMP directives and +/// This file implements semantic analysis for OpenMP directives and /// clauses. /// //===----------------------------------------------------------------------===// @@ -35,17 +35,17 @@ using namespace clang; // Stack of data-sharing attributes for variables //===----------------------------------------------------------------------===// -static Expr *CheckMapClauseExpressionBase( +static const Expr *checkMapClauseExpressionBase( Sema &SemaRef, Expr *E, OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, OpenMPClauseKind CKind, bool NoDiagnose); namespace { -/// \brief Default data sharing attributes, which can be applied to directive. +/// Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { - DSA_unspecified = 0, /// \brief Data sharing attribute not specified. - DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'. - DSA_shared = 1 << 1, /// \brief Default data sharing attribute 'shared'. + DSA_unspecified = 0, /// Data sharing attribute not specified. + DSA_none = 1 << 0, /// Default data sharing attribute 'none'. + DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. }; /// Attributes of the defaultmap clause. @@ -54,51 +54,53 @@ enum DefaultMapAttributes { DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'. }; -/// \brief Stack for tracking declarations used in OpenMP directives and +/// Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. -class DSAStackTy final { +class DSAStackTy { public: - struct DSAVarData final { + struct DSAVarData { OpenMPDirectiveKind DKind = OMPD_unknown; OpenMPClauseKind CKind = OMPC_unknown; - Expr *RefExpr = nullptr; + const Expr *RefExpr = nullptr; DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; DSAVarData() = default; - DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, Expr *RefExpr, - DeclRefExpr *PrivateCopy, SourceLocation ImplicitDSALoc) + DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, + const Expr *RefExpr, DeclRefExpr *PrivateCopy, + SourceLocation ImplicitDSALoc) : DKind(DKind), CKind(CKind), RefExpr(RefExpr), PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {} }; - typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4> - OperatorOffsetTy; + using OperatorOffsetTy = + llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>; private: - struct DSAInfo final { + struct DSAInfo { OpenMPClauseKind Attributes = OMPC_unknown; /// Pointer to a reference expression and a flag which shows that the /// variable is marked as lastprivate(true) or not (false). - llvm::PointerIntPair<Expr *, 1, bool> RefExpr; + llvm::PointerIntPair<const Expr *, 1, bool> RefExpr; DeclRefExpr *PrivateCopy = nullptr; }; - typedef llvm::DenseMap<ValueDecl *, DSAInfo> DeclSAMapTy; - typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy; - typedef std::pair<unsigned, VarDecl *> LCDeclInfo; - typedef llvm::DenseMap<ValueDecl *, LCDeclInfo> LoopControlVariablesMapTy; + using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>; + using AlignedMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>; + using LCDeclInfo = std::pair<unsigned, VarDecl *>; + using LoopControlVariablesMapTy = + llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>; /// Struct that associates a component with the clause kind where they are /// found. struct MappedExprComponentTy { OMPClauseMappableExprCommon::MappableExprComponentLists Components; OpenMPClauseKind Kind = OMPC_unknown; }; - typedef llvm::DenseMap<ValueDecl *, MappedExprComponentTy> - MappedExprComponentsTy; - typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>> - CriticalsWithHintsTy; - typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy> - DoacrossDependMapTy; + using MappedExprComponentsTy = + llvm::DenseMap<const ValueDecl *, MappedExprComponentTy>; + using CriticalsWithHintsTy = + llvm::StringMap<std::pair<const OMPCriticalDirective *, llvm::APSInt>>; + using DoacrossDependMapTy = + llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>; struct ReductionData { - typedef llvm::PointerEmbeddedInt<BinaryOperatorKind, 16> BOKPtrType; + using BOKPtrType = llvm::PointerEmbeddedInt<BinaryOperatorKind, 16>; SourceRange ReductionRange; llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp; ReductionData() = default; @@ -111,9 +113,10 @@ private: ReductionOp = RefExpr; } }; - typedef llvm::DenseMap<ValueDecl *, ReductionData> DeclReductionMapTy; + using DeclReductionMapTy = + llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>; - struct SharingMapTy final { + struct SharingMapTy { DeclSAMapTy SharingMap; DeclReductionMapTy ReductionMap; AlignedMapTy AlignedMap; @@ -131,10 +134,10 @@ private: /// get the data (loop counters etc.) about enclosing loop-based construct. /// This data is required during codegen. DoacrossDependMapTy DoacrossDepends; - /// \brief first argument (Expr *) contains optional argument of the + /// first argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. - llvm::PointerIntPair<Expr *, 1, bool> OrderedRegion; + llvm::PointerIntPair<const Expr *, 1, bool> OrderedRegion; bool NowaitRegion = false; bool CancelRegion = false; unsigned AssociatedLoops = 1; @@ -148,25 +151,25 @@ private: SharingMapTy() = default; }; - typedef SmallVector<SharingMapTy, 4> StackTy; + using StackTy = SmallVector<SharingMapTy, 4>; - /// \brief Stack of used declaration and their data-sharing attributes. + /// Stack of used declaration and their data-sharing attributes. DeclSAMapTy Threadprivates; const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr; SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack; - /// \brief true, if check for DSA must be from parent directive, false, if + /// true, if check for DSA must be from parent directive, false, if /// from current directive. OpenMPClauseKind ClauseKindMode = OMPC_unknown; Sema &SemaRef; bool ForceCapturing = false; CriticalsWithHintsTy Criticals; - typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; + using iterator = StackTy::const_reverse_iterator; - DSAVarData getDSA(StackTy::reverse_iterator &Iter, ValueDecl *D); + DSAVarData getDSA(iterator &Iter, ValueDecl *D) const; - /// \brief Checks if the variable is a local for OpenMP region. - bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); + /// Checks if the variable is a local for OpenMP region. + bool isOpenMPLocal(VarDecl *D, iterator Iter) const; bool isStackEmpty() const { return Stack.empty() || @@ -223,59 +226,61 @@ public: } } - void addCriticalWithHint(OMPCriticalDirective *D, llvm::APSInt Hint) { - Criticals[D->getDirectiveName().getAsString()] = std::make_pair(D, Hint); + void addCriticalWithHint(const OMPCriticalDirective *D, llvm::APSInt Hint) { + Criticals.try_emplace(D->getDirectiveName().getAsString(), D, Hint); } - const std::pair<OMPCriticalDirective *, llvm::APSInt> + const std::pair<const OMPCriticalDirective *, llvm::APSInt> getCriticalWithHint(const DeclarationNameInfo &Name) const { auto I = Criticals.find(Name.getAsString()); if (I != Criticals.end()) return I->second; return std::make_pair(nullptr, llvm::APSInt()); } - /// \brief If 'aligned' declaration for given variable \a D was not seen yet, + /// If 'aligned' declaration for given variable \a D was not seen yet, /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. - Expr *addUniqueAligned(ValueDecl *D, Expr *NewDE); + const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE); - /// \brief Register specified variable as loop control variable. - void addLoopControlVariable(ValueDecl *D, VarDecl *Capture); - /// \brief Check if the specified variable is a loop control variable for + /// Register specified variable as loop control variable. + void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture); + /// Check if the specified variable is a loop control variable for /// current region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - LCDeclInfo isLoopControlVariable(ValueDecl *D); - /// \brief Check if the specified variable is a loop control variable for + const LCDeclInfo isLoopControlVariable(const ValueDecl *D) const; + /// Check if the specified variable is a loop control variable for /// parent region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - LCDeclInfo isParentLoopControlVariable(ValueDecl *D); - /// \brief Get the loop control variable for the I-th loop (or nullptr) in + const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const; + /// Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. - ValueDecl *getParentLoopControlVariable(unsigned I); + const ValueDecl *getParentLoopControlVariable(unsigned I) const; - /// \brief Adds explicit data sharing attribute to the specified declaration. - void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + /// Adds explicit data sharing attribute to the specified declaration. + void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, DeclRefExpr *PrivateCopy = nullptr); /// Adds additional information for the reduction items with the reduction id /// represented as an operator. - void addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, BinaryOperatorKind BOK); /// Adds additional information for the reduction items with the reduction id /// represented as reduction identifier. - void addTaskgroupReductionData(ValueDecl *D, SourceRange SR, + void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, const Expr *ReductionRef); /// Returns the location and reduction operation from the innermost parent /// region for the given \p D. - DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, - BinaryOperatorKind &BOK, - Expr *&TaskgroupDescriptor); + const DSAVarData + getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR, + BinaryOperatorKind &BOK, + Expr *&TaskgroupDescriptor) const; /// Returns the location and reduction operation from the innermost parent /// region for the given \p D. - DSAVarData getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, - const Expr *&ReductionRef, - Expr *&TaskgroupDescriptor); + const DSAVarData + getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR, + const Expr *&ReductionRef, + Expr *&TaskgroupDescriptor) const; /// Return reduction reference expression for the current taskgroup. Expr *getTaskgroupReductionRef() const { assert(Stack.back().first.back().Directive == OMPD_taskgroup && @@ -285,74 +290,75 @@ public: } /// Checks if the given \p VD declaration is actually a taskgroup reduction /// descriptor variable at the \p Level of OpenMP regions. - bool isTaskgroupReductionRef(ValueDecl *VD, unsigned Level) const { + bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const { return Stack.back().first[Level].TaskgroupReductionRef && cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef) ->getDecl() == VD; } - /// \brief Returns data sharing attributes from top of the stack for the + /// Returns data sharing attributes from top of the stack for the /// specified declaration. - DSAVarData getTopDSA(ValueDecl *D, bool FromParent); - /// \brief Returns data-sharing attributes for the specified declaration. - DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent); - /// \brief Checks if the specified variables has data-sharing attributes which + const DSAVarData getTopDSA(ValueDecl *D, bool FromParent); + /// Returns data-sharing attributes for the specified declaration. + const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const; + /// Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. - DSAVarData hasDSA(ValueDecl *D, - const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - bool FromParent); - /// \brief Checks if the specified variables has data-sharing attributes which + const DSAVarData + hasDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + bool FromParent) const; + /// Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any innermost directive which /// matches \a DPred predicate. - DSAVarData + const DSAVarData hasInnermostDSA(ValueDecl *D, - const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - bool FromParent); - /// \brief Checks if the specified variables has explicit data-sharing + const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + bool FromParent) const; + /// Checks if the specified variables has explicit data-sharing /// attributes which match specified \a CPred predicate at the specified /// OpenMP region. - bool hasExplicitDSA(ValueDecl *D, - const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level, bool NotLastprivate = false); + bool hasExplicitDSA(const ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + unsigned Level, bool NotLastprivate = false) const; - /// \brief Returns true if the directive at level \Level matches in the + /// Returns true if the directive at level \Level matches in the /// specified \a DPred predicate. bool hasExplicitDirective( - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - unsigned Level); + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + unsigned Level) const; - /// \brief Finds a directive which matches specified \a DPred predicate. - bool hasDirective(const llvm::function_ref<bool(OpenMPDirectiveKind, - const DeclarationNameInfo &, - SourceLocation)> &DPred, - bool FromParent); + /// Finds a directive which matches specified \a DPred predicate. + bool hasDirective( + const llvm::function_ref<bool( + OpenMPDirectiveKind, const DeclarationNameInfo &, SourceLocation)> + DPred, + bool FromParent) const; - /// \brief Returns currently analyzed directive. + /// Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive; } - /// \brief Returns directive kind at specified level. + /// Returns directive kind at specified level. OpenMPDirectiveKind getDirective(unsigned Level) const { assert(!isStackEmpty() && "No directive at specified level."); return Stack.back().first[Level].Directive; } - /// \brief Returns parent directive. + /// Returns parent directive. OpenMPDirectiveKind getParentDirective() const { if (isStackEmpty() || Stack.back().first.size() == 1) return OMPD_unknown; return std::next(Stack.back().first.rbegin())->Directive; } - /// \brief Set default data sharing attribute to none. + /// Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { assert(!isStackEmpty()); Stack.back().first.back().DefaultAttr = DSA_none; Stack.back().first.back().DefaultAttrLoc = Loc; } - /// \brief Set default data sharing attribute to shared. + /// Set default data sharing attribute to shared. void setDefaultDSAShared(SourceLocation Loc) { assert(!isStackEmpty()); Stack.back().first.back().DefaultAttr = DSA_shared; @@ -385,66 +391,66 @@ public: : Stack.back().first.back().DefaultMapAttrLoc; } - /// \brief Checks if the specified variable is a threadprivate. + /// Checks if the specified variable is a threadprivate. bool isThreadPrivate(VarDecl *D) { - DSAVarData DVar = getTopDSA(D, false); + const DSAVarData DVar = getTopDSA(D, false); return isOpenMPThreadPrivate(DVar.CKind); } - /// \brief Marks current region as ordered (it has an 'ordered' clause). - void setOrderedRegion(bool IsOrdered, Expr *Param) { + /// Marks current region as ordered (it has an 'ordered' clause). + void setOrderedRegion(bool IsOrdered, const Expr *Param) { assert(!isStackEmpty()); Stack.back().first.back().OrderedRegion.setInt(IsOrdered); Stack.back().first.back().OrderedRegion.setPointer(Param); } - /// \brief Returns true, if parent region is ordered (has associated + /// Returns true, if parent region is ordered (has associated /// 'ordered' clause), false - otherwise. bool isParentOrderedRegion() const { if (isStackEmpty() || Stack.back().first.size() == 1) return false; return std::next(Stack.back().first.rbegin())->OrderedRegion.getInt(); } - /// \brief Returns optional parameter for the ordered region. - Expr *getParentOrderedRegionParam() const { + /// Returns optional parameter for the ordered region. + const Expr *getParentOrderedRegionParam() const { if (isStackEmpty() || Stack.back().first.size() == 1) return nullptr; return std::next(Stack.back().first.rbegin())->OrderedRegion.getPointer(); } - /// \brief Marks current region as nowait (it has a 'nowait' clause). + /// Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { assert(!isStackEmpty()); Stack.back().first.back().NowaitRegion = IsNowait; } - /// \brief Returns true, if parent region is nowait (has associated + /// Returns true, if parent region is nowait (has associated /// 'nowait' clause), false - otherwise. bool isParentNowaitRegion() const { if (isStackEmpty() || Stack.back().first.size() == 1) return false; return std::next(Stack.back().first.rbegin())->NowaitRegion; } - /// \brief Marks parent region as cancel region. + /// Marks parent region as cancel region. void setParentCancelRegion(bool Cancel = true) { if (!isStackEmpty() && Stack.back().first.size() > 1) { auto &StackElemRef = *std::next(Stack.back().first.rbegin()); StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel; } } - /// \brief Return true if current region has inner cancel construct. + /// Return true if current region has inner cancel construct. bool isCancelRegion() const { return isStackEmpty() ? false : Stack.back().first.back().CancelRegion; } - /// \brief Set collapse value for the region. + /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { assert(!isStackEmpty()); Stack.back().first.back().AssociatedLoops = Val; } - /// \brief Return collapse value for region. + /// Return collapse value for region. unsigned getAssociatedLoops() const { return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops; } - /// \brief Marks current target region as one with closely nested teams + /// Marks current target region as one with closely nested teams /// region. void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { if (!isStackEmpty() && Stack.back().first.size() > 1) { @@ -452,11 +458,11 @@ public: TeamsRegionLoc; } } - /// \brief Returns true, if current region has closely nested teams region. + /// 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). + /// Returns location of the nested teams region (if any). SourceLocation getInnerTeamsRegionLoc() const { return isStackEmpty() ? SourceLocation() : Stack.back().first.back().InnerTeamsRegionLoc; @@ -465,10 +471,7 @@ public: Scope *getCurScope() const { return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope; } - Scope *getCurScope() { - return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope; - } - SourceLocation getConstructLoc() { + SourceLocation getConstructLoc() const { return isStackEmpty() ? SourceLocation() : Stack.back().first.back().ConstructLoc; } @@ -476,10 +479,11 @@ public: /// Do the check specified in \a Check to all component lists and return true /// if any issue is found. bool checkMappableExprComponentListsForDecl( - ValueDecl *VD, bool CurrentRegionOnly, + const ValueDecl *VD, bool CurrentRegionOnly, const llvm::function_ref< bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, - OpenMPClauseKind)> &Check) { + OpenMPClauseKind)> + Check) const { if (isStackEmpty()) return false; auto SI = Stack.back().first.rbegin(); @@ -488,16 +492,16 @@ public: if (SI == SE) return false; - if (CurrentRegionOnly) { + if (CurrentRegionOnly) SE = std::next(SI); - } else { - ++SI; - } + else + std::advance(SI, 1); for (; SI != SE; ++SI) { auto MI = SI->MappedExprComponents.find(VD); if (MI != SI->MappedExprComponents.end()) - for (auto &L : MI->second.Components) + for (OMPClauseMappableExprCommon::MappableExprComponentListRef L : + MI->second.Components) if (Check(L, MI->second.Kind)) return true; } @@ -507,10 +511,11 @@ public: /// Do the check specified in \a Check to all component lists at a given level /// and return true if any issue is found. bool checkMappableExprComponentListsForDeclAtLevel( - ValueDecl *VD, unsigned Level, + const ValueDecl *VD, unsigned Level, const llvm::function_ref< bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, - OpenMPClauseKind)> &Check) { + OpenMPClauseKind)> + Check) const { if (isStackEmpty()) return false; @@ -522,7 +527,8 @@ public: auto MI = StartI->MappedExprComponents.find(VD); if (MI != StartI->MappedExprComponents.end()) - for (auto &L : MI->second.Components) + for (OMPClauseMappableExprCommon::MappableExprComponentListRef L : + MI->second.Components) if (Check(L, MI->second.Kind)) return true; return false; @@ -531,12 +537,13 @@ public: /// Create a new mappable expression component list associated with a given /// declaration and initialize it with the provided list of components. void addMappableExpressionComponents( - ValueDecl *VD, + const ValueDecl *VD, OMPClauseMappableExprCommon::MappableExprComponentListRef Components, OpenMPClauseKind WhereFoundClauseKind) { assert(!isStackEmpty() && "Not expecting to retrieve components from a empty stack!"); - auto &MEC = Stack.back().first.back().MappedExprComponents[VD]; + MappedExprComponentTy &MEC = + Stack.back().first.back().MappedExprComponents[VD]; // Create new entry and append the new components there. MEC.Components.resize(MEC.Components.size() + 1); MEC.Components.back().append(Components.begin(), Components.end()); @@ -547,18 +554,19 @@ public: assert(!isStackEmpty()); return Stack.back().first.size() - 1; } - void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) { + void addDoacrossDependClause(OMPDependClause *C, + const OperatorOffsetTy &OpsOffs) { assert(!isStackEmpty() && Stack.back().first.size() > 1); - auto &StackElem = *std::next(Stack.back().first.rbegin()); + SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); assert(isOpenMPWorksharingDirective(StackElem.Directive)); - StackElem.DoacrossDepends.insert({C, OpsOffs}); + StackElem.DoacrossDepends.try_emplace(C, OpsOffs); } llvm::iterator_range<DoacrossDependMapTy::const_iterator> getDoacrossDependClauses() const { assert(!isStackEmpty()); - auto &StackElem = Stack.back().first.back(); + const SharingMapTy &StackElem = Stack.back().first.back(); if (isOpenMPWorksharingDirective(StackElem.Directive)) { - auto &Ref = StackElem.DoacrossDepends; + const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends; return llvm::make_range(Ref.begin(), Ref.end()); } return llvm::make_range(StackElem.DoacrossDepends.end(), @@ -569,29 +577,34 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { return isOpenMPParallelDirective(DKind) || isOpenMPTaskingDirective(DKind) || isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown; } + } // namespace -static Expr *getExprAsWritten(Expr *E) { - if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) +static const Expr *getExprAsWritten(const Expr *E) { + if (const auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) E = ExprTemp->getSubExpr(); - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) E = MTE->GetTemporaryExpr(); - while (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) + while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) E = Binder->getSubExpr(); - if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExprAsWritten(); return E->IgnoreParens(); } -static ValueDecl *getCanonicalDecl(ValueDecl *D) { - if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) - if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) +static Expr *getExprAsWritten(Expr *E) { + return const_cast<Expr *>(getExprAsWritten(const_cast<const Expr *>(E))); +} + +static const ValueDecl *getCanonicalDecl(const ValueDecl *D) { + if (const auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) + if (const auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) D = ME->getMemberDecl(); - auto *VD = dyn_cast<VarDecl>(D); - auto *FD = dyn_cast<FieldDecl>(D); + const auto *VD = dyn_cast<VarDecl>(D); + const auto *FD = dyn_cast<FieldDecl>(D); if (VD != nullptr) { VD = VD->getCanonicalDecl(); D = VD; @@ -603,11 +616,16 @@ static ValueDecl *getCanonicalDecl(ValueDecl *D) { return D; } -DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, - ValueDecl *D) { +static ValueDecl *getCanonicalDecl(ValueDecl *D) { + return const_cast<ValueDecl *>( + getCanonicalDecl(const_cast<const ValueDecl *>(D))); +} + +DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter, + ValueDecl *D) const { D = getCanonicalDecl(D); auto *VD = dyn_cast<VarDecl>(D); - auto *FD = dyn_cast<FieldDecl>(D); + const auto *FD = dyn_cast<FieldDecl>(D); DSAVarData DVar; if (isStackEmpty() || Iter == Stack.back().first.rend()) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -615,7 +633,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 (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) + if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(VD)) DVar.CKind = OMPC_shared; // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced @@ -646,9 +664,10 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { - DVar.RefExpr = Iter->SharingMap[D].RefExpr.getPointer(); - DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy; - DVar.CKind = Iter->SharingMap[D].Attributes; + const DSAInfo &Data = Iter->SharingMap.lookup(D); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; } @@ -683,7 +702,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, // bound to the current team is shared. if (isOpenMPTaskingDirective(DVar.DKind)) { DSAVarData DVarTemp; - auto I = Iter, E = Stack.back().first.rend(); + iterator I = Iter, E = Stack.back().first.rend(); do { ++I; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables @@ -711,74 +730,75 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, return getDSA(++Iter, D); } -Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { +const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D, + const Expr *NewDE) { assert(!isStackEmpty() && "Data sharing attributes stack is empty"); D = getCanonicalDecl(D); - auto &StackElem = Stack.back().first.back(); + SharingMapTy &StackElem = Stack.back().first.back(); auto It = StackElem.AlignedMap.find(D); if (It == StackElem.AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); StackElem.AlignedMap[D] = NewDE; return nullptr; - } else { - assert(It->second && "Unexpected nullptr expr in the aligned map"); - return It->second; } - return nullptr; + assert(It->second && "Unexpected nullptr expr in the aligned map"); + return It->second; } -void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) { +void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - auto &StackElem = Stack.back().first.back(); - StackElem.LCVMap.insert( - {D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)}); + SharingMapTy &StackElem = Stack.back().first.back(); + StackElem.LCVMap.try_emplace( + D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture)); } -DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) { +const DSAStackTy::LCDeclInfo +DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - auto &StackElem = Stack.back().first.back(); + const SharingMapTy &StackElem = Stack.back().first.back(); auto It = StackElem.LCVMap.find(D); if (It != StackElem.LCVMap.end()) return It->second; return {0, nullptr}; } -DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { +const DSAStackTy::LCDeclInfo +DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const { assert(!isStackEmpty() && Stack.back().first.size() > 1 && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - auto &StackElem = *std::next(Stack.back().first.rbegin()); + const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); auto It = StackElem.LCVMap.find(D); if (It != StackElem.LCVMap.end()) return It->second; return {0, nullptr}; } -ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { +const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const { assert(!isStackEmpty() && Stack.back().first.size() > 1 && "Data-sharing attributes stack is empty"); - auto &StackElem = *std::next(Stack.back().first.rbegin()); + const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin()); if (StackElem.LCVMap.size() < I) return nullptr; - for (auto &Pair : StackElem.LCVMap) + for (const auto &Pair : StackElem.LCVMap) if (Pair.second.first == I) return Pair.first; return nullptr; } -void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, +void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, DeclRefExpr *PrivateCopy) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { - auto &Data = Threadprivates[D]; + DSAInfo &Data = Threadprivates[D]; Data.Attributes = A; Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; } else { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); - auto &Data = Stack.back().first.back().SharingMap[D]; + DSAInfo &Data = Stack.back().first.back().SharingMap[D]; assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || @@ -793,7 +813,8 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, Data.RefExpr.setPointerAndInt(E, IsLastprivate); Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { - auto &Data = Stack.back().first.back().SharingMap[PrivateCopy->getDecl()]; + DSAInfo &Data = + Stack.back().first.back().SharingMap[PrivateCopy->getDecl()]; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -801,13 +822,14 @@ void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, } } -/// \brief Build a variable declaration for OpenMP loop iteration variable. +/// Build a variable declaration for OpenMP loop iteration variable. static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, - StringRef Name, const AttrVec *Attrs = nullptr) { + StringRef Name, const AttrVec *Attrs = nullptr, + DeclRefExpr *OrigRef = nullptr) { DeclContext *DC = SemaRef.CurContext; IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = + auto *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); if (Attrs) { for (specific_attr_iterator<AlignedAttr> I(Attrs->begin()), E(Attrs->end()); @@ -815,6 +837,10 @@ static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, Decl->addAttr(*I); } Decl->setImplicit(); + if (OrigRef) { + Decl->addAttr( + OMPReferencedVarAttr::CreateImplicit(SemaRef.Context, OrigRef)); + } return Decl; } @@ -828,14 +854,14 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, VK_LValue); } -void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, +void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, BinaryOperatorKind BOK) { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); assert( Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && "Additional reduction info may be specified only for reduction items."); - auto &ReductionData = Stack.back().first.back().ReductionMap[D]; + ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && Stack.back().first.back().Directive == OMPD_taskgroup && "Additional reduction info may be specified only once for reduction " @@ -844,21 +870,21 @@ void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, Expr *&TaskgroupReductionRef = Stack.back().first.back().TaskgroupReductionRef; if (!TaskgroupReductionRef) { - auto *VD = buildVarDecl(SemaRef, SR.getBegin(), - SemaRef.Context.VoidPtrTy, ".task_red."); + VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(), + SemaRef.Context.VoidPtrTy, ".task_red."); TaskgroupReductionRef = buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); } } -void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, +void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, const Expr *ReductionRef) { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); assert( Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction && "Additional reduction info may be specified only for reduction items."); - auto &ReductionData = Stack.back().first.back().ReductionMap[D]; + ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && Stack.back().first.back().Directive == OMPD_taskgroup && "Additional reduction info may be specified only once for reduction " @@ -867,28 +893,27 @@ void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, Expr *&TaskgroupReductionRef = Stack.back().first.back().TaskgroupReductionRef; if (!TaskgroupReductionRef) { - auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, - ".task_red."); + VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(), + SemaRef.Context.VoidPtrTy, ".task_red."); TaskgroupReductionRef = buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); } } -DSAStackTy::DSAVarData -DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, - BinaryOperatorKind &BOK, - Expr *&TaskgroupDescriptor) { +const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( + const ValueDecl *D, SourceRange &SR, BinaryOperatorKind &BOK, + Expr *&TaskgroupDescriptor) const { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); if (Stack.back().first.empty()) return DSAVarData(); - for (auto I = std::next(Stack.back().first.rbegin(), 1), - E = Stack.back().first.rend(); + for (iterator I = std::next(Stack.back().first.rbegin(), 1), + E = Stack.back().first.rend(); I != E; std::advance(I, 1)) { - auto &Data = I->SharingMap[D]; + const DSAInfo &Data = I->SharingMap.lookup(D); if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) continue; - auto &ReductionData = I->ReductionMap[D]; + const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || ReductionData.ReductionOp.is<const Expr *>()) return DSAVarData(); @@ -904,21 +929,20 @@ DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, return DSAVarData(); } -DSAStackTy::DSAVarData -DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, - const Expr *&ReductionRef, - Expr *&TaskgroupDescriptor) { +const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( + const ValueDecl *D, SourceRange &SR, const Expr *&ReductionRef, + Expr *&TaskgroupDescriptor) const { D = getCanonicalDecl(D); assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); if (Stack.back().first.empty()) return DSAVarData(); - for (auto I = std::next(Stack.back().first.rbegin(), 1), - E = Stack.back().first.rend(); + for (iterator I = std::next(Stack.back().first.rbegin(), 1), + E = Stack.back().first.rend(); I != E; std::advance(I, 1)) { - auto &Data = I->SharingMap[D]; + const DSAInfo &Data = I->SharingMap.lookup(D); if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) continue; - auto &ReductionData = I->ReductionMap[D]; + const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || !ReductionData.ReductionOp.is<const Expr *>()) return DSAVarData(); @@ -934,12 +958,13 @@ DSAStackTy::getTopMostTaskgroupReductionData(ValueDecl *D, SourceRange &SR, return DSAVarData(); } -bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { +bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const { D = D->getCanonicalDecl(); - if (!isStackEmpty() && Stack.back().first.size() > 1) { - reverse_iterator I = Iter, E = Stack.back().first.rend(); + if (!isStackEmpty()) { + iterator I = Iter, E = Stack.back().first.rend(); Scope *TopScope = nullptr; - while (I != E && !isParallelOrTaskRegion(I->Directive)) + while (I != E && !isParallelOrTaskRegion(I->Directive) && + !isOpenMPTargetExecutionDirective(I->Directive)) ++I; if (I == E) return false; @@ -952,35 +977,80 @@ bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { return false; } -DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { +const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, + bool FromParent) { D = getCanonicalDecl(D); DSAVarData DVar; + auto *VD = dyn_cast<VarDecl>(D); + auto TI = Threadprivates.find(D); + if (TI != Threadprivates.end()) { + DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); + DVar.CKind = OMPC_threadprivate; + return DVar; + } + if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) { + DVar.RefExpr = buildDeclRefExpr( + SemaRef, VD, D->getType().getNonReferenceType(), + VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation()); + DVar.CKind = OMPC_threadprivate; + addDSA(D, DVar.RefExpr, OMPC_threadprivate); + return DVar; + } // 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. - auto *VD = dyn_cast<VarDecl>(D); if ((VD && VD->getTLSKind() != VarDecl::TLS_None && !(VD->hasAttr<OMPThreadPrivateDeclAttr>() && SemaRef.getLangOpts().OpenMPUseTLS && SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || (VD && VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) { - addDSA(D, buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), - D->getLocation()), - OMPC_threadprivate); - } - auto TI = Threadprivates.find(D); - if (TI != Threadprivates.end()) { - DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); - DVar.CKind = OMPC_threadprivate; - return DVar; - } else if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) { DVar.RefExpr = buildDeclRefExpr( - SemaRef, VD, D->getType().getNonReferenceType(), - VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation()); + SemaRef, VD, D->getType().getNonReferenceType(), D->getLocation()); DVar.CKind = OMPC_threadprivate; addDSA(D, DVar.RefExpr, OMPC_threadprivate); + return DVar; + } + if (SemaRef.getLangOpts().OpenMPCUDAMode && VD && + VD->isLocalVarDeclOrParm() && !isStackEmpty() && + !isLoopControlVariable(D).first) { + iterator IterTarget = + std::find_if(Stack.back().first.rbegin(), Stack.back().first.rend(), + [](const SharingMapTy &Data) { + return isOpenMPTargetExecutionDirective(Data.Directive); + }); + if (IterTarget != Stack.back().first.rend()) { + iterator ParentIterTarget = std::next(IterTarget, 1); + for (iterator Iter = Stack.back().first.rbegin(); + Iter != ParentIterTarget; std::advance(Iter, 1)) { + if (isOpenMPLocal(VD, Iter)) { + DVar.RefExpr = + buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), + D->getLocation()); + DVar.CKind = OMPC_threadprivate; + return DVar; + } + } + if (!isClauseParsingMode() || IterTarget != Stack.back().first.rbegin()) { + auto DSAIter = IterTarget->SharingMap.find(D); + if (DSAIter != IterTarget->SharingMap.end() && + isOpenMPPrivate(DSAIter->getSecond().Attributes)) { + DVar.RefExpr = DSAIter->getSecond().RefExpr.getPointer(); + DVar.CKind = OMPC_threadprivate; + return DVar; + } + iterator End = Stack.back().first.rend(); + if (!SemaRef.isOpenMPCapturedByRef( + D, std::distance(ParentIterTarget, End))) { + DVar.RefExpr = + buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), + IterTarget->ConstructLoc); + DVar.CKind = OMPC_threadprivate; + return DVar; + } + } + } } if (isStackEmpty()) @@ -994,7 +1064,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. - auto &&MatchesAlways = [](OpenMPDirectiveKind) -> bool { return true; }; + auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; }; if (VD && VD->isStaticDataMember()) { DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent); if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) @@ -1011,21 +1081,21 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { // in a Construct, C/C++, predetermined, p.6] // Variables with const qualified type having no mutable member are // shared. - CXXRecordDecl *RD = + const CXXRecordDecl *RD = SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; - if (auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD)) - if (auto *CTD = CTSD->getSpecializedTemplate()) + if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(RD)) + if (const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate()) RD = CTD->getTemplatedDecl(); if (IsConstant && !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasDefinition() && RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - DSAVarData DVarTemp = hasDSA( - D, [](OpenMPClauseKind C) -> bool { return C == OMPC_firstprivate; }, - MatchesAlways, FromParent); + DSAVarData DVarTemp = + hasDSA(D, [](OpenMPClauseKind C) { return C == OMPC_firstprivate; }, + MatchesAlways, FromParent); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) - return DVar; + return DVarTemp; DVar.CKind = OMPC_shared; return DVar; @@ -1033,14 +1103,16 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { // Explicitly specified attributes and local variables with predetermined // attributes. - auto I = Stack.back().first.rbegin(); - auto EndI = Stack.back().first.rend(); + iterator I = Stack.back().first.rbegin(); + iterator EndI = Stack.back().first.rend(); if (FromParent && I != EndI) std::advance(I, 1); - if (I->SharingMap.count(D)) { - DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer(); - DVar.PrivateCopy = I->SharingMap[D].PrivateCopy; - DVar.CKind = I->SharingMap[D].Attributes; + auto It = I->SharingMap.find(D); + if (It != I->SharingMap.end()) { + const DSAInfo &Data = It->getSecond(); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; DVar.DKind = I->Directive; } @@ -1048,36 +1120,36 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { return DVar; } -DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, - bool FromParent) { +const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, + bool FromParent) const { if (isStackEmpty()) { - StackTy::reverse_iterator I; + iterator I; return getDSA(I, D); } D = getCanonicalDecl(D); - auto StartI = Stack.back().first.rbegin(); - auto EndI = Stack.back().first.rend(); + iterator StartI = Stack.back().first.rbegin(); + iterator EndI = Stack.back().first.rend(); if (FromParent && StartI != EndI) std::advance(StartI, 1); return getDSA(StartI, D); } -DSAStackTy::DSAVarData +const DSAStackTy::DSAVarData DSAStackTy::hasDSA(ValueDecl *D, - const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - bool FromParent) { + const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + bool FromParent) const { if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto I = Stack.back().first.rbegin(); - auto EndI = Stack.back().first.rend(); + iterator I = Stack.back().first.rbegin(); + iterator EndI = Stack.back().first.rend(); if (FromParent && I != EndI) std::advance(I, 1); for (; I != EndI; std::advance(I, 1)) { if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive)) continue; - auto NewI = I; + iterator NewI = I; DSAVarData DVar = getDSA(NewI, D); if (I == NewI && CPred(DVar.CKind)) return DVar; @@ -1085,27 +1157,27 @@ DSAStackTy::hasDSA(ValueDecl *D, return {}; } -DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( - ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - bool FromParent) { +const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( + ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + bool FromParent) const { if (isStackEmpty()) return {}; D = getCanonicalDecl(D); - auto StartI = Stack.back().first.rbegin(); - auto EndI = Stack.back().first.rend(); + iterator StartI = Stack.back().first.rbegin(); + iterator EndI = Stack.back().first.rend(); if (FromParent && StartI != EndI) std::advance(StartI, 1); if (StartI == EndI || !DPred(StartI->Directive)) return {}; - auto NewI = StartI; + iterator NewI = StartI; DSAVarData DVar = getDSA(NewI, D); return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData(); } bool DSAStackTy::hasExplicitDSA( - ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level, bool NotLastprivate) { + const ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, + unsigned Level, bool NotLastprivate) const { if (isStackEmpty()) return false; D = getCanonicalDecl(D); @@ -1114,15 +1186,16 @@ bool DSAStackTy::hasExplicitDSA( if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); - return (StartI->SharingMap.count(D) > 0) && - StartI->SharingMap[D].RefExpr.getPointer() && - CPred(StartI->SharingMap[D].Attributes) && - (!NotLastprivate || !StartI->SharingMap[D].RefExpr.getInt()); + auto I = StartI->SharingMap.find(D); + return (I != StartI->SharingMap.end()) && + I->getSecond().RefExpr.getPointer() && + CPred(I->getSecond().Attributes) && + (!NotLastprivate || !I->getSecond().RefExpr.getInt()); } bool DSAStackTy::hasExplicitDirective( - const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, - unsigned Level) { + const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred, + unsigned Level) const { if (isStackEmpty()) return false; auto StartI = Stack.back().first.begin(); @@ -1136,8 +1209,8 @@ bool DSAStackTy::hasExplicitDirective( bool DSAStackTy::hasDirective( const llvm::function_ref<bool(OpenMPDirectiveKind, const DeclarationNameInfo &, SourceLocation)> - &DPred, - bool FromParent) { + DPred, + bool FromParent) const { // We look only in the enclosing region. if (isStackEmpty()) return false; @@ -1166,15 +1239,26 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { DSAStack->popFunction(OldFSI); } -bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { +static llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> +isDeclareTargetDeclaration(const ValueDecl *VD) { + for (const Decl *D : VD->redecls()) { + if (!D->hasAttrs()) + continue; + if (const auto *Attr = D->getAttr<OMPDeclareTargetDeclAttr>()) + return Attr->getMapType(); + } + return llvm::None; +} + +bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); - auto &Ctx = getASTContext(); + ASTContext &Ctx = getASTContext(); bool IsByRef = true; // Find the directive that is associated with the provided scope. D = cast<ValueDecl>(D->getCanonicalDecl()); - auto Ty = D->getType(); + QualType Ty = D->getType(); if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { // This table summarizes how a given variable should be passed to the device @@ -1241,7 +1325,9 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { bool IsVariableAssociatedWithSection = false; DSAStack->checkMappableExprComponentListsForDeclAtLevel( - D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + D, Level, + [&IsVariableUsedInMapClause, &IsVariableAssociatedWithSection, D]( + OMPClauseMappableExprCommon::MappableExprComponentListRef MapExprComponents, OpenMPClauseKind WhereFoundClauseKind) { // Only the map clause information influences how a variable is @@ -1331,20 +1417,22 @@ bool Sema::isInOpenMPTargetExecutionDirective() const { false); } -VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { +VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); // If we are attempting to capture a global variable in a directive with // 'target' we return true so that this global is also mapped to the device. // - // FIXME: If the declaration is enclosed in a 'declare target' directive, - // then it should not be captured. Therefore, an extra check has to be - // inserted here once support for 'declare target' is added. - // auto *VD = dyn_cast<VarDecl>(D); - if (VD && !VD->hasLocalStorage() && isInOpenMPTargetExecutionDirective()) + if (VD && !VD->hasLocalStorage() && isInOpenMPTargetExecutionDirective()) { + // If the declaration is enclosed in a 'declare target' directive, + // then it should not be captured. + // + if (isDeclareTargetDeclaration(VD)) + return nullptr; return VD; + } if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || @@ -1355,12 +1443,13 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || (VD && DSAStack->isForceVarCapturing())) return VD ? VD : Info.second; - auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); + DSAStackTy::DSAVarData DVarPrivate = + DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); - DVarPrivate = DSAStack->hasDSA( - D, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, - DSAStack->isClauseParsingMode()); + DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, + [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } @@ -1374,11 +1463,10 @@ void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, FunctionScopesIndex -= Regions.size(); } -bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { +bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); return DSAStack->hasExplicitDSA( - D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, - Level) || + D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || (DSAStack->isClauseParsingMode() && DSAStack->getClauseParsingMode() == OMPC_private) || // Consider taskgroup reduction descriptor variable a private to avoid @@ -1389,7 +1477,8 @@ bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { DSAStack->isTaskgroupReductionRef(D, Level)); } -void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) { +void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, + unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); OpenMPClauseKind OMPC = OMPC_unknown; @@ -1414,7 +1503,11 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) { } if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, NewLevel)) { - OMPC = OMPC_firstprivate; + OMPC = OMPC_map; + if (D->getType()->isScalarType() && + DSAStack->getDefaultDMAAtLevel(NewLevel) != + DefaultMapAttributes::DMA_tofrom_scalar) + OMPC = OMPC_firstprivate; break; } } @@ -1422,11 +1515,12 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, ValueDecl *D, unsigned Level) { FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC)); } -bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) { +bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, + unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); // Return true if the current level is no longer enclosed in a target region. - auto *VD = dyn_cast<VarDecl>(D); + const auto *VD = dyn_cast<VarDecl>(D); return VD && !VD->hasLocalStorage() && DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level); @@ -1456,28 +1550,29 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // clause requires an accessible, unambiguous default constructor for the // class type, unless the list item is also specified in a firstprivate // clause. - if (auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { - for (auto *C : D->clauses()) { + if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { + for (OMPClause *C : D->clauses()) { if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) { SmallVector<Expr *, 8> PrivateCopies; - for (auto *DE : Clause->varlists()) { + for (Expr *DE : Clause->varlists()) { if (DE->isValueDependent() || DE->isTypeDependent()) { PrivateCopies.push_back(nullptr); continue; } auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens()); - VarDecl *VD = cast<VarDecl>(DRE->getDecl()); + auto *VD = cast<VarDecl>(DRE->getDecl()); QualType Type = VD->getType().getNonReferenceType(); - auto DVar = DSAStack->getTopDSA(VD, false); + const DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(VD, /*FromParent=*/false); if (DVar.CKind == OMPC_lastprivate) { // 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 = buildVarDecl( + VarDecl *VDPrivate = buildVarDecl( *this, DE->getExprLoc(), Type.getUnqualifiedType(), - VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr); + VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE); ActOnUninitializedDecl(VDPrivate); if (VDPrivate->isInvalidDecl()) continue; @@ -1507,7 +1602,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, namespace { -class VarDeclFilterCCC : public CorrectionCandidateCallback { +class VarDeclFilterCCC final : public CorrectionCandidateCallback { private: Sema &SemaRef; @@ -1515,7 +1610,7 @@ public: explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); - if (auto *VD = dyn_cast_or_null<VarDecl>(ND)) { + if (const auto *VD = dyn_cast_or_null<VarDecl>(ND)) { return VD->hasGlobalStorage() && SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); @@ -1524,7 +1619,7 @@ public: } }; -class VarOrFuncDeclFilterCCC : public CorrectionCandidateCallback { +class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback { private: Sema &SemaRef; @@ -1568,12 +1663,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, << Id.getName(); return ExprError(); } - } else { - if (!(VD = Lookup.getAsSingle<VarDecl>())) { - Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName(); - Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); - return ExprError(); - } + } else if (!(VD = Lookup.getAsSingle<VarDecl>())) { + Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName(); + Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); + return ExprError(); } Lookup.suppressDiagnostics(); @@ -1591,7 +1684,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, } VarDecl *CanonicalVD = VD->getCanonicalDecl(); - NamedDecl *ND = cast<NamedDecl>(CanonicalVD); + NamedDecl *ND = CanonicalVD; // OpenMP [2.9.2, Restrictions, C/C++, p.2] // A threadprivate directive for file-scope variables must appear outside // any definition or declaration. @@ -1679,12 +1772,13 @@ Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, } namespace { -class LocalVarRefChecker : public ConstStmtVisitor<LocalVarRefChecker, bool> { +class LocalVarRefChecker final + : public ConstStmtVisitor<LocalVarRefChecker, bool> { Sema &SemaRef; public: bool VisitDeclRefExpr(const DeclRefExpr *E) { - if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { + if (const auto *VD = dyn_cast<VarDecl>(E->getDecl())) { if (VD->hasLocalStorage()) { SemaRef.Diag(E->getLocStart(), diag::err_omp_local_var_in_threadprivate_init) @@ -1697,7 +1791,7 @@ public: return false; } bool VisitStmt(const Stmt *S) { - for (auto Child : S->children()) { + for (const Stmt *Child : S->children()) { if (Child && Visit(Child)) return true; } @@ -1710,9 +1804,9 @@ public: OMPThreadPrivateDecl * Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { SmallVector<Expr *, 8> Vars; - for (auto &RefExpr : VarList) { - DeclRefExpr *DE = cast<DeclRefExpr>(RefExpr); - VarDecl *VD = cast<VarDecl>(DE->getDecl()); + for (Expr *RefExpr : VarList) { + auto *DE = cast<DeclRefExpr>(RefExpr); + auto *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); // Mark variable as used. @@ -1766,7 +1860,7 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { // Check if initial value of threadprivate variable reference variable with // local storage (it is not supported by runtime). - if (auto Init = VD->getAnyInitializer()) { + if (const Expr *Init = VD->getAnyInitializer()) { LocalVarRefChecker Checker(*this); if (Checker.Visit(Init)) continue; @@ -1776,7 +1870,7 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { DSAStack->addDSA(VD, DE, OMPC_threadprivate); VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( Context, SourceRange(Loc, Loc))); - if (auto *ML = Context.getASTMutationListener()) + if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPThreadPrivate(VD); } OMPThreadPrivateDecl *D = nullptr; @@ -1788,8 +1882,9 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { return D; } -static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, - const ValueDecl *D, DSAStackTy::DSAVarData DVar, +static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, + const ValueDecl *D, + const DSAStackTy::DSAVarData &DVar, bool IsLoopIterVar = false) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) @@ -1845,15 +1940,15 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, } namespace { -class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> { +class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { DSAStackTy *Stack; Sema &SemaRef; - bool ErrorFound; - CapturedStmt *CS; - llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; - llvm::SmallVector<Expr *, 8> ImplicitMap; - llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; - llvm::DenseSet<ValueDecl *> ImplicitDeclarations; + bool ErrorFound = false; + CapturedStmt *CS = nullptr; + llvm::SmallVector<Expr *, 4> ImplicitFirstprivate; + llvm::SmallVector<Expr *, 4> ImplicitMap; + Sema::VarsWithInheritedDSAType VarsWithInheritedDSA; + llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations; public: void VisitDeclRefExpr(DeclRefExpr *E) { @@ -1866,17 +1961,20 @@ public: if (VD->hasLocalStorage() && !CS->capturesVariable(VD)) return; - auto DVar = Stack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); // Check if the variable has explicit DSA set and stop analysis if it so. if (DVar.RefExpr || !ImplicitDeclarations.insert(VD).second) return; // Skip internally declared static variables. - if (VD->hasGlobalStorage() && !CS->capturesVariable(VD)) + llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + isDeclareTargetDeclaration(VD); + if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) && + (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) return; - auto ELoc = E->getExprLoc(); - auto DKind = Stack->getCurrentDirective(); + SourceLocation ELoc = E->getExprLoc(); + OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); // The default(none) clause requires that each variable that is referenced // in the construct, and does not have a predetermined data-sharing // attribute, must have its data-sharing attribute explicitly determined @@ -1919,7 +2017,7 @@ public: IsFirstprivate = IsFirstprivate || (VD->getType().getNonReferenceType()->isScalarType() && - Stack->getDefaultDMA() != DMA_tofrom_scalar); + Stack->getDefaultDMA() != DMA_tofrom_scalar && !Res); if (IsFirstprivate) ImplicitFirstprivate.emplace_back(E); else @@ -1933,8 +2031,8 @@ public: // enclosing worksharing or parallel construct may not be accessed in an // explicit task. DVar = Stack->hasInnermostDSA( - VD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, - [](OpenMPDirectiveKind K) -> bool { + VD, [](OpenMPClauseKind C) { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) { return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); }, @@ -1942,12 +2040,12 @@ public: if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); - ReportOriginalDSA(SemaRef, Stack, VD, DVar); + reportOriginalDsa(SemaRef, Stack, VD, DVar); return; } // Define implicit data-sharing attributes for task. - DVar = Stack->getImplicitDSA(VD, false); + DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false); if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && !Stack->isLoopControlVariable(VD).first) ImplicitFirstprivate.push_back(E); @@ -1962,7 +2060,7 @@ public: if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { if (!FD) return; - auto DVar = Stack->getTopDSA(FD, false); + DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false); // Check if the variable has explicit DSA set and stop analysis if it // so. if (DVar.RefExpr || !ImplicitDeclarations.insert(FD).second) @@ -1990,14 +2088,14 @@ public: return; } - auto ELoc = E->getExprLoc(); + SourceLocation ELoc = E->getExprLoc(); // OpenMP [2.9.3.6, Restrictions, p.2] // A list item that appears in a reduction clause of the innermost // enclosing worksharing or parallel construct may not be accessed in // an explicit task. DVar = Stack->hasInnermostDSA( - FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, - [](OpenMPDirectiveKind K) -> bool { + FD, [](OpenMPClauseKind C) { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) { return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); }, @@ -2005,12 +2103,12 @@ public: if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); - ReportOriginalDSA(SemaRef, Stack, FD, DVar); + reportOriginalDsa(SemaRef, Stack, FD, DVar); return; } // Define implicit data-sharing attributes for task. - DVar = Stack->getImplicitDSA(FD, false); + DVar = Stack->getImplicitDSA(FD, /*FromParent=*/false); if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && !Stack->isLoopControlVariable(FD).first) ImplicitFirstprivate.push_back(E); @@ -2018,10 +2116,10 @@ public: } if (isOpenMPTargetExecutionDirective(DKind)) { OMPClauseMappableExprCommon::MappableExprComponentList CurComponents; - if (!CheckMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map, + if (!checkMapClauseExpressionBase(SemaRef, E, CurComponents, OMPC_map, /*NoDiagnose=*/true)) return; - auto *VD = cast<ValueDecl>( + const auto *VD = cast<ValueDecl>( CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl()); if (!Stack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -2041,8 +2139,8 @@ public: CCI->getAssociatedExpression()))) return false; - Decl *CCD = CCI->getAssociatedDeclaration(); - Decl *SCD = SC.getAssociatedDeclaration(); + const Decl *CCD = CCI->getAssociatedDeclaration(); + const Decl *SCD = SC.getAssociatedDeclaration(); CCD = CCD ? CCD->getCanonicalDecl() : nullptr; SCD = SCD ? SCD->getCanonicalDecl() : nullptr; if (SCD != CCD) @@ -2055,18 +2153,19 @@ public: })) { Visit(E->getBase()); } - } else + } else { Visit(E->getBase()); + } } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { - for (auto *C : S->clauses()) { + for (OMPClause *C : S->clauses()) { // Skip analysis of arguments of implicitly defined firstprivate clause // for task|target directives. // Skip analysis of arguments of implicitly defined map clause for target // directives. if (C && !((isa<OMPFirstprivateClause>(C) || isa<OMPMapClause>(C)) && C->isImplicit())) { - for (auto *CC : C->children()) { + for (Stmt *CC : C->children()) { if (CC) Visit(CC); } @@ -2074,18 +2173,18 @@ public: } } void VisitStmt(Stmt *S) { - for (auto *C : S->children()) { + for (Stmt *C : S->children()) { if (C && !isa<OMPExecutableDirective>(C)) Visit(C); } } - bool isErrorFound() { return ErrorFound; } + bool isErrorFound() const { return ErrorFound; } ArrayRef<Expr *> getImplicitFirstprivate() const { return ImplicitFirstprivate; } ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; } - llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() { + const Sema::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const { return VarsWithInheritedDSA; } @@ -2103,7 +2202,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_teams: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { @@ -2121,15 +2220,37 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_target_parallel_for_simd: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, ParamsTarget); - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType ParamsTeamsOrParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), @@ -2141,6 +2262,37 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { ParamsTeamsOrParallel); break; } + case OMPD_target: + case OMPD_target_simd: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline)); + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + std::make_pair(StringRef(), QualType())); + break; + } case OMPD_simd: case OMPD_for: case OMPD_for_simd: @@ -2154,9 +2306,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_distribute_simd: case OMPD_ordered: case OMPD_atomic: - case OMPD_target_data: - case OMPD_target: - case OMPD_target_simd: { + case OMPD_target_data: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -2165,17 +2315,21 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_task: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {VoidPtrTy}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), - std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), - std::make_pair(".privates.", Context.VoidPtrTy.withConst()), - std::make_pair(".copy_fn.", - Context.getPointerType(CopyFnType).withConst()), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -2185,35 +2339,40 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); + Context, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_taskloop: case OMPD_taskloop_simd: { QualType KmpInt32Ty = - Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); + Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) + .withConst(); QualType KmpUInt64Ty = - Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0); + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0) + .withConst(); QualType KmpInt64Ty = - Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1); - QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1) + .withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {VoidPtrTy}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), - std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), - std::make_pair(".privates.", - Context.VoidPtrTy.withConst().withRestrict()), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), std::make_pair( ".copy_fn.", Context.getPointerType(CopyFnType).withConst().withRestrict()), std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), std::make_pair(".lb.", KmpUInt64Ty), - std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty), + std::make_pair(".ub.", KmpUInt64Ty), + std::make_pair(".st.", KmpInt64Ty), std::make_pair(".liter.", KmpInt32Ty), - std::make_pair(".reductions.", - Context.VoidPtrTy.withConst().withRestrict()), + std::make_pair(".reductions.", VoidPtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -2222,30 +2381,86 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); + Context, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(".previous.lb.", Context.getSizeType().withConst()), + std::make_pair(".previous.ub.", Context.getSizeType().withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + break; + } case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + + QualType Args[] = {VoidPtrTy}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline)); + Sema::CapturedParamNameType ParamsTarget[] = { + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'target' with no implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsTarget); + + Sema::CapturedParamNameType ParamsTeams[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(".previous.lb.", Context.getSizeType()), - std::make_pair(".previous.ub.", Context.getSizeType()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; + // Start a captured region for 'target' with no implicit parameters. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); + ParamsTeams); + + Sema::CapturedParamNameType ParamsParallel[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(".previous.lb.", Context.getSizeType().withConst()), + std::make_pair(".previous.ub.", Context.getSizeType().withConst()), + std::make_pair(StringRef(), QualType()) // __context with shared vars + }; + // Start a captured region for 'teams' or 'parallel'. Both regions have + // the same implicit parameters. + ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, + ParamsParallel); break; } + case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -2261,8 +2476,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Sema::CapturedParamNameType ParamsParallel[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(".previous.lb.", Context.getSizeType()), - std::make_pair(".previous.ub.", Context.getSizeType()), + std::make_pair(".previous.lb.", Context.getSizeType().withConst()), + std::make_pair(".previous.ub.", Context.getSizeType().withConst()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; // Start a captured region for 'teams' or 'parallel'. Both regions have @@ -2274,17 +2489,21 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_target_update: case OMPD_target_enter_data: case OMPD_target_exit_data: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); + QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict(); + QualType KmpInt32PtrTy = + Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {VoidPtrTy}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), - std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), - std::make_pair(".privates.", Context.VoidPtrTy.withConst()), - std::make_pair(".copy_fn.", - Context.getPointerType(CopyFnType).withConst()), + std::make_pair(".part_id.", KmpInt32PtrTy), + std::make_pair(".privates.", VoidPtrTy), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -2294,7 +2513,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); + Context, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_threadprivate: @@ -2343,7 +2562,7 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty, CaptureExpr->getLocStart()); if (!WithInit) - CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange())); + CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C)); S.CurContext->addHiddenDecl(CED); S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false); return CED; @@ -2352,12 +2571,11 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, bool WithInit) { OMPCapturedExprDecl *CD; - if (auto *VD = S.IsOpenMPCapturedDecl(D)) { + if (VarDecl *VD = S.isOpenMPCapturedDecl(D)) CD = cast<OMPCapturedExprDecl>(VD); - } else { + else CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit, /*AsExpression=*/false); - } return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), CaptureExpr->getExprLoc()); } @@ -2395,7 +2613,7 @@ class CaptureRegionUnwinderRAII { private: Sema &S; bool &ErrorFound; - OpenMPDirectiveKind DKind; + OpenMPDirectiveKind DKind = OMPD_unknown; public: CaptureRegionUnwinderRAII(Sema &S, bool &ErrorFound, @@ -2425,16 +2643,16 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective()); OMPOrderedClause *OC = nullptr; OMPScheduleClause *SC = nullptr; - SmallVector<OMPLinearClause *, 4> LCs; - SmallVector<OMPClauseWithPreInit *, 8> PICs; + SmallVector<const OMPLinearClause *, 4> LCs; + SmallVector<const OMPClauseWithPreInit *, 4> PICs; // This is required for proper codegen. - for (auto *Clause : Clauses) { + for (OMPClause *Clause : Clauses) { if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && Clause->getClauseKind() == OMPC_in_reduction) { // Capture taskgroup task_reduction descriptors inside the tasking regions // with the corresponding in_reduction items. auto *IRC = cast<OMPInReductionClause>(Clause); - for (auto *E : IRC->taskgroup_descriptors()) + for (Expr *E : IRC->taskgroup_descriptors()) if (E) MarkDeclarationsReferencedInExpr(E); } @@ -2445,7 +2663,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, Clause->getClauseKind() == OMPC_copyin)) { DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin); // Mark all variables in private list clauses as used in inner region. - for (auto *VarRef : Clause->children()) { + for (Stmt *VarRef : Clause->children()) { if (auto *E = cast_or_null<Expr>(VarRef)) { MarkDeclarationsReferencedInExpr(E); } @@ -2456,7 +2674,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, if (auto *C = OMPClauseWithPreInit::get(Clause)) PICs.push_back(C); if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { - if (auto *E = C->getPostUpdateExpr()) + if (Expr *E = C->getPostUpdateExpr()) MarkDeclarationsReferencedInExpr(E); } } @@ -2483,7 +2701,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ErrorFound = true; } if (!LCs.empty() && OC && OC->getNumForLoops()) { - for (auto *C : LCs) { + for (const OMPLinearClause *C : LCs) { Diag(C->getLocStart(), diag::err_omp_linear_ordered) << SourceRange(OC->getLocStart(), OC->getLocEnd()); } @@ -2505,7 +2723,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, // Required for proper codegen of combined directives. // TODO: add processing for other clauses. if (ThisCaptureRegion != OMPD_unknown) { - for (auto *C : PICs) { + for (const clang::OMPClauseWithPreInit *C : PICs) { OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion(); // Find the particular capture region for the clause if the // directive is a combined one with multiple capture regions. @@ -2515,7 +2733,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, if (CaptureRegion == ThisCaptureRegion || CaptureRegion == OMPD_unknown) { if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) { - for (auto *D : DS->decls()) + for (Decl *D : DS->decls()) MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D)); } } @@ -2542,14 +2760,14 @@ static bool checkCancelRegion(Sema &SemaRef, OpenMPDirectiveKind CurrentRegion, return true; } -static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, +static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, OpenMPDirectiveKind CurrentRegion, const DeclarationNameInfo &CurrentName, OpenMPDirectiveKind CancelRegion, SourceLocation StartLoc) { if (Stack->getCurScope()) { - auto ParentRegion = Stack->getParentDirective(); - auto OffendingRegion = ParentRegion; + OpenMPDirectiveKind ParentRegion = Stack->getParentDirective(); + OpenMPDirectiveKind OffendingRegion = ParentRegion; bool NestingProhibited = false; bool CloseNesting = true; bool OrphanSeen = false; @@ -2642,12 +2860,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, bool DeadLock = Stack->hasDirective( [CurrentName, &PreviousCriticalLoc](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, - SourceLocation Loc) -> bool { + SourceLocation Loc) { if (K == OMPD_critical && DNI.getName() == CurrentName.getName()) { PreviousCriticalLoc = Loc; return true; - } else - return false; + } + return false; }, false /* skip top directive */); if (DeadLock) { @@ -2732,12 +2950,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // target region, the behavior is unspecified. NestingProhibited = Stack->hasDirective( [&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &, - SourceLocation) -> bool { + SourceLocation) { if (isOpenMPTargetExecutionDirective(K)) { OffendingRegion = K; return true; - } else - return false; + } + return false; }, false /* don't skip top directive */); CloseNesting = false; @@ -2765,7 +2983,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers( OMPD_unknown + 1); SmallVector<SourceLocation, 4> NameModifierLoc; - for (const auto *C : Clauses) { + for (const OMPClause *C : Clauses) { if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) { // At most one if clause without a directive-name-modifier can appear on // the directive. @@ -2831,7 +3049,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, diag::err_omp_unnamed_if_clause) << (TotalAllowedNum > 1) << Values; } - for (auto Loc : NameModifierLoc) { + for (SourceLocation Loc : NameModifierLoc) { S.Diag(Loc, diag::note_omp_previous_named_if_clause); } ErrorFound = true; @@ -2851,7 +3069,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( return StmtError(); llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; - llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; + VarsWithInheritedDSAType VarsWithInheritedDSA; bool ErrorFound = false; ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); if (AStmt && !CurContext->isDependentContext()) { @@ -2875,9 +3093,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(), DSAChecker.getImplicitMap().end()); // Mark taskgroup task_reduction descriptors as implicitly firstprivate. - for (auto *C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) { - for (auto *E : IRC->taskgroup_descriptors()) + for (Expr *E : IRC->taskgroup_descriptors()) if (E) ImplicitFirstprivates.emplace_back(E); } @@ -2889,8 +3107,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( ClausesWithImplicit.push_back(Implicit); ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() != ImplicitFirstprivates.size(); - } else + } else { ErrorFound = true; + } } if (!ImplicitMaps.empty()) { if (OMPClause *Implicit = ActOnOpenMPMapClause( @@ -2900,8 +3119,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( ClausesWithImplicit.emplace_back(Implicit); ErrorFound |= cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size(); - } else + } else { ErrorFound = true; + } } } @@ -3153,7 +3373,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( llvm_unreachable("Unknown OpenMP directive"); } - for (auto P : VarsWithInheritedDSA) { + for (const auto &P : VarsWithInheritedDSA) { Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); } @@ -3183,7 +3403,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); return DG; } - auto *ADecl = DG.get().getSingleDecl(); + Decl *ADecl = DG.get().getSingleDecl(); if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) ADecl = FTD->getTemplatedDecl(); @@ -3205,16 +3425,16 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( // The uniform clause declares one or more arguments to have an invariant // value for all concurrent invocations of the function in the execution of a // single SIMD loop. - llvm::DenseMap<Decl *, Expr *> UniformedArgs; - Expr *UniformedLinearThis = nullptr; - for (auto *E : Uniforms) { + llvm::DenseMap<const Decl *, const Expr *> UniformedArgs; + const Expr *UniformedLinearThis = nullptr; + for (const Expr *E : Uniforms) { E = E->IgnoreParenImpCasts(); - if (auto *DRE = dyn_cast<DeclRefExpr>(E)) - if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) if (FD->getNumParams() > PVD->getFunctionScopeIndex() && FD->getParamDecl(PVD->getFunctionScopeIndex()) ->getCanonicalDecl() == PVD->getCanonicalDecl()) { - UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E)); + UniformedArgs.try_emplace(PVD->getCanonicalDecl(), E); continue; } if (isa<CXXThisExpr>(E)) { @@ -3232,13 +3452,13 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( // function in any of the linear, aligned, or uniform clauses. // The type of list items appearing in the aligned clause must be array, // pointer, reference to array, or reference to pointer. - llvm::DenseMap<Decl *, Expr *> AlignedArgs; - Expr *AlignedThis = nullptr; - for (auto *E : Aligneds) { + llvm::DenseMap<const Decl *, const Expr *> AlignedArgs; + const Expr *AlignedThis = nullptr; + for (const Expr *E : Aligneds) { E = E->IgnoreParenImpCasts(); - if (auto *DRE = dyn_cast<DeclRefExpr>(E)) - if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { - auto *CanonPVD = PVD->getCanonicalDecl(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + const VarDecl *CanonPVD = PVD->getCanonicalDecl(); if (FD->getNumParams() > PVD->getFunctionScopeIndex() && FD->getParamDecl(PVD->getFunctionScopeIndex()) ->getCanonicalDecl() == CanonPVD) { @@ -3283,8 +3503,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( // positive integer expression. If no optional parameter is specified, // implementation-defined default alignments for SIMD instructions on the // target platforms are assumed. - SmallVector<Expr *, 4> NewAligns; - for (auto *E : Alignments) { + SmallVector<const Expr *, 4> NewAligns; + for (Expr *E : Alignments) { ExprResult Align; if (E) Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned); @@ -3299,16 +3519,16 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( // When a linear-step expression is specified in a linear clause it must be // either a constant integer expression or an integer-typed parameter that is // specified in a uniform clause on the directive. - llvm::DenseMap<Decl *, Expr *> LinearArgs; + llvm::DenseMap<const Decl *, const Expr *> LinearArgs; const bool IsUniformedThis = UniformedLinearThis != nullptr; auto MI = LinModifiers.begin(); - for (auto *E : Linears) { + for (const Expr *E : Linears) { auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI); ++MI; E = E->IgnoreParenImpCasts(); - if (auto *DRE = dyn_cast<DeclRefExpr>(E)) - if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { - auto *CanonPVD = PVD->getCanonicalDecl(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + const VarDecl *CanonPVD = PVD->getCanonicalDecl(); if (FD->getNumParams() > PVD->getFunctionScopeIndex() && FD->getParamDecl(PVD->getFunctionScopeIndex()) ->getCanonicalDecl() == CanonPVD) { @@ -3368,25 +3588,25 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( Expr *Step = nullptr; Expr *NewStep = nullptr; SmallVector<Expr *, 4> NewSteps; - for (auto *E : Steps) { + for (Expr *E : Steps) { // Skip the same step expression, it was checked already. if (Step == E || !E) { NewSteps.push_back(E ? NewStep : nullptr); continue; } Step = E; - if (auto *DRE = dyn_cast<DeclRefExpr>(Step)) - if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { - auto *CanonPVD = PVD->getCanonicalDecl(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(Step)) + if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + const VarDecl *CanonPVD = PVD->getCanonicalDecl(); if (UniformedArgs.count(CanonPVD) == 0) { Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param) << Step->getSourceRange(); } else if (E->isValueDependent() || E->isTypeDependent() || E->isInstantiationDependent() || E->containsUnexpandedParameterPack() || - CanonPVD->getType()->hasIntegerRepresentation()) + CanonPVD->getType()->hasIntegerRepresentation()) { NewSteps.push_back(Step); - else { + } else { Diag(Step->getExprLoc(), diag::err_omp_expected_int_param) << Step->getSourceRange(); } @@ -3421,7 +3641,7 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -3429,108 +3649,110 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); } namespace { -/// \brief Helper class for checking canonical form of the OpenMP loops and +/// Helper class for checking canonical form of the OpenMP loops and /// extracting iteration space of each loop in the loop nest, that will be used /// for IR generation. class OpenMPIterationSpaceChecker { - /// \brief Reference to Sema. + /// Reference to Sema. Sema &SemaRef; - /// \brief A location for diagnostics (when there is no some better location). + /// A location for diagnostics (when there is no some better location). SourceLocation DefaultLoc; - /// \brief A location for diagnostics (when increment is not compatible). + /// A location for diagnostics (when increment is not compatible). SourceLocation ConditionLoc; - /// \brief A source location for referring to loop init later. + /// A source location for referring to loop init later. SourceRange InitSrcRange; - /// \brief A source location for referring to condition later. + /// A source location for referring to condition later. SourceRange ConditionSrcRange; - /// \brief A source location for referring to increment later. + /// A source location for referring to increment later. SourceRange IncrementSrcRange; - /// \brief Loop variable. + /// Loop variable. ValueDecl *LCDecl = nullptr; - /// \brief Reference to loop variable. + /// Reference to loop variable. Expr *LCRef = nullptr; - /// \brief Lower bound (initializer for the var). + /// Lower bound (initializer for the var). Expr *LB = nullptr; - /// \brief Upper bound. + /// Upper bound. Expr *UB = nullptr; - /// \brief Loop step (increment). + /// Loop step (increment). Expr *Step = nullptr; - /// \brief This flag is true when condition is one of: + /// This flag is true when condition is one of: /// Var < UB /// Var <= UB /// UB > Var /// UB >= Var bool TestIsLessOp = false; - /// \brief This flag is true when condition is strict ( < or > ). + /// This flag is true when condition is strict ( < or > ). bool TestIsStrictOp = false; - /// \brief This flag is true when step is subtracted on each iteration. + /// This flag is true when step is subtracted on each iteration. bool SubtractStep = false; public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} - /// \brief Check init-expr for canonical loop form and save loop counter + /// Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. - bool CheckInit(Stmt *S, bool EmitDiags = true); - /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags + bool checkAndSetInit(Stmt *S, bool EmitDiags = true); + /// Check test-expr for canonical form, save upper-bound (#UB), flags /// for less/greater and for strict/non-strict comparison. - bool CheckCond(Expr *S); - /// \brief Check incr-expr for canonical loop form and return true if it + bool checkAndSetCond(Expr *S); + /// Check incr-expr for canonical loop form and return true if it /// does not conform, otherwise save loop step (#Step). - bool CheckInc(Expr *S); - /// \brief Return the loop counter variable. - ValueDecl *GetLoopDecl() const { return LCDecl; } - /// \brief Return the reference expression to loop counter variable. - Expr *GetLoopDeclRefExpr() const { return LCRef; } - /// \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. + bool checkAndSetInc(Expr *S); + /// Return the loop counter variable. + ValueDecl *getLoopDecl() const { return LCDecl; } + /// Return the reference expression to loop counter variable. + Expr *getLoopDeclRefExpr() const { return LCRef; } + /// Source range of the loop init. + SourceRange getInitSrcRange() const { return InitSrcRange; } + /// Source range of the loop condition. + SourceRange getConditionSrcRange() const { return ConditionSrcRange; } + /// Source range of the loop increment. + SourceRange getIncrementSrcRange() const { return IncrementSrcRange; } + /// True if the step should be subtracted. + bool shouldSubtractStep() const { return SubtractStep; } + /// Build the expression to calculate the number of iterations. + Expr *buildNumIterations( + Scope *S, const bool LimitedType, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; + /// Build the precondition expression for the loops. Expr * - BuildNumIterations(Scope *S, const bool LimitedType, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; - /// \brief Build the precondition expression for the loops. - Expr *BuildPreCond(Scope *S, Expr *Cond, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; - /// \brief Build reference expression to the counter be used for codegen. - DeclRefExpr *BuildCounterVar(llvm::MapVector<Expr *, DeclRefExpr *> &Captures, - DSAStackTy &DSA) const; - /// \brief Build reference expression to the private counter be used for + buildPreCond(Scope *S, Expr *Cond, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const; + /// Build reference expression to the counter be used for codegen. + DeclRefExpr * + buildCounterVar(llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, + DSAStackTy &DSA) const; + /// Build reference expression to the private counter be used for /// codegen. - Expr *BuildPrivateCounterVar() const; - /// \brief Build initialization 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; + Expr *buildPrivateCounterVar() const; + /// Build initialization of the counter be used for codegen. + Expr *buildCounterInit() const; + /// Build step of the counter be used for codegen. + Expr *buildCounterStep() const; + /// Return true if any expression is dependent. + bool dependent() const; private: - /// \brief Check the right-hand side of an assignment in the increment + /// Check the right-hand side of an assignment in the increment /// expression. - bool CheckIncRHS(Expr *RHS); - /// \brief Helper to set loop counter variable and its initializer. - bool SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); - /// \brief Helper to set upper bound. - bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, + bool checkAndSetIncRHS(Expr *RHS); + /// Helper to set loop counter variable and its initializer. + bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); + /// Helper to set upper bound. + bool setUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); - /// \brief Helper to set loop increment. - bool SetStep(Expr *NewStep, bool Subtract); + /// Helper to set loop increment. + bool setStep(Expr *NewStep, bool Subtract); }; -bool OpenMPIterationSpaceChecker::Dependent() const { +bool OpenMPIterationSpaceChecker::dependent() const { if (!LCDecl) { assert(!LB && !UB && !Step); return false; @@ -3540,7 +3762,7 @@ bool OpenMPIterationSpaceChecker::Dependent() const { (Step && Step->isValueDependent()); } -bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, +bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewLCRefExpr, Expr *NewLB) { // State consistency checking to ensure correct usage. @@ -3560,7 +3782,7 @@ bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, return false; } -bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, +bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && @@ -3575,7 +3797,7 @@ bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, return false; } -bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { +bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); if (!NewStep) @@ -3632,7 +3854,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { return false; } -bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { +bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { // Check init-expr for canonical loop form and save loop counter // variable - #Var and its initialization value - #LB. // OpenMP [2.6] Canonical loop form. init-expr may be one of the following: @@ -3656,17 +3878,17 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { S = E->IgnoreParens(); if (auto *BO = dyn_cast<BinaryOperator>(S)) { if (BO->getOpcode() == BO_Assign) { - auto *LHS = BO->getLHS()->IgnoreParens(); + Expr *LHS = BO->getLHS()->IgnoreParens(); if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return SetLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); } } } else if (auto *DS = dyn_cast<DeclStmt>(S)) { @@ -3678,28 +3900,28 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); - return SetLCDeclAndLB(Var, nullptr, Var->getInit()); + return setLCDeclAndLB(Var, nullptr, Var->getInit()); } } } } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { if (CE->getOperator() == OO_Equal) { - auto *LHS = CE->getArg(0); + Expr *LHS = CE->getArg(0); if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) - return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); - return SetLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); } if (auto *ME = dyn_cast<MemberExpr>(LHS)) { if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) - return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); } } } - if (Dependent() || SemaRef.CurContext->isDependentContext()) + if (dependent() || SemaRef.CurContext->isDependentContext()) return false; if (EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) @@ -3708,29 +3930,29 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { return true; } -/// \brief Ignore parenthesizes, implicit casts, copy constructor and return the +/// Ignore parenthesizes, implicit casts, copy constructor and return the /// variable (which may be the loop variable) if possible. -static const ValueDecl *GetInitLCDecl(Expr *E) { +static const ValueDecl *getInitLCDecl(const Expr *E) { if (!E) return nullptr; E = getExprAsWritten(E); - if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(E)) + if (const auto *CE = dyn_cast_or_null<CXXConstructExpr>(E)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); - if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) { - if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) { + if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) return getCanonicalDecl(VD); } - if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) + if (const auto *ME = dyn_cast_or_null<MemberExpr>(E)) if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) return getCanonicalDecl(ME->getMemberDecl()); return nullptr; } -bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { +bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { // Check test-expr for canonical form, save upper-bound UB, flags for // less/greater and for strict/non-strict comparison. // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: @@ -3745,13 +3967,13 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { SourceLocation CondLoc = S->getLocStart(); if (auto *BO = dyn_cast<BinaryOperator>(S)) { if (BO->isRelationalOp()) { - if (GetInitLCDecl(BO->getLHS()) == LCDecl) - return SetUB(BO->getRHS(), + if (getInitLCDecl(BO->getLHS()) == LCDecl) + return setUB(BO->getRHS(), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - if (GetInitLCDecl(BO->getRHS()) == LCDecl) - return SetUB(BO->getLHS(), + if (getInitLCDecl(BO->getRHS()) == LCDecl) + return setUB(BO->getLHS(), (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); @@ -3764,12 +3986,12 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { case OO_GreaterEqual: case OO_Less: case OO_LessEqual: - if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, + if (getInitLCDecl(CE->getArg(0)) == LCDecl) + return setUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); - if (GetInitLCDecl(CE->getArg(1)) == LCDecl) - return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, + if (getInitLCDecl(CE->getArg(1)) == LCDecl) + return setUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); break; @@ -3778,14 +4000,14 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { } } } - if (Dependent() || SemaRef.CurContext->isDependentContext()) + if (dependent() || SemaRef.CurContext->isDependentContext()) return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) << S->getSourceRange() << LCDecl; return true; } -bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { +bool OpenMPIterationSpaceChecker::checkAndSetIncRHS(Expr *RHS) { // RHS of canonical loop form increment can be: // var + incr // incr + var @@ -3795,28 +4017,28 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { if (auto *BO = dyn_cast<BinaryOperator>(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; - if (GetInitLCDecl(BO->getLHS()) == LCDecl) - return SetStep(BO->getRHS(), !IsAdd); - if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl) - return SetStep(BO->getLHS(), false); + if (getInitLCDecl(BO->getLHS()) == LCDecl) + return setStep(BO->getRHS(), !IsAdd); + if (IsAdd && getInitLCDecl(BO->getRHS()) == LCDecl) + return setStep(BO->getLHS(), /*Subtract=*/false); } } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { - if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return SetStep(CE->getArg(1), !IsAdd); - if (IsAdd && GetInitLCDecl(CE->getArg(1)) == LCDecl) - return SetStep(CE->getArg(0), false); + if (getInitLCDecl(CE->getArg(0)) == LCDecl) + return setStep(CE->getArg(1), !IsAdd); + if (IsAdd && getInitLCDecl(CE->getArg(1)) == LCDecl) + return setStep(CE->getArg(0), /*Subtract=*/false); } } - if (Dependent() || SemaRef.CurContext->isDependentContext()) + if (dependent() || SemaRef.CurContext->isDependentContext()) return false; SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) << RHS->getSourceRange() << LCDecl; return true; } -bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { +bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) { // Check incr-expr for canonical loop form and return true if it // does not conform. // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following: @@ -3842,22 +4064,22 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { S = S->IgnoreParens(); if (auto *UO = dyn_cast<UnaryOperator>(S)) { if (UO->isIncrementDecrementOp() && - GetInitLCDecl(UO->getSubExpr()) == LCDecl) - return SetStep(SemaRef + getInitLCDecl(UO->getSubExpr()) == LCDecl) + return setStep(SemaRef .ActOnIntegerConstant(UO->getLocStart(), (UO->isDecrementOp() ? -1 : 1)) .get(), - false); + /*Subtract=*/false); } else if (auto *BO = dyn_cast<BinaryOperator>(S)) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: - if (GetInitLCDecl(BO->getLHS()) == LCDecl) - return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); + if (getInitLCDecl(BO->getLHS()) == LCDecl) + return setStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); break; case BO_Assign: - if (GetInitLCDecl(BO->getLHS()) == LCDecl) - return CheckIncRHS(BO->getRHS()); + if (getInitLCDecl(BO->getLHS()) == LCDecl) + return checkAndSetIncRHS(BO->getRHS()); break; default: break; @@ -3866,28 +4088,28 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: - if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return SetStep(SemaRef + if (getInitLCDecl(CE->getArg(0)) == LCDecl) + return setStep(SemaRef .ActOnIntegerConstant( CE->getLocStart(), ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)) .get(), - false); + /*Subtract=*/false); break; case OO_PlusEqual: case OO_MinusEqual: - if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); + if (getInitLCDecl(CE->getArg(0)) == LCDecl) + return setStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); break; case OO_Equal: - if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return CheckIncRHS(CE->getArg(1)); + if (getInitLCDecl(CE->getArg(0)) == LCDecl) + return checkAndSetIncRHS(CE->getArg(1)); break; default: break; } } - if (Dependent() || SemaRef.CurContext->isDependentContext()) + if (dependent() || SemaRef.CurContext->isDependentContext()) return false; SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) << S->getSourceRange() << LCDecl; @@ -3896,7 +4118,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { static ExprResult tryBuildCapture(Sema &SemaRef, Expr *Capture, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { if (SemaRef.CurContext->isDependentContext()) return ExprResult(Capture); if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) @@ -3912,17 +4134,17 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, return Res; } -/// \brief Build the expression to calculate the number of iterations. -Expr *OpenMPIterationSpaceChecker::BuildNumIterations( +/// Build the expression to calculate the number of iterations. +Expr *OpenMPIterationSpaceChecker::buildNumIterations( Scope *S, const bool LimitedType, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { ExprResult Diff; - auto VarType = LCDecl->getType().getNonReferenceType(); + QualType VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower - auto *UBExpr = TestIsLessOp ? UB : LB; - auto *LBExpr = TestIsLessOp ? LB : UB; + Expr *UBExpr = TestIsLessOp ? UB : LB; + Expr *LBExpr = TestIsLessOp ? LB : UB; Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) @@ -3951,7 +4173,7 @@ Expr *OpenMPIterationSpaceChecker::BuildNumIterations( return nullptr; // Upper - Lower [- 1] + Step - auto NewStep = tryBuildCapture(SemaRef, Step, Captures); + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); if (!NewStep.isUsable()) return nullptr; Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); @@ -3970,7 +4192,7 @@ Expr *OpenMPIterationSpaceChecker::BuildNumIterations( // OpenMP runtime requires 32-bit or 64-bit loop variables. QualType Type = Diff.get()->getType(); - auto &C = SemaRef.Context; + ASTContext &C = SemaRef.Context; bool UseVarType = VarType->hasIntegerRepresentation() && C.getTypeSize(Type) > C.getTypeSize(VarType); if (!Type->isIntegerType() || UseVarType) { @@ -4009,22 +4231,23 @@ Expr *OpenMPIterationSpaceChecker::BuildNumIterations( return Diff.get(); } -Expr *OpenMPIterationSpaceChecker::BuildPreCond( +Expr *OpenMPIterationSpaceChecker::buildPreCond( Scope *S, Expr *Cond, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { // Try to build LB <op> UB, where <op> is <, >, <=, or >=. bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - auto NewLB = tryBuildCapture(SemaRef, LB, Captures); - auto NewUB = tryBuildCapture(SemaRef, UB, Captures); + ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures); + ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures); if (!NewLB.isUsable() || !NewUB.isUsable()) return nullptr; - auto CondExpr = SemaRef.BuildBinOp( - S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) - : (TestIsStrictOp ? BO_GT : BO_GE), - NewLB.get(), NewUB.get()); + ExprResult CondExpr = + SemaRef.BuildBinOp(S, DefaultLoc, + TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) + : (TestIsStrictOp ? BO_GT : BO_GE), + NewLB.get(), NewUB.get()); if (CondExpr.isUsable()) { if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(), SemaRef.Context.BoolTy)) @@ -4037,15 +4260,16 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond( return CondExpr.isUsable() ? CondExpr.get() : Cond; } -/// \brief Build reference expression to the counter be used for codegen. -DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( - llvm::MapVector<Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const { +/// Build reference expression to the counter be used for codegen. +DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar( + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const { auto *VD = dyn_cast<VarDecl>(LCDecl); if (!VD) { - VD = SemaRef.IsOpenMPCapturedDecl(LCDecl); - auto *Ref = buildDeclRefExpr( + VD = SemaRef.isOpenMPCapturedDecl(LCDecl); + DeclRefExpr *Ref = buildDeclRefExpr( SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); - DSAStackTy::DSAVarData Data = DSA.getTopDSA(LCDecl, /*FromParent=*/false); + const DSAStackTy::DSAVarData Data = + DSA.getTopDSA(LCDecl, /*FromParent=*/false); // If the loop control decl is explicitly marked as private, do not mark it // as captured again. if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr) @@ -4056,12 +4280,15 @@ DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( DefaultLoc); } -Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { +Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const { if (LCDecl && !LCDecl->isInvalidDecl()) { - auto Type = LCDecl->getType().getNonReferenceType(); - auto *PrivateVar = - buildVarDecl(SemaRef, DefaultLoc, Type, LCDecl->getName(), - LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr); + QualType Type = LCDecl->getType().getNonReferenceType(); + VarDecl *PrivateVar = buildVarDecl( + SemaRef, DefaultLoc, Type, LCDecl->getName(), + LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr, + isa<VarDecl>(LCDecl) + ? buildDeclRefExpr(SemaRef, cast<VarDecl>(LCDecl), Type, DefaultLoc) + : nullptr); if (PrivateVar->isInvalidDecl()) return nullptr; return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); @@ -4069,35 +4296,35 @@ Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { return nullptr; } -/// \brief Build initialization of the counter to be used for codegen. -Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } +/// Build initialization of the counter to 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; } +/// Build step of the counter be used for codegen. +Expr *OpenMPIterationSpaceChecker::buildCounterStep() const { return Step; } -/// \brief Iteration space of a single for loop. +/// Iteration space of a single for loop. struct LoopIterationSpace final { - /// \brief Condition of the loop. + /// Condition of the loop. Expr *PreCond = nullptr; - /// \brief This expression calculates the number of iterations in the loop. + /// This expression calculates the number of iterations in the loop. /// It is always possible to calculate it before starting the loop. Expr *NumIterations = nullptr; - /// \brief The loop counter variable. + /// The loop counter variable. Expr *CounterVar = nullptr; - /// \brief Private loop counter variable. + /// Private loop counter variable. Expr *PrivateCounterVar = nullptr; - /// \brief This is initializer for the initial value of #CounterVar. + /// This is initializer for the initial value of #CounterVar. Expr *CounterInit = nullptr; - /// \brief This is step for the #CounterVar used to generate its update: + /// This is step for the #CounterVar used to generate its update: /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. Expr *CounterStep = nullptr; - /// \brief Should step be subtracted? + /// Should step be subtracted? bool Subtract = false; - /// \brief Source range of the loop init. + /// Source range of the loop init. SourceRange InitSrcRange; - /// \brief Source range of the loop condition. + /// Source range of the loop condition. SourceRange CondSrcRange; - /// \brief Source range of the loop increment. + /// Source range of the loop increment. SourceRange IncSrcRange; }; @@ -4110,15 +4337,15 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); - if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { - if (auto *D = ISC.GetLoopDecl()) { + if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { + if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast<VarDecl>(D); if (!VD) { - if (auto *Private = IsOpenMPCapturedDecl(D)) + if (VarDecl *Private = isOpenMPCapturedDecl(D)) { VD = Private; - else { - auto *Ref = buildCapture(*this, D, ISC.GetLoopDeclRefExpr(), - /*WithInit=*/false); + } else { + DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), + /*WithInit=*/false); VD = cast<VarDecl>(Ref->getDecl()); } } @@ -4129,15 +4356,15 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { } } -/// \brief Called on a for stmt to check and extract its iteration space +/// Called on a for stmt to check and extract its iteration space /// for further processing (such as collapsing). -static bool CheckOpenMPIterationSpace( +static bool checkOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, + Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, LoopIterationSpace &ResultIterSpace, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block auto *For = dyn_cast_or_null<ForStmt>(S); @@ -4168,22 +4395,22 @@ static bool CheckOpenMPIterationSpace( OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc()); // Check init. - auto Init = For->getInit(); - if (ISC.CheckInit(Init)) + Stmt *Init = For->getInit(); + if (ISC.checkAndSetInit(Init)) return true; bool HasErrors = false; // Check loop variable's type. - if (auto *LCDecl = ISC.GetLoopDecl()) { - auto *LoopDeclRefExpr = ISC.GetLoopDeclRefExpr(); + if (ValueDecl *LCDecl = ISC.getLoopDecl()) { + Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); // OpenMP [2.6, Canonical Loop Form] // Var is one of the following: // A variable of signed or unsigned integer type. // For C++, a variable of a random access iterator type. // For C, a variable of a pointer type. - auto VarType = LCDecl->getType().getNonReferenceType(); + QualType VarType = LCDecl->getType().getNonReferenceType(); if (!VarType->isDependentType() && !VarType->isIntegerType() && !VarType->isPointerType() && !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { @@ -4214,7 +4441,7 @@ static bool CheckOpenMPIterationSpace( DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); // If LoopVarRefExpr is nullptr it means the corresponding loop variable is // declared in the loop and it is predetermined as a private. - auto PredeterminedCKind = + OpenMPClauseKind PredeterminedCKind = isOpenMPSimdDirective(DKind) ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; @@ -4230,7 +4457,7 @@ static bool CheckOpenMPIterationSpace( << getOpenMPClauseName(PredeterminedCKind); if (DVar.RefExpr == nullptr) DVar.CKind = PredeterminedCKind; - ReportOriginalDSA(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); + reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); HasErrors = true; } else if (LoopDeclRefExpr != nullptr) { // Make the loop iteration variable private (for worksharing constructs), @@ -4247,31 +4474,31 @@ static bool CheckOpenMPIterationSpace( assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); // Check test-expr. - HasErrors |= ISC.CheckCond(For->getCond()); + HasErrors |= ISC.checkAndSetCond(For->getCond()); // Check incr-expr. - HasErrors |= ISC.CheckInc(For->getInc()); + HasErrors |= ISC.checkAndSetInc(For->getInc()); } - if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) + if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. ResultIterSpace.PreCond = - ISC.BuildPreCond(DSA.getCurScope(), For->getCond(), Captures); - ResultIterSpace.NumIterations = ISC.BuildNumIterations( + ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures); + ResultIterSpace.NumIterations = ISC.buildNumIterations( DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), Captures); - ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures, DSA); - ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); - ResultIterSpace.CounterInit = ISC.BuildCounterInit(); - ResultIterSpace.CounterStep = ISC.BuildCounterStep(); - ResultIterSpace.InitSrcRange = ISC.GetInitSrcRange(); - ResultIterSpace.CondSrcRange = ISC.GetConditionSrcRange(); - ResultIterSpace.IncSrcRange = ISC.GetIncrementSrcRange(); - ResultIterSpace.Subtract = ISC.ShouldSubtractStep(); + ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA); + ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar(); + 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.PreCond == nullptr || ResultIterSpace.NumIterations == nullptr || @@ -4283,13 +4510,13 @@ static bool CheckOpenMPIterationSpace( return HasErrors; } -/// \brief Build 'VarRef = Start. +/// Build 'VarRef = Start. static ExprResult -BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, +buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, ExprResult Start, - llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { // Build 'VarRef = Start. - auto NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), @@ -4301,17 +4528,16 @@ BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, return ExprError(); } - auto Init = + ExprResult Init = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); return Init; } -/// \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, - llvm::MapVector<Expr *, DeclRefExpr *> *Captures = nullptr) { +/// Build 'VarRef = Start + Iter * Step'. +static ExprResult buildCounterUpdate( + Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, + ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract, + llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() || @@ -4378,12 +4604,12 @@ BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, return Update; } -/// \brief Convert integer expression \a E to make it have at least \a Bits +/// Convert integer expression \a E to make it have at least \a Bits /// bits. -static ExprResult WidenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { +static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { if (E == nullptr) return ExprError(); - auto &C = SemaRef.Context; + ASTContext &C = SemaRef.Context; QualType OldType = E->getType(); unsigned HasBits = C.getTypeSize(OldType); if (HasBits >= Bits) @@ -4394,9 +4620,9 @@ static ExprResult WidenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { true); } -/// \brief Check if the given expression \a E is a constant integer that fits +/// 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) { +static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) { if (E == nullptr) return false; llvm::APSInt Result; @@ -4419,10 +4645,10 @@ static Stmt *buildPreInits(ASTContext &Context, /// Build preinits statement for the given declarations. static Stmt * buildPreInits(ASTContext &Context, - const llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + const llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { if (!Captures.empty()) { SmallVector<Decl *, 16> PreInits; - for (auto &Pair : Captures) + for (const auto &Pair : Captures) PreInits.push_back(Pair.second->getDecl()); return buildPreInits(Context, PreInits); } @@ -4433,7 +4659,7 @@ buildPreInits(ASTContext &Context, static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) { Expr *PostUpdate = nullptr; if (!PostUpdates.empty()) { - for (auto *E : PostUpdates) { + for (Expr *E : PostUpdates) { Expr *ConvE = S.BuildCStyleCastExpr( E->getExprLoc(), S.Context.getTrivialTypeSourceInfo(S.Context.VoidTy), @@ -4449,14 +4675,14 @@ static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) { return PostUpdate; } -/// \brief Called on a for stmt to check itself and nested loops (if any). +/// Called on a for stmt to check itself and nested loops (if any). /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, /// number of collapsed loops otherwise. static unsigned -CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, +checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, + Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; if (CollapseLoopCountExpr) { @@ -4482,12 +4708,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; 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, + if (checkOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, CollapseLoopCountExpr, OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt], Captures)) @@ -4537,26 +4763,28 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Precondition tests if there is at least one iteration (all conditions are // true). auto PreCond = ExprResult(IterSpaces[0].PreCond); - auto N0 = IterSpaces[0].NumIterations; - ExprResult LastIteration32 = WidenIterationCount( - 32 /* Bits */, SemaRef - .PerformImplicitConversion( - N0->IgnoreImpCasts(), N0->getType(), - Sema::AA_Converting, /*AllowExplicit=*/true) - .get(), - SemaRef); - ExprResult LastIteration64 = WidenIterationCount( - 64 /* Bits */, SemaRef - .PerformImplicitConversion( - N0->IgnoreImpCasts(), N0->getType(), - Sema::AA_Converting, /*AllowExplicit=*/true) - .get(), + Expr *N0 = IterSpaces[0].NumIterations; + ExprResult LastIteration32 = + widenIterationCount(/*Bits=*/32, + SemaRef + .PerformImplicitConversion( + N0->IgnoreImpCasts(), N0->getType(), + Sema::AA_Converting, /*AllowExplicit=*/true) + .get(), + SemaRef); + ExprResult LastIteration64 = widenIterationCount( + /*Bits=*/64, + SemaRef + .PerformImplicitConversion(N0->IgnoreImpCasts(), N0->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true) + .get(), SemaRef); if (!LastIteration32.isUsable() || !LastIteration64.isUsable()) return NestedLoopCount; - auto &C = SemaRef.Context; + ASTContext &C = SemaRef.Context; bool AllCountsNeedLessThan32Bits = C.getTypeSize(N0->getType()) < 32; Scope *CurScope = DSA.getCurScope(); @@ -4566,7 +4794,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SemaRef.BuildBinOp(CurScope, PreCond.get()->getExprLoc(), BO_LAnd, PreCond.get(), IterSpaces[Cnt].PreCond); } - auto N = IterSpaces[Cnt].NumIterations; + Expr *N = IterSpaces[Cnt].NumIterations; SourceLocation Loc = N->getExprLoc(); AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32; if (LastIteration32.isUsable()) @@ -4592,8 +4820,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (LastIteration32.isUsable() && C.getTypeSize(LastIteration32.get()->getType()) == 32 && (AllCountsNeedLessThan32Bits || NestedLoopCount == 1 || - FitsInto( - 32 /* Bits */, + fitsInto( + /*Bits=*/32, LastIteration32.get()->getType()->hasSignedIntegerRepresentation(), LastIteration64.get(), SemaRef))) LastIteration = LastIteration32; @@ -4681,7 +4909,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT, UB.get(), LastIteration.get()); ExprResult CondOp = SemaRef.ActOnConditionalOp( - InitLoc, InitLoc, IsUBGreater.get(), LastIteration.get(), UB.get()); + LastIteration.get()->getExprLoc(), InitLoc, IsUBGreater.get(), + LastIteration.get(), UB.get()); EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(), CondOp.get()); EUB = SemaRef.ActOnFinishFullExpr(EUB.get()); @@ -4691,7 +4920,6 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // enclosing region. E.g. in 'distribute parallel for' the bounds obtained // by scheduling 'distribute' have to be passed to the schedule of 'for'. if (isOpenMPLoopBoundSharingDirective(DKind)) { - // Lower bound variable, initialized with zero. VarDecl *CombLBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.comb.lb"); @@ -4716,7 +4944,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, CombCondOp.get()); CombEUB = SemaRef.ActOnFinishFullExpr(CombEUB.get()); - auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); + const CapturedDecl *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); // We expect to have at least 2 more parameters than the 'parallel' // directive does - the lower and upper bounds of the previous schedule. assert(CD->getNumParams() >= 4 && @@ -4724,8 +4952,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Set the proper type for the bounds given what we learned from the // enclosed loops. - auto *PrevLBDecl = CD->getParam(/*PrevLB=*/2); - auto *PrevUBDecl = CD->getParam(/*PrevUB=*/3); + ImplicitParamDecl *PrevLBDecl = CD->getParam(/*PrevLB=*/2); + ImplicitParamDecl *PrevUBDecl = CD->getParam(/*PrevUB=*/3); // Previous lower and upper bounds are obtained from the region // parameters. @@ -4764,7 +4992,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops. - SourceLocation CondLoc; + SourceLocation CondLoc = AStmt->getLocStart(); ExprResult Cond = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) @@ -4777,7 +5005,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get()); } // Loop increment (IV = IV + 1) - SourceLocation IncLoc; + SourceLocation IncLoc = AStmt->getLocStart(); ExprResult Inc = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, IV.get(), SemaRef.ActOnIntegerConstant(IncLoc, 1).get()); @@ -4844,7 +5072,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // directive with for as IV = IV + ST; ensure upper bound expression based // on PrevUB instead of NumIterations - used to implement 'for' when found // in combination with 'distribute', like in 'distribute parallel for' - SourceLocation DistIncLoc; + SourceLocation DistIncLoc = AStmt->getLocStart(); ExprResult DistCond, DistInc, PrevEUB; if (isOpenMPLoopBoundSharingDirective(DKind)) { DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get()); @@ -4860,7 +5088,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build expression: UB = min(UB, prevUB) for #for in composite or combined // construct - SourceLocation DistEUBLoc; + SourceLocation DistEUBLoc = AStmt->getLocStart(); ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, DistEUBLoc, BO_GT, UB.get(), PrevUB.get()); ExprResult CondOp = SemaRef.ActOnConditionalOp( @@ -4905,16 +5133,16 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()); - auto *CounterVar = buildDeclRefExpr(SemaRef, VD, IS.CounterVar->getType(), - IS.CounterVar->getExprLoc(), - /*RefersToCapture=*/true); - ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, + DeclRefExpr *CounterVar = buildDeclRefExpr( + SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), + /*RefersToCapture=*/true); + ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Captures); if (!Init.isUsable()) { HasErrors = true; break; } - ExprResult Update = BuildCounterUpdate( + ExprResult Update = buildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, IS.CounterStep, IS.Subtract, &Captures); if (!Update.isUsable()) { @@ -4923,7 +5151,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step - ExprResult Final = BuildCounterUpdate( + ExprResult Final = buildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); if (!Final.isUsable()) { @@ -4996,10 +5224,10 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get(); // Fill data for doacross depend clauses. - for (auto Pair : DSA.getDoacrossDependClauses()) { - if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) + for (const auto &Pair : DSA.getDoacrossDependClauses()) { + if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) { Pair.first->setCounterValue(CounterVal); - else { + } else { if (NestedLoopCount != Pair.second.size() || NestedLoopCount != LoopMultipliers.size() + 1) { // Erroneous case - clause has some problems. @@ -5064,10 +5292,10 @@ static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) { static bool checkSimdlenSafelenSpecified(Sema &S, const ArrayRef<OMPClause *> Clauses) { - OMPSafelenClause *Safelen = nullptr; - OMPSimdlenClause *Simdlen = nullptr; + const OMPSafelenClause *Safelen = nullptr; + const OMPSimdlenClause *Simdlen = nullptr; - for (auto *Clause : Clauses) { + for (const OMPClause *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_safelen) Safelen = cast<OMPSafelenClause>(Clause); else if (Clause->getClauseKind() == OMPC_simdlen) @@ -5078,8 +5306,8 @@ static bool checkSimdlenSafelenSpecified(Sema &S, if (Simdlen && Safelen) { llvm::APSInt SimdlenRes, SafelenRes; - auto SimdlenLength = Simdlen->getSimdlen(); - auto SafelenLength = Safelen->getSafelen(); + const Expr *SimdlenLength = Simdlen->getSimdlen(); + const Expr *SafelenLength = Safelen->getSafelen(); if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() || SimdlenLength->isInstantiationDependent() || SimdlenLength->containsUnexpandedParameterPack()) @@ -5104,10 +5332,10 @@ static bool checkSimdlenSafelenSpecified(Sema &S, return false; } -StmtResult Sema::ActOnOpenMPSimdDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { +StmtResult +Sema::ActOnOpenMPSimdDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5115,7 +5343,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -5126,7 +5354,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -5138,15 +5366,15 @@ StmtResult Sema::ActOnOpenMPSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } -StmtResult Sema::ActOnOpenMPForDirective( - ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { +StmtResult +Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, + SourceLocation StartLoc, SourceLocation EndLoc, + VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5154,7 +5382,7 @@ StmtResult Sema::ActOnOpenMPForDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -5165,7 +5393,7 @@ StmtResult Sema::ActOnOpenMPForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -5174,15 +5402,14 @@ StmtResult Sema::ActOnOpenMPForDirective( } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5191,7 +5418,7 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -5202,7 +5429,7 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -5214,7 +5441,7 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPForSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -5251,7 +5478,7 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); @@ -5265,7 +5492,7 @@ StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentCancelRegion(DSAStack->isCancelRegion()); return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt, @@ -5281,13 +5508,13 @@ StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); // OpenMP [2.7.3, single Construct, Restrictions] // The copyprivate clause must not be used with the nowait clause. - OMPClause *Nowait = nullptr; - OMPClause *Copyprivate = nullptr; - for (auto *Clause : Clauses) { + const OMPClause *Nowait = nullptr; + const OMPClause *Copyprivate = nullptr; + for (const OMPClause *Clause : Clauses) { if (Clause->getClauseKind() == OMPC_nowait) Nowait = Clause; else if (Clause->getClauseKind() == OMPC_copyprivate) @@ -5311,7 +5538,7 @@ StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt); } @@ -5328,7 +5555,7 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( llvm::APSInt Hint; SourceLocation HintLoc; bool DependentHint = false; - for (auto *C : Clauses) { + for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_hint) { if (!DirName.getName()) { Diag(C->getLocStart(), diag::err_omp_hint_clause_no_name); @@ -5336,9 +5563,9 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( } Expr *E = cast<OMPHintClause>(C)->getHint(); if (E->isTypeDependent() || E->isValueDependent() || - E->isInstantiationDependent()) + E->isInstantiationDependent()) { DependentHint = true; - else { + } else { Hint = E->EvaluateKnownConstInt(Context); HintLoc = C->getLocStart(); } @@ -5346,26 +5573,27 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( } if (ErrorFound) return StmtError(); - auto Pair = DSAStack->getCriticalWithHint(DirName); + const auto Pair = DSAStack->getCriticalWithHint(DirName); if (Pair.first && DirName.getName() && !DependentHint) { if (llvm::APSInt::compareValues(Hint, Pair.second) != 0) { Diag(StartLoc, diag::err_omp_critical_with_hint); - if (HintLoc.isValid()) { + if (HintLoc.isValid()) Diag(HintLoc, diag::note_omp_critical_hint_here) << 0 << Hint.toString(/*Radix=*/10, /*Signed=*/false); - } else + else Diag(StartLoc, diag::note_omp_critical_no_hint) << 0; - if (auto *C = Pair.first->getSingleClause<OMPHintClause>()) { + if (const auto *C = Pair.first->getSingleClause<OMPHintClause>()) { Diag(C->getLocStart(), diag::note_omp_critical_hint_here) << 1 << C->getHint()->EvaluateKnownConstInt(Context).toString( /*Radix=*/10, /*Signed=*/false); - } else + } else { Diag(Pair.first->getLocStart(), diag::note_omp_critical_no_hint) << 1; + } } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); auto *Dir = OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc, Clauses, AStmt); @@ -5376,12 +5604,11 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( StmtResult Sema::ActOnOpenMPParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -5393,7 +5620,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_parallel_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -5404,7 +5631,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -5413,7 +5640,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -5421,12 +5648,11 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( StmtResult Sema::ActOnOpenMPParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -5438,7 +5664,7 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -5446,7 +5672,7 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -5458,7 +5684,7 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -5496,7 +5722,7 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPParallelSectionsDirective::Create( Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); @@ -5516,7 +5742,7 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); @@ -5546,7 +5772,7 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTaskgroupDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, @@ -5564,13 +5790,13 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - OMPClause *DependFound = nullptr; - OMPClause *DependSourceClause = nullptr; - OMPClause *DependSinkClause = nullptr; + const OMPClause *DependFound = nullptr; + const OMPClause *DependSourceClause = nullptr; + const OMPClause *DependSinkClause = nullptr; bool ErrorFound = false; - OMPThreadsClause *TC = nullptr; - OMPSIMDClause *SC = nullptr; - for (auto *C : Clauses) { + const OMPThreadsClause *TC = nullptr; + const OMPSIMDClause *SC = nullptr; + for (const OMPClause *C : Clauses) { if (auto *DC = dyn_cast<OMPDependClause>(C)) { DependFound = C; if (DC->getDependencyKind() == OMPC_DEPEND_source) { @@ -5579,8 +5805,9 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, << getOpenMPDirectiveName(OMPD_ordered) << getOpenMPClauseName(OMPC_depend) << 2; ErrorFound = true; - } else + } else { DependSourceClause = C; + } if (DependSinkClause) { Diag(C->getLocStart(), diag::err_omp_depend_sink_source_not_allowed) << 0; @@ -5594,10 +5821,11 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, } DependSinkClause = C; } - } else if (C->getClauseKind() == OMPC_threads) + } else if (C->getClauseKind() == OMPC_threads) { TC = cast<OMPThreadsClause>(C); - else if (C->getClauseKind() == OMPC_simd) + } else if (C->getClauseKind() == OMPC_simd) { SC = cast<OMPSIMDClause>(C); + } } if (!ErrorFound && !SC && isOpenMPSimdDirective(DSAStack->getParentDirective())) { @@ -5615,7 +5843,7 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, diag::err_omp_ordered_directive_without_param); ErrorFound = true; } else if (TC || Clauses.empty()) { - if (auto *Param = DSAStack->getParentOrderedRegionParam()) { + if (const Expr *Param = DSAStack->getParentOrderedRegionParam()) { SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc; Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr); @@ -5629,57 +5857,57 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, if (AStmt) { assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); } return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } namespace { -/// \brief Helper class for checking expression in 'omp atomic [update]' +/// Helper class for checking expression in 'omp atomic [update]' /// construct. class OpenMPAtomicUpdateChecker { - /// \brief Error results for atomic update expressions. + /// Error results for atomic update expressions. enum ExprAnalysisErrorCode { - /// \brief A statement is not an expression statement. + /// A statement is not an expression statement. NotAnExpression, - /// \brief Expression is not builtin binary or unary operation. + /// Expression is not builtin binary or unary operation. NotABinaryOrUnaryExpression, - /// \brief Unary operation is not post-/pre- increment/decrement operation. + /// Unary operation is not post-/pre- increment/decrement operation. NotAnUnaryIncDecExpression, - /// \brief An expression is not of scalar type. + /// An expression is not of scalar type. NotAScalarType, - /// \brief A binary operation is not an assignment operation. + /// A binary operation is not an assignment operation. NotAnAssignmentOp, - /// \brief RHS part of the binary operation is not a binary expression. + /// RHS part of the binary operation is not a binary expression. NotABinaryExpression, - /// \brief RHS part is not additive/multiplicative/shift/biwise binary + /// RHS part is not additive/multiplicative/shift/biwise binary /// expression. NotABinaryOperator, - /// \brief RHS binary operation does not have reference to the updated LHS + /// RHS binary operation does not have reference to the updated LHS /// part. NotAnUpdateExpression, - /// \brief No errors is found. + /// No errors is found. NoError }; - /// \brief Reference to Sema. + /// Reference to Sema. Sema &SemaRef; - /// \brief A location for note diagnostics (when error is found). + /// A location for note diagnostics (when error is found). SourceLocation NoteLoc; - /// \brief 'x' lvalue part of the source atomic expression. + /// 'x' lvalue part of the source atomic expression. Expr *X; - /// \brief 'expr' rvalue part of the source atomic expression. + /// 'expr' rvalue part of the source atomic expression. Expr *E; - /// \brief Helper expression of the form + /// Helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. Expr *UpdateExpr; - /// \brief Is 'x' a LHS in a RHS part of full update expression. It is + /// Is 'x' a LHS in a RHS part of full update expression. It is /// important for non-associative operations. bool IsXLHSInRHSPart; BinaryOperatorKind Op; SourceLocation OpLoc; - /// \brief true if the source expression is a postfix unary operation, false + /// true if the source expression is a postfix unary operation, false /// if it is a prefix unary operation. bool IsPostfixUpdate; @@ -5687,7 +5915,7 @@ public: OpenMPAtomicUpdateChecker(Sema &SemaRef) : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr), IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {} - /// \brief Check specified statement that it is suitable for 'atomic update' + /// Check specified statement that it is suitable for 'atomic update' /// constructs and extract 'x', 'expr' and Operation from the original /// expression. If DiagId and NoteId == 0, then only check is performed /// without error notification. @@ -5695,19 +5923,19 @@ public: /// \param NoteId Diagnostic note for the main error message. /// \return true if statement is not an update expression, false otherwise. bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0); - /// \brief Return the 'x' lvalue part of the source atomic expression. + /// Return the 'x' lvalue part of the source atomic expression. Expr *getX() const { return X; } - /// \brief Return the 'expr' rvalue part of the source atomic expression. + /// Return the 'expr' rvalue part of the source atomic expression. Expr *getExpr() const { return E; } - /// \brief Return the update expression used in calculation of the updated + /// Return the update expression used in calculation of the updated /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. Expr *getUpdateExpr() const { return UpdateExpr; } - /// \brief Return true if 'x' is LHS in RHS part of full update expression, + /// Return true if 'x' is LHS in RHS part of full update expression, /// false otherwise. bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; } - /// \brief true if the source expression is a postfix unary operation, false + /// true if the source expression is a postfix unary operation, false /// if it is a prefix unary operation. bool isPostfixUpdate() const { return IsPostfixUpdate; } @@ -5727,15 +5955,15 @@ bool OpenMPAtomicUpdateChecker::checkBinaryOperation( // x = expr binop x; if (AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getLHS(); - if (auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>( + if (const auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>( AtomicBinOp->getRHS()->IgnoreParenImpCasts())) { if (AtomicInnerBinOp->isMultiplicativeOp() || AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() || AtomicInnerBinOp->isBitwiseOp()) { Op = AtomicInnerBinOp->getOpcode(); OpLoc = AtomicInnerBinOp->getOperatorLoc(); - auto *LHS = AtomicInnerBinOp->getLHS(); - auto *RHS = AtomicInnerBinOp->getRHS(); + Expr *LHS = AtomicInnerBinOp->getLHS(); + Expr *RHS = AtomicInnerBinOp->getRHS(); llvm::FoldingSetNodeID XId, LHSId, RHSId; X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(), /*Canonical=*/true); @@ -5779,7 +6007,8 @@ bool OpenMPAtomicUpdateChecker::checkBinaryOperation( SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; return true; - } else if (SemaRef.CurContext->isDependentContext()) + } + if (SemaRef.CurContext->isDependentContext()) E = X = UpdateExpr = nullptr; return ErrorFound != NoError; } @@ -5801,7 +6030,7 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, AtomicBody = AtomicBody->IgnoreParenImpCasts(); if (AtomicBody->getType()->isScalarType() || AtomicBody->isInstantiationDependent()) { - if (auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>( + if (const auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>( AtomicBody->IgnoreParenImpCasts())) { // Check for Compound Assignment Operation Op = BinaryOperator::getOpForCompoundAssignment( @@ -5815,7 +6044,7 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, // Check for Binary Operation if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId)) return true; - } else if (auto *AtomicUnaryOp = dyn_cast<UnaryOperator>( + } else if (const auto *AtomicUnaryOp = dyn_cast<UnaryOperator>( AtomicBody->IgnoreParenImpCasts())) { // Check for Unary Operation if (AtomicUnaryOp->isIncrementDecrementOp()) { @@ -5851,7 +6080,8 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; return true; - } else if (SemaRef.CurContext->isDependentContext()) + } + if (SemaRef.CurContext->isDependentContext()) E = X = UpdateExpr = nullptr; if (ErrorFound == NoError && E && X) { // Build an update expression of form 'OpaqueValueExpr(x) binop @@ -5861,7 +6091,7 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue); auto *OVEExpr = new (SemaRef.getASTContext()) OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue); - auto Update = + ExprResult Update = SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr, IsXLHSInRHSPart ? OVEExpr : OVEX); if (Update.isInvalid()) @@ -5890,7 +6120,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. OpenMPClauseKind AtomicKind = OMPC_unknown; SourceLocation AtomicKindLoc; - for (auto *C : Clauses) { + for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || C->getClauseKind() == OMPC_update || C->getClauseKind() == OMPC_capture) { @@ -5906,7 +6136,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } } - auto Body = CS->getCapturedStmt(); + Stmt *Body = CS->getCapturedStmt(); if (auto *EWC = dyn_cast<ExprWithCleanups>(Body)) Body = EWC->getSubExpr(); @@ -5950,8 +6180,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, SourceRange ErrorRange, NoteRange; // If clause is read: // v = x; - if (auto *AtomicBody = dyn_cast<Expr>(Body)) { - auto *AtomicBinOp = + if (const auto *AtomicBody = dyn_cast<Expr>(Body)) { + const auto *AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); @@ -5959,7 +6189,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && (V->isInstantiationDependent() || V->getType()->isScalarType())) { if (!X->isLValue() || !V->isLValue()) { - auto NotLValueExpr = X->isLValue() ? V : X; + const Expr *NotLValueExpr = X->isLValue() ? V : X; ErrorFound = NotAnLValue; ErrorLoc = AtomicBinOp->getExprLoc(); ErrorRange = AtomicBinOp->getSourceRange(); @@ -5968,7 +6198,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } } else if (!X->isInstantiationDependent() || !V->isInstantiationDependent()) { - auto NotScalarExpr = + const Expr *NotScalarExpr = (X->isInstantiationDependent() || X->getType()->isScalarType()) ? V : X; @@ -5998,7 +6228,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound << NoteRange; return StmtError(); - } else if (CurContext->isDependentContext()) + } + if (CurContext->isDependentContext()) V = X = nullptr; } else if (AtomicKind == OMPC_write) { enum { @@ -6012,8 +6243,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, SourceRange ErrorRange, NoteRange; // If clause is write: // x = expr; - if (auto *AtomicBody = dyn_cast<Expr>(Body)) { - auto *AtomicBinOp = + if (const auto *AtomicBody = dyn_cast<Expr>(Body)) { + const auto *AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getLHS(); @@ -6029,7 +6260,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } } else if (!X->isInstantiationDependent() || !E->isInstantiationDependent()) { - auto NotScalarExpr = + const Expr *NotScalarExpr = (X->isInstantiationDependent() || X->getType()->isScalarType()) ? E : X; @@ -6059,7 +6290,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Diag(NoteLoc, diag::note_omp_atomic_read_write) << ErrorFound << NoteRange; return StmtError(); - } else if (CurContext->isDependentContext()) + } + if (CurContext->isDependentContext()) E = X = nullptr; } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) { // If clause is update: @@ -6093,7 +6325,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; - if (auto *AtomicBody = dyn_cast<Expr>(Body)) { + if (const auto *AtomicBody = dyn_cast<Expr>(Body)) { // If clause is a capture: // v = x++; // v = x--; @@ -6102,7 +6334,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // v = x binop= expr; // v = x = x binop expr; // v = x = expr binop x; - auto *AtomicBinOp = + const auto *AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { V = AtomicBinOp->getLHS(); @@ -6131,9 +6363,9 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; return StmtError(); - } else if (CurContext->isDependentContext()) { - UE = V = E = X = nullptr; } + if (CurContext->isDependentContext()) + UE = V = E = X = nullptr; } else { // If clause is a capture: // { v = x; x = expr; } @@ -6154,8 +6386,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, if (auto *CS = dyn_cast<CompoundStmt>(Body)) { // Check that this is { expr1; expr2; } if (CS->size() == 2) { - auto *First = CS->body_front(); - auto *Second = CS->body_back(); + Stmt *First = CS->body_front(); + Stmt *Second = CS->body_back(); if (auto *EWC = dyn_cast<ExprWithCleanups>(First)) First = EWC->getSubExpr()->IgnoreParenImpCasts(); if (auto *EWC = dyn_cast<ExprWithCleanups>(Second)) @@ -6177,7 +6409,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // { v = x; x = x binop expr; } // { v = x; x = expr binop x; } // Check that the first expression has form v = x. - auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); + Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID XId, PossibleXId; Checker.getX()->Profile(XId, Context, /*Canonical=*/true); PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); @@ -6207,7 +6439,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // { x = x binop expr; v = x; } // { x = expr binop x; v = x; } // Check that the second expression has form v = x. - auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); + Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID XId, PossibleXId; Checker.getX()->Profile(XId, Context, /*Canonical=*/true); PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); @@ -6248,9 +6480,9 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, SecondBinOp ? SecondBinOp->getSourceRange() : SourceRange(ErrorLoc, ErrorLoc); } else { - auto *PossibleXRHSInFirst = + Expr *PossibleXRHSInFirst = FirstBinOp->getRHS()->IgnoreParenImpCasts(); - auto *PossibleXLHSInSecond = + Expr *PossibleXLHSInSecond = SecondBinOp->getLHS()->IgnoreParenImpCasts(); llvm::FoldingSetNodeID X1Id, X2Id; PossibleXRHSInFirst->Profile(X1Id, Context, @@ -6293,13 +6525,13 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, << ErrorRange; Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; return StmtError(); - } else if (CurContext->isDependentContext()) { - UE = V = E = X = nullptr; } + if (CurContext->isDependentContext()) + UE = V = E = X = nullptr; } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, X, V, E, UE, IsXLHSInRHSPart, @@ -6313,25 +6545,35 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 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(); + } // 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); + const Stmt *S = CS->IgnoreContainers(/*IgnoreCaptured=*/true); bool OMPTeamsFound = true; - if (auto *CS = dyn_cast<CompoundStmt>(S)) { + if (const auto *CS = dyn_cast<CompoundStmt>(S)) { auto I = CS->body_begin(); while (I != CS->body_end()) { - auto *OED = dyn_cast<OMPExecutableDirective>(*I); + const auto *OED = dyn_cast<OMPExecutableDirective>(*I); if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { OMPTeamsFound = false; break; @@ -6341,7 +6583,7 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, assert(I != CS->body_end() && "Not found statement"); S = *I; } else { - auto *OED = dyn_cast<OMPExecutableDirective>(S); + const auto *OED = dyn_cast<OMPExecutableDirective>(S); OMPTeamsFound = OED && isOpenMPTeamsDirective(OED->getDirectiveKind()); } if (!OMPTeamsFound) { @@ -6354,7 +6596,7 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } @@ -6366,15 +6608,25 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 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(); + setFunctionHasBranchProtectedScope(); return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); @@ -6382,12 +6634,11 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPTargetParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6409,7 +6660,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6420,7 +6671,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -6429,7 +6680,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( } } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -6466,7 +6717,7 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); @@ -6479,7 +6730,7 @@ Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6516,7 +6767,7 @@ Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6553,7 +6804,7 @@ StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6585,7 +6836,7 @@ StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6593,7 +6844,7 @@ StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -6635,9 +6886,9 @@ StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses, static bool checkGrainsizeNumTasksClauses(Sema &S, ArrayRef<OMPClause *> Clauses) { - OMPClause *PrevClause = nullptr; + const OMPClause *PrevClause = nullptr; bool ErrorFound = false; - for (auto *C : Clauses) { + for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_grainsize || C->getClauseKind() == OMPC_num_tasks) { if (!PrevClause) @@ -6659,9 +6910,9 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, static bool checkReductionClauseWithNogroup(Sema &S, ArrayRef<OMPClause *> Clauses) { - OMPClause *ReductionClause = nullptr; - OMPClause *NogroupClause = nullptr; - for (auto *C : Clauses) { + const OMPClause *ReductionClause = nullptr; + const OMPClause *NogroupClause = nullptr; + for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_reduction) { ReductionClause = C; if (NogroupClause) @@ -6686,8 +6937,7 @@ static bool checkReductionClauseWithNogroup(Sema &S, StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -6696,7 +6946,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_taskloop, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_taskloop, getCollapseNumberExpr(Clauses), /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6716,15 +6966,14 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( if (checkReductionClauseWithNogroup(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -6733,7 +6982,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses), /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6744,7 +6993,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -6766,15 +7015,14 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -6783,7 +7031,7 @@ StmtResult Sema::ActOnOpenMPDistributeDirective( // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_distribute, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6792,19 +7040,18 @@ StmtResult Sema::ActOnOpenMPDistributeDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPDistributeDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6826,7 +7073,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -6836,7 +7083,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -6844,12 +7091,11 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6871,7 +7117,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -6883,7 +7129,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -6895,19 +7141,18 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6929,7 +7174,7 @@ StmtResult Sema::ActOnOpenMPDistributeSimdDirective( // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -6940,7 +7185,7 @@ StmtResult Sema::ActOnOpenMPDistributeSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -6952,19 +7197,18 @@ StmtResult Sema::ActOnOpenMPDistributeSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPDistributeSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -6985,7 +7229,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -6997,7 +7241,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7008,19 +7252,18 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTargetSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7042,7 +7285,7 @@ StmtResult Sema::ActOnOpenMPTargetSimdDirective( // In presence of clause 'collapse' with number of loops, it will define the // nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -7053,7 +7296,7 @@ StmtResult Sema::ActOnOpenMPTargetSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7065,19 +7308,18 @@ StmtResult Sema::ActOnOpenMPTargetSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7099,7 +7341,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. unsigned NestedLoopCount = - CheckOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses), + checkOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) @@ -7108,7 +7350,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp teams distribute loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -7118,12 +7360,11 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7146,7 +7387,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -7159,7 +7400,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7171,7 +7412,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -7181,12 +7422,11 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7209,7 +7449,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - auto NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -7222,7 +7462,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7234,7 +7474,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -7244,12 +7484,11 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7272,7 +7511,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - unsigned NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -7283,7 +7522,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -7299,7 +7538,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7317,7 +7556,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); } - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); @@ -7325,12 +7564,11 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. @@ -7352,7 +7590,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - auto NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_target_teams_distribute, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -7362,33 +7600,42 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp target teams distribute loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_target_teams_distribute_parallel_for); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 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' with number of loops, it will // define the nested loops number. - auto NestedLoopCount = CheckOpenMPLoop( - OMPD_target_teams_distribute_parallel_for, - getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + unsigned NestedLoopCount = checkOpenMPLoop( + OMPD_target_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -7396,7 +7643,18 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp target teams distribute parallel for loop exprs were not built"); - getCurFunction()->setHasBranchProtectedScope(); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (OMPClause *C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -7404,27 +7662,37 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + 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. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = getOpenMPCaptureLevels( + OMPD_target_teams_distribute_parallel_for_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 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' with number of loops, it will // define the nested loops number. - auto NestedLoopCount = CheckOpenMPLoop( - OMPD_target_teams_distribute_parallel_for_simd, - getCollapseNumberExpr(Clauses), - nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, - VarsWithImplicitDSA, B); + unsigned NestedLoopCount = + checkOpenMPLoop(OMPD_target_teams_distribute_parallel_for_simd, + getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, CS, *this, + *DSAStack, VarsWithImplicitDSA, B); if (NestedLoopCount == 0) return StmtError(); @@ -7434,7 +7702,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7446,15 +7714,14 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc, - llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -7480,7 +7747,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. - auto NestedLoopCount = CheckOpenMPLoop( + unsigned NestedLoopCount = checkOpenMPLoop( OMPD_target_teams_distribute_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, *this, *DSAStack, VarsWithImplicitDSA, B); @@ -7492,7 +7759,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. - for (auto C : Clauses) { + for (OMPClause *C : Clauses) { if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, @@ -7504,7 +7771,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeSimdDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -7612,13 +7879,18 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel: case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: // If this clause applies to the nested 'parallel' region, capture within // the 'target' region, otherwise do not capture. if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_target; break; + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + // If this clause applies to the nested 'parallel' region, capture within + // the 'teams' region, otherwise do not capture. + if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) + CaptureRegion = OMPD_teams; + break; case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_teams; @@ -7682,12 +7954,12 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel: case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_target; break; case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_teams; break; case OMPD_parallel: @@ -7870,20 +8142,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( break; case OMPC_schedule: switch (DKind) { - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - CaptureRegion = OMPD_target; - break; - case OMPD_teams_distribute_parallel_for: - case OMPD_teams_distribute_parallel_for_simd: - CaptureRegion = OMPD_teams; - break; case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: CaptureRegion = OMPD_parallel; break; case OMPD_for: @@ -7941,18 +8209,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_teams_distribute_parallel_for_simd: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: - CaptureRegion = OMPD_teams; - break; case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: - CaptureRegion = OMPD_target; + CaptureRegion = OMPD_teams; break; case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: - CaptureRegion = OMPD_parallel; - break; case OMPD_distribute: case OMPD_distribute_simd: // Do not capture thread_limit-clause expressions. @@ -8007,19 +8271,19 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_update: case OMPD_target_enter_data: case OMPD_target_exit_data: - CaptureRegion = OMPD_task; - break; + case OMPD_target: + case OMPD_target_simd: case OMPD_target_teams: + case OMPD_target_parallel: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: + CaptureRegion = OMPD_task; + break; case OMPD_target_data: - case OMPD_target: - case OMPD_target_simd: - case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: // Do not capture device-clause expressions. break; case OMPD_teams_distribute_parallel_for: @@ -8137,7 +8401,7 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -8209,7 +8473,7 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc, return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser); } -static bool IsNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, +static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, bool StrictlyPositive) { if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() && @@ -8245,7 +8509,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, // OpenMP [2.5, Restrictions] // The num_threads expression must evaluate to a positive integer value. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_threads, /*StrictlyPositive=*/true)) return nullptr; @@ -8254,7 +8518,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -8352,8 +8616,9 @@ OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc, if (NumForLoopsResult.isInvalid()) return nullptr; NumForLoops = NumForLoopsResult.get(); - } else + } else { NumForLoops = nullptr; + } DSAStack->setOrderedRegion(/*IsOrdered=*/true, NumForLoops); return new (Context) OMPOrderedClause(NumForLoops, StartLoc, LParenLoc, EndLoc); @@ -8431,24 +8696,23 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, ArrayRef<unsigned> Exclude = llvm::None) { - std::string Values; + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); unsigned Bound = Last >= 2 ? Last - 2 : 0; unsigned Skipped = Exclude.size(); auto S = Exclude.begin(), E = Exclude.end(); - for (unsigned i = First; i < Last; ++i) { - if (std::find(S, E, i) != E) { + for (unsigned I = First; I < Last; ++I) { + if (std::find(S, E, I) != E) { --Skipped; continue; } - Values += "'"; - Values += getOpenMPSimpleClauseTypeName(K, i); - Values += "'"; - if (i == Bound - Skipped) - Values += " or "; - else if (i != Bound + 1 - Skipped) - Values += ", "; + Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'"; + if (I == Bound - Skipped) + Out << " or "; + else if (I != Bound + 1 - Skipped) + Out << ", "; } - return Values; + return Out.str(); } OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, @@ -8682,7 +8946,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -8986,13 +9250,13 @@ getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, } IsArrayExpr = NoArrayExpr; if (AllowArraySection) { if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) { - auto *Base = ASE->getBase()->IgnoreParenImpCasts(); + Expr *Base = ASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); RefExpr = Base; IsArrayExpr = ArraySubscript; } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) { - auto *Base = OASE->getBase()->IgnoreParenImpCasts(); + Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) @@ -9010,10 +9274,10 @@ getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, (S.getCurrentThisType().isNull() || !ME || !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) || !isa<FieldDecl>(ME->getMemberDecl()))) { - if (IsArrayExpr != NoArrayExpr) + if (IsArrayExpr != NoArrayExpr) { S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr << ERange; - else { + } else { S.Diag(ELoc, AllowArraySection ? diag::err_omp_expected_var_name_member_expr_or_array_item @@ -9032,7 +9296,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> PrivateCopies; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); SourceLocation ELoc; SourceRange ERange; @@ -9064,15 +9328,15 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } - auto CurrDir = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && isOpenMPTaskingDirective(CurrDir)) { @@ -9091,14 +9355,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if (CurrDir == OMPD_target || CurrDir == OMPD_target_parallel || - CurrDir == OMPD_target_teams || - CurrDir == OMPD_target_teams_distribute || - CurrDir == OMPD_target_teams_distribute_parallel_for || - CurrDir == OMPD_target_teams_distribute_parallel_for_simd || - CurrDir == OMPD_target_teams_distribute_simd || - CurrDir == OMPD_target_parallel_for_simd || - CurrDir == OMPD_target_parallel_for) { + if (isOpenMPTargetExecutionDirective(CurrDir)) { OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, @@ -9111,7 +9368,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, << getOpenMPClauseName(OMPC_private) << getOpenMPClauseName(ConflictKind) << getOpenMPDirectiveName(CurrDir); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -9126,12 +9383,14 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // IdResolver, so the code in the OpenMP region uses original variable for // proper diagnostics. Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); + VarDecl *VDPrivate = + buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr, + VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr); ActOnUninitializedDecl(VDPrivate); if (VDPrivate->isInvalidDecl()) continue; - auto VDPrivateRefExpr = buildDeclRefExpr( + DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); DeclRefExpr *Ref = nullptr; @@ -9156,7 +9415,7 @@ class DiagsUninitializedSeveretyRAII { private: DiagnosticsEngine &Diags; SourceLocation SavedLoc; - bool IsIgnored; + bool IsIgnored = false; public: DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc, @@ -9184,9 +9443,9 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SmallVector<Decl *, 4> ExprCaptures; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); - auto ImplicitClauseLoc = DSAStack->getConstructLoc(); + SourceLocation ImplicitClauseLoc = DSAStack->getConstructLoc(); - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP firstprivate clause."); SourceLocation ELoc; SourceRange ERange; @@ -9218,12 +9477,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous copy constructor for the // class type. - auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); + QualType ElemType = Context.getBaseElementType(Type).getNonReferenceType(); // If an implicit firstprivate variable found it was checked already. DSAStackTy::DSAVarData TopDVar; if (!IsImplicitClause) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); TopDVar = DVar; OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); bool IsConstant = ElemType.isConstant(Context); @@ -9241,7 +9501,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } @@ -9261,7 +9521,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } @@ -9292,7 +9552,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_firstprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -9309,8 +9569,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // from the worksharing construct. if (isOpenMPTaskingDirective(CurrDir)) { DVar = DSAStack->hasInnermostDSA( - D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, - [](OpenMPDirectiveKind K) -> bool { + D, [](OpenMPClauseKind C) { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) { return isOpenMPParallelDirective(K) || isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); @@ -9322,7 +9582,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, isOpenMPTeamsDirective(DVar.DKind))) { Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate) << getOpenMPDirectiveName(DVar.DKind); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -9334,8 +9594,9 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( VD, /*CurrentRegionOnly=*/true, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef, - OpenMPClauseKind WhereFoundClauseKind) -> bool { + [&ConflictKind]( + OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind WhereFoundClauseKind) { ConflictKind = WhereFoundClauseKind; return true; })) { @@ -9343,7 +9604,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, << getOpenMPClauseName(OMPC_firstprivate) << getOpenMPClauseName(ConflictKind) << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -9365,8 +9626,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, } Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); + VarDecl *VDPrivate = + buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr, + VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr); // 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 @@ -9376,13 +9639,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // For arrays generate initializer for single element and replace it by the // original array element in CodeGen. if (Type->isArrayType()) { - auto VDInit = + VarDecl *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, D->getName()); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc); - auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); + Expr *Init = DefaultLvalueConversion(VDInitRefExpr).get(); ElemType = ElemType.getUnqualifiedType(); - auto *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, - ".firstprivate.temp"); + VarDecl *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, + ".firstprivate.temp"); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInitTemp); InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc); @@ -9396,8 +9659,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // Remove temp variable declaration. Context.Deallocate(VDInitTemp); } else { - auto *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type, - ".firstprivate.temp"); + VarDecl *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type, + ".firstprivate.temp"); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(), RefExpr->getExprLoc()); AddInitializerToDecl(VDPrivate, @@ -9412,16 +9675,16 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, continue; } CurContext->addDecl(VDPrivate); - auto VDPrivateRefExpr = buildDeclRefExpr( + DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), RefExpr->getExprLoc()); DeclRefExpr *Ref = nullptr; if (!VD && !CurContext->isDependentContext()) { - if (TopDVar.CKind == OMPC_lastprivate) + if (TopDVar.CKind == OMPC_lastprivate) { Ref = TopDVar.PrivateCopy; - else { + } else { Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); - if (!IsOpenMPCapturedDecl(D)) + if (!isOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } } @@ -9451,7 +9714,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> AssignmentOps; SmallVector<Decl *, 4> ExprCaptures; SmallVector<Expr *, 4> ExprPostUpdates; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); SourceLocation ELoc; SourceRange ERange; @@ -9488,7 +9751,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] // A list item may appear in a firstprivate or lastprivate clause but not // both. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && (isOpenMPDistributeDirective(CurrDir) || DVar.CKind != OMPC_firstprivate) && @@ -9496,7 +9759,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_lastprivate); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } @@ -9515,7 +9778,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_lastprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -9529,19 +9792,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, ERange.getBegin(), - Type.getUnqualifiedType(), ".lastprivate.src", - D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PseudoSrcExpr = + VarDecl *SrcVD = buildVarDecl(*this, ERange.getBegin(), + Type.getUnqualifiedType(), ".lastprivate.src", + D->hasAttrs() ? &D->getAttrs() : nullptr); + DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc); - auto *DstVD = + VarDecl *DstVD = buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst", D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); + DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign, - PseudoDstExpr, PseudoSrcExpr); + ExprResult AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign, + PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, @@ -9551,15 +9814,15 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, DeclRefExpr *Ref = nullptr; if (!VD && !CurContext->isDependentContext()) { - if (TopDVar.CKind == OMPC_firstprivate) + if (TopDVar.CKind == OMPC_firstprivate) { Ref = TopDVar.PrivateCopy; - else { + } else { Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); - if (!IsOpenMPCapturedDecl(D)) + if (!isOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } if (TopDVar.CKind == OMPC_firstprivate || - (!IsOpenMPCapturedDecl(D) && + (!isOpenMPCapturedDecl(D) && Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) { ExprResult RefRes = DefaultLvalueConversion(Ref); if (!RefRes.isUsable()) @@ -9596,7 +9859,7 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); SourceLocation ELoc; SourceRange ERange; @@ -9618,17 +9881,17 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } DeclRefExpr *Ref = nullptr; - if (!VD && IsOpenMPCapturedDecl(D) && !CurContext->isDependentContext()) + if (!VD && isOpenMPCapturedDecl(D) && !CurContext->isDependentContext()) Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref); Vars.push_back((VD || !Ref || CurContext->isDependentContext()) @@ -9648,23 +9911,21 @@ class DSARefChecker : public StmtVisitor<DSARefChecker, bool> { public: bool VisitDeclRefExpr(DeclRefExpr *E) { - if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) { - DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, false); + if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { + DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); if (DVar.CKind == OMPC_shared && !DVar.RefExpr) return false; if (DVar.CKind != OMPC_unknown) return true; DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( - VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, + VD, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; }, /*FromParent=*/true); - if (DVarPrivate.CKind != OMPC_unknown) - return true; - return false; + return DVarPrivate.CKind != OMPC_unknown; } return false; } bool VisitStmt(Stmt *S) { - for (auto Child : S->children()) { + for (Stmt *Child : S->children()) { if (Child && Visit(Child)) return true; } @@ -9679,8 +9940,8 @@ namespace { // DeclRefExpr to specified OMPCapturedExprDecl. class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> { typedef TreeTransform<TransformExprToCaptures> BaseTransform; - ValueDecl *Field; - DeclRefExpr *CapturedExpr; + ValueDecl *Field = nullptr; + DeclRefExpr *CapturedExpr = nullptr; public: TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl) @@ -9698,12 +9959,12 @@ public: }; } // namespace -template <typename T> -static T filterLookupForUDR(SmallVectorImpl<UnresolvedSet<8>> &Lookups, - const llvm::function_ref<T(ValueDecl *)> &Gen) { - for (auto &Set : Lookups) { +template <typename T, typename U> +static T filterLookupForUDR(SmallVectorImpl<U> &Lookups, + const llvm::function_ref<T(ValueDecl *)> Gen) { + for (U &Set : Lookups) { for (auto *D : Set) { - if (auto Res = Gen(cast<ValueDecl>(D))) + if (T Res = Gen(cast<ValueDecl>(D))) return Res; } } @@ -9722,7 +9983,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); Lookup.suppressDiagnostics(); while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { - auto *D = Lookup.getRepresentativeDecl(); + NamedDecl *D = Lookup.getRepresentativeDecl(); do { S = S->getParent(); } while (S && !S->isDeclScope(D)); @@ -9736,7 +9997,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) { Lookups.push_back(UnresolvedSet<8>()); Decl *PrevD = nullptr; - for (auto *D : ULE->decls()) { + for (NamedDecl *D : ULE->decls()) { if (D == PrevD) Lookups.push_back(UnresolvedSet<8>()); else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) @@ -9747,14 +10008,14 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() || Ty->isInstantiationDependentType() || Ty->containsUnexpandedParameterPack() || - filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool { + filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) { return !D->isInvalidDecl() && (D->getType()->isDependentType() || D->getType()->isInstantiationDependentType() || D->getType()->containsUnexpandedParameterPack()); })) { UnresolvedSet<8> ResSet; - for (auto &Set : Lookups) { + for (const UnresolvedSet<8> &Set : Lookups) { ResSet.append(Set.begin(), Set.end()); // The last item marks the end of all declarations at the specified scope. ResSet.addDecl(Set[Set.size() - 1]); @@ -9856,7 +10117,7 @@ struct ReductionData { }; } // namespace -static bool CheckOMPArraySectionConstantForReduction( +static bool checkOMPArraySectionConstantForReduction( ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, SmallVectorImpl<llvm::APSInt> &ArraySizes) { const Expr *Length = OASE->getLength(); @@ -9918,14 +10179,14 @@ static bool CheckOMPArraySectionConstantForReduction( return true; } -static bool ActOnOMPReductionKindClause( +static bool actOnOMPReductionKindClause( Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) { - auto DN = ReductionId.getName(); - auto OOK = DN.getCXXOverloadedOperator(); + DeclarationName DN = ReductionId.getName(); + OverloadedOperatorKind OOK = DN.getCXXOverloadedOperator(); BinaryOperatorKind BOK = BO_Comma; ASTContext &Context = S.Context; @@ -9999,7 +10260,7 @@ static bool ActOnOMPReductionKindClause( case NUM_OVERLOADED_OPERATORS: llvm_unreachable("Unexpected reduction identifier"); case OO_None: - if (auto *II = DN.getAsIdentifierInfo()) { + if (IdentifierInfo *II = DN.getAsIdentifierInfo()) { if (II->isStr("max")) BOK = BO_GT; else if (II->isStr("min")) @@ -10016,7 +10277,7 @@ static bool ActOnOMPReductionKindClause( auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end(); bool FirstIter = true; - for (auto RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); // OpenMP [2.1, C/C++] // A list item is a variable or array section, subject to the restrictions @@ -10057,23 +10318,25 @@ static bool ActOnOMPReductionKindClause( QualType Type; auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens()); auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens()); - if (ASE) + if (ASE) { Type = ASE->getType().getNonReferenceType(); - else if (OASE) { - auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); - if (auto *ATy = BaseType->getAsArrayTypeUnsafe()) + } else if (OASE) { + QualType BaseType = + OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else Type = BaseType->getPointeeType(); Type = Type.getNonReferenceType(); - } else + } else { Type = Context.getBaseElementType(D->getType().getNonReferenceType()); + } auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. - if (S.RequireCompleteType(ELoc, Type, + if (S.RequireCompleteType(ELoc, D->getType(), diag::err_omp_reduction_incomplete_type)) continue; // OpenMP [2.14.3.6, reduction clause, Restrictions] @@ -10117,19 +10380,19 @@ static bool ActOnOMPReductionKindClause( // Any number of reduction clauses can be specified on the directive, // but a list item can appear only once in the reduction clauses for that // directive. - DSAStackTy::DSAVarData DVar; - DVar = Stack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D, /*FromParent=*/false); if (DVar.CKind == OMPC_reduction) { S.Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(ClauseKind); if (DVar.RefExpr) S.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); continue; - } else if (DVar.CKind != OMPC_unknown) { + } + if (DVar.CKind != OMPC_unknown) { S.Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); - ReportOriginalDSA(S, Stack, D, DVar); + reportOriginalDsa(S, Stack, D, DVar); continue; } @@ -10146,7 +10409,7 @@ static bool ActOnOMPReductionKindClause( S.Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(S, Stack, D, DVar); + reportOriginalDsa(S, Stack, D, DVar); continue; } } @@ -10212,11 +10475,11 @@ static bool ActOnOMPReductionKindClause( } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); - auto *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs", - D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); - auto PrivateTy = Type; + VarDecl *LHSVD = buildVarDecl(S, ELoc, Type, ".reduction.lhs", + D->hasAttrs() ? &D->getAttrs() : nullptr); + VarDecl *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + QualType PrivateTy = Type; // Try if we can determine constant lengths for all array sections and avoid // the VLA. @@ -10224,15 +10487,14 @@ static bool ActOnOMPReductionKindClause( if (OASE) { bool SingleElement; llvm::SmallVector<llvm::APSInt, 4> ArraySizes; - ConstantLengthOASE = CheckOMPArraySectionConstantForReduction( + ConstantLengthOASE = checkOMPArraySectionConstantForReduction( Context, OASE, SingleElement, ArraySizes); // If we don't have a single element, we must emit a constant array type. if (ConstantLengthOASE && !SingleElement) { - for (auto &Size : ArraySizes) { + for (llvm::APSInt &Size : ArraySizes) PrivateTy = Context.getConstantArrayType( PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); - } } } @@ -10255,15 +10517,18 @@ static bool ActOnOMPReductionKindClause( new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); } else if (!ASE && !OASE && - Context.getAsArrayType(D->getType().getNonReferenceType())) + Context.getAsArrayType(D->getType().getNonReferenceType())) { PrivateTy = D->getType().getNonReferenceType(); + } // Private copy. - auto *PrivateVD = buildVarDecl(S, ELoc, PrivateTy, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); + VarDecl *PrivateVD = + buildVarDecl(S, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr, + VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr); // Add initializer for private variable. Expr *Init = nullptr; - auto *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc); - auto *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc); + DeclRefExpr *LHSDRE = buildDeclRefExpr(S, LHSVD, Type, ELoc); + DeclRefExpr *RHSDRE = buildDeclRefExpr(S, RHSVD, Type, ELoc); if (DeclareReductionRef.isUsable()) { auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>(); auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl()); @@ -10301,7 +10566,7 @@ static bool ActOnOMPReductionKindClause( Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } else if (Type->isScalarType()) { - auto Size = Context.getTypeSize(Type); + uint64_t Size = Context.getTypeSize(Type); QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); @@ -10322,7 +10587,7 @@ static bool ActOnOMPReductionKindClause( // the reduction list item type'. if (Type->isIntegerType() || Type->isPointerType()) { bool IsSigned = Type->hasSignedIntegerRepresentation(); - auto Size = Context.getTypeSize(Type); + uint64_t Size = Context.getTypeSize(Type); QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); llvm::APInt InitValue = @@ -10333,7 +10598,7 @@ static bool ActOnOMPReductionKindClause( Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); if (Type->isPointerType()) { // Cast to pointer type. - auto CastExpr = S.BuildCStyleCastExpr( + ExprResult CastExpr = S.BuildCStyleCastExpr( ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init); if (CastExpr.isInvalid()) continue; @@ -10394,7 +10659,7 @@ static bool ActOnOMPReductionKindClause( // codegen. PrivateVD->setInit(RHSVD->getInit()); PrivateVD->setInitStyle(RHSVD->getInitStyle()); - auto *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc); + DeclRefExpr *PrivateDRE = buildDeclRefExpr(S, PrivateVD, PrivateTy, ELoc); ExprResult ReductionOp; if (DeclareReductionRef.isUsable()) { QualType RedTy = DeclareReductionRef.get()->getType(); @@ -10506,7 +10771,7 @@ static bool ActOnOMPReductionKindClause( } else { VarsExpr = Ref = buildCapture(S, D, SimpleRefExpr, /*WithInit=*/false); } - if (!S.IsOpenMPCapturedDecl(D)) { + if (!S.isOpenMPCapturedDecl(D)) { RD.ExprCaptures.emplace_back(Ref->getDecl()); if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { ExprResult RefRes = S.DefaultLvalueConversion(Ref); @@ -10551,8 +10816,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions) { ReductionData RD(VarList.size()); - - if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, + if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, UnresolvedReductions, RD)) @@ -10572,10 +10836,9 @@ OMPClause *Sema::ActOnOpenMPTaskReductionClause( CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions) { ReductionData RD(VarList.size()); - - if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction, - VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionIdScopeSpec, ReductionId, + if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_task_reduction, VarList, + StartLoc, LParenLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, UnresolvedReductions, RD)) return nullptr; @@ -10593,8 +10856,7 @@ OMPClause *Sema::ActOnOpenMPInReductionClause( CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions) { ReductionData RD(VarList.size()); - - if (ActOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList, + if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_in_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, UnresolvedReductions, RD)) @@ -10618,10 +10880,10 @@ bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, return false; } -bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, +bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type) { - auto *VD = dyn_cast_or_null<VarDecl>(D); + const auto *VD = dyn_cast_or_null<VarDecl>(D); // A variable must not have an incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type)) return true; @@ -10678,7 +10940,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause( SmallVector<Expr *, 4> ExprPostUpdates; if (CheckOpenMPLinearModifier(LinKind, LinLoc)) LinKind = OMPC_LINEAR_val; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); SourceLocation ELoc; SourceRange ERange; @@ -10702,11 +10964,11 @@ OMPClause *Sema::ActOnOpenMPLinearClause( // A list-item cannot appear in more than one linear clause. // A list-item that appears in a linear clause cannot appear in any // other data-sharing attribute clause. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_linear); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } @@ -10715,16 +10977,18 @@ OMPClause *Sema::ActOnOpenMPLinearClause( Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType(); // Build private copy of original var. - auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc); + VarDecl *Private = + buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr, + VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr); + DeclRefExpr *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc); // Build var to save initial value. VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start"); Expr *InitExpr; DeclRefExpr *Ref = nullptr; if (!VD && !CurContext->isDependentContext()) { Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); - if (!IsOpenMPCapturedDecl(D)) { + if (!isOpenMPCapturedDecl(D)) { ExprCaptures.push_back(Ref->getDecl()); if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { ExprResult RefRes = DefaultLvalueConversion(Ref); @@ -10746,7 +11010,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause( InitExpr = VD ? SimpleRefExpr : Ref; AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(), /*DirectInit=*/false); - auto InitRef = buildDeclRefExpr(*this, Init, Type, ELoc); + DeclRefExpr *InitRef = buildDeclRefExpr(*this, Init, Type, ELoc); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref); Vars.push_back((VD || CurContext->isDependentContext()) @@ -10810,16 +11074,15 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *CalcStep = Clause.getCalcStep(); // OpenMP [2.14.3.7, linear clause] // If linear-step is not specified it is assumed to be 1. - if (Step == nullptr) + if (!Step) Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(); - else if (CalcStep) { + else if (CalcStep) Step = cast<BinaryOperator>(CalcStep)->getLHS(); - } bool HasErrors = false; auto CurInit = Clause.inits().begin(); auto CurPrivate = Clause.privates().begin(); - auto LinKind = Clause.getModifier(); - for (auto &RefExpr : Clause.varlists()) { + OpenMPLinearClauseKind LinKind = Clause.getModifier(); + for (Expr *RefExpr : Clause.varlists()) { SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -10860,22 +11123,22 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // Build update: Var = InitExpr + IV * Step ExprResult Update; - if (!Info.first) { + if (!Info.first) Update = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, + buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step, /* Subtract */ false); - } else + else Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step ExprResult Final; - if (!Info.first) { - Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, - /* Subtract */ false); - } else + if (!Info.first) + Final = + buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, + InitExpr, NumIterations, Step, /*Subtract=*/false); + else Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), /*DiscardedValue=*/true); @@ -10899,9 +11162,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, OMPClause *Sema::ActOnOpenMPAlignedClause( ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { - SmallVector<Expr *, 8> Vars; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); SourceLocation ELoc; SourceRange ERange; @@ -10938,7 +11200,7 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. - if (Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) { + if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) { Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange; Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); @@ -10946,7 +11208,7 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( } DeclRefExpr *Ref = nullptr; - if (!VD && IsOpenMPCapturedDecl(D)) + if (!VD && isOpenMPCapturedDecl(D)) Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); Vars.push_back(DefaultFunctionArrayConversion( (VD || !Ref) ? RefExpr->IgnoreParens() : Ref) @@ -10980,7 +11242,7 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> SrcExprs; SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyin clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. @@ -10996,7 +11258,7 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A list item is a variable name. // OpenMP [2.14.4.1, Restrictions, p.1] // A list item that appears in a copyin clause must be threadprivate. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); + auto *DE = dyn_cast<DeclRefExpr>(RefExpr); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name_member_expr) << 0 << RefExpr->getSourceRange(); @@ -11004,7 +11266,7 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, } Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); + auto *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { @@ -11029,21 +11291,22 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. - auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = + QualType ElemType = Context.getBaseElementType(Type).getNonReferenceType(); + VarDecl *SrcVD = buildVarDecl(*this, DE->getLocStart(), ElemType.getUnqualifiedType(), ".copyin.src", VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = buildDeclRefExpr( + DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr( *this, SrcVD, ElemType.getUnqualifiedType(), DE->getExprLoc()); - auto *DstVD = + VarDecl *DstVD = buildVarDecl(*this, DE->getLocStart(), ElemType, ".copyin.dst", VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoDstExpr = + DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, ElemType, DE->getExprLoc()); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, - PseudoDstExpr, PseudoSrcExpr); + ExprResult AssignmentOp = + BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, PseudoDstExpr, + PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), @@ -11073,7 +11336,7 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> SrcExprs; SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); SourceLocation ELoc; SourceRange ERange; @@ -11098,13 +11361,14 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // A list item that appears in a copyprivate clause may not appear in a // private or firstprivate clause on the single construct. if (!VD || !DSAStack->isThreadPrivate(VD)) { - auto DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } @@ -11117,7 +11381,7 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } } @@ -11143,16 +11407,16 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // operator for the class type. Type = Context.getBaseElementType(Type.getNonReferenceType()) .getUnqualifiedType(); - auto *SrcVD = + VarDecl *SrcVD = buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.src", D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc); - auto *DstVD = + DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc); + VarDecl *DstVD = buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst", D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); - auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, - PseudoDstExpr, PseudoSrcExpr); + DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); + ExprResult AssignmentOp = BuildBinOp( + DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, @@ -11162,7 +11426,7 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - assert(VD || IsOpenMPCapturedDecl(D)); + assert(VD || isOpenMPCapturedDecl(D)); Vars.push_back( VD ? RefExpr->IgnoreParens() : buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false)); @@ -11214,143 +11478,139 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); if (DepKind == OMPC_DEPEND_sink) { - if (auto *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) { + if (const Expr *OrderedCountExpr = DSAStack->getParentOrderedRegionParam()) { TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context); TotalDepCount.setIsUnsigned(/*Val=*/true); } } - if ((DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) || - DSAStack->getParentOrderedRegionParam()) { - for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + Expr *SimpleExpr = RefExpr->IgnoreParenCasts(); + if (DepKind == OMPC_DEPEND_sink) { + if (DSAStack->getParentOrderedRegionParam() && + DepCounter >= TotalDepCount) { + Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); + continue; + } + ++DepCounter; + // OpenMP [2.13.9, Summary] + // depend(dependence-type : vec), where dependence-type is: + // 'sink' and where vec is the iteration vector, which has the form: + // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] + // where n is the value specified by the ordered clause in the loop + // directive, xi denotes the loop iteration variable of the i-th nested + // loop associated with the loop directive, and di is a constant + // non-negative integer. + if (CurContext->isDependentContext()) { // It will be analyzed later. Vars.push_back(RefExpr); continue; } + SimpleExpr = SimpleExpr->IgnoreImplicit(); + OverloadedOperatorKind OOK = OO_None; + SourceLocation OOLoc; + Expr *LHS = SimpleExpr; + Expr *RHS = nullptr; + if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) { + OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); + OOLoc = BO->getOperatorLoc(); + LHS = BO->getLHS()->IgnoreParenImpCasts(); + RHS = BO->getRHS()->IgnoreParenImpCasts(); + } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) { + OOK = OCE->getOperator(); + OOLoc = OCE->getOperatorLoc(); + LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); + } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) { + OOK = MCE->getMethodDecl() + ->getNameInfo() + .getName() + .getCXXOverloadedOperator(); + OOLoc = MCE->getCallee()->getExprLoc(); + LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); + RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + } + SourceLocation ELoc; + SourceRange ERange; + auto Res = getPrivateItem(*this, LHS, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; - SourceLocation ELoc = RefExpr->getExprLoc(); - auto *SimpleExpr = RefExpr->IgnoreParenCasts(); - if (DepKind == OMPC_DEPEND_sink) { - if (DepCounter >= TotalDepCount) { - Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); - continue; - } - ++DepCounter; - // OpenMP [2.13.9, Summary] - // depend(dependence-type : vec), where dependence-type is: - // 'sink' and where vec is the iteration vector, which has the form: - // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn] - // where n is the value specified by the ordered clause in the loop - // directive, xi denotes the loop iteration variable of the i-th nested - // loop associated with the loop directive, and di is a constant - // non-negative integer. - if (CurContext->isDependentContext()) { - // It will be analyzed later. - Vars.push_back(RefExpr); - continue; - } - SimpleExpr = SimpleExpr->IgnoreImplicit(); - OverloadedOperatorKind OOK = OO_None; - SourceLocation OOLoc; - Expr *LHS = SimpleExpr; - Expr *RHS = nullptr; - if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) { - OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); - OOLoc = BO->getOperatorLoc(); - LHS = BO->getLHS()->IgnoreParenImpCasts(); - RHS = BO->getRHS()->IgnoreParenImpCasts(); - } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) { - OOK = OCE->getOperator(); - OOLoc = OCE->getOperatorLoc(); - LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); - } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) { - OOK = MCE->getMethodDecl() - ->getNameInfo() - .getName() - .getCXXOverloadedOperator(); - OOLoc = MCE->getCallee()->getExprLoc(); - LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); - RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - } - SourceLocation ELoc; - SourceRange ERange; - auto Res = getPrivateItem(*this, LHS, ELoc, ERange, - /*AllowArraySection=*/false); - if (Res.second) { - // It will be analyzed later. - Vars.push_back(RefExpr); - } - ValueDecl *D = Res.first; - if (!D) - continue; - - if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { - Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); - continue; - } - if (RHS) { - ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( - RHS, OMPC_depend, /*StrictlyPositive=*/false); - if (RHSRes.isInvalid()) - continue; - } - if (!CurContext->isDependentContext() && - DSAStack->getParentOrderedRegionParam() && - DepCounter != DSAStack->isParentLoopControlVariable(D).first) { - ValueDecl* VD = DSAStack->getParentLoopControlVariable( - DepCounter.getZExtValue()); - if (VD) { - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) - << 1 << VD; - } else { - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0; - } - continue; - } - OpsOffs.push_back({RHS, OOK}); - } else { - auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (ASE && - !ASE->getBase() - ->getType() - .getNonReferenceType() - ->isPointerType() && - !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); - continue; - } - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - ExprResult Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, - RefExpr->IgnoreParenImpCasts()); - getDiagnostics().setSuppressAllDiagnostics(Suppress); - if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); + if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { + Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + continue; + } + if (RHS) { + ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( + RHS, OMPC_depend, /*StrictlyPositive=*/false); + if (RHSRes.isInvalid()) continue; - } } - Vars.push_back(RefExpr->IgnoreParenImpCasts()); + if (!CurContext->isDependentContext() && + DSAStack->getParentOrderedRegionParam() && + DepCounter != DSAStack->isParentLoopControlVariable(D).first) { + const ValueDecl *VD = + DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue()); + if (VD) + Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 1 << VD; + else + Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0; + continue; + } + OpsOffs.emplace_back(RHS, OOK); + } else { + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (ASE && + !ASE->getBase()->getType().getNonReferenceType()->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << RefExpr->getSourceRange(); + continue; + } + bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); + getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + ExprResult Res = + CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); + getDiagnostics().setSuppressAllDiagnostics(Suppress); + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << RefExpr->getSourceRange(); + continue; + } } + Vars.push_back(RefExpr->IgnoreParenImpCasts()); + } - if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && - TotalDepCount > VarList.size() && - DSAStack->getParentOrderedRegionParam() && - DSAStack->getParentLoopControlVariable(VarList.size() + 1)) { - Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) << 1 - << DSAStack->getParentLoopControlVariable(VarList.size() + 1); - } - if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink && - Vars.empty()) - return nullptr; + if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && + TotalDepCount > VarList.size() && + DSAStack->getParentOrderedRegionParam() && + DSAStack->getParentLoopControlVariable(VarList.size() + 1)) { + Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1); } + if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink && + Vars.empty()) + return nullptr; + auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, DepLoc, ColonLoc, Vars); - if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) + if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) && + DSAStack->isParentOrderedRegion()) DSAStack->addDoacrossDependClause(C, OpsOffs); return C; } @@ -11363,7 +11623,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, // OpenMP [2.9.1, Restrictions] // The device expression must evaluate to a non-negative integer value. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_device, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device, /*StrictlyPositive=*/false)) return nullptr; @@ -11372,46 +11632,50 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, getOpenMPCaptureRegionForClause(DKind, OMPC_device); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } - return new (Context) - OMPDeviceClause(ValExpr, HelperValStmt, StartLoc, LParenLoc, EndLoc); + return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, EndLoc); } -static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, - DSAStackTy *Stack, QualType QTy) { +static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, + DSAStackTy *Stack, QualType QTy, + bool FullCheck = true) { NamedDecl *ND; if (QTy->isIncompleteType(&ND)) { SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; } + if (FullCheck && !SemaRef.CurContext->isDependentContext() && + !QTy.isTrivialType(SemaRef.Context)) + SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR; return true; } -/// \brief Return true if it can be proven that the provided array expression +/// Return true if it can be proven that the provided array expression /// (array section or array subscript) does NOT specify the whole size of the /// array whose base type is \a BaseQTy. -static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, +static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, const Expr *E, QualType BaseQTy) { - auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + const auto *OASE = dyn_cast<OMPArraySectionExpr>(E); // If this is an array subscript, it refers to the whole size if the size of // the dimension is constant and equals 1. Also, an array section assumes the // format of an array subscript if no colon is used. if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) { - if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) return ATy->getSize().getSExtValue() != 1; // Size can't be evaluated statically. return false; } assert(OASE && "Expecting array section if not an array subscript."); - auto *LowerBound = OASE->getLowerBound(); - auto *Length = OASE->getLength(); + const Expr *LowerBound = OASE->getLowerBound(); + const Expr *Length = OASE->getLength(); // If there is a lower bound that does not evaluates to zero, we are not // covering the whole dimension. @@ -11434,7 +11698,7 @@ static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, // We can only check if the length is the same as the size of the dimension // if we have a constant array. - auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()); + const auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()); if (!CATy) return false; @@ -11448,10 +11712,10 @@ static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, // Return true if it can be proven that the provided array expression (array // section or array subscript) does NOT specify a single element of the array // whose base type is \a BaseQTy. -static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, +static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, const Expr *E, QualType BaseQTy) { - auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + const auto *OASE = dyn_cast<OMPArraySectionExpr>(E); // An array subscript always refer to a single element. Also, an array section // assumes the format of an array subscript if no colon is used. @@ -11459,13 +11723,13 @@ static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, return false; assert(OASE && "Expecting array section if not an array subscript."); - auto *Length = OASE->getLength(); + const Expr *Length = OASE->getLength(); // If we don't have a length we have to check if the array has unitary size // for this dimension. Also, we should always expect a length if the base type // is pointer. if (!Length) { - if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) return ATy->getSize().getSExtValue() != 1; // We cannot assume anything. return false; @@ -11483,7 +11747,7 @@ static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, // cannot be determined and do all the necessary checks to see if the expression // is valid as a standalone mappable expression. In the process, record all the // components of the expression. -static Expr *CheckMapClauseExpressionBase( +static const Expr *checkMapClauseExpressionBase( Sema &SemaRef, Expr *E, OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, OpenMPClauseKind CKind, bool NoDiagnose) { @@ -11509,7 +11773,7 @@ static Expr *CheckMapClauseExpressionBase( // // We want to retrieve the member expression 'this->S'; - Expr *RelevantExpr = nullptr; + const Expr *RelevantExpr = nullptr; // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2] // If a list item is an array section, it must specify contiguous storage. @@ -11548,7 +11812,7 @@ static Expr *CheckMapClauseExpressionBase( // Record the component. CurComponents.emplace_back(CurE, CurE->getDecl()); } else if (auto *CurE = dyn_cast<MemberExpr>(E)) { - auto *BaseE = CurE->getBase()->IgnoreParenImpCasts(); + Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts(); if (isa<CXXThisExpr>(BaseE)) // We found a base expression: this->Val. @@ -11592,15 +11856,13 @@ static Expr *CheckMapClauseExpressionBase( // A list item cannot be a variable that is a member of a structure with // a union type. // - if (auto *RT = CurType->getAs<RecordType>()) { - if (RT->isUnionType()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) - << CurE->getSourceRange(); - return nullptr; - } - continue; + if (CurType->isUnionType()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << CurE->getSourceRange(); + return nullptr; } + continue; } // If we got a member expression, we should not expect any array section @@ -11630,7 +11892,7 @@ static Expr *CheckMapClauseExpressionBase( // If we got an array subscript that express the whole dimension we // can have any array expressions before. If it only expressing part of // the dimension, we can only have unitary-size array expressions. - if (CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, + if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, E->getType())) AllowWholeSizeArraySection = false; @@ -11658,9 +11920,9 @@ static Expr *CheckMapClauseExpressionBase( } bool NotWhole = - CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); + checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); bool NotUnity = - CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); + checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); if (AllowWholeSizeArraySection) { // Any array section is currently allowed. Allowing a whole size array @@ -11698,8 +11960,8 @@ static Expr *CheckMapClauseExpressionBase( // Return true if expression E associated with value VD has conflicts with other // map information. -static bool CheckMapConflicts( - Sema &SemaRef, DSAStackTy *DSAS, ValueDecl *VD, Expr *E, +static bool checkMapConflicts( + Sema &SemaRef, DSAStackTy *DSAS, const ValueDecl *VD, const Expr *E, bool CurrentRegionOnly, OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents, OpenMPClauseKind CKind) { @@ -11721,17 +11983,19 @@ static bool CheckMapConflicts( bool FoundError = DSAS->checkMappableExprComponentListsForDecl( VD, CurrentRegionOnly, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef - StackComponents, - OpenMPClauseKind) -> bool { - + [&IsEnclosedByDataEnvironmentExpr, &SemaRef, VD, CurrentRegionOnly, ELoc, + ERange, CKind, &EnclosingExpr, + CurComponents](OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents, + OpenMPClauseKind) { assert(!StackComponents.empty() && "Map clause expression with no components!"); assert(StackComponents.back().getAssociatedDeclaration() == VD && "Map clause expression with unexpected base!"); + (void)VD; // The whole expression in the stack. - auto *RE = StackComponents.front().getAssociatedExpression(); + const Expr *RE = StackComponents.front().getAssociatedExpression(); // Expressions must start from the same base. Here we detect at which // point both expressions diverge from each other and see if we can @@ -11774,17 +12038,17 @@ static bool CheckMapConflicts( // If they are, the maps completely overlap, which is legal. for (; SI != SE; ++SI) { QualType Type; - if (auto *ASE = + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) { Type = ASE->getBase()->IgnoreParenImpCasts()->getType(); - } else if (auto *OASE = dyn_cast<OMPArraySectionExpr>( + } else if (const auto *OASE = dyn_cast<OMPArraySectionExpr>( SI->getAssociatedExpression())) { - auto *E = OASE->getBase()->IgnoreParenImpCasts(); + const Expr *E = OASE->getBase()->IgnoreParenImpCasts(); Type = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); } if (Type.isNull() || Type->isAnyPointerType() || - CheckArrayExpressionDoesNotReferToWholeSize( + checkArrayExpressionDoesNotReferToWholeSize( SemaRef, SI->getAssociatedExpression(), Type)) break; } @@ -11797,9 +12061,9 @@ static bool CheckMapConflicts( // other, it means they are sharing storage. if (CI == CE && SI == SE) { if (CurrentRegionOnly) { - if (CKind == OMPC_map) + if (CKind == OMPC_map) { SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; - else { + } else { assert(CKind == OMPC_to || CKind == OMPC_from); SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) << ERange; @@ -11807,12 +12071,11 @@ static bool CheckMapConflicts( SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) << RE->getSourceRange(); return true; - } else { - // If we find the same expression in the enclosing data environment, - // that is legal. - IsEnclosedByDataEnvironmentExpr = true; - return false; } + // If we find the same expression in the enclosing data environment, + // that is legal. + IsEnclosedByDataEnvironmentExpr = true; + return false; } QualType DerivedType = @@ -11842,14 +12105,21 @@ static bool CheckMapConflicts( DerivedLoc, diag::err_omp_pointer_mapped_along_with_derived_section) << DerivedLoc; - } else { + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } + if (CI->getAssociatedExpression()->getStmtClass() != + SI->getAssociatedExpression()->getStmtClass() || + CI->getAssociatedDeclaration()->getCanonicalDecl() == + SI->getAssociatedDeclaration()->getCanonicalDecl()) { assert(CI != CE && SI != SE); - SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_derreferenced) + SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_dereferenced) << DerivedLoc; + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; } - SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) - << RE->getSourceRange(); - return true; } // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4] @@ -11858,9 +12128,9 @@ static bool CheckMapConflicts( // // An expression is a subset of the other. if (CurrentRegionOnly && (CI == CE || SI == SE)) { - if (CKind == OMPC_map) + if (CKind == OMPC_map) { SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; - else { + } else { assert(CKind == OMPC_to || CKind == OMPC_from); SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) << ERange; @@ -11912,7 +12182,7 @@ static bool CheckMapConflicts( namespace { // Utility struct that gathers all the related lists associated with a mappable // expression. -struct MappableVarListInfo final { +struct MappableVarListInfo { // The list of expressions. ArrayRef<Expr *> VarList; // The list of processed expressions. @@ -11952,11 +12222,11 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // In the end we should have the same amount of declarations and component // lists. - for (auto &RE : MVLI.VarList) { + for (Expr *RE : MVLI.VarList) { assert(RE && "Null expr in omp to/from/map clause"); SourceLocation ELoc = RE->getExprLoc(); - auto *VE = RE->IgnoreParenLValueCasts(); + const Expr *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || @@ -11967,7 +12237,7 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, continue; } - auto *SimpleExpr = RE->IgnoreParenCasts(); + Expr *SimpleExpr = RE->IgnoreParenCasts(); if (!RE->IgnoreParenImpCasts()->isLValue()) { SemaRef.Diag(ELoc, @@ -11981,8 +12251,8 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // Obtain the array or member expression bases if required. Also, fill the // components array with all the components identified in the process. - auto *BE = CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, - CKind, /*NoDiagnose=*/false); + const Expr *BE = checkMapClauseExpressionBase( + SemaRef, SimpleExpr, CurComponents, CKind, /*NoDiagnose=*/false); if (!BE) continue; @@ -11999,7 +12269,7 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, "Expecting components to have associated only canonical declarations."); auto *VD = dyn_cast<VarDecl>(CurDeclaration); - auto *FD = dyn_cast<FieldDecl>(CurDeclaration); + const auto *FD = dyn_cast<FieldDecl>(CurDeclaration); assert((VD || FD) && "Only variables or fields are expected here!"); (void)FD; @@ -12009,10 +12279,10 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // OpenMP 4.5 [2.10.5, target update Construct] // threadprivate variables cannot appear in a from clause. if (VD && DSAS->isThreadPrivate(VD)) { - auto DVar = DSAS->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false); SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause) << getOpenMPClauseName(CKind); - ReportOriginalDSA(SemaRef, DSAS, VD, DVar); + reportOriginalDsa(SemaRef, DSAS, VD, DVar); continue; } @@ -12024,11 +12294,11 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // with the current construct separately from the enclosing data // environment, because the restrictions are different. We only have to // check conflicts across regions for the map clauses. - if (CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + if (checkMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, /*CurrentRegionOnly=*/true, CurComponents, CKind)) break; if (CKind == OMPC_map && - CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + checkMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, /*CurrentRegionOnly=*/false, CurComponents, CKind)) break; @@ -12036,13 +12306,20 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] // If the type of a list item is a reference to a type T then the type will // be considered to be T for all purposes of this clause. - QualType Type = CurDeclaration->getType().getNonReferenceType(); + auto I = llvm::find_if( + CurComponents, + [](const OMPClauseMappableExprCommon::MappableComponent &MC) { + return MC.getAssociatedDeclaration(); + }); + assert(I != CurComponents.end() && "Null decl on map clause."); + QualType Type = + I->getAssociatedDeclaration()->getType().getNonReferenceType(); // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4] // A list item in a to or from clause must have a mappable type. // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] // A list item must have a mappable type. - if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef, + if (!checkTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef, DSAS, Type)) continue; @@ -12078,18 +12355,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct - if ((DKind == OMPD_target || DKind == OMPD_target_teams || - DKind == OMPD_target_teams_distribute || - DKind == OMPD_target_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd) && VD) { - auto DVar = DSAS->getTopDSA(VD, false); + if (VD && isOpenMPTargetExecutionDirective(DKind)) { + DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false); if (isOpenMPPrivate(DVar.CKind)) { SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_map) << getOpenMPDirectiveName(DSAS->getCurrentDirective()); - ReportOriginalDSA(SemaRef, DSAS, CurDeclaration, DVar); + reportOriginalDsa(SemaRef, DSAS, CurDeclaration, DVar); continue; } } @@ -12190,14 +12463,14 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, /*AllowInlineNamespace=*/false); llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious; - auto Filter = Lookup.makeFilter(); + LookupResult::Filter Filter = Lookup.makeFilter(); while (Filter.hasNext()) { auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next()); if (InCompoundScope) { auto I = UsedAsPrevious.find(PrevDecl); if (I == UsedAsPrevious.end()) UsedAsPrevious[PrevDecl] = false; - if (auto *D = PrevDecl->getPrevDeclInScope()) + if (OMPDeclareReductionDecl *D = PrevDecl->getPrevDeclInScope()) UsedAsPrevious[D] = true; } PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = @@ -12205,7 +12478,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( } Filter.done(); if (InCompoundScope) { - for (auto &PrevData : UsedAsPrevious) { + for (const auto &PrevData : UsedAsPrevious) { if (!PrevData.second) { PrevDRD = PrevData.first; break; @@ -12221,8 +12494,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope(); } while (PrevDRDInScope != nullptr); } - for (auto &TyData : ReductionTypes) { - auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType()); + for (const auto &TyData : ReductionTypes) { + const auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType()); bool Invalid = false; if (I != PreviousRedeclTypes.end()) { Diag(TyData.second, diag::err_omp_declare_reduction_redefinition) @@ -12251,7 +12524,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { // Enter new function scope. PushFunctionScope(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); getCurFunction()->setHasOMPDeclareReductionCombiner(); if (S != nullptr) @@ -12269,7 +12542,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { // reference. C lang does not support references, so pass all parameters as // pointers. // Create 'T omp_in;' variable. - auto *OmpInParm = + VarDecl *OmpInParm = buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in"); // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will // be replaced by '*omp_parm' during codegen. This required because 'omp_out' @@ -12277,7 +12550,7 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { // reference. C lang does not support references, so pass all parameters as // pointers. // Create 'T omp_out;' variable. - auto *OmpOutParm = + VarDecl *OmpOutParm = buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out"); if (S != nullptr) { PushOnScopeChains(OmpInParm, S); @@ -12307,7 +12580,7 @@ VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { // Enter new function scope. PushFunctionScope(); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); if (S != nullptr) PushDeclContext(S, DRD); @@ -12324,7 +12597,7 @@ VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { // reference. C lang does not support references, so pass all parameters as // pointers. // Create 'T omp_priv;' variable. - auto *OmpPrivParm = + VarDecl *OmpPrivParm = buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv"); // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will // be replaced by '*omp_parm' during codegen. This required because 'omp_orig' @@ -12332,7 +12605,7 @@ VarDecl *Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { // reference. C lang does not support references, so pass all parameters as // pointers. // Create 'T omp_orig;' variable. - auto *OmpOrigParm = + VarDecl *OmpOrigParm = buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig"); if (S != nullptr) { PushOnScopeChains(OmpPrivParm, S); @@ -12367,13 +12640,14 @@ void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) { - for (auto *D : DeclReductions.get()) { + for (Decl *D : DeclReductions.get()) { if (IsValid) { - auto *DRD = cast<OMPDeclareReductionDecl>(D); - if (S != nullptr) - PushOnScopeChains(DRD, S, /*AddToContext=*/false); - } else + if (S) + PushOnScopeChains(cast<OMPDeclareReductionDecl>(D), S, + /*AddToContext=*/false); + } else { D->setInvalidDecl(); + } } return DeclReductions; } @@ -12387,7 +12661,7 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, // OpenMP [teams Constrcut, Restrictions] // The num_teams expression must evaluate to a positive integer value. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_teams, /*StrictlyPositive=*/true)) return nullptr; @@ -12396,7 +12670,7 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -12414,7 +12688,7 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, // OpenMP [teams Constrcut, Restrictions] // The thread_limit expression must evaluate to a positive integer value. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_thread_limit, /*StrictlyPositive=*/true)) return nullptr; @@ -12423,7 +12697,7 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -12440,7 +12714,7 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, // OpenMP [2.9.1, task Constrcut] // The priority-value is a non-negative numerical scalar expression. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority, /*StrictlyPositive=*/false)) return nullptr; @@ -12456,7 +12730,7 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the grainsize clause must be a positive integer // expression. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, /*StrictlyPositive=*/true)) return nullptr; @@ -12472,7 +12746,7 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the num_tasks clause must be a positive integer // expression. - if (!IsNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks, + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks, /*StrictlyPositive=*/true)) return nullptr; @@ -12534,7 +12808,7 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause( OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); - llvm::MapVector<Expr *, DeclRefExpr *> Captures; + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); HelperValStmt = buildPreInits(Context, Captures); } @@ -12599,7 +12873,6 @@ bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) { void Sema::ActOnFinishOpenMPDeclareTargetDirective() { assert(IsInOpenMPDeclareTargetContext && "Unexpected ActOnFinishOpenMPDeclareTargetDirective"); - IsInOpenMPDeclareTargetContext = false; } @@ -12634,9 +12907,8 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); - if (!ND->hasAttr<OMPDeclareTargetDeclAttr>()) { - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); ND->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); @@ -12645,15 +12917,16 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) << Id.getName(); } - } else + } else { Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName(); + } } static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, Sema &SemaRef, Decl *D) { if (!D) return; - Decl *LD = nullptr; + const Decl *LD = nullptr; if (isa<TagDecl>(D)) { LD = cast<TagDecl>(D)->getDefinition(); } else if (isa<VarDecl>(D)) { @@ -12662,56 +12935,63 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, // If this is an implicit variable that is legal and we do not need to do // anything. if (cast<VarDecl>(D)->isImplicit()) { - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); D->addAttr(A); if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(D, A); return; } - - } else if (isa<FunctionDecl>(D)) { + } else if (const auto *F = dyn_cast<FunctionDecl>(D)) { const FunctionDecl *FD = nullptr; - if (cast<FunctionDecl>(D)->hasBody(FD)) - LD = const_cast<FunctionDecl *>(FD); - - // If the definition is associated with the current declaration in the - // target region (it can be e.g. a lambda) that is legal and we do not need - // to do anything else. - if (LD == D) { - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( - SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); - D->addAttr(A); - if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) - ML->DeclarationMarkedOpenMPDeclareTarget(D, A); - return; + if (cast<FunctionDecl>(D)->hasBody(FD)) { + LD = FD; + // If the definition is associated with the current declaration in the + // target region (it can be e.g. a lambda) that is legal and we do not + // need to do anything else. + if (LD == D) { + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + return; + } + } else if (F->isFunctionTemplateSpecialization() && + F->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation) { + // Check if the function is implicitly instantiated from the template + // defined in the declare target region. + const FunctionTemplateDecl *FTD = F->getPrimaryTemplate(); + if (FTD && FTD->hasAttr<OMPDeclareTargetDeclAttr>()) + return; } } if (!LD) LD = D; if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() && - (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) { + ((isa<VarDecl>(LD) && !isa<ParmVarDecl>(LD)) || isa<FunctionDecl>(LD))) { // Outlined declaration is not declared target. - if (LD->isOutOfLine()) { - SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); - SemaRef.Diag(SL, diag::note_used_here) << SR; - } else { - DeclContext *DC = LD->getDeclContext(); - while (DC) { - if (isa<FunctionDecl>(DC) && - cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>()) - break; - DC = DC->getParent(); - } - if (DC) - return; + if (!isa<FunctionDecl>(LD)) { + if (LD->isOutOfLine()) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } else { + const DeclContext *DC = LD->getDeclContext(); + while (DC && + (!isa<FunctionDecl>(DC) || + !cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>())) + DC = DC->getParent(); + if (DC) + return; - // Is not declared in target context. - SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); - SemaRef.Diag(SL, diag::note_used_here) << SR; + // Is not declared in target context. + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } } // Mark decl as declared target to prevent further diagnostic. - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); D->addAttr(A); if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) @@ -12722,11 +13002,9 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, ValueDecl *VD) { - if (VD->hasAttr<OMPDeclareTargetDeclAttr>()) - return true; - if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType())) - return false; - return true; + return VD->hasAttr<OMPDeclareTargetDeclAttr>() || + checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(), + /*FullCheck=*/false); } void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, @@ -12735,22 +13013,27 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, return; SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); SourceLocation SL = E ? E->getLocStart() : D->getLocation(); - // 2.10.6: threadprivate variable cannot appear in a declare target directive. - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (auto *VD = dyn_cast<VarDecl>(D)) { + // Only global variables can be marked as declare target. + if (VD->isLocalVarDeclOrParm()) + return; + // 2.10.6: threadprivate variable cannot appear in a declare target + // directive. if (DSAStack->isThreadPrivate(VD)) { Diag(SL, diag::err_omp_threadprivate_in_target); - ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false)); + reportOriginalDsa(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false)); return; } } - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + if (auto *VD = dyn_cast<ValueDecl>(D)) { // Problem if any with var declared with incomplete type will be reported // as normal, so no need to check it here. if ((E || !VD->getType()->isIncompleteType()) && !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { // Mark decl as declared target to prevent further diagnostic. - if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) { - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD) || + isa<FunctionTemplateDecl>(VD)) { + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( Context, OMPDeclareTargetDeclAttr::MT_To); VD->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) @@ -12759,7 +13042,7 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, return; } } - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->hasAttr<OMPDeclareTargetDeclAttr>() && (FD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() == OMPDeclareTargetDeclAttr::MT_Link)) { @@ -12769,11 +13052,22 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, return; } } + if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) { + if (FTD->hasAttr<OMPDeclareTargetDeclAttr>() && + (FTD->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() == + OMPDeclareTargetDeclAttr::MT_Link)) { + assert(IdLoc.isValid() && "Source location is expected"); + Diag(IdLoc, diag::err_omp_function_in_link_clause); + Diag(FTD->getLocation(), diag::note_defined_here) << FTD; + return; + } + } if (!E) { // Checking declaration inside declare target region. if (!D->hasAttr<OMPDeclareTargetDeclAttr>() && - (isa<VarDecl>(D) || isa<FunctionDecl>(D))) { - Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + (isa<VarDecl>(D) || isa<FunctionDecl>(D) || + isa<FunctionTemplateDecl>(D))) { + auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( Context, OMPDeclareTargetDeclAttr::MT_To); D->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) @@ -12820,7 +13114,7 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> PrivateCopies; SmallVector<Expr *, 8> Inits; - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause."); SourceLocation ELoc; SourceRange ERange; @@ -12849,20 +13143,22 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, } // Build the private variable and the expression that refers to it. - auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), - D->hasAttrs() ? &D->getAttrs() : nullptr); + auto VDPrivate = + buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr, + VD ? cast<DeclRefExpr>(SimpleRefExpr) : nullptr); if (VDPrivate->isInvalidDecl()) continue; CurContext->addDecl(VDPrivate); - auto VDPrivateRefExpr = buildDeclRefExpr( + DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); // Add temporary variable to initialize the private copy of the pointer. - auto *VDInit = + VarDecl *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type, ".devptr.temp"); - auto *VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(), - RefExpr->getExprLoc()); + DeclRefExpr *VDInitRefExpr = buildDeclRefExpr( + *this, VDInit, RefExpr->getType(), RefExpr->getExprLoc()); AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(VDInitRefExpr).get(), /*DirectInit=*/false); @@ -12902,7 +13198,7 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { MappableVarListInfo MVLI(VarList); - for (auto &RefExpr : VarList) { + for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause."); SourceLocation ELoc; SourceRange ERange; @@ -12927,17 +13223,17 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, // Check if the declaration in the clause does not show up in any data // sharing attribute. - auto DVar = DSAStack->getTopDSA(D, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (isOpenMPPrivate(DVar.CKind)) { Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_is_device_ptr) << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); - ReportOriginalDSA(*this, DSAStack, D, DVar); + reportOriginalDsa(*this, DSAStack, D, DVar); continue; } - Expr *ConflictExpr; + const Expr *ConflictExpr; if (DSAStack->checkMappableExprComponentListsForDecl( D, /*CurrentRegionOnly=*/true, [&ConflictExpr]( diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index f2b1963df1ed..08af485ef4c7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -223,6 +223,7 @@ bool StandardConversionSequence::isPointerConversionToBool() const { // a pointer. if (getToType(1)->isBooleanType() && (getFromType()->isPointerType() || + getFromType()->isMemberPointerType() || getFromType()->isObjCObjectPointerType() || getFromType()->isBlockPointerType() || getFromType()->isNullPtrType() || @@ -288,11 +289,11 @@ static const Expr *IgnoreNarrowingConversion(const Expr *Converted) { /// value of the expression prior to the narrowing conversion. /// \param ConstantType If this is an NK_Constant_Narrowing conversion, the /// type of the expression prior to the narrowing conversion. -NarrowingKind -StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, - const Expr *Converted, - APValue &ConstantValue, - QualType &ConstantType) const { +/// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions +/// from floating point types to integral types should be ignored. +NarrowingKind StandardConversionSequence::getNarrowingKind( + ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue, + QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const { assert(Ctx.getLangOpts().CPlusPlus && "narrowing check outside C++"); // C++11 [dcl.init.list]p7: @@ -327,7 +328,10 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, FloatingIntegralConversion: if (FromType->isRealFloatingType() && ToType->isIntegralType(Ctx)) { return NK_Type_Narrowing; - } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) { + } else if (FromType->isIntegralOrUnscopedEnumerationType() && + ToType->isRealFloatingType()) { + if (IgnoreFloatToIntegralConversion) + return NK_Not_Narrowing; llvm::APSInt IntConstantValue; const Expr *Initializer = IgnoreNarrowingConversion(Converted); assert(Initializer && "Unknown conversion expression"); @@ -580,7 +584,7 @@ namespace { }; } -/// \brief Convert from Sema's representation of template deduction information +/// Convert from Sema's representation of template deduction information /// to the form used in overload-candidate information. DeductionFailureInfo clang::MakeDeductionFailureInfo(ASTContext &Context, @@ -625,6 +629,8 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } + case Sema::TDK_IncompletePack: + // FIXME: It's slightly wasteful to allocate two TemplateArguments for this. case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. @@ -667,6 +673,7 @@ void DeductionFailureInfo::Destroy() { case Sema::TDK_NonDependentConversionFailure: break; + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: @@ -716,6 +723,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_InvalidExplicitArguments: return TemplateParameter::getFromOpaqueValue(Data); + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: return static_cast<DFIParamWithArguments*>(Data)->Param; @@ -736,6 +744,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: @@ -773,6 +782,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { case Sema::TDK_NonDependentConversionFailure: return nullptr; + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: @@ -794,6 +804,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: @@ -997,6 +1008,13 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, Match = *I; return Ovl_Match; } + + // Builtins that have custom typechecking or have a reference should + // not be overloadable or redeclarable. + if (!getASTContext().canBuiltinBeRedeclared(OldF)) { + Match = *I; + return Ovl_NonFunction; + } } else if (isa<UsingDecl>(OldD) || isa<UsingPackDecl>(OldD)) { // We can overload with these, which can show up when doing // redeclaration checks for UsingDecls. @@ -1182,7 +1200,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return false; } -/// \brief Checks availability of the function depending on the current +/// Checks availability of the function depending on the current /// function context. Inside an unavailable function, unavailability is ignored. /// /// \returns true if \arg FD is unavailable and current context is inside @@ -1200,7 +1218,7 @@ bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) { return true; } -/// \brief Tries a user-defined conversion from From to ToType. +/// Tries a user-defined conversion from From to ToType. /// /// Produces an implicit conversion sequence for when a standard conversion /// is not an option. See TryImplicitConversion for more information. @@ -1412,7 +1430,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS, Action); } -/// \brief Determine whether the conversion from FromType to ToType is a valid +/// Determine whether the conversion from FromType to ToType is a valid /// conversion that strips "noexcept" or "noreturn" off the nested function /// type. bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, @@ -1473,12 +1491,10 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, // Drop 'noexcept' if not present in target type. if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) { const auto *ToFPT = cast<FunctionProtoType>(ToFn); - if (FromFPT->isNothrow(Context) && !ToFPT->isNothrow(Context)) { + if (FromFPT->isNothrow() && !ToFPT->isNothrow()) { FromFn = cast<FunctionType>( - Context.getFunctionType(FromFPT->getReturnType(), - FromFPT->getParamTypes(), - FromFPT->getExtProtoInfo().withExceptionSpec( - FunctionProtoType::ExceptionSpecInfo())) + Context.getFunctionTypeWithExceptionSpec(QualType(FromFPT, 0), + EST_None) .getTypePtr()); Changed = true; } @@ -1511,7 +1527,7 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, return true; } -/// \brief Determine whether the conversion from FromType to ToType is a valid +/// Determine whether the conversion from FromType to ToType is a valid /// vector conversion. /// /// \param ICK Will be set to the vector conversion kind, if this is a vector @@ -1766,8 +1782,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, (FromType == S.Context.LongDoubleTy && ToType == S.Context.Float128Ty)); if (Float128AndLongDouble && - (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != - &llvm::APFloat::IEEEdouble())) + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == + &llvm::APFloat::PPCDoubleDouble())) return false; } // Floating point conversions (C++ 4.8). @@ -1998,6 +2014,14 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { isCompleteType(From->getLocStart(), FromType)) return Context.hasSameUnqualifiedType( ToType, FromEnumType->getDecl()->getPromotionType()); + + // C++ [conv.prom]p5: + // If the bit-field has an enumerated type, it is treated as any other + // value of that type for promotion purposes. + // + // ... so do not fall through into the bit-field checks below in C++. + if (getLangOpts().CPlusPlus) + return false; } // C++0x [conv.prom]p2: @@ -2045,6 +2069,11 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // other value of that type for promotion purposes (C++ 4.5p3). // FIXME: We should delay checking of bit-fields until we actually perform the // conversion. + // + // FIXME: In C, only bit-fields of types _Bool, int, or unsigned int may be + // promoted, per C11 6.3.1.1/2. We promote all bit-fields (including enum + // bit-fields and those whose underlying type is larger than int) for GCC + // compatibility. if (From) { if (FieldDecl *MemberDecl = From->getSourceBitField()) { llvm::APSInt BitWidth; @@ -2111,7 +2140,7 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { return false; } -/// \brief Determine if a conversion is a complex promotion. +/// Determine if a conversion is a complex promotion. /// /// A complex promotion is defined as a complex -> complex conversion /// where the conversion between the underlying real types is a @@ -2345,7 +2374,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return false; } -/// \brief Adopt the given qualifiers for the given type. +/// Adopt the given qualifiers for the given type. static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){ Qualifiers TQs = T.getQualifiers(); @@ -2533,7 +2562,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, return false; } -/// \brief Determine whether this is an Objective-C writeback conversion, +/// Determine whether this is an Objective-C writeback conversion, /// used for parameter passing when performing automatic reference counting. /// /// \param FromType The type we're converting form. @@ -2593,7 +2622,7 @@ bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType, IncompatibleObjC)) return false; - /// \brief Construct the type we're converting to, which is a pointer to + /// Construct the type we're converting to, which is a pointer to /// __autoreleasing pointee. FromPointee = Context.getQualifiedType(FromPointee, FromQuals); ConvertedType = Context.getPointerType(FromPointee); @@ -2803,9 +2832,9 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, // Handle exception specification differences on canonical type (in C++17 // onwards). if (cast<FunctionProtoType>(FromFunction->getCanonicalTypeUnqualified()) - ->isNothrow(Context) != + ->isNothrow() != cast<FunctionProtoType>(ToFunction->getCanonicalTypeUnqualified()) - ->isNothrow(Context)) { + ->isNothrow()) { PDiag << ft_noexcept; return; } @@ -3065,7 +3094,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, // in multi-level pointers, subject to the following rules: [...] bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; - while (Context.UnwrapSimilarPointerTypes(FromType, ToType)) { + while (Context.UnwrapSimilarTypes(FromType, ToType)) { // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification // conversion. Then, if all is well, we unwrap one more level of @@ -3121,6 +3150,15 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, = PreviousToQualsIncludeConst && ToQuals.hasConst(); } + // Allows address space promotion by language rules implemented in + // Type::Qualifiers::isAddressSpaceSupersetOf. + Qualifiers FromQuals = FromType.getQualifiers(); + Qualifiers ToQuals = ToType.getQualifiers(); + if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) && + !FromQuals.isAddressSpaceSupersetOf(ToQuals)) { + return false; + } + // We are left with FromType and ToType being the pointee types // after unwrapping the original FromType and ToType the same number // of types. If we unwrapped any pointers, and if FromType and @@ -3129,7 +3167,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType); } -/// \brief - Determine whether this is a conversion from a scalar type to an +/// - Determine whether this is a conversion from a scalar type to an /// atomic type. /// /// If successful, updates \c SCS's second and third steps in the conversion @@ -3472,7 +3510,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { return true; } -/// \brief Compare the user-defined conversion functions or constructors +/// Compare the user-defined conversion functions or constructors /// of two user-defined conversion sequences to determine whether any ordering /// is possible. static ImplicitConversionSequence::CompareKind @@ -3620,16 +3658,6 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc, return Result; } -static bool hasSimilarType(ASTContext &Context, QualType T1, QualType T2) { - while (Context.UnwrapSimilarPointerTypes(T1, T2)) { - Qualifiers Quals; - T1 = Context.getUnqualifiedArrayType(T1, Quals); - T2 = Context.getUnqualifiedArrayType(T2, Quals); - } - - return Context.hasSameUnqualifiedType(T1, T2); -} - // Per 13.3.3.2p3, compare the given standard conversion sequences to // determine if one is a proper subset of the other. static ImplicitConversionSequence::CompareKind @@ -3653,7 +3681,7 @@ compareStandardConversionSubsets(ASTContext &Context, Result = ImplicitConversionSequence::Worse; else return ImplicitConversionSequence::Indistinguishable; - } else if (!hasSimilarType(Context, SCS1.getToType(1), SCS2.getToType(1))) + } else if (!Context.hasSimilarType(SCS1.getToType(1), SCS2.getToType(1))) return ImplicitConversionSequence::Indistinguishable; if (SCS1.Third == SCS2.Third) { @@ -3674,7 +3702,7 @@ compareStandardConversionSubsets(ASTContext &Context, return ImplicitConversionSequence::Indistinguishable; } -/// \brief Determine whether one of the given reference bindings is better +/// Determine whether one of the given reference bindings is better /// than the other based on what kind of bindings they are. static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1, @@ -3927,7 +3955,7 @@ CompareQualificationConversions(Sema &S, : ImplicitConversionSequence::Better; } - while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) { + while (S.Context.UnwrapSimilarTypes(T1, T2)) { // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification // conversion. Then, if all is well, we unwrap one more level of @@ -4199,7 +4227,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc, return ImplicitConversionSequence::Indistinguishable; } -/// \brief Determine whether the given type is valid, e.g., it is not an invalid +/// Determine whether the given type is valid, e.g., it is not an invalid /// C++ class. static bool isTypeValid(QualType T) { if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) @@ -4302,7 +4330,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, return Ref_Related; } -/// \brief Look for a user-defined conversion to a value reference-compatible +/// Look for a user-defined conversion to a value reference-compatible /// with DeclType. Return true if something definite is found. static bool FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, @@ -4429,7 +4457,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, llvm_unreachable("Invalid OverloadResult!"); } -/// \brief Compute an implicit conversion sequence for reference +/// Compute an implicit conversion sequence for reference /// initialization. static ImplicitConversionSequence TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, @@ -5137,6 +5165,13 @@ Sema::PerformObjectArgumentInitialization(Expr *From, FromRecordType = From->getType(); DestType = ImplicitParamRecordType; FromClassification = From->Classify(Context); + + // When performing member access on an rvalue, materialize a temporary. + if (From->isRValue()) { + From = CreateMaterializeTemporaryExpr(FromRecordType, From, + Method->getRefQualifier() != + RefQualifierKind::RQ_RValue); + } } // Note that we always use the true parent context when performing @@ -5399,10 +5434,11 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, SmallVector<PartialDiagnosticAt, 8> Notes; Expr::EvalResult Eval; Eval.Diag = &Notes; + Expr::ConstExprUsage Usage = CCE == Sema::CCEK_TemplateArg + ? Expr::EvaluateForMangling + : Expr::EvaluateForCodeGen; - if ((T->isReferenceType() - ? !Result.get()->EvaluateAsLValue(Eval, S.Context) - : !Result.get()->EvaluateAsRValue(Eval, S.Context)) || + if (!Result.get()->EvaluateAsConstantExpr(Eval, Usage, S.Context) || (RequireInt && !Eval.Val.isInt())) { // The expression can't be folded, so we can't keep it at this position in // the AST. @@ -5641,7 +5677,7 @@ collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType, } } -/// \brief Attempt to convert the given expression to a type which is accepted +/// Attempt to convert the given expression to a type which is accepted /// by the given converter. /// /// This routine will attempt to convert an expression of class type to a @@ -5959,6 +5995,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() && + !Function->getAttr<TargetAttr>()->isDefaultVersion()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_non_default_multiversion_function; + return; + } + if (Constructor) { // C++ [class.copy]p3: // A member function template is never instantiated to perform the copy @@ -6239,12 +6282,17 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg, if (!Function->isVariadic() && Args.size() < Function->getNumParams()) { for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) { ParmVarDecl *P = Function->getParamDecl(i); - ExprResult R = S.PerformCopyInitialization( - InitializedEntity::InitializeParameter(S.Context, - Function->getParamDecl(i)), - SourceLocation(), - P->hasUninstantiatedDefaultArg() ? P->getUninstantiatedDefaultArg() - : P->getDefaultArg()); + Expr *DefArg = P->hasUninstantiatedDefaultArg() + ? P->getUninstantiatedDefaultArg() + : P->getDefaultArg(); + // This can only happen in code completion, i.e. when PartialOverloading + // is true. + if (!DefArg) + return false; + ExprResult R = + S.PerformCopyInitialization(InitializedEntity::InitializeParameter( + S.Context, Function->getParamDecl(i)), + SourceLocation(), DefArg); if (R.isInvalid()) return false; ConvertedArgs.push_back(R.get()); @@ -6355,67 +6403,65 @@ bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, }); } -/// \brief Add all of the function declarations in the given function set to +/// Add all of the function declarations in the given function set to /// the overload candidate set. void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args, - OverloadCandidateSet& CandidateSet, + OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, bool SuppressUserConversions, bool PartialOverloading, bool FirstArgumentIsBase) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { NamedDecl *D = F.getDecl()->getUnderlyingDecl(); - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - ArrayRef<Expr *> FunctionArgs = Args; - if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) { - QualType ObjectType; - Expr::Classification ObjectClassification; - if (Args.size() > 0) { - if (Expr *E = Args[0]) { - // Use the explit base to restrict the lookup: - ObjectType = E->getType(); - ObjectClassification = E->Classify(Context); - } // .. else there is an implit base. - FunctionArgs = Args.slice(1); - } - AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), - cast<CXXMethodDecl>(FD)->getParent(), ObjectType, - ObjectClassification, FunctionArgs, CandidateSet, - SuppressUserConversions, PartialOverloading); - } else { - // Slice the first argument (which is the base) when we access - // static method as non-static - if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) && - !isa<CXXConstructorDecl>(FD)))) { - assert(cast<CXXMethodDecl>(FD)->isStatic()); - FunctionArgs = Args.slice(1); - } - AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, - SuppressUserConversions, PartialOverloading); - } - } else { - FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D); - if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && - !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) { - QualType ObjectType; - Expr::Classification ObjectClassification; + ArrayRef<Expr *> FunctionArgs = Args; + + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); + FunctionDecl *FD = + FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D); + + if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) { + QualType ObjectType; + Expr::Classification ObjectClassification; + if (Args.size() > 0) { if (Expr *E = Args[0]) { - // Use the explit base to restrict the lookup: + // Use the explicit base to restrict the lookup: ObjectType = E->getType(); ObjectClassification = E->Classify(Context); - } // .. else there is an implit base. + } // .. else there is an implicit base. + FunctionArgs = Args.slice(1); + } + if (FunTmpl) { AddMethodTemplateCandidate( FunTmpl, F.getPair(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), ExplicitTemplateArgs, ObjectType, ObjectClassification, - Args.slice(1), CandidateSet, SuppressUserConversions, + FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); } else { - AddTemplateOverloadCandidate(FunTmpl, F.getPair(), - ExplicitTemplateArgs, Args, - CandidateSet, SuppressUserConversions, - PartialOverloading); + AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), + cast<CXXMethodDecl>(FD)->getParent(), ObjectType, + ObjectClassification, FunctionArgs, CandidateSet, + SuppressUserConversions, PartialOverloading); + } + } else { + // This branch handles both standalone functions and static methods. + + // Slice the first argument (which is the base) when we access + // static method as non-static. + if (Args.size() > 0 && + (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) && + !isa<CXXConstructorDecl>(FD)))) { + assert(cast<CXXMethodDecl>(FD)->isStatic()); + FunctionArgs = Args.slice(1); + } + if (FunTmpl) { + AddTemplateOverloadCandidate( + FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, + CandidateSet, SuppressUserConversions, PartialOverloading); + } else { + AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, + SuppressUserConversions, PartialOverloading); } } } @@ -6583,9 +6629,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, Candidate.DeductionFailure.Data = FailedAttr; return; } + + if (Method->isMultiVersion() && Method->hasAttr<TargetAttr>() && + !Method->getAttr<TargetAttr>()->isDefaultVersion()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_non_default_multiversion_function; + } } -/// \brief Add a C++ member function template as a candidate to the candidate +/// Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member /// function template specialization. void @@ -6653,7 +6705,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, Conversions); } -/// \brief Add a C++ function template specialization as a candidate +/// Add a C++ function template specialization as a candidate /// in the candidate set, using template argument deduction to produce /// an appropriate function template specialization. void @@ -6986,9 +7038,15 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.DeductionFailure.Data = FailedAttr; return; } + + if (Conversion->isMultiVersion() && Conversion->hasAttr<TargetAttr>() && + !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_non_default_multiversion_function; + } } -/// \brief Adds a conversion function template specialization +/// Adds a conversion function template specialization /// candidate to the overload set, using template argument deduction /// to deduce the template arguments of the conversion function /// template from the type that we are converting to (C++ @@ -7143,7 +7201,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } -/// \brief Add overload candidates for overloaded operators that are +/// Add overload candidates for overloaded operators that are /// member functions. /// /// Add the overloaded operator candidates that are member functions @@ -7279,18 +7337,18 @@ class BuiltinCandidateTypeSet { /// used in the built-in candidates. TypeSet EnumerationTypes; - /// \brief The set of vector types that will be used in the built-in + /// The set of vector types that will be used in the built-in /// candidates. TypeSet VectorTypes; - /// \brief A flag indicating non-record types are viable candidates + /// A flag indicating non-record types are viable candidates bool HasNonRecordTypes; - /// \brief A flag indicating whether either arithmetic or enumeration types + /// A flag indicating whether either arithmetic or enumeration types /// were present in the candidate set. bool HasArithmeticOrEnumeralTypes; - /// \brief A flag indicating whether the nullptr type was present in the + /// A flag indicating whether the nullptr type was present in the /// candidate set. bool HasNullPtrType; @@ -7543,7 +7601,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } } -/// \brief Helper function for AddBuiltinOperatorCandidates() that adds +/// Helper function for AddBuiltinOperatorCandidates() that adds /// the volatile- and non-volatile-qualified assignment operators for the /// given type to the candidate set. static void AddBuiltinAssignmentOperatorCandidates(Sema &S, @@ -7621,7 +7679,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { namespace { -/// \brief Helper class to manage the addition of builtin operator overload +/// Helper class to manage the addition of builtin operator overload /// candidates. It provides shared state and utility methods used throughout /// the process, as well as a helper method to add each group of builtin /// operator overloads from the standard to a candidate set. @@ -7677,6 +7735,8 @@ class BuiltinOperatorOverloadBuilder { ArithmeticTypes.push_back(S.Context.BoolTy); ArithmeticTypes.push_back(S.Context.CharTy); ArithmeticTypes.push_back(S.Context.WCharTy); + if (S.Context.getLangOpts().Char8) + ArithmeticTypes.push_back(S.Context.Char8Ty); ArithmeticTypes.push_back(S.Context.Char16Ty); ArithmeticTypes.push_back(S.Context.Char32Ty); ArithmeticTypes.push_back(S.Context.SignedCharTy); @@ -7692,7 +7752,7 @@ class BuiltinOperatorOverloadBuilder { "Enough inline storage for all arithmetic types."); } - /// \brief Helper method to factor out the common pattern of adding overloads + /// Helper method to factor out the common pattern of adding overloads /// for '++' and '--' builtin operators. void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy, bool HasVolatile, @@ -7752,11 +7812,13 @@ public: InitArithmeticTypes(); } + // Increment is deprecated for bool since C++17. + // // C++ [over.built]p3: // - // For every pair (T, VQ), where T is an arithmetic type, and VQ - // is either volatile or empty, there exist candidate operator - // functions of the form + // For every pair (T, VQ), where T is an arithmetic type other + // than bool, and VQ is either volatile or empty, there exist + // candidate operator functions of the form // // VQ T& operator++(VQ T&); // T operator++(VQ T&, int); @@ -7773,10 +7835,16 @@ public: if (!HasArithmeticOrEnumeralCandidateType) return; - for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); - Arith < NumArithmeticTypes; ++Arith) { + for (unsigned Arith = 0; Arith < NumArithmeticTypes; ++Arith) { + const auto TypeOfT = ArithmeticTypes[Arith]; + if (TypeOfT == S.Context.BoolTy) { + if (Op == OO_MinusMinus) + continue; + if (Op == OO_PlusPlus && S.getLangOpts().CPlusPlus17) + continue; + } addPlusPlusMinusMinusStyleOverloads( - ArithmeticTypes[Arith], + TypeOfT, VisibleTypeConversionsQuals.hasVolatile(), VisibleTypeConversionsQuals.hasRestrict()); } @@ -7948,7 +8016,8 @@ public: // bool operator>=(T, T); // bool operator==(T, T); // bool operator!=(T, T); - void addRelationalPointerOrEnumeralOverloads() { + // R operator<=>(T, T) + void addGenericBinaryPointerOrEnumeralOverloads() { // C++ [over.match.oper]p3: // [...]the built-in candidates include all of the candidate operator // functions defined in 13.6 that, compared to the given operator, [...] @@ -8021,7 +8090,6 @@ public: UserDefinedBinaryOperators.count(std::make_pair(CanonType, CanonType))) continue; - QualType ParamTypes[2] = { *Enum, *Enum }; S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); } @@ -8139,6 +8207,41 @@ public: } } + // C++2a [over.built]p14: + // + // For every integral type T there exists a candidate operator function + // of the form + // + // std::strong_ordering operator<=>(T, T) + // + // C++2a [over.built]p15: + // + // For every pair of floating-point types L and R, there exists a candidate + // operator function of the form + // + // std::partial_ordering operator<=>(L, R); + // + // FIXME: The current specification for integral types doesn't play nice with + // the direction of p0946r0, which allows mixed integral and unscoped-enum + // comparisons. Under the current spec this can lead to ambiguity during + // overload resolution. For example: + // + // enum A : int {a}; + // auto x = (a <=> (long)42); + // + // error: call is ambiguous for arguments 'A' and 'long'. + // note: candidate operator<=>(int, int) + // note: candidate operator<=>(long, long) + // + // To avoid this error, this function deviates from the specification and adds + // the mixed overloads `operator<=>(L, R)` where L and R are promoted + // arithmetic types (the same as the generic relational overloads). + // + // For now this function acts as a placeholder. + void addThreeWayArithmeticOverloads() { + addGenericBinaryArithmeticOverloads(); + } + // C++ [over.built]p17: // // For every pair of promoted integral types L and R, there @@ -8707,12 +8810,14 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Greater: case OO_LessEqual: case OO_GreaterEqual: - OpBuilder.addRelationalPointerOrEnumeralOverloads(); + OpBuilder.addGenericBinaryPointerOrEnumeralOverloads(); OpBuilder.addGenericBinaryArithmeticOverloads(); break; case OO_Spaceship: - llvm_unreachable("<=> expressions not supported yet"); + OpBuilder.addGenericBinaryPointerOrEnumeralOverloads(); + OpBuilder.addThreeWayArithmeticOverloads(); + break; case OO_Percent: case OO_Caret: @@ -8783,7 +8888,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } } -/// \brief Add function candidates found via argument-dependent lookup +/// Add function candidates found via argument-dependent lookup /// to the set of overloading candidates. /// /// This routine performs argument-dependent name lookup based on the @@ -8889,6 +8994,47 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, return Cand1I == Cand1Attrs.end() ? Comparison::Equal : Comparison::Better; } +static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2) { + if (!Cand1.Function || !Cand1.Function->isMultiVersion() || !Cand2.Function || + !Cand2.Function->isMultiVersion()) + return false; + + // If this is a cpu_dispatch/cpu_specific multiversion situation, prefer + // cpu_dispatch, else arbitrarily based on the identifiers. + bool Cand1CPUDisp = Cand1.Function->hasAttr<CPUDispatchAttr>(); + bool Cand2CPUDisp = Cand2.Function->hasAttr<CPUDispatchAttr>(); + const auto *Cand1CPUSpec = Cand1.Function->getAttr<CPUSpecificAttr>(); + const auto *Cand2CPUSpec = Cand2.Function->getAttr<CPUSpecificAttr>(); + + if (!Cand1CPUDisp && !Cand2CPUDisp && !Cand1CPUSpec && !Cand2CPUSpec) + return false; + + if (Cand1CPUDisp && !Cand2CPUDisp) + return true; + if (Cand2CPUDisp && !Cand1CPUDisp) + return false; + + if (Cand1CPUSpec && Cand2CPUSpec) { + if (Cand1CPUSpec->cpus_size() != Cand2CPUSpec->cpus_size()) + return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size(); + + std::pair<CPUSpecificAttr::cpus_iterator, CPUSpecificAttr::cpus_iterator> + FirstDiff = std::mismatch( + Cand1CPUSpec->cpus_begin(), Cand1CPUSpec->cpus_end(), + Cand2CPUSpec->cpus_begin(), + [](const IdentifierInfo *LHS, const IdentifierInfo *RHS) { + return LHS->getName() == RHS->getName(); + }); + + assert(FirstDiff.first != Cand1CPUSpec->cpus_end() && + "Two different cpu-specific versions should not have the same " + "identifier list, otherwise they'd be the same decl!"); + return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName(); + } + llvm_unreachable("No way to get here unless both had cpu_dispatch"); +} + /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). bool clang::isBetterOverloadCandidate( @@ -9086,7 +9232,10 @@ bool clang::isBetterOverloadCandidate( functionHasPassObjectSizeParams(Cand1.Function); bool HasPS2 = Cand2.Function != nullptr && functionHasPassObjectSizeParams(Cand2.Function); - return HasPS1 != HasPS2 && HasPS1; + if (HasPS1 != HasPS2 && HasPS1) + return true; + + return isBetterMultiversionCandidate(Cand1, Cand2); } /// Determine whether two declarations are "equivalent" for the purposes of @@ -9156,7 +9305,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( } } -/// \brief Computes the best viable function (C++ 13.3.3) +/// Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// /// \param Loc The location of the function name (or operator symbol) for @@ -9247,66 +9396,77 @@ enum OverloadCandidateKind { oc_function, oc_method, oc_constructor, - oc_function_template, - oc_method_template, - oc_constructor_template, oc_implicit_default_constructor, oc_implicit_copy_constructor, oc_implicit_move_constructor, oc_implicit_copy_assignment, oc_implicit_move_assignment, - oc_inherited_constructor, - oc_inherited_constructor_template + oc_inherited_constructor +}; + +enum OverloadCandidateSelect { + ocs_non_template, + ocs_template, + ocs_described_template, }; -static OverloadCandidateKind +static std::pair<OverloadCandidateKind, OverloadCandidateSelect> ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, std::string &Description) { - bool isTemplate = false; + bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl(); if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) { isTemplate = true; Description = S.getTemplateArgumentBindingsText( - FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs()); + FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs()); } - if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { - if (!Ctor->isImplicit()) { - if (isa<ConstructorUsingShadowDecl>(Found)) - return isTemplate ? oc_inherited_constructor_template - : oc_inherited_constructor; - else - return isTemplate ? oc_constructor_template : oc_constructor; - } + OverloadCandidateSelect Select = [&]() { + if (!Description.empty()) + return ocs_described_template; + return isTemplate ? ocs_template : ocs_non_template; + }(); - if (Ctor->isDefaultConstructor()) - return oc_implicit_default_constructor; + OverloadCandidateKind Kind = [&]() { + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { + if (!Ctor->isImplicit()) { + if (isa<ConstructorUsingShadowDecl>(Found)) + return oc_inherited_constructor; + else + return oc_constructor; + } - if (Ctor->isMoveConstructor()) - return oc_implicit_move_constructor; + if (Ctor->isDefaultConstructor()) + return oc_implicit_default_constructor; - assert(Ctor->isCopyConstructor() && - "unexpected sort of implicit constructor"); - return oc_implicit_copy_constructor; - } + if (Ctor->isMoveConstructor()) + return oc_implicit_move_constructor; - if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { - // This actually gets spelled 'candidate function' for now, but - // it doesn't hurt to split it out. - if (!Meth->isImplicit()) - return isTemplate ? oc_method_template : oc_method; + assert(Ctor->isCopyConstructor() && + "unexpected sort of implicit constructor"); + return oc_implicit_copy_constructor; + } - if (Meth->isMoveAssignmentOperator()) - return oc_implicit_move_assignment; + if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { + // This actually gets spelled 'candidate function' for now, but + // it doesn't hurt to split it out. + if (!Meth->isImplicit()) + return oc_method; - if (Meth->isCopyAssignmentOperator()) - return oc_implicit_copy_assignment; + if (Meth->isMoveAssignmentOperator()) + return oc_implicit_move_assignment; - assert(isa<CXXConversionDecl>(Meth) && "expected conversion"); - return oc_method; - } + if (Meth->isCopyAssignmentOperator()) + return oc_implicit_copy_assignment; - return isTemplate ? oc_function_template : oc_function; + assert(isa<CXXConversionDecl>(Meth) && "expected conversion"); + return oc_method; + } + + return oc_function; + }(); + + return std::make_pair(Kind, Select); } void MaybeEmitInheritedConstructorNote(Sema &S, Decl *FoundDecl) { @@ -9332,7 +9492,7 @@ static bool isFunctionAlwaysEnabled(const ASTContext &Ctx, return true; } -/// \brief Returns true if we can take the address of the function. +/// Returns true if we can take the address of the function. /// /// \param Complain - If true, we'll emit a diagnostic /// \param InOverloadResolution - For the purposes of emitting a diagnostic, are @@ -9394,11 +9554,16 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, QualType DestType, bool TakingAddress) { if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn)) return; + if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() && + !Fn->getAttr<TargetAttr>()->isDefaultVersion()) + return; std::string FnDesc; - OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Found, Fn, FnDesc); + std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair = + ClassifyOverloadCandidate(*this, Found, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) - << (unsigned) K << Fn << FnDesc; + << (unsigned)KSPair.first << (unsigned)KSPair.second + << Fn << FnDesc; HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); @@ -9472,7 +9637,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, } std::string FnDesc; - OverloadCandidateKind FnKind = + std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); Expr *FromExpr = Conv.Bad.FromExpr; @@ -9487,9 +9652,9 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, DeclarationName Name = cast<OverloadExpr>(E)->getName(); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << ToTy << Name << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << ToTy + << Name << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9516,43 +9681,38 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy - << FromQs.getAddressSpaceAttributePrintValue() - << ToQs.getAddressSpaceAttributePrintValue() - << (unsigned) isObjectArgument << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << ToTy << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy - << FromQs.getObjCLifetime() << ToQs.getObjCLifetime() - << (unsigned) isObjectArgument << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << FromQs.getObjCLifetime() << ToQs.getObjCLifetime() + << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy - << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr() - << (unsigned) isObjectArgument << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr() + << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } if (FromQs.hasUnaligned() != ToQs.hasUnaligned()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_unaligned) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << FromQs.hasUnaligned() << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << FromQs.hasUnaligned() << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9562,14 +9722,14 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (isObjectArgument) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << (CVR - 1); + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << (CVR - 1); } else { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << (CVR - 1) << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << (CVR - 1) << I + 1; } MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; @@ -9579,9 +9739,9 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, // telling the user that it has type void is not useful. if (FromExpr && isa<InitListExpr>(FromExpr)) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << ToTy << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9595,10 +9755,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (TempFromTy->isIncompleteType()) { // Emit the generic diagnostic and, optionally, add the hints to it. S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1 - << (unsigned) (Cand->Fix.Kind); + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << ToTy << (unsigned)isObjectArgument << I + 1 + << (unsigned)(Cand->Fix.Kind); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; @@ -9636,21 +9796,19 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, ToTy.getNonReferenceType().getCanonicalType() == FromTy.getNonReferenceType().getCanonicalType()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_lvalue) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << (unsigned) isObjectArgument << I + 1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (unsigned)isObjectArgument << I + 1 + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } } if (BaseToDerivedConversion) { - S.Diag(Fn->getLocation(), - diag::note_ovl_candidate_bad_base_to_derived_conv) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << (BaseToDerivedConversion - 1) - << FromTy << ToTy << I+1; + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_base_to_derived_conv) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << (BaseToDerivedConversion - 1) << FromTy << ToTy << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9661,9 +9819,9 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, Qualifiers ToQs = CToTy.getQualifiers(); if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv) - << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9675,10 +9833,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, // Emit the generic diagnostic and, optionally, add the hints to it. PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); - FDiag << (unsigned) FnKind << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I + 1 - << (unsigned) (Cand->Fix.Kind); + FDiag << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy + << ToTy << (unsigned)isObjectArgument << I + 1 + << (unsigned)(Cand->Fix.Kind); // If we can fix the conversion, suggest the FixIts. for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(), @@ -9751,17 +9909,18 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, } std::string Description; - OverloadCandidateKind FnKind = + std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = ClassifyOverloadCandidate(S, Found, Fn, Description); if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) - << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr) - << mode << Fn->getParamDecl(0) << NumFormalArgs; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << Description << mode << Fn->getParamDecl(0) << NumFormalArgs; else S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) - << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr) - << mode << modeCount << NumFormalArgs; + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << Description << mode << modeCount << NumFormalArgs; + MaybeEmitInheritedConstructorNote(S, Found); } @@ -9802,6 +9961,17 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } + case Sema::TDK_IncompletePack: { + assert(ParamD && "no parameter found for incomplete deduction result"); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_incomplete_deduction_pack) + << ParamD->getDeclName() + << (DeductionFailure.getFirstArg()->pack_size() + 1) + << *DeductionFailure.getFirstArg(); + MaybeEmitInheritedConstructorNote(S, Found); + return; + } + case Sema::TDK_Underqualified: { assert(ParamD && "no parameter found for bad qualifiers deduction result"); TemplateTypeParmDecl *TParam = cast<TemplateTypeParmDecl>(ParamD); @@ -10036,11 +10206,13 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { CalleeTarget = S.IdentifyCUDATarget(Callee); std::string FnDesc; - OverloadCandidateKind FnKind = + std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) - << (unsigned)FnKind << CalleeTarget << CallerTarget; + << (unsigned)FnKindPair.first << (unsigned)ocs_non_template + << FnDesc /* Ignored */ + << CalleeTarget << CallerTarget; // This could be an implicit constructor for which we could not infer the // target due to a collsion. Diagnose that case. @@ -10049,7 +10221,7 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { CXXRecordDecl *ParentClass = Meth->getParent(); Sema::CXXSpecialMember CSM; - switch (FnKind) { + switch (FnKindPair.first) { default: return; case oc_implicit_default_constructor: @@ -10121,12 +10293,12 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, if (Cand->Viable) { if (Fn->isDeleted() || S.isFunctionConsideredUnavailable(Fn)) { std::string FnDesc; - OverloadCandidateKind FnKind = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); + std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) - << FnKind << FnDesc - << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0); + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10195,6 +10367,9 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, assert(!Available); break; } + case ovl_non_default_multiversion_function: + // Do nothing, these should simply be ignored. + break; } } @@ -10276,6 +10451,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { case Sema::TDK_Invalid: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: return 1; case Sema::TDK_Underqualified: @@ -10512,9 +10688,8 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, } } -/// PrintOverloadCandidates - When overload resolution fails, prints -/// diagnostic messages containing the candidates in the candidate -/// set. +/// When overload resolution fails, prints diagnostic messages containing the +/// candidates in the candidate set. void OverloadCandidateSet::NoteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, StringRef Opc, SourceLocation OpLoc, @@ -10661,8 +10836,8 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) { // in general, want to list every possible builtin candidate. } - std::sort(Cands.begin(), Cands.end(), - CompareTemplateSpecCandidatesForDisplay(S)); + llvm::sort(Cands.begin(), Cands.end(), + CompareTemplateSpecCandidatesForDisplay(S)); // FIXME: Perhaps rename OverloadsShown and getShowOverloads() // for generalization purposes (?). @@ -10931,6 +11106,11 @@ private: if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) if (!Caller->isImplicit() && !S.IsAllowedCUDACall(Caller, FunDecl)) return false; + if (FunDecl->isMultiVersion()) { + const auto *TA = FunDecl->getAttr<TargetAttr>(); + if (TA && !TA->isDefaultVersion()) + return false; + } // If any candidate has a placeholder return type, trigger its deduction // now. @@ -11012,9 +11192,9 @@ private: MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates, SourceExpr->getLocStart(), S.PDiag(), S.PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0].second->getDeclName(), + << Matches[0].second->getDeclName(), S.PDiag(diag::note_ovl_candidate) - << (unsigned)oc_function_template, + << (unsigned)oc_function << (unsigned)ocs_described_template, Complain, TargetFunctionType); if (Result != MatchesCopy.end()) { @@ -11176,7 +11356,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, return Fn; } -/// \brief Given an expression that refers to an overloaded function, try to +/// Given an expression that refers to an overloaded function, try to /// resolve that function to a single function that can have its address taken. /// This will modify `Pair` iff it returns non-null. /// @@ -11212,7 +11392,7 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, return Result; } -/// \brief Given an overloaded function, tries to turn it into a non-overloaded +/// Given an overloaded function, tries to turn it into a non-overloaded /// function reference using resolveAddressOfOnlyViableOverloadCandidate. This /// will perform access checks, diagnose the use of the resultant decl, and, if /// requested, potentially perform a function-to-pointer decay. @@ -11226,7 +11406,8 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( DeclAccessPair DAP; FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP); - if (!Found) + if (!Found || Found->isCPUDispatchMultiVersion() || + Found->isCPUSpecificMultiVersion()) return false; // Emitting multiple diagnostics for a function that is both inaccessible and @@ -11242,7 +11423,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( return true; } -/// \brief Given an expression that refers to an overloaded function, try to +/// Given an expression that refers to an overloaded function, try to /// resolve that overloaded function expression down to a single function. /// /// This routine can only resolve template-ids that refer to a single function @@ -11411,7 +11592,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization( return true; } -/// \brief Add a single candidate to the overload set. +/// Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, @@ -11450,7 +11631,7 @@ static void AddOverloadedCallCandidate(Sema &S, assert(!KnownValid && "unhandled case in overloaded call candidate"); } -/// \brief Add the overload candidates named by callee and/or found by argument +/// Add the overload candidates named by callee and/or found by argument /// dependent lookup to the given overload set. void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef<Expr *> Args, @@ -11742,7 +11923,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, RParenLoc); } -/// \brief Constructs and populates an OverloadedCandidateSet from +/// Constructs and populates an OverloadedCandidateSet from /// the given function. /// \returns true when an the ExprResult output parameter has been set. bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, @@ -11882,7 +12063,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, << Fn->getSourceRange(); CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args); - // We emitted an error for the unvailable/deleted function call but keep + // We emitted an error for the unavailable/deleted function call but keep // the call in the AST. FunctionDecl *FDecl = (*Best)->Function; Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); @@ -11948,7 +12129,7 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) { (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin())); } -/// \brief Create a unary operation that may resolve to an overloaded +/// Create a unary operation that may resolve to an overloaded /// operator. /// /// \param OpLoc The location of the operator itself (e.g., '*'). @@ -11994,7 +12175,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, if (Input->isTypeDependent()) { if (Fns.empty()) return new (Context) UnaryOperator(Input, Opc, Context.DependentTy, - VK_RValue, OK_Ordinary, OpLoc); + VK_RValue, OK_Ordinary, OpLoc, false); CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators UnresolvedLookupExpr *Fn @@ -12093,7 +12274,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, // break out so that we will build the appropriate built-in // operator node. ExprResult InputRes = PerformImplicitConversion( - Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing); + Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing, + CCK_ForBuiltinOverloadedOp); if (InputRes.isInvalid()) return ExprError(); Input = InputRes.get(); @@ -12139,7 +12321,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } -/// \brief Create a binary operation that may resolve to an overloaded +/// Create a binary operation that may resolve to an overloaded /// operator. /// /// \param OpLoc The location of the operator itself (e.g., '+'). @@ -12337,16 +12519,16 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - ExprResult ArgsRes0 = - PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0], - Best->Conversions[0], AA_Passing); + ExprResult ArgsRes0 = PerformImplicitConversion( + Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0], + AA_Passing, CCK_ForBuiltinOverloadedOp); if (ArgsRes0.isInvalid()) return ExprError(); Args[0] = ArgsRes0.get(); - ExprResult ArgsRes1 = - PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1], - Best->Conversions[1], AA_Passing); + ExprResult ArgsRes1 = PerformImplicitConversion( + Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1], + AA_Passing, CCK_ForBuiltinOverloadedOp); if (ArgsRes1.isInvalid()) return ExprError(); Args[1] = ArgsRes1.get(); @@ -12362,7 +12544,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BO_Comma) break; - // For class as left operand for assignment or compound assigment + // For class as left operand for assignment or compound assignment // operator do not fall through to handling in built-in, but report that // no overloaded assignment operator found ExprResult Result = ExprError(); @@ -12549,16 +12731,16 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - ExprResult ArgsRes0 = - PerformImplicitConversion(Args[0], Best->BuiltinParamTypes[0], - Best->Conversions[0], AA_Passing); + ExprResult ArgsRes0 = PerformImplicitConversion( + Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0], + AA_Passing, CCK_ForBuiltinOverloadedOp); if (ArgsRes0.isInvalid()) return ExprError(); Args[0] = ArgsRes0.get(); - ExprResult ArgsRes1 = - PerformImplicitConversion(Args[1], Best->BuiltinParamTypes[1], - Best->Conversions[1], AA_Passing); + ExprResult ArgsRes1 = PerformImplicitConversion( + Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1], + AA_Passing, CCK_ForBuiltinOverloadedOp); if (ArgsRes1.isInvalid()) return ExprError(); Args[1] = ArgsRes1.get(); @@ -13524,7 +13706,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc()); + UnOp->getOperatorLoc(), false); } } Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), @@ -13535,7 +13717,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, return new (Context) UnaryOperator(SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc()); + UnOp->getOperatorLoc(), false); } // C++ [except.spec]p17: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp index 58980be64a30..4484e9b3513b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp @@ -132,7 +132,8 @@ namespace { uop->getType(), uop->getValueKind(), uop->getObjectKind(), - uop->getOperatorLoc()); + uop->getOperatorLoc(), + uop->canOverflow()); } if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { @@ -189,11 +190,12 @@ namespace { Sema &S; unsigned ResultIndex; SourceLocation GenericLoc; + bool IsUnique; SmallVector<Expr *, 4> Semantics; - PseudoOpBuilder(Sema &S, SourceLocation genericLoc) + PseudoOpBuilder(Sema &S, SourceLocation genericLoc, bool IsUnique) : S(S), ResultIndex(PseudoObjectExpr::NoResult), - GenericLoc(genericLoc) {} + GenericLoc(genericLoc), IsUnique(IsUnique) {} virtual ~PseudoOpBuilder() {} @@ -207,6 +209,9 @@ namespace { assert(ResultIndex == PseudoObjectExpr::NoResult); ResultIndex = Semantics.size(); Semantics.push_back(resultExpr); + // An OVE is not unique if it is used as the result expression. + if (auto *OVE = dyn_cast<OpaqueValueExpr>(Semantics.back())) + OVE->setIsUnique(false); } ExprResult buildRValueOperation(Expr *op); @@ -226,6 +231,9 @@ namespace { void setResultToLastSemantic() { assert(ResultIndex == PseudoObjectExpr::NoResult); ResultIndex = Semantics.size() - 1; + // An OVE is not unique if it is used as the result expression. + if (auto *OVE = dyn_cast<OpaqueValueExpr>(Semantics.back())) + OVE->setIsUnique(false); } /// Return true if assignments have a non-void result. @@ -245,7 +253,7 @@ namespace { virtual ExprResult buildGet() = 0; virtual ExprResult buildSet(Expr *, SourceLocation, bool captureSetValueAsResult) = 0; - /// \brief Should the result of an assignment be the formal result of the + /// Should the result of an assignment be the formal result of the /// setter call or the value that was passed to the setter? /// /// Different pseudo-object language features use different language rules @@ -273,10 +281,10 @@ namespace { Selector GetterSelector; public: - ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : - PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), - SyntacticRefExpr(nullptr), InstanceReceiver(nullptr), Getter(nullptr), - Setter(nullptr) { + ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr, bool IsUnique) + : PseudoOpBuilder(S, refExpr->getLocation(), IsUnique), + RefExpr(refExpr), SyntacticRefExpr(nullptr), + InstanceReceiver(nullptr), Getter(nullptr), Setter(nullptr) { } ExprResult buildRValueOperation(Expr *op); @@ -313,11 +321,10 @@ namespace { Selector AtIndexSetterSelector; public: - ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) : - PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), - RefExpr(refExpr), - InstanceBase(nullptr), InstanceKey(nullptr), - AtIndexGetter(nullptr), AtIndexSetter(nullptr) {} + ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr, bool IsUnique) + : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin(), IsUnique), + RefExpr(refExpr), InstanceBase(nullptr), InstanceKey(nullptr), + AtIndexGetter(nullptr), AtIndexSetter(nullptr) {} ExprResult buildRValueOperation(Expr *op); ExprResult buildAssignmentOperation(Scope *Sc, @@ -341,11 +348,11 @@ namespace { MSPropertyRefExpr *getBaseMSProperty(MSPropertySubscriptExpr *E); public: - MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : - PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), - RefExpr(refExpr), InstanceBase(nullptr) {} - MSPropertyOpBuilder(Sema &S, MSPropertySubscriptExpr *refExpr) - : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), + MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr, bool IsUnique) + : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin(), IsUnique), + RefExpr(refExpr), InstanceBase(nullptr) {} + MSPropertyOpBuilder(Sema &S, MSPropertySubscriptExpr *refExpr, bool IsUnique) + : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin(), IsUnique), InstanceBase(nullptr) { RefExpr = getBaseMSProperty(refExpr); } @@ -364,7 +371,9 @@ OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(), e->getValueKind(), e->getObjectKind(), e); - + if (IsUnique) + captured->setIsUnique(true); + // Make sure we bind that in the semantics. addSemanticExpr(captured); return captured; @@ -396,6 +405,8 @@ OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { if (e == Semantics[index]) break; } ResultIndex = index; + // An OVE is not unique if it is used as the result expression. + cast<OpaqueValueExpr>(e)->setIsUnique(false); return cast<OpaqueValueExpr>(e); } @@ -527,9 +538,12 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, (result.get()->isTypeDependent() || CanCaptureValue(result.get()))) setResultToLastSemantic(); - UnaryOperator *syntactic = - new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, - VK_LValue, OK_Ordinary, opcLoc); + UnaryOperator *syntactic = new (S.Context) UnaryOperator( + syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc, + !resultType->isDependentType() + ? S.Context.getTypeSize(resultType) >= + S.Context.getTypeSize(S.Context.IntTy) + : false); return complete(syntactic); } @@ -961,11 +975,11 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, } ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { - if (isWeakProperty() && + if (isWeakProperty() && !S.isUnevaluatedContext() && !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, SyntacticForm->getLocStart())) - S.recordUseOfEvaluatedWeak(SyntacticRefExpr, - SyntacticRefExpr->isMessagingGetter()); + S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr, + SyntacticRefExpr->isMessagingGetter()); return PseudoOpBuilder::complete(SyntacticForm); } @@ -1524,20 +1538,20 @@ ExprResult Sema::checkPseudoObjectRValue(Expr *E) { Expr *opaqueRef = E->IgnoreParens(); if (ObjCPropertyRefExpr *refExpr = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { - ObjCPropertyOpBuilder builder(*this, refExpr); + ObjCPropertyOpBuilder builder(*this, refExpr, true); return builder.buildRValueOperation(E); } else if (ObjCSubscriptRefExpr *refExpr = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { - ObjCSubscriptOpBuilder builder(*this, refExpr); + ObjCSubscriptOpBuilder builder(*this, refExpr, true); return builder.buildRValueOperation(E); } else if (MSPropertyRefExpr *refExpr = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { - MSPropertyOpBuilder builder(*this, refExpr); + MSPropertyOpBuilder builder(*this, refExpr, true); return builder.buildRValueOperation(E); } else if (MSPropertySubscriptExpr *RefExpr = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { - MSPropertyOpBuilder Builder(*this, RefExpr); + MSPropertyOpBuilder Builder(*this, RefExpr, true); return Builder.buildRValueOperation(E); } else { llvm_unreachable("unknown pseudo-object kind!"); @@ -1550,24 +1564,24 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, // Do nothing if the operand is dependent. if (op->isTypeDependent()) return new (Context) UnaryOperator(op, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc); + VK_RValue, OK_Ordinary, opcLoc, false); assert(UnaryOperator::isIncrementDecrementOp(opcode)); Expr *opaqueRef = op->IgnoreParens(); if (ObjCPropertyRefExpr *refExpr = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { - ObjCPropertyOpBuilder builder(*this, refExpr); + ObjCPropertyOpBuilder builder(*this, refExpr, false); return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) { Diag(opcLoc, diag::err_illegal_container_subscripting_op); return ExprError(); } else if (MSPropertyRefExpr *refExpr = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { - MSPropertyOpBuilder builder(*this, refExpr); + MSPropertyOpBuilder builder(*this, refExpr, false); return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else if (MSPropertySubscriptExpr *RefExpr = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { - MSPropertyOpBuilder Builder(*this, RefExpr); + MSPropertyOpBuilder Builder(*this, RefExpr, false); return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else { llvm_unreachable("unknown pseudo-object kind!"); @@ -1590,22 +1604,23 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, RHS = result.get(); } + bool IsSimpleAssign = opcode == BO_Assign; Expr *opaqueRef = LHS->IgnoreParens(); if (ObjCPropertyRefExpr *refExpr = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { - ObjCPropertyOpBuilder builder(*this, refExpr); + ObjCPropertyOpBuilder builder(*this, refExpr, IsSimpleAssign); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else if (ObjCSubscriptRefExpr *refExpr = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { - ObjCSubscriptOpBuilder builder(*this, refExpr); + ObjCSubscriptOpBuilder builder(*this, refExpr, IsSimpleAssign); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else if (MSPropertyRefExpr *refExpr = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { - MSPropertyOpBuilder builder(*this, refExpr); + MSPropertyOpBuilder builder(*this, refExpr, IsSimpleAssign); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else if (MSPropertySubscriptExpr *RefExpr = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { - MSPropertyOpBuilder Builder(*this, RefExpr); + MSPropertyOpBuilder Builder(*this, RefExpr, IsSimpleAssign); return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else { llvm_unreachable("unknown pseudo-object kind!"); @@ -1633,9 +1648,9 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { Expr *syntax = E->getSyntacticForm(); if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); - return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), - uop->getValueKind(), uop->getObjectKind(), - uop->getOperatorLoc()); + return new (Context) UnaryOperator( + op, uop->getOpcode(), uop->getType(), uop->getValueKind(), + uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow()); } else if (CompoundAssignOperator *cop = dyn_cast<CompoundAssignOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 1ebc36716a88..b2f9783d44f1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -121,7 +121,7 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { } } -/// \brief Diagnose unused comparisons, both builtin and overloaded operators. +/// Diagnose unused comparisons, both builtin and overloaded operators. /// For '==' and '!=', suggest fixits for '=' or '|='. /// /// Adding a cast to void (or other expression wrappers) will prevent the @@ -337,8 +337,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2); } -void Sema::ActOnStartOfCompoundStmt() { - PushCompoundScope(); +void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) { + PushCompoundScope(IsStmtExpr); } void Sema::ActOnFinishOfCompoundStmt() { @@ -392,65 +392,79 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, return CompoundStmt::Create(Context, Elts, L, R); } +ExprResult +Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) { + if (!Val.get()) + return Val; + + if (DiagnoseUnexpandedParameterPack(Val.get())) + return ExprError(); + + // If we're not inside a switch, let the 'case' statement handling diagnose + // this. Just clean up after the expression as best we can. + if (!getCurFunction()->SwitchStack.empty()) { + Expr *CondExpr = + getCurFunction()->SwitchStack.back().getPointer()->getCond(); + if (!CondExpr) + return ExprError(); + QualType CondType = CondExpr->getType(); + + auto CheckAndFinish = [&](Expr *E) { + if (CondType->isDependentType() || E->isTypeDependent()) + return ExprResult(E); + + if (getLangOpts().CPlusPlus11) { + // C++11 [stmt.switch]p2: the constant-expression shall be a converted + // constant expression of the promoted type of the switch condition. + llvm::APSInt TempVal; + return CheckConvertedConstantExpression(E, CondType, TempVal, + CCEK_CaseValue); + } + + ExprResult ER = E; + if (!E->isValueDependent()) + ER = VerifyIntegerConstantExpression(E); + if (!ER.isInvalid()) + ER = DefaultLvalueConversion(ER.get()); + if (!ER.isInvalid()) + ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast); + return ER; + }; + + ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); + if (Converted.get() == Val.get()) + Converted = CheckAndFinish(Val.get()); + if (Converted.isInvalid()) + return ExprError(); + Val = Converted; + } + + return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false, + getLangOpts().CPlusPlus11); +} + StmtResult -Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, - SourceLocation DotDotDotLoc, Expr *RHSVal, +Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHSVal, + SourceLocation DotDotDotLoc, ExprResult RHSVal, SourceLocation ColonLoc) { - assert(LHSVal && "missing expression in case statement"); + assert((LHSVal.isInvalid() || LHSVal.get()) && "missing LHS value"); + assert((DotDotDotLoc.isInvalid() ? RHSVal.isUnset() + : RHSVal.isInvalid() || RHSVal.get()) && + "missing RHS value"); if (getCurFunction()->SwitchStack.empty()) { Diag(CaseLoc, diag::err_case_not_in_switch); 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()) + if (LHSVal.isInvalid() || RHSVal.isInvalid()) { + getCurFunction()->SwitchStack.back().setInt(true); 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. - if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) { - LHSVal = VerifyIntegerConstantExpression(LHSVal).get(); - if (!LHSVal) - return StmtError(); - } - - // GCC extension: The expression shall be an integer constant. - - if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent()) { - RHSVal = VerifyIntegerConstantExpression(RHSVal).get(); - // Recover from an error by just forgetting about it. - } } - 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(LHS.get(), RHS.get(), CaseLoc, DotDotDotLoc, ColonLoc); - getCurFunction()->SwitchStack.back()->addSwitchCase(CS); + CaseStmt(LHSVal.get(), RHSVal.get(), CaseLoc, DotDotDotLoc, ColonLoc); + getCurFunction()->SwitchStack.back().getPointer()->addSwitchCase(CS); return CS; } @@ -473,7 +487,7 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, } DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt); - getCurFunction()->SwitchStack.back()->addSwitchCase(DS); + getCurFunction()->SwitchStack.back().getPointer()->addSwitchCase(DS); return DS; } @@ -557,7 +571,7 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, return StmtError(); if (IsConstexpr || isa<ObjCAvailabilityCheckExpr>(Cond.get().second)) - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); DiagnoseUnusedExprResult(thenStmt); DiagnoseUnusedExprResult(elseStmt); @@ -679,20 +693,44 @@ ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) { if (CondResult.isInvalid()) return ExprError(); + // FIXME: PerformContextualImplicitConversion doesn't always tell us if it + // failed and produced a diagnostic. + Cond = CondResult.get(); + if (!Cond->isTypeDependent() && + !Cond->getType()->isIntegralOrEnumerationType()) + return ExprError(); + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - return UsualUnaryConversions(CondResult.get()); + return UsualUnaryConversions(Cond); } StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond) { - if (Cond.isInvalid()) - return StmtError(); + Expr *CondExpr = Cond.get().second; + assert((Cond.isInvalid() || CondExpr) && "switch with no condition"); + + if (CondExpr && !CondExpr->isTypeDependent()) { + // We have already converted the expression to an integral or enumeration + // type, when we parsed the switch condition. If we don't have an + // appropriate type now, enter the switch scope but remember that it's + // invalid. + assert(CondExpr->getType()->isIntegralOrEnumerationType() && + "invalid condition type"); + if (CondExpr->isKnownToHaveBooleanValue()) { + // switch(bool_expr) {...} is often a programmer error, e.g. + // switch(n && mask) { ... } // Doh - should be "n & mask". + // One can always use an if statement instead of switch(bool_expr). + Diag(SwitchLoc, diag::warn_bool_switch_condition) + << CondExpr->getSourceRange(); + } + } - getCurFunction()->setHasBranchIntoScope(); + setFunctionHasBranchIntoScope(); SwitchStmt *SS = new (Context) - SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second); - getCurFunction()->SwitchStack.push_back(SS); + SwitchStmt(Context, InitStmt, Cond.get().first, CondExpr); + getCurFunction()->SwitchStack.push_back( + FunctionScopeInfo::SwitchInfo(SS, false)); return SS; } @@ -705,6 +743,10 @@ static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) { /// type. static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val, unsigned UnpromotedWidth, bool UnpromotedSign) { + // In C++11 onwards, this is checked by the language rules. + if (S.getLangOpts().CPlusPlus11) + return; + // 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? @@ -759,7 +801,7 @@ static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S, static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond, const Expr *Case) { - QualType CondType = GetTypeBeforeIntegralPromotion(Cond); + QualType CondType = Cond->getType(); QualType CaseType = Case->getType(); const EnumType *CondEnumType = CondType->getAs<EnumType>(); @@ -787,7 +829,8 @@ StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { SwitchStmt *SS = cast<SwitchStmt>(Switch); - assert(SS == getCurFunction()->SwitchStack.back() && + bool CaseListIsIncomplete = getCurFunction()->SwitchStack.back().getInt(); + assert(SS == getCurFunction()->SwitchStack.back().getPointer() && "switch stack missing push/pop!"); getCurFunction()->SwitchStack.pop_back(); @@ -800,10 +843,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, QualType CondType = CondExpr->getType(); - const Expr *CondExprBeforePromotion = CondExpr; - QualType CondTypeBeforePromotion = - GetTypeBeforeIntegralPromotion(CondExprBeforePromotion); - // C++ 6.4.2.p2: // Integral promotions are performed (on the switch condition). // @@ -811,21 +850,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // type (before the promotion) doesn't make sense, even when it can // be represented by the promoted type. Therefore we need to find // the pre-promotion type of the switch condition. - if (!CondExpr->isTypeDependent()) { - // We have already converted the expression to an integral or enumeration - // type, when we started the switch statement. If we don't have an - // appropriate type now, just return an error. - if (!CondType->isIntegralOrEnumerationType()) - return StmtError(); - - if (CondExpr->isKnownToHaveBooleanValue()) { - // switch(bool_expr) {...} is often a programmer error, e.g. - // switch(n && mask) { ... } // Doh - should be "n & mask". - // One can always use an if statement instead of switch(bool_expr). - Diag(SwitchLoc, diag::warn_bool_switch_condition) - << CondExpr->getSourceRange(); - } - } + const Expr *CondExprBeforePromotion = CondExpr; + QualType CondTypeBeforePromotion = + GetTypeBeforeIntegralPromotion(CondExprBeforePromotion); // Get the bitwidth of the switched-on value after promotions. We must // convert the integer case values to this width before comparison. @@ -878,50 +905,32 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Expr *Lo = CS->getLHS(); - if (Lo->isTypeDependent() || Lo->isValueDependent()) { + if (Lo->isValueDependent()) { HasDependentValue = true; break; } - checkEnumTypesInSwitchStmt(*this, CondExpr, Lo); - - llvm::APSInt LoVal; - - if (getLangOpts().CPlusPlus11) { - // C++11 [stmt.switch]p2: the constant-expression shall be a converted - // constant expression of the promoted type of the switch condition. - ExprResult ConvLo = - CheckConvertedConstantExpression(Lo, CondType, LoVal, CCEK_CaseValue); - if (ConvLo.isInvalid()) { - CaseListIsErroneous = true; - continue; - } - Lo = ConvLo.get(); - } else { - // We already verified that the expression has a i-c-e value (C99 - // 6.8.4.2p3) - get that value now. - LoVal = Lo->EvaluateKnownConstInt(Context); - - // If the LHS is not the same type as the condition, insert an implicit - // cast. - Lo = DefaultLvalueConversion(Lo).get(); - Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get(); - } + // We already verified that the expression has a constant value; + // get that value (prior to conversions). + const Expr *LoBeforePromotion = Lo; + GetTypeBeforeIntegralPromotion(LoBeforePromotion); + llvm::APSInt LoVal = LoBeforePromotion->EvaluateKnownConstInt(Context); // Check the unconverted value is within the range of possible values of // the switch expression. checkCaseValue(*this, Lo->getLocStart(), LoVal, CondWidthBeforePromotion, CondIsSignedBeforePromotion); + // FIXME: This duplicates the check performed for warn_not_in_enum below. + checkEnumTypesInSwitchStmt(*this, CondExprBeforePromotion, + LoBeforePromotion); + // Convert the value to the same width/sign as the condition. AdjustAPSInt(LoVal, CondWidth, CondIsSigned); - CS->setLHS(Lo); - // If this is a case range, remember it in CaseRanges, otherwise CaseVals. if (CS->getRHS()) { - if (CS->getRHS()->isTypeDependent() || - CS->getRHS()->isValueDependent()) { + if (CS->getRHS()->isValueDependent()) { HasDependentValue = true; break; } @@ -1002,27 +1011,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, llvm::APSInt &LoVal = CaseRanges[i].first; CaseStmt *CR = CaseRanges[i].second; Expr *Hi = CR->getRHS(); - llvm::APSInt HiVal; - - if (getLangOpts().CPlusPlus11) { - // C++11 [stmt.switch]p2: the constant-expression shall be a converted - // constant expression of the promoted type of the switch condition. - ExprResult ConvHi = - CheckConvertedConstantExpression(Hi, CondType, HiVal, - CCEK_CaseValue); - if (ConvHi.isInvalid()) { - CaseListIsErroneous = true; - continue; - } - Hi = ConvHi.get(); - } else { - HiVal = Hi->EvaluateKnownConstInt(Context); - // If the RHS is not the same type as the condition, insert an - // implicit cast. - Hi = DefaultLvalueConversion(Hi).get(); - Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get(); - } + const Expr *HiBeforePromotion = Hi; + GetTypeBeforeIntegralPromotion(HiBeforePromotion); + llvm::APSInt HiVal = HiBeforePromotion->EvaluateKnownConstInt(Context); // Check the unconverted value is within the range of possible values of // the switch expression. @@ -1032,8 +1024,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // Convert the value to the same width/sign as the condition. AdjustAPSInt(HiVal, CondWidth, CondIsSigned); - CR->setRHS(Hi); - // If the low value is bigger than the high value, the case is empty. if (LoVal > HiVal) { Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) @@ -1104,7 +1094,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } // Complain if we have a constant condition and we didn't find a match. - if (!CaseListIsErroneous && ShouldCheckConstantCond) { + if (!CaseListIsErroneous && !CaseListIsIncomplete && + ShouldCheckConstantCond) { // TODO: it would be nice if we printed enums as enums, chars as // chars, etc. Diag(CondExpr->getExprLoc(), diag::warn_missing_case_for_condition) @@ -1120,8 +1111,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>(); // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !HasConstantCond && ET && - ET->getDecl()->isCompleteDefinition()) { + if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond && + ET && ET->getDecl()->isCompleteDefinition()) { const EnumDecl *ED = ET->getDecl(); EnumValsTy EnumVals; @@ -1873,7 +1864,7 @@ StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc) { - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); ExprResult CollectionExprResult = CheckObjCForCollectionOperand(ForLoc, collection); @@ -2025,7 +2016,7 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, /// Build a variable declaration for a for-range statement. VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, - QualType Type, const char *Name) { + QualType Type, StringRef Name) { DeclContext *DC = SemaRef.CurContext; IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); @@ -2094,10 +2085,12 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, } // Build auto && __range = range-init + // Divide by 2, since the variables are in the inner scope (loop body). + const auto DepthStr = std::to_string(S->getDepth() / 2); SourceLocation RangeLoc = Range->getLocStart(); VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc, Context.getAutoRRefDeductType(), - "__range"); + std::string("__range") + DepthStr); if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, diag::err_for_range_deduction_failure)) { LoopVar->setInvalidDecl(); @@ -2119,7 +2112,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, DS, RParenLoc, Kind); } -/// \brief Create the initialization, compare, and increment steps for +/// Create the initialization, compare, and increment steps for /// the range-based for loop expression. /// This function does not handle array-based for loops, /// which are created in Sema::BuildCXXForRangeStmt. @@ -2340,10 +2333,12 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, return StmtError(); // Build auto __begin = begin-expr, __end = end-expr. + // Divide by 2, since the variables are in the inner scope (loop body). + const auto DepthStr = std::to_string(S->getDepth() / 2); VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, - "__begin"); + std::string("__begin") + DepthStr); VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, - "__end"); + std::string("__end") + DepthStr); // Build begin-expr and end-expr and attach to __begin and __end variables. ExprResult BeginExpr, EndExpr; @@ -2387,7 +2382,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // FIXME: This results in codegen generating IR that recalculates the // run-time number of elements (as opposed to just using the IR Value // that corresponds to the run-time value of each bound that was - // generated when the array was created.) If this proves too embarassing + // generated when the array was created.) If this proves too embarrassing // even for unoptimized IR, consider passing a magic-value/cookie to // codegen that then knows to simply use that initial llvm::Value (that // corresponds to the bound at time of array creation) within @@ -2657,7 +2652,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, if (ReturnsReference) { // Loop variable creates a temporary. Suggest either to go with - // non-reference loop variable to indiciate a copy is made, or + // non-reference loop variable to indicate a copy is made, or // the correct time to bind a const reference. SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy) << VD << VariableType << E->getType(); @@ -2718,7 +2713,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, /// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them. /// 1) for (const foo &x : foos) where foos only returns a copy. Suggest /// using "const foo x" to show that a copy is made -/// 2) for (const bar &x : foos) where bar is a temporary intialized by bar. +/// 2) for (const bar &x : foos) where bar is a temporary initialized by bar. /// Suggest either "const bar x" to keep the copying or "const foo& x" to /// prevent the copy. /// 3) for (const foo x : foos) where x is constructed from a reference foo. @@ -2780,7 +2775,7 @@ StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) { StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl) { - getCurFunction()->setHasBranchIntoScope(); + setFunctionHasBranchIntoScope(); TheDecl->markUsed(Context); return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc); } @@ -2807,7 +2802,7 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, return StmtError(); E = ExprRes.get(); - getCurFunction()->setHasIndirectGoto(); + setFunctionHasIndirectGoto(); return new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E); } @@ -2847,7 +2842,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { return new (Context) BreakStmt(BreakLoc); } -/// \brief Determine whether the given expression is a candidate for +/// Determine whether the given expression is a candidate for /// copy elision in either a return statement or a throw expression. /// /// \param ReturnType If we're determining the copy elision candidate for @@ -2858,7 +2853,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \param E The expression being returned from the function or block, or /// being thrown. /// -/// \param AllowParamOrMoveConstructible Whether we allow function parameters or +/// \param CESK Whether we allow function parameters or /// id-expressions that could be moved out of the function to be considered NRVO /// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to /// determine whether we should try to move as part of a return or throw (which @@ -2867,10 +2862,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E, - bool AllowParamOrMoveConstructible) { - if (!getLangOpts().CPlusPlus) - return nullptr; - + CopyElisionSemanticsKind CESK) { // - 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()); @@ -2880,13 +2872,13 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E, if (!VD) return nullptr; - if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible)) + if (isCopyElisionCandidate(ReturnType, VD, CESK)) return VD; return nullptr; } bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, - bool AllowParamOrMoveConstructible) { + CopyElisionSemanticsKind CESK) { QualType VDType = VD->getType(); // - in a return statement in a function with ... // ... a class return type ... @@ -2895,16 +2887,17 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, return false; // ... the same cv-unqualified type as the function return type ... // When considering moving this expression out, allow dissimilar types. - if (!AllowParamOrMoveConstructible && !VDType->isDependentType() && + if (!(CESK & CES_AllowDifferentTypes) && !VDType->isDependentType() && !Context.hasSameUnqualifiedType(ReturnType, VDType)) return false; } // ...object (other than a function or catch-clause parameter)... if (VD->getKind() != Decl::Var && - !(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar)) + !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar)) + return false; + if (!(CESK & CES_AllowExceptionVariables) && VD->isExceptionVariable()) return false; - if (VD->isExceptionVariable()) return false; // ...automatic... if (!VD->hasLocalStorage()) return false; @@ -2914,7 +2907,7 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, // variable will no longer be used. if (VD->hasAttr<BlocksAttr>()) return false; - if (AllowParamOrMoveConstructible) + if (CESK & CES_AllowDifferentTypes) return true; // ...non-volatile... @@ -2929,7 +2922,95 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, return true; } -/// \brief Perform the initialization of a potentially-movable value, which +/// Try to perform the initialization of a potentially-movable value, +/// which is the operand to a return or throw statement. +/// +/// This routine implements C++14 [class.copy]p32, which attempts to treat +/// returned lvalues as rvalues in certain cases (to prefer move construction), +/// then falls back to treating them as lvalues if that failed. +/// +/// \param ConvertingConstructorsOnly If true, follow [class.copy]p32 and reject +/// resolutions that find non-constructors, such as derived-to-base conversions +/// or `operator T()&&` member functions. If false, do consider such +/// conversion sequences. +/// +/// \param Res We will fill this in if move-initialization was possible. +/// If move-initialization is not possible, such that we must fall back to +/// treating the operand as an lvalue, we will leave Res in its original +/// invalid state. +static void TryMoveInitialization(Sema& S, + const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, + Expr *&Value, + bool ConvertingConstructorsOnly, + ExprResult &Res) { + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), + CK_NoOp, Value, VK_XValue); + + Expr *InitExpr = &AsRvalue; + + InitializationKind Kind = InitializationKind::CreateCopy( + Value->getLocStart(), Value->getLocStart()); + + InitializationSequence Seq(S, Entity, Kind, InitExpr); + + if (!Seq) + return; + + for (const InitializationSequence::Step &Step : Seq.steps()) { + if (Step.Kind != InitializationSequence::SK_ConstructorInitialization && + Step.Kind != InitializationSequence::SK_UserConversion) + continue; + + FunctionDecl *FD = Step.Function.Function; + if (ConvertingConstructorsOnly) { + if (isa<CXXConstructorDecl>(FD)) { + // C++14 [class.copy]p32: + // [...] If the first overload resolution fails or was not performed, + // or if the type of the first parameter of the selected constructor + // is not an rvalue reference to the object's type (possibly + // cv-qualified), overload resolution is performed again, considering + // the object as an lvalue. + const RValueReferenceType *RRefType = + FD->getParamDecl(0)->getType()->getAs<RValueReferenceType>(); + if (!RRefType) + break; + if (!S.Context.hasSameUnqualifiedType(RRefType->getPointeeType(), + NRVOCandidate->getType())) + break; + } else { + continue; + } + } else { + if (isa<CXXConstructorDecl>(FD)) { + // Check that overload resolution selected a constructor taking an + // rvalue reference. If it selected an lvalue reference, then we + // didn't need to cast this thing to an rvalue in the first place. + if (!isa<RValueReferenceType>(FD->getParamDecl(0)->getType())) + break; + } else if (isa<CXXMethodDecl>(FD)) { + // Check that overload resolution selected a conversion operator + // taking an rvalue reference. + if (cast<CXXMethodDecl>(FD)->getRefQualifier() != RQ_RValue) + break; + } else { + continue; + } + } + + // Promote "AsRvalue" to the heap, since we now need this + // expression node to persist. + Value = ImplicitCastExpr::Create(S.Context, Value->getType(), CK_NoOp, + Value, nullptr, VK_XValue); + + // Complete type-checking the initialization of the return type + // using the constructor we found. + Res = Seq.Perform(S, Entity, Kind, Value); + } +} + +/// Perform the initialization of a potentially-movable value, which /// is the result of return value. /// /// This routine implements C++14 [class.copy]p32, which attempts to treat @@ -2952,52 +3033,82 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // were designated by an rvalue. ExprResult Res = ExprError(); - if (AllowNRVO && !NRVOCandidate) - NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true); - - if (AllowNRVO && NRVOCandidate) { - ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), - CK_NoOp, Value, VK_XValue); - - Expr *InitExpr = &AsRvalue; - - InitializationKind Kind = InitializationKind::CreateCopy( - Value->getLocStart(), Value->getLocStart()); - - InitializationSequence Seq(*this, Entity, Kind, InitExpr); - if (Seq) { - for (const InitializationSequence::Step &Step : Seq.steps()) { - if (!(Step.Kind == - InitializationSequence::SK_ConstructorInitialization || - (Step.Kind == InitializationSequence::SK_UserConversion && - isa<CXXConstructorDecl>(Step.Function.Function)))) - continue; - - CXXConstructorDecl *Constructor = - cast<CXXConstructorDecl>(Step.Function.Function); - - const RValueReferenceType *RRefType - = Constructor->getParamDecl(0)->getType() - ->getAs<RValueReferenceType>(); - - // [...] If the first overload resolution fails or was not performed, or - // if the type of the first parameter of the selected constructor is not - // an rvalue reference to the object's type (possibly cv-qualified), - // overload resolution is performed again, considering the object as an - // lvalue. - if (!RRefType || - !Context.hasSameUnqualifiedType(RRefType->getPointeeType(), - NRVOCandidate->getType())) - break; + if (AllowNRVO) { + bool AffectedByCWG1579 = false; + + if (!NRVOCandidate) { + NRVOCandidate = getCopyElisionCandidate(ResultType, Value, CES_Default); + if (NRVOCandidate && + !getDiagnostics().isIgnored(diag::warn_return_std_move_in_cxx11, + Value->getExprLoc())) { + const VarDecl *NRVOCandidateInCXX11 = + getCopyElisionCandidate(ResultType, Value, CES_FormerDefault); + AffectedByCWG1579 = (!NRVOCandidateInCXX11); + } + } - // Promote "AsRvalue" to the heap, since we now need this - // expression node to persist. - Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp, - Value, nullptr, VK_XValue); + if (NRVOCandidate) { + TryMoveInitialization(*this, Entity, NRVOCandidate, ResultType, Value, + true, Res); + } - // Complete type-checking the initialization of the return type - // using the constructor we found. - Res = Seq.Perform(*this, Entity, Kind, Value); + if (!Res.isInvalid() && AffectedByCWG1579) { + QualType QT = NRVOCandidate->getType(); + if (QT.getNonReferenceType() + .getUnqualifiedType() + .isTriviallyCopyableType(Context)) { + // Adding 'std::move' around a trivially copyable variable is probably + // pointless. Don't suggest it. + } else { + // Common cases for this are returning unique_ptr<Derived> from a + // function of return type unique_ptr<Base>, or returning T from a + // function of return type Expected<T>. This is totally fine in a + // post-CWG1579 world, but was not fine before. + assert(!ResultType.isNull()); + SmallString<32> Str; + Str += "std::move("; + Str += NRVOCandidate->getDeclName().getAsString(); + Str += ")"; + Diag(Value->getExprLoc(), diag::warn_return_std_move_in_cxx11) + << Value->getSourceRange() + << NRVOCandidate->getDeclName() << ResultType << QT; + Diag(Value->getExprLoc(), diag::note_add_std_move_in_cxx11) + << FixItHint::CreateReplacement(Value->getSourceRange(), Str); + } + } else if (Res.isInvalid() && + !getDiagnostics().isIgnored(diag::warn_return_std_move, + Value->getExprLoc())) { + const VarDecl *FakeNRVOCandidate = + getCopyElisionCandidate(QualType(), Value, CES_AsIfByStdMove); + if (FakeNRVOCandidate) { + QualType QT = FakeNRVOCandidate->getType(); + if (QT->isLValueReferenceType()) { + // Adding 'std::move' around an lvalue reference variable's name is + // dangerous. Don't suggest it. + } else if (QT.getNonReferenceType() + .getUnqualifiedType() + .isTriviallyCopyableType(Context)) { + // Adding 'std::move' around a trivially copyable variable is probably + // pointless. Don't suggest it. + } else { + ExprResult FakeRes = ExprError(); + Expr *FakeValue = Value; + TryMoveInitialization(*this, Entity, FakeNRVOCandidate, ResultType, + FakeValue, false, FakeRes); + if (!FakeRes.isInvalid()) { + bool IsThrow = + (Entity.getKind() == InitializedEntity::EK_Exception); + SmallString<32> Str; + Str += "std::move("; + Str += FakeNRVOCandidate->getDeclName().getAsString(); + Str += ")"; + Diag(Value->getExprLoc(), diag::warn_return_std_move) + << Value->getSourceRange() + << FakeNRVOCandidate->getDeclName() << IsThrow; + Diag(Value->getExprLoc(), diag::note_add_std_move) + << FixItHint::CreateReplacement(Value->getSourceRange(), Str); + } + } } } } @@ -3011,7 +3122,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, return Res; } -/// \brief Determine whether the declared return type of the specified function +/// Determine whether the declared return type of the specified function /// contains 'auto'. static bool hasDeducedReturnType(FunctionDecl *FD) { const FunctionProtoType *FPT = @@ -3145,7 +3256,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, FnRetType, NRVOCandidate != nullptr); @@ -3158,7 +3269,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { RetValExp = Res.get(); CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc); } else { - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); } if (RetValExp) { @@ -3183,7 +3294,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } namespace { -/// \brief Marks all typedefs in all local classes in a type referenced. +/// Marks all typedefs in all local classes in a type referenced. /// /// In a function like /// auto f() { @@ -3528,7 +3639,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization, // the C version of which boils down to CheckSingleAssignmentConstraints. if (RetValExp) - NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false); + NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, CES_Strict); if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc, @@ -3603,7 +3714,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, if (!getLangOpts().ObjCExceptions) Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try"; - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); unsigned NumCatchStmts = CatchStmts.size(); return ObjCAtTryStmt::Create(Context, AtLoc, Try, CatchStmts.data(), NumCatchStmts, Finally); @@ -3694,7 +3805,7 @@ StmtResult Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, Stmt *SyncBody) { // We can't jump into or indirect-jump out of a @synchronized block. - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody); } @@ -3710,7 +3821,7 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, StmtResult Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) { - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); return new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body); } @@ -3822,7 +3933,11 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef<Stmt *> Handlers) { // Don't report an error if 'try' is used in system headers. if (!getLangOpts().CXXExceptions && - !getSourceManager().isInSystemHeader(TryLoc)) + !getSourceManager().isInSystemHeader(TryLoc) && + (!getLangOpts().OpenMPIsDevice || + !getLangOpts().OpenMPHostCXXExceptions || + isInOpenMPTargetExecutionDirective() || + isInOpenMPDeclareTargetContext())) Diag(TryLoc, diag::err_exceptions_disabled) << "try"; // Exceptions aren't allowed in CUDA device code. @@ -4036,32 +4151,29 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, return RD; } -static void buildCapturedStmtCaptureList( - SmallVectorImpl<CapturedStmt::Capture> &Captures, - SmallVectorImpl<Expr *> &CaptureInits, - ArrayRef<CapturingScopeInfo::Capture> Candidates) { - - typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter; - for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) { - - if (Cap->isThisCapture()) { - Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), +static void +buildCapturedStmtCaptureList(SmallVectorImpl<CapturedStmt::Capture> &Captures, + SmallVectorImpl<Expr *> &CaptureInits, + ArrayRef<sema::Capture> Candidates) { + for (const sema::Capture &Cap : Candidates) { + if (Cap.isThisCapture()) { + Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), CapturedStmt::VCK_This)); - CaptureInits.push_back(Cap->getInitExpr()); + CaptureInits.push_back(Cap.getInitExpr()); continue; - } else if (Cap->isVLATypeCapture()) { + } else if (Cap.isVLATypeCapture()) { Captures.push_back( - CapturedStmt::Capture(Cap->getLocation(), CapturedStmt::VCK_VLAType)); + CapturedStmt::Capture(Cap.getLocation(), CapturedStmt::VCK_VLAType)); CaptureInits.push_back(nullptr); continue; } - Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), - Cap->isReferenceCapture() + Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), + Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef : CapturedStmt::VCK_ByCopy, - Cap->getVariable())); - CaptureInits.push_back(Cap->getInitExpr()); + Cap.getVariable())); + CaptureInits.push_back(Cap.getInitExpr()); } } @@ -4111,7 +4223,9 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, assert(!ContextIsFound && "null type has been found already for '__context' parameter"); IdentifierInfo *ParamName = &Context.Idents.get("__context"); - QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)); + QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)) + .withConst() + .withRestrict(); auto *Param = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType, ImplicitParamDecl::CapturedContext); @@ -4160,7 +4274,7 @@ void Sema::ActOnCapturedRegionError() { SmallVector<Decl*, 4> Fields(Record->fields()); ActOnFields(/*Scope=*/nullptr, Record->getLocation(), Record, Fields, - SourceLocation(), SourceLocation(), /*AttributeList=*/nullptr); + SourceLocation(), SourceLocation(), ParsedAttributesView()); PopDeclContext(); PopFunctionScopeInfo(); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp index fc1cc7bbe544..7e26b71c0482 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp @@ -109,7 +109,7 @@ static bool CheckNakedParmReference(Expr *E, Sema &S) { return false; } -/// \brief Returns true if given expression is not compatible with inline +/// Returns true if given expression is not compatible with inline /// assembly's memory constraint; false otherwise. static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E, TargetInfo::ConstraintInfo &Info, @@ -793,7 +793,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef<Expr*> Exprs, SourceLocation EndLoc) { bool IsSimple = (NumOutputs != 0 || NumInputs != 0); - getCurFunction()->setHasBranchProtectedScope(); + setFunctionHasBranchProtectedScope(); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp index e55e20c2827f..e39a65c6ce0c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp @@ -23,7 +23,7 @@ using namespace clang; using namespace sema; -static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, +static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { FallThroughAttr Attr(A.getRange(), S.Context, A.getAttributeSpellingListIndex()); @@ -53,7 +53,7 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, return ::new (S.Context) auto(Attr); } -static Attr *handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A, +static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { if (A.getNumArgs() < 1) { S.Diag(A.getLoc(), diag::err_attribute_too_few_arguments) @@ -78,7 +78,7 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const AttributeList &A, DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex()); } -static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, +static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange) { IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0); IdentifierLoc *OptionLoc = A.getArgAsIdent(1); @@ -246,7 +246,7 @@ CheckForIncompatibleAttributes(Sema &S, } } -static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A, +static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's // useful for OpenCL 1.x too and doesn't require HW support. @@ -288,21 +288,21 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A, return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor); } -static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, +static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { switch (A.getKind()) { - case AttributeList::UnknownAttribute: + case ParsedAttr::UnknownAttribute: S.Diag(A.getLoc(), A.isDeclspecAttribute() ? diag::warn_unhandled_ms_attribute_ignored : diag::warn_unknown_attribute_ignored) << A.getName(); return nullptr; - case AttributeList::AT_FallThrough: + case ParsedAttr::AT_FallThrough: return handleFallThroughAttr(S, St, A, Range); - case AttributeList::AT_LoopHint: + case ParsedAttr::AT_LoopHint: return handleLoopHintAttr(S, St, A, Range); - case AttributeList::AT_OpenCLUnrollHint: + case ParsedAttr::AT_OpenCLUnrollHint: return handleOpenCLUnrollHint(S, St, A, Range); - case AttributeList::AT_Suppress: + case ParsedAttr::AT_Suppress: return handleSuppressAttr(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize @@ -313,11 +313,12 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, } } -StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, +StmtResult Sema::ProcessStmtAttributes(Stmt *S, + const ParsedAttributesView &AttrList, SourceRange Range) { SmallVector<const Attr*, 8> Attrs; - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) + for (const ParsedAttr &AL : AttrList) { + if (Attr *a = ProcessStmtAttribute(*this, S, AL, Range)) Attrs.push_back(a); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index 7c6af5793fc5..dd1163267119 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -46,7 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, } namespace clang { -/// \brief [temp.constr.decl]p2: A template's associated constraints are +/// [temp.constr.decl]p2: A template's associated constraints are /// defined as a single constraint-expression derived from the introduced /// constraint-expressions [ ... ]. /// @@ -65,7 +65,7 @@ static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, return Params->getRequiresClause(); } -/// \brief Determine whether the declaration found is acceptable as the name +/// Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns NULL. static NamedDecl *isAcceptableTemplateName(ASTContext &Context, @@ -105,6 +105,12 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, return nullptr; } + // 'using Dependent::foo;' can resolve to a template name. + // 'using typename Dependent::foo;' cannot (not even if 'foo' is an + // injected-class-name). + if (isa<UnresolvedUsingValueDecl>(D)) + return D; + return nullptr; } @@ -158,7 +164,7 @@ bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, @@ -189,8 +195,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, QualType ObjectType = ObjectTypePtr.get(); LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName); - LookupTemplateName(R, S, SS, ObjectType, EnteringContext, - MemberOfUnknownSpecialization); + if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization)) + return TNK_Non_template; if (R.empty()) return TNK_Non_template; if (R.isAmbiguous()) { // Suppress diagnostics; we'll redo this lookup later. @@ -213,6 +220,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); + } else if (isa<UnresolvedUsingValueDecl>((*R.begin())->getUnderlyingDecl())) { + // We don't yet know whether this is a template-name or not. + MemberOfUnknownSpecialization = true; + return TNK_Non_template; } else { TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl()); @@ -252,8 +263,10 @@ bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); - LookupTemplateName(R, S, SS, /*ObjectType*/QualType(), - /*EnteringContext*/false, MemberOfUnknownSpecialization); + if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), + /*EnteringContext*/ false, + MemberOfUnknownSpecialization)) + return false; if (R.empty()) return false; if (R.isAmbiguous()) { @@ -298,39 +311,40 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, return true; } -void Sema::LookupTemplateName(LookupResult &Found, +bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization) { + bool &MemberOfUnknownSpecialization, + SourceLocation TemplateKWLoc) { // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; - bool isDependent = false; + bool IsDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); - isDependent = ObjectType->isDependentType(); - assert((isDependent || !ObjectType->isIncompleteType() || + IsDependent = !LookupCtx; + assert((IsDependent || !ObjectType->isIncompleteType() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); // Template names cannot appear inside an Objective-C class or object type. if (ObjectType->isObjCObjectOrInterfaceType()) { Found.clear(); - return; + return false; } } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = isDependentScopeSpecifier(SS); + IsDependent = !LookupCtx; // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) - return; + return true; } bool ObjectTypeSearchedInScope = false; @@ -341,34 +355,43 @@ void Sema::LookupTemplateName(LookupResult &Found, // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Found, LookupCtx); - if (!ObjectType.isNull() && Found.empty()) { - // C++ [basic.lookup.classref]p1: - // In a class member access expression (5.2.5), if the . or -> token is - // immediately followed by an identifier followed by a <, the - // identifier must be looked up to determine whether the < is the - // beginning of a template argument list (14.2) or a less-than operator. - // The identifier is first looked up in the class of the object - // expression. If the identifier is not found, it is then looked up in - // the context of the entire postfix-expression and shall name a class - // or function template. - if (S) LookupName(Found, S); - ObjectTypeSearchedInScope = true; + + // FIXME: The C++ standard does not clearly specify what happens in the + // case where the object type is dependent, and implementations vary. In + // Clang, we treat a name after a . or -> as a template-name if lookup + // finds a non-dependent member or member of the current instantiation that + // is a type template, or finds no such members and lookup in the context + // of the postfix-expression finds a type template. In the latter case, the + // name is nonetheless dependent, and we may resolve it to a member of an + // unknown specialization when we come to instantiate the template. + IsDependent |= Found.wasNotFoundInCurrentInstantiation(); + } + + if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { + // C++ [basic.lookup.classref]p1: + // In a class member access expression (5.2.5), if the . or -> token is + // immediately followed by an identifier followed by a <, the + // identifier must be looked up to determine whether the < is the + // beginning of a template argument list (14.2) or a less-than operator. + // The identifier is first looked up in the class of the object + // expression. If the identifier is not found, it is then looked up in + // the context of the entire postfix-expression and shall name a class + // template. + if (S) + LookupName(Found, S); + + if (!ObjectType.isNull()) { + // FIXME: We should filter out all non-type templates here, particularly + // variable templates and concepts. But the exclusion of alias templates + // and template template parameters is a wording defect. AllowFunctionTemplatesInLookup = false; + ObjectTypeSearchedInScope = true; } - } else if (isDependent && (!S || ObjectType.isNull())) { - // We cannot look into a dependent object type or nested nme - // specifier. - MemberOfUnknownSpecialization = true; - return; - } else { - // Perform unqualified name lookup in the current scope. - LookupName(Found, S); - if (!ObjectType.isNull()) - AllowFunctionTemplatesInLookup = false; + IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } - if (Found.empty() && !isDependent) { + if (Found.empty() && !IsDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); @@ -402,11 +425,27 @@ void Sema::LookupTemplateName(LookupResult &Found, } } + NamedDecl *ExampleLookupResult = + Found.empty() ? nullptr : Found.getRepresentativeDecl(); FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { - if (isDependent) + if (IsDependent) { MemberOfUnknownSpecialization = true; - return; + return false; + } + + // If a 'template' keyword was used, a lookup that finds only non-template + // names is an error. + if (ExampleLookupResult && TemplateKWLoc.isValid()) { + Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) + << Found.getLookupName() << SS.getRange(); + Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(), + diag::note_template_kw_refers_to_non_template) + << Found.getLookupName(); + return true; + } + + return false; } if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope && @@ -453,6 +492,8 @@ void Sema::LookupTemplateName(LookupResult &Found, } } } + + return false; } void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, @@ -467,20 +508,41 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, DeclContext *LookupCtx = nullptr; NamedDecl *Found = nullptr; + bool MissingTemplateKeyword = false; // Figure out what name we looked up. - if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) { + if (auto *DRE = dyn_cast<DeclRefExpr>(TemplateName.get())) { + NameInfo = DRE->getNameInfo(); + SS.Adopt(DRE->getQualifierLoc()); + LookupKind = LookupOrdinaryName; + Found = DRE->getFoundDecl(); + } else if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) { NameInfo = ME->getMemberNameInfo(); SS.Adopt(ME->getQualifierLoc()); LookupKind = LookupMemberName; LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl(); Found = ME->getMemberDecl(); + } else if (auto *DSDRE = + dyn_cast<DependentScopeDeclRefExpr>(TemplateName.get())) { + NameInfo = DSDRE->getNameInfo(); + SS.Adopt(DSDRE->getQualifierLoc()); + MissingTemplateKeyword = true; + } else if (auto *DSME = + dyn_cast<CXXDependentScopeMemberExpr>(TemplateName.get())) { + NameInfo = DSME->getMemberNameInfo(); + SS.Adopt(DSME->getQualifierLoc()); + MissingTemplateKeyword = true; } else { - auto *DRE = cast<DeclRefExpr>(TemplateName.get()); - NameInfo = DRE->getNameInfo(); - SS.Adopt(DRE->getQualifierLoc()); - LookupKind = LookupOrdinaryName; - Found = DRE->getFoundDecl(); + llvm_unreachable("unexpected kind of potential template name"); + } + + // If this is a dependent-scope lookup, diagnose that the 'template' keyword + // was missing. + if (MissingTemplateKeyword) { + Diag(NameInfo.getLocStart(), diag::err_template_kw_missing) + << "" << NameInfo.getName().getAsString() + << SourceRange(Less, Greater); + return; } // Try to correct the name by looking for templates and C++ named casts. @@ -765,7 +827,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, llvm_unreachable("Unhandled parsed template argument"); } -/// \brief Translates template arguments as provided by the parser +/// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, TemplateArgumentListInfo &TemplateArgs) { @@ -783,6 +845,56 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } +/// Convert a parsed type into a parsed template argument. This is mostly +/// trivial, except that we may have parsed a C++17 deduced class template +/// specialization type, in which case we should form a template template +/// argument instead of a type template argument. +ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { + TypeSourceInfo *TInfo; + QualType T = GetTypeFromParser(ParsedType.get(), &TInfo); + if (T.isNull()) + return ParsedTemplateArgument(); + assert(TInfo && "template argument with no location"); + + // If we might have formed a deduced template specialization type, convert + // it to a template template argument. + if (getLangOpts().CPlusPlus17) { + TypeLoc TL = TInfo->getTypeLoc(); + SourceLocation EllipsisLoc; + if (auto PET = TL.getAs<PackExpansionTypeLoc>()) { + EllipsisLoc = PET.getEllipsisLoc(); + TL = PET.getPatternLoc(); + } + + CXXScopeSpec SS; + if (auto ET = TL.getAs<ElaboratedTypeLoc>()) { + SS.Adopt(ET.getQualifierLoc()); + TL = ET.getNamedTypeLoc(); + } + + if (auto DTST = TL.getAs<DeducedTemplateSpecializationTypeLoc>()) { + TemplateName Name = DTST.getTypePtr()->getTemplateName(); + if (SS.isSet()) + Name = Context.getQualifiedTemplateName(SS.getScopeRep(), + /*HasTemplateKeyword*/ false, + Name.getAsTemplateDecl()); + ParsedTemplateArgument Result(SS, TemplateTy::make(Name), + DTST.getTemplateNameLoc()); + if (EllipsisLoc.isValid()) + Result = Result.getTemplatePackExpansion(EllipsisLoc); + return Result; + } + } + + // This is a normal type template argument. Note, if the type template + // argument is an injected-class-name for a template, it has a dual nature + // and can be used as either a type or a template. We handle that in + // convertTypeTemplateArgumentToTemplate. + return ParsedTemplateArgument(ParsedTemplateArgument::Type, + ParsedType.get().getAsOpaquePtr(), + TInfo->getTypeLoc().getLocStart()); +} + /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter @@ -854,7 +966,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } -/// \brief Check that the type of a non-type template parameter is +/// Check that the type of a non-type template parameter is /// well-formed. /// /// \returns the (possibly-promoted) parameter type if valid; @@ -933,9 +1045,9 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] // p1 - // template-parameter:
- // ...
- // parameter-declaration
+ // template-parameter: + // ... + // parameter-declaration // p2 // ... A storage class shall not be specified in a template-parameter // declaration. @@ -1151,17 +1263,13 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { T->setQualifierInfo(SS.getWithLocInContext(T->getASTContext())); } -DeclResult -Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, - TemplateParameterList *TemplateParams, - AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, - unsigned NumOuterTemplateParamLists, - TemplateParameterList** OuterTemplateParamLists, - SkipBodyInfo *SkipBody) { +DeclResult Sema::CheckClassTemplate( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, + AccessSpecifier AS, SourceLocation ModulePrivateLoc, + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) { assert(TemplateParams && TemplateParams->size() > 0 && "No template parameters"); assert(TUK != TUK_Reference && "Can only declare or define class templates"); @@ -1212,7 +1320,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } else if (TUK != TUK_Friend && TUK != TUK_Reference) - diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc); + diagnoseQualifiedDeclaration(SS, SemanticContext, Name, NameLoc, false); LookupQualifiedName(Previous, SemanticContext); } else { @@ -1501,8 +1609,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TUK == TUK_Definition) NewClass->startDefinition(); - if (Attr) - ProcessDeclAttributeList(S, NewClass, Attr); + ProcessDeclAttributeList(S, NewClass, Attr); if (PrevClassTemplate) mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); @@ -1885,6 +1992,8 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // FIXME: Add a kind for this to give more meaningful diagnostics. But can // this substitution process actually fail? InstantiatingTemplate BuildingDeductionGuides(*this, Loc, Template); + if (BuildingDeductionGuides.isInvalid()) + return; // Convert declared constructors into deduction guide templates. // FIXME: Skip constructors for which deduction must necessarily fail (those @@ -1925,7 +2034,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, ->setIsCopyDeductionCandidate(); } -/// \brief Diagnose the presence of a default template argument on a +/// Diagnose the presence of a default template argument on a /// template parameter, which is ill-formed in certain contexts. /// /// \returns true if the default template argument should be dropped. @@ -1981,7 +2090,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, llvm_unreachable("Invalid TemplateParamListContext!"); } -/// \brief Check for unexpanded parameter packs within the template parameters +/// Check for unexpanded parameter packs within the template parameters /// of a template template parameter, recursively. static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP) { @@ -2012,7 +2121,7 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S, return false; } -/// \brief Checks the validity of a template parameter list, possibly +/// Checks the validity of a template parameter list, possibly /// considering the template parameter list from a previous /// declaration. /// @@ -2379,7 +2488,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, return SourceRange(); } -/// \brief Match the given template parameter lists to the given scope +/// Match the given template parameter lists to the given scope /// specifier, returning the template parameter list that applies to the /// name. /// @@ -3476,7 +3585,7 @@ noteNonDeducibleParameters(Sema &S, TemplateParameterList *TemplateParams, const llvm::SmallBitVector &DeducibleParams) { for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + NamedDecl *Param = TemplateParams->getParam(I); if (Param->getDeclName()) S.Diag(Param->getLocation(), diag::note_non_deducible_parameter) << Param->getDeclName(); @@ -3754,7 +3863,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( } namespace { -/// \brief A partial specialization whose template arguments have matched +/// A partial specialization whose template arguments have matched /// a given template-id. struct PartialSpecMatchResult { VarTemplatePartialSpecializationDecl *Partial; @@ -3938,6 +4047,16 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS, /*FoundD=*/nullptr, TemplateArgs); } +void Sema::diagnoseMissingTemplateArguments(TemplateName Name, + SourceLocation Loc) { + Diag(Loc, diag::err_template_missing_args) + << (int)getTemplateNameKindForDiagnostics(Name) << Name; + if (TemplateDecl *TD = Name.getAsTemplateDecl()) { + Diag(TD->getLocation(), diag::note_template_decl_here) + << TD->getTemplateParameters()->getSourceRange(); + } +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -3957,11 +4076,23 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, assert(!R.empty() && "empty lookup results when building templateid"); assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); + // Non-function templates require a template argument list. + if (auto *TD = R.getAsSingle<TemplateDecl>()) { + if (!TemplateArgs && !isa<FunctionTemplateDecl>(TD)) { + diagnoseMissingTemplateArguments(TemplateName(TD), R.getNameLoc()); + return ExprError(); + } + } + + auto AnyDependentArguments = [&]() -> bool { + bool InstantiationDependent; + return TemplateArgs && + TemplateSpecializationType::anyDependentTemplateArguments( + *TemplateArgs, InstantiationDependent); + }; + // In C++1y, check variable template ids. - bool InstantiationDependent; - if (R.getAsSingle<VarTemplateDecl>() && - !TemplateSpecializationType::anyDependentTemplateArguments( - *TemplateArgs, InstantiationDependent)) { + if (R.getAsSingle<VarTemplateDecl>() && !AnyDependentArguments()) { return CheckVarTemplateId(SS, R.getLookupNameInfo(), R.getAsSingle<VarTemplateDecl>(), TemplateKWLoc, TemplateArgs); @@ -3997,15 +4128,17 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, bool MemberOfUnknownSpecialization; LookupResult R(*this, NameInfo, LookupOrdinaryName); - LookupTemplateName(R, (Scope*)nullptr, SS, QualType(), /*Entering*/ false, - MemberOfUnknownSpecialization); + if (LookupTemplateName(R, (Scope *)nullptr, SS, QualType(), + /*Entering*/false, MemberOfUnknownSpecialization, + TemplateKWLoc)) + return ExprError(); if (R.isAmbiguous()) return ExprError(); if (R.empty()) { - Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_non_template) - << NameInfo.getName() << SS.getRange(); + Diag(NameInfo.getLoc(), diag::err_no_member) + << NameInfo.getName() << DC << SS.getRange(); return ExprError(); } @@ -4020,7 +4153,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs); } -/// \brief Form a dependent template name. +/// Form a dependent template name. /// /// This action forms a dependent template name given the template /// name and its (presumably dependent) scope specifier. For @@ -4030,7 +4163,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - UnqualifiedId &Name, + const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Result, @@ -4068,17 +4201,20 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, ObjectType, EnteringContext, Result, MemberOfUnknownSpecialization); - if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && - isa<CXXRecordDecl>(LookupCtx) && - (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || - cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) { + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) { // This is a dependent template. Handle it below. } else if (TNK == TNK_Non_template) { - Diag(Name.getLocStart(), - diag::err_template_kw_refers_to_non_template) - << GetNameFromUnqualifiedId(Name).getName() - << Name.getSourceRange() - << TemplateKWLoc; + // Do the lookup again to determine if this is a "nothing found" case or + // a "not a template" case. FIXME: Refactor isTemplateName so we don't + // need to do this. + DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); + LookupResult R(*this, DNI.getName(), Name.getLocStart(), + LookupOrdinaryName); + bool MOUS; + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, + MOUS, TemplateKWLoc)) + Diag(Name.getLocStart(), diag::err_no_member) + << DNI.getName() << LookupCtx << SS.getRange(); return TNK_Non_template; } else { // We found something; return it. @@ -4148,16 +4284,13 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, ArgType = Arg.getAsType(); TSI = AL.getTypeSourceInfo(); break; - case TemplateArgument::Template: { + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { // We have a template type parameter but the template argument // is a template without any arguments. SourceRange SR = AL.getSourceRange(); - TemplateName Name = Arg.getAsTemplate(); - Diag(SR.getBegin(), diag::err_template_missing_args) - << (int)getTemplateNameKindForDiagnostics(Name) << Name << SR; - if (TemplateDecl *Decl = Name.getAsTemplateDecl()) - Diag(Decl->getLocation(), diag::note_template_decl_here); - + TemplateName Name = Arg.getAsTemplateOrTemplatePattern(); + diagnoseMissingTemplateArguments(Name, SR.getEnd()); return true; } case TemplateArgument::Expression: { @@ -4250,7 +4383,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return false; } -/// \brief Substitute template arguments into the default template argument for +/// Substitute template arguments into the default template argument for /// the given template type parameter. /// /// \param SemaRef the semantic analysis object for which we are performing @@ -4306,7 +4439,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, return ArgType; } -/// \brief Substitute template arguments into the default template argument for +/// Substitute template arguments into the default template argument for /// the given non-type template parameter. /// /// \param SemaRef the semantic analysis object for which we are performing @@ -4354,7 +4487,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); } -/// \brief Substitute template arguments into the default template argument for +/// Substitute template arguments into the default template argument for /// the given template template parameter. /// /// \param SemaRef the semantic analysis object for which we are performing @@ -4418,7 +4551,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, TemplateArgLists); } -/// \brief If the given template parameter has a default template +/// If the given template parameter has a default template /// argument, substitute into that default template argument and /// return the corresponding template argument. TemplateArgumentLoc @@ -4519,7 +4652,7 @@ static TemplateArgumentLoc convertTypeTemplateArgumentToTemplate(TypeLoc TLoc) { return TemplateArgumentLoc(); } -/// \brief Check that the given template argument corresponds to the given +/// Check that the given template argument corresponds to the given /// template parameter. /// /// \param Param The template parameter against which the argument will be @@ -4566,6 +4699,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) NTTPType = NTTP->getExpansionType(ArgumentPackIndex); + // FIXME: Do we need to substitute into parameters here if they're + // instantiation-dependent but not dependent? if (NTTPType->isDependentType() && !isa<TemplateTemplateParmDecl>(Template) && !Template->getDeclContext()->isDependentContext()) { @@ -4597,11 +4732,15 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Expression: { TemplateArgument Result; + unsigned CurSFINAEErrors = NumSFINAEErrors; ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(), Result, CTAK); if (Res.isInvalid()) return true; + // If the current template argument causes an error, give up now. + if (CurSFINAEErrors < NumSFINAEErrors) + return true; // If the resulting expression is new, then use it in place of the // old expression in the template argument. @@ -4705,9 +4844,15 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param); + TemplateParameterList *Params = TempParm->getTemplateParameters(); + if (TempParm->isExpandedParameterPack()) + Params = TempParm->getExpansionTemplateParameters(ArgumentPackIndex); + // Substitute into the template parameter list of the template // template parameter, since previously-supplied template arguments // may appear within the template template parameter. + // + // FIXME: Skip this if the parameters aren't instantiation-dependent. { // Set up a template instantiation context. LocalInstantiationScope Scope(*this); @@ -4718,10 +4863,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - TempParm = cast_or_null<TemplateTemplateParmDecl>( - SubstDecl(TempParm, CurContext, - MultiLevelTemplateArgumentList(TemplateArgs))); - if (!TempParm) + Params = SubstTemplateParams(Params, CurContext, + MultiLevelTemplateArgumentList(TemplateArgs)); + if (!Params) return true; } @@ -4742,7 +4886,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex)) + if (CheckTemplateTemplateArgument(Params, Arg)) return true; Converted.push_back(Arg.getArgument()); @@ -4770,28 +4914,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return false; } -/// \brief Diagnose an arity mismatch in the -static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs) { - TemplateParameterList *Params = Template->getTemplateParameters(); - unsigned NumParams = Params->size(); - unsigned NumArgs = TemplateArgs.size(); - - SourceRange Range; - if (NumArgs > NumParams) - Range = SourceRange(TemplateArgs[NumParams].getLocation(), - TemplateArgs.getRAngleLoc()); - S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << (NumArgs > NumParams) - << (int)S.getTemplateNameKindForDiagnostics(TemplateName(Template)) - << Template << Range; - S.Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; -} - -/// \brief Check whether the template parameter is a pack expansion, and if so, +/// Check whether the template parameter is a pack expansion, and if so, /// determine the number of parameters produced by that expansion. For instance: /// /// \code @@ -4844,10 +4967,18 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, // FIXME: If there's a more recent default argument that *is* visible, // diagnose that it was declared too late. - return diagnoseArityMismatch(S, TD, Loc, Args); + TemplateParameterList *Params = TD->getTemplateParameters(); + + S.Diag(Loc, diag::err_template_arg_list_different_arity) + << /*not enough args*/0 + << (int)S.getTemplateNameKindForDiagnostics(TemplateName(TD)) + << TD; + S.Diag(TD->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; } -/// \brief Check that the given template argument list is well-formed +/// Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, @@ -4896,7 +5027,7 @@ bool Sema::CheckTemplateArgumentList( } else if (ArgIdx == NumArgs && !PartialTemplateArgs) { // Not enough arguments for this parameter pack. Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << false + << /*not enough args*/0 << (int)getTemplateNameKindForDiagnostics(TemplateName(Template)) << Template; Diag(Template->getLocation(), diag::note_template_decl_here) @@ -5091,8 +5222,16 @@ bool Sema::CheckTemplateArgumentList( // If we have any leftover arguments, then there were too many arguments. // Complain and fail. - if (ArgIdx < NumArgs) - return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs); + if (ArgIdx < NumArgs) { + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << /*too many args*/1 + << (int)getTemplateNameKindForDiagnostics(TemplateName(Template)) + << Template + << SourceRange(NewArgs[ArgIdx].getLocation(), NewArgs.getRAngleLoc()); + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; + } // No problems found with the new argument list, propagate changes back // to caller. @@ -5197,6 +5336,11 @@ bool UnnamedLocalNoLinkageFinder::VisitVectorType(const VectorType* T) { return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitDependentVectorType( + const DependentVectorType *T) { + return Visit(T->getElementType()); +} + bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) { return Visit(T->getElementType()); } @@ -5354,7 +5498,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } -/// \brief Check a template argument against its corresponding +/// Check a template argument against its corresponding /// template type parameter. /// /// This routine implements the semantics of C++ [temp.arg.type]. It @@ -5392,7 +5536,7 @@ enum NullPointerValueKind { NPV_Error }; -/// \brief Determine whether the given template argument is a null pointer +/// Determine whether the given template argument is a null pointer /// value of the appropriate type. static NullPointerValueKind isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, @@ -5488,7 +5632,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, return NPV_NotNullPointer; } -/// \brief Checks whether the given template argument is compatible with its +/// Checks whether the given template argument is compatible with its /// template parameter. static bool CheckTemplateArgumentIsCompatibleWithParameter( Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, @@ -5545,7 +5689,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter( return false; } -/// \brief Checks whether the given template argument is the address +/// Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. static bool CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, @@ -5833,7 +5977,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return false; } -/// \brief Checks whether the given template argument is a pointer to +/// Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. static bool CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, @@ -5883,17 +6027,16 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, } // A constant of pointer-to-member type. else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) { - if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) { - if (VD->getType()->isMemberPointerType()) { - if (isa<NonTypeTemplateParmDecl>(VD)) { - if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - VD = cast<ValueDecl>(VD->getCanonicalDecl()); - Converted = TemplateArgument(VD, ParamType); - } - return Invalid; + ValueDecl *VD = DRE->getDecl(); + if (VD->getType()->isMemberPointerType()) { + if (isa<NonTypeTemplateParmDecl>(VD)) { + if (Arg->isTypeDependent() || Arg->isValueDependent()) { + Converted = TemplateArgument(Arg); + } else { + VD = cast<ValueDecl>(VD->getCanonicalDecl()); + Converted = TemplateArgument(VD, ParamType); } + return Invalid; } } @@ -5963,7 +6106,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, return true; } -/// \brief Check a template argument against its corresponding +/// Check a template argument against its corresponding /// non-type template parameter. /// /// This routine implements the semantics of C++ [temp.arg.nontype]. @@ -6118,7 +6261,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a predefined __func__ variable if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { if (isa<CXXUuidofExpr>(E)) { - Converted = TemplateArgument(const_cast<Expr*>(E)); + Converted = TemplateArgument(ArgResult.get()); break; } Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) @@ -6481,14 +6624,13 @@ static void DiagnoseTemplateParameterListArityMismatch( Sema &S, TemplateParameterList *New, TemplateParameterList *Old, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); -/// \brief Check a template argument against its corresponding +/// Check a template argument against its corresponding /// template template parameter. /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateArgumentLoc &Arg, - unsigned ArgumentPackIndex) { +bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, + TemplateArgumentLoc &Arg) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { @@ -6523,10 +6665,6 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, << Template; } - TemplateParameterList *Params = Param->getTemplateParameters(); - if (Param->isExpandedParameterPack()) - Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); - // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. @@ -6553,7 +6691,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, Arg.getLocation()); } -/// \brief Given a non-type template argument that refers to a +/// Given a non-type template argument that refers to a /// declaration and the type of its corresponding non-type template /// parameter, produce an expression that properly refers to that /// declaration. @@ -6584,7 +6722,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, assert(Arg.getKind() == TemplateArgument::Declaration && "Only declaration template arguments permitted here"); - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + ValueDecl *VD = Arg.getAsDecl(); if (VD->getDeclContext()->isRecord() && (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || @@ -6676,7 +6814,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, return BuildDeclRefExpr(VD, T, VK, Loc); } -/// \brief Construct a new expression that refers to the given +/// Construct a new expression that refers to the given /// integral template argument with the given source-location /// information. /// @@ -6701,11 +6839,11 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, Expr *E; if (T->isAnyCharacterType()) { - // This does not need to handle u8 character literals because those are - // of type char, and so can also be covered by an ASCII character literal. CharacterLiteral::CharacterKind Kind; if (T->isWideCharType()) Kind = CharacterLiteral::Wide; + else if (T->isChar8Type() && getLangOpts().Char8) + Kind = CharacterLiteral::UTF8; else if (T->isChar16Type()) Kind = CharacterLiteral::UTF16; else if (T->isChar32Type()) @@ -6736,7 +6874,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, return E; } -/// \brief Match two template parameters within template parameter lists. +/// Match two template parameters within template parameter lists. static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain, Sema::TemplateParameterListEqualKind Kind, @@ -6839,7 +6977,7 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, return true; } -/// \brief Diagnose a known arity mismatch when comparing template argument +/// Diagnose a known arity mismatch when comparing template argument /// lists. static void DiagnoseTemplateParameterListArityMismatch(Sema &S, @@ -6861,7 +6999,7 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S, << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } -/// \brief Determine whether the given template parameter lists are +/// Determine whether the given template parameter lists are /// equivalent. /// /// \param New The new template parameter list, typically written in the @@ -6953,7 +7091,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return true; } -/// \brief Check whether a template can be declared within this scope. +/// Check whether a template can be declared within this scope. /// /// If the template declaration is valid in this scope, returns /// false. Otherwise, issues a diagnostic and returns true. @@ -7002,7 +7140,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { << TemplateParams->getSourceRange(); } -/// \brief Determine what kind of template specialization the given declaration +/// Determine what kind of template specialization the given declaration /// is. static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D) { if (!D) @@ -7018,7 +7156,7 @@ static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D) { return TSK_Undeclared; } -/// \brief Check whether a specialization is well-formed in the current +/// Check whether a specialization is well-formed in the current /// context. /// /// This routine determines whether a template specialization can be declared @@ -7072,120 +7210,43 @@ static bool CheckTemplateSpecializationScope(Sema &S, } // C++ [temp.expl.spec]p2: - // An explicit specialization shall be declared in the namespace - // of which the template is a member, or, for member templates, in - // the namespace of which the enclosing class or enclosing class - // template is a member. An explicit specialization of a member - // function, member class or static data member of a class - // template shall be declared in the namespace of which the class - // template is a member. Such a declaration may also be a - // definition. If the declaration is not a definition, the - // specialization may be defined later in the name- space in which - // the explicit specialization was declared, or in a namespace - // that encloses the one in which the explicit specialization was - // declared. + // An explicit specialization may be declared in any scope in which + // the corresponding primary template may be defined. if (S.CurContext->getRedeclContext()->isFunctionOrMethod()) { S.Diag(Loc, diag::err_template_spec_decl_function_scope) << Specialized; return true; } - if (S.CurContext->isRecord() && !IsPartialSpecialization) { - if (S.getLangOpts().MicrosoftExt) { - // Do not warn for class scope explicit specialization during - // instantiation, warning was already emitted during pattern - // semantic analysis. - if (!S.inTemplateInstantiation()) - S.Diag(Loc, diag::ext_function_specialization_in_class) - << Specialized; - } else { - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - } - - if (S.CurContext->isRecord() && - !S.CurContext->Equals(Specialized->getDeclContext())) { - // Make sure that we're specializing in the right record context. - // Otherwise, things can go horribly wrong. - S.Diag(Loc, diag::err_template_spec_decl_class_scope) - << Specialized; - return true; - } - // C++ [temp.class.spec]p6: - // A class template partial specialization may be declared or redeclared - // in any namespace scope in which its definition may be defined (14.5.1 - // and 14.5.2). - DeclContext *SpecializedContext - = Specialized->getDeclContext()->getEnclosingNamespaceContext(); - DeclContext *DC = S.CurContext->getEnclosingNamespaceContext(); - - // Make sure that this redeclaration (or definition) occurs in an enclosing - // namespace. - // Note that HandleDeclarator() performs this check for explicit - // specializations of function templates, static data members, and member - // functions, so we skip the check here for those kinds of entities. - // FIXME: HandleDeclarator's diagnostics aren't quite as good, though. - // Should we refactor that check, so that it occurs later? - if (!DC->Encloses(SpecializedContext) && - !(isa<FunctionTemplateDecl>(Specialized) || - isa<FunctionDecl>(Specialized) || - isa<VarTemplateDecl>(Specialized) || - isa<VarDecl>(Specialized))) { + // A class template partial specialization may be declared in any + // scope in which the primary template may be defined. + DeclContext *SpecializedContext = + Specialized->getDeclContext()->getRedeclContext(); + DeclContext *DC = S.CurContext->getRedeclContext(); + + // Make sure that this redeclaration (or definition) occurs in the same + // scope or an enclosing namespace. + if (!(DC->isFileContext() ? DC->Encloses(SpecializedContext) + : DC->Equals(SpecializedContext))) { if (isa<TranslationUnitDecl>(SpecializedContext)) S.Diag(Loc, diag::err_template_spec_redecl_global_scope) << EntityKind << Specialized; - else if (isa<NamespaceDecl>(SpecializedContext)) { + else { + auto *ND = cast<NamedDecl>(SpecializedContext); int Diag = diag::err_template_spec_redecl_out_of_scope; - if (S.getLangOpts().MicrosoftExt) + if (S.getLangOpts().MicrosoftExt && !DC->isRecord()) Diag = diag::ext_ms_template_spec_redecl_out_of_scope; S.Diag(Loc, Diag) << EntityKind << Specialized - << cast<NamedDecl>(SpecializedContext); - } else - llvm_unreachable("unexpected namespace context for specialization"); + << ND << isa<CXXRecordDecl>(ND); + } S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } else if ((!PrevDecl || - getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared || - getTemplateSpecializationKind(PrevDecl) == - TSK_ImplicitInstantiation)) { - // C++ [temp.exp.spec]p2: - // An explicit specialization shall be declared in the namespace of which - // the template is a member, or, for member templates, in the namespace - // of which the enclosing class or enclosing class template is a member. - // An explicit specialization of a member function, member class or - // static data member of a class template shall be declared in the - // namespace of which the class template is a member. - // - // C++11 [temp.expl.spec]p2: - // An explicit specialization shall be declared in a namespace enclosing - // the specialized template. - // C++11 [temp.explicit]p3: - // An explicit instantiation shall appear in an enclosing namespace of its - // template. - if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) { - bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext); - if (isa<TranslationUnitDecl>(SpecializedContext)) { - assert(!IsCPlusPlus11Extension && - "DC encloses TU but isn't in enclosing namespace set"); - S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) - << EntityKind << Specialized; - } else if (isa<NamespaceDecl>(SpecializedContext)) { - int Diag; - if (!IsCPlusPlus11Extension) - Diag = diag::err_template_spec_decl_out_of_scope; - else if (!S.getLangOpts().CPlusPlus11) - Diag = diag::ext_template_spec_decl_out_of_scope; - else - Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope; - S.Diag(Loc, Diag) - << EntityKind << Specialized << cast<NamedDecl>(SpecializedContext); - } - S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - } + // Don't allow specializing in the wrong class during error recovery. + // Otherwise, things can go horribly wrong. + if (DC->isRecord()) + return true; } return false; @@ -7211,7 +7272,7 @@ static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) { return Checker.MatchLoc; } -/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs +/// Subroutine of Sema::CheckTemplatePartialSpecializationArgs /// that checks non-type template partial specialization arguments. static bool CheckNonTypeTemplatePartialSpecializationArgs( Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param, @@ -7299,7 +7360,7 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( return false; } -/// \brief Check the non-type template arguments of a class template +/// Check the non-type template arguments of a class template /// partial specialization according to C++ [temp.class.spec]p9. /// /// \param TemplateNameLoc the location of the template name. @@ -7335,16 +7396,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs( return false; } -DeclResult -Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, - TagUseKind TUK, - SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, - TemplateIdAnnotation &TemplateId, - AttributeList *Attr, - MultiTemplateParamsArg - TemplateParameterLists, - SkipBodyInfo *SkipBody) { +DeclResult Sema::ActOnClassTemplateSpecialization( + Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, + const ParsedAttributesView &Attr, + MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(TUK != TUK_Reference && "References are not specializations"); CXXScopeSpec &SS = TemplateId.SS; @@ -7586,10 +7642,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->AddSpecialization(Specialization, InsertPos); if (CurContext->isDependentContext()) { - // -fms-extensions permits specialization of nested classes without - // fully specializing the outer class(es). - assert(getLangOpts().MicrosoftExt && - "Only possible with -fms-extensions!"); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType( CanonTemplate, Converted); @@ -7649,8 +7701,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } } - if (Attr) - ProcessDeclAttributeList(S, Specialization, Attr); + ProcessDeclAttributeList(S, Specialization, Attr); // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. @@ -7717,7 +7768,7 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S, return NewDecl; } -/// \brief Strips various properties off an implicit instantiation +/// Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { D->dropAttr<DLLImportAttr>(); @@ -7727,7 +7778,7 @@ static void StripImplicitInstantiation(NamedDecl *D) { FD->setInlineSpecified(false); } -/// \brief Compute the diagnostic location for an explicit instantiation +/// Compute the diagnostic location for an explicit instantiation // declaration or definition. static SourceLocation DiagLocForExplicitInstantiation( NamedDecl* D, SourceLocation PointOfInstantiation) { @@ -7744,7 +7795,7 @@ static SourceLocation DiagLocForExplicitInstantiation( return PrevDiagLoc; } -/// \brief Diagnose cases where we have an explicit template specialization +/// Diagnose cases where we have an explicit template specialization /// before/after an explicit template instantiation, producing diagnostics /// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. @@ -7890,7 +7941,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; case TSK_ExplicitInstantiationDeclaration: - // We're explicity instantiating a definition for something for which we + // We're explicitly instantiating a definition for something for which we // were previously asked to suppress instantiations. That's fine. // C++0x [temp.explicit]p4: @@ -7929,7 +7980,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, llvm_unreachable("Missing specialization/instantiation case?"); } -/// \brief Perform semantic analysis for the given dependent function +/// Perform semantic analysis for the given dependent function /// template specialization. /// /// The only possible way to get a dependent function template specialization @@ -7952,24 +8003,41 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, // the correct context. DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); LookupResult::Filter F = Previous.makeFilter(); + enum DiscardReason { NotAFunctionTemplate, NotAMemberOfEnclosing }; + SmallVector<std::pair<DiscardReason, Decl *>, 8> DiscardedCandidates; while (F.hasNext()) { NamedDecl *D = F.next()->getUnderlyingDecl(); - if (!isa<FunctionTemplateDecl>(D) || - !FDLookupContext->InEnclosingNamespaceSetOf( - D->getDeclContext()->getRedeclContext())) + if (!isa<FunctionTemplateDecl>(D)) { + F.erase(); + DiscardedCandidates.push_back(std::make_pair(NotAFunctionTemplate, D)); + continue; + } + + if (!FDLookupContext->InEnclosingNamespaceSetOf( + D->getDeclContext()->getRedeclContext())) { F.erase(); + DiscardedCandidates.push_back(std::make_pair(NotAMemberOfEnclosing, D)); + continue; + } } F.done(); - // Should this be diagnosed here? - if (Previous.empty()) return true; + if (Previous.empty()) { + Diag(FD->getLocation(), + diag::err_dependent_function_template_spec_no_match); + for (auto &P : DiscardedCandidates) + Diag(P.second->getLocation(), + diag::note_dependent_function_template_spec_discard_reason) + << P.first; + return true; + } FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(), ExplicitTemplateArgs); return false; } -/// \brief Perform semantic analysis for the given function template +/// Perform semantic analysis for the given function template /// specialization. /// /// This routine performs all of the semantic analysis required for an @@ -8192,7 +8260,7 @@ bool Sema::CheckFunctionTemplateSpecialization( return false; } -/// \brief Perform semantic analysis for the given non-template member +/// Perform semantic analysis for the given non-template member /// specialization. /// /// This routine performs all of the semantic analysis required for an @@ -8402,7 +8470,7 @@ void Sema::CompleteMemberSpecialization(NamedDecl *Member, llvm_unreachable("unknown member specialization kind"); } -/// \brief Check the scope of an explicit instantiation. +/// Check the scope of an explicit instantiation. /// /// \returns true if a serious error occurs, false otherwise. static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, @@ -8456,7 +8524,7 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, return false; } -/// \brief Determine whether the given scope specifier has a template-id in it. +/// Determine whether the given scope specifier has a template-id in it. static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) return false; @@ -8502,19 +8570,12 @@ static void dllExportImportClassTemplateSpecialization( } // Explicit instantiation of a class template specialization -DeclResult -Sema::ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - const CXXScopeSpec &SS, - TemplateTy TemplateD, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation RAngleLoc, - AttributeList *Attr) { +DeclResult Sema::ActOnExplicitInstantiation( + Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, + unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, + TemplateTy TemplateD, SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc, const ParsedAttributesView &Attr) { // Find the class template we're specializing TemplateName Name = TemplateD.get(); TemplateDecl *TD = Name.getAsTemplateDecl(); @@ -8555,11 +8616,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (TSK == TSK_ExplicitInstantiationDeclaration) { // Check for dllexport class template instantiation declarations. - for (AttributeList *A = Attr; A; A = A->getNext()) { - if (A->getKind() == AttributeList::AT_DLLExport) { + for (const ParsedAttr &AL : Attr) { + if (AL.getKind() == ParsedAttr::AT_DLLExport) { Diag(ExternLoc, diag::warn_attribute_dllexport_explicit_instantiation_decl); - Diag(A->getLoc(), diag::note_attribute); + Diag(AL.getLoc(), diag::note_attribute); break; } } @@ -8579,10 +8640,10 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Check for dllimport class template instantiation definitions. bool DLLImport = ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>(); - for (AttributeList *A = Attr; A; A = A->getNext()) { - if (A->getKind() == AttributeList::AT_DLLImport) + for (const ParsedAttr &AL : Attr) { + if (AL.getKind() == ParsedAttr::AT_DLLImport) DLLImport = true; - if (A->getKind() == AttributeList::AT_DLLExport) { + if (AL.getKind() == ParsedAttr::AT_DLLExport) { // dllexport trumps dllimport here. DLLImport = false; break; @@ -8692,8 +8753,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setBraceRange(SourceRange()); bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>(); - if (Attr) - ProcessDeclAttributeList(S, Specialization, Attr); + ProcessDeclAttributeList(S, Specialization, Attr); // Add the explicit instantiation into its lexical context. However, // since explicit instantiations are never found by name lookup, we @@ -8791,15 +8851,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Explicit instantiation of a member class of a class template. DeclResult -Sema::ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - CXXScopeSpec &SS, - IdentifierInfo *Name, - SourceLocation NameLoc, - AttributeList *Attr) { +Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, + SourceLocation TemplateLoc, unsigned TagSpec, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr) { bool Owned = false; bool IsDependent = false; @@ -9101,8 +9157,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (PrevTemplate) { // Merge attributes. - if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList()) - ProcessDeclAttributeList(S, Prev, Attr); + ProcessDeclAttributeList(S, Prev, D.getDeclSpec().getAttributes()); } if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateVariableDefinition(D.getIdentifierLoc(), Prev); @@ -9138,7 +9193,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // template. UnresolvedSet<8> TemplateMatches; FunctionDecl *NonTemplateMatch = nullptr; - AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc()); for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { @@ -9186,7 +9240,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (LangOpts.CUDA && IdentifyCUDATarget(Specialization, /* IgnoreImplicitHDAttributes = */ true) != - IdentifyCUDATarget(Attr)) { + IdentifyCUDATarget(D.getDeclSpec().getAttributes())) { FailedCandidates.addCandidate().set( P.getPair(), FunTmpl->getTemplatedDecl(), MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); @@ -9265,8 +9319,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return (Decl*) nullptr; } - if (Attr) - ProcessDeclAttributeList(S, Specialization, Attr); + ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes()); // In MSVC mode, dllimported explicit instantiation definitions are treated as // instantiation declarations. @@ -9478,8 +9531,7 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, EnableIfTy.getAs<TemplateSpecializationTypeLoc>(); if (!EnableIfTSTLoc || EnableIfTSTLoc.getNumArgs() == 0) return false; - const TemplateSpecializationType *EnableIfTST = - cast<TemplateSpecializationType>(EnableIfTSTLoc.getTypePtr()); + const TemplateSpecializationType *EnableIfTST = EnableIfTSTLoc.getTypePtr(); // ... which names a complete class template declaration... const TemplateDecl *EnableIfDecl = @@ -9511,7 +9563,7 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return true; } -/// \brief Build the type that describes a C++ typename specifier, +/// Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, @@ -9686,7 +9738,7 @@ namespace { : TreeTransform<CurrentInstantiationRebuilder>(SemaRef), Loc(Loc), Entity(Entity) { } - /// \brief Determine whether the given type \p T has already been + /// Determine whether the given type \p T has already been /// transformed. /// /// For the purposes of type reconstruction, a type has already been @@ -9695,14 +9747,14 @@ namespace { return T.isNull() || !T->isDependentType(); } - /// \brief Returns the location of the entity whose type is being + /// Returns the location of the entity whose type is being /// rebuilt. SourceLocation getBaseLocation() { return Loc; } - /// \brief Returns the name of the entity whose type is being rebuilt. + /// Returns the name of the entity whose type is being rebuilt. DeclarationName getBaseEntity() { return Entity; } - /// \brief Sets the "base" location and entity when that + /// Sets the "base" location and entity when that /// information is known based on another transformation. void setBase(SourceLocation Loc, DeclarationName Entity) { this->Loc = Loc; @@ -9716,7 +9768,7 @@ namespace { }; } // end anonymous namespace -/// \brief Rebuilds a type within the context of the current instantiation. +/// Rebuilds a type within the context of the current instantiation. /// /// The type \p T is part of the type of an out-of-line member definition of /// a class template (or class template partial specialization) that was parsed @@ -9774,7 +9826,7 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { return false; } -/// \brief Rebuild the template parameters now that we know we're in a current +/// Rebuild the template parameters now that we know we're in a current /// instantiation. bool Sema::RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params) { @@ -9813,7 +9865,7 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation( return false; } -/// \brief Produces a formatted string that describes the binding of +/// Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, @@ -9891,7 +9943,7 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() { } namespace { -/// \brief Walk the path from which a declaration was instantiated, and check +/// Walk the path from which a declaration was instantiated, and check /// that every explicit specialization along that path is visible. This enforces /// C++ [temp.expl.spec]/6: /// @@ -10027,7 +10079,7 @@ void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec); } -/// \brief Check whether a template partial specialization that we've discovered +/// Check whether a template partial specialization that we've discovered /// is hidden, and produce suitable diagnostics if so. void Sema::checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index d09cf9933ecf..633b2837e1fe 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1,60 +1,97 @@ -//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/ +//===- SemaTemplateDeduction.cpp - Template Argument Deduction ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -//===----------------------------------------------------------------------===/ // -// This file implements C++ template argument deduction. +//===----------------------------------------------------------------------===// // -//===----------------------------------------------------------------------===/ +// This file implements C++ template argument deduction. +// +//===----------------------------------------------------------------------===// #include "clang/Sema/TemplateDeduction.h" #include "TreeTransform.h" +#include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" -#include "clang/AST/DeclObjC.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeOrdering.h" -#include "clang/Sema/DeclSpec.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Sema/Ownership.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> +#include <cassert> +#include <tuple> +#include <utility> namespace clang { - using namespace sema; - /// \brief Various flags that control template argument deduction. + + /// Various flags that control template argument deduction. /// /// These flags can be bitwise-OR'd together. enum TemplateDeductionFlags { - /// \brief No template argument deduction flags, which indicates the + /// No template argument deduction flags, which indicates the /// strictest results for template argument deduction (as used for, e.g., /// matching class template partial specializations). TDF_None = 0, - /// \brief Within template argument deduction from a function call, we are + + /// Within template argument deduction from a function call, we are /// matching with a parameter type for which the original parameter was /// a reference. TDF_ParamWithReferenceType = 0x1, - /// \brief Within template argument deduction from a function call, we + + /// Within template argument deduction from a function call, we /// are matching in a case where we ignore cv-qualifiers. TDF_IgnoreQualifiers = 0x02, - /// \brief Within template argument deduction from a function call, + + /// Within template argument deduction from a function call, /// we are matching in a case where we can perform template argument /// deduction from a template-id of a derived class of the argument type. TDF_DerivedClass = 0x04, - /// \brief Allow non-dependent types to differ, e.g., when performing + + /// Allow non-dependent types to differ, e.g., when performing /// template argument deduction from a function call where conversions /// may apply. TDF_SkipNonDependent = 0x08, - /// \brief Whether we are performing template argument deduction for + + /// Whether we are performing template argument deduction for /// parameters and arguments in a top-level template argument TDF_TopLevelParameterTypeList = 0x10, - /// \brief Within template argument deduction from overload resolution per + + /// Within template argument deduction from overload resolution per /// C++ [over.over] allow matching function types that are compatible in /// terms of noreturn and default calling convention adjustments, or /// similarly matching a declared template specialization against a @@ -62,12 +99,18 @@ namespace clang { /// deduction where the parameter is a function type that can be converted /// to the argument type. TDF_AllowCompatibleFunctionType = 0x20, + + /// Within template argument deduction for a conversion function, we are + /// matching with an argument type for which the original argument was + /// a reference. + TDF_ArgWithReferenceType = 0x40, }; } using namespace clang; +using namespace sema; -/// \brief Compare two APSInts, extending and switching the sign as +/// Compare two APSInts, extending and switching the sign as /// necessary to compare their values regardless of underlying type. static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { if (Y.getBitWidth() > X.getBitWidth()) @@ -125,14 +168,14 @@ static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, bool OnlyDeduced, unsigned Level, llvm::SmallBitVector &Deduced); -/// \brief If the given expression is of a form that permits the deduction +/// If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that /// non-type template parameter. static NonTypeTemplateParmDecl * getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { // If we are within an alias template, the expression may have undergone // any number of parameter substitutions already. - while (1) { + while (true) { if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E)) E = IC->getSubExpr(); else if (SubstNonTypeTemplateParmExpr *Subst = @@ -150,7 +193,7 @@ getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { return nullptr; } -/// \brief Determine whether two declaration pointers refer to the same +/// Determine whether two declaration pointers refer to the same /// declaration. static bool isSameDeclaration(Decl *X, Decl *Y) { if (NamedDecl *NX = dyn_cast<NamedDecl>(X)) @@ -161,7 +204,7 @@ static bool isSameDeclaration(Decl *X, Decl *Y) { return X->getCanonicalDecl() == Y->getCanonicalDecl(); } -/// \brief Verify that the given, deduced template arguments are compatible. +/// Verify that the given, deduced template arguments are compatible. /// /// \returns The deduced template argument, or a NULL template argument if /// the deduced template arguments were incompatible. @@ -270,7 +313,7 @@ checkDeducedTemplateArguments(ASTContext &Context, return Y; } - // If we deduced two declarations, make sure they they refer to the + // If we deduced two declarations, make sure that they refer to the // same declaration. if (Y.getKind() == TemplateArgument::Declaration && isSameDeclaration(X.getAsDecl(), Y.getAsDecl())) @@ -297,7 +340,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // All other combinations are incompatible. return DeducedTemplateArgument(); - case TemplateArgument::Pack: + case TemplateArgument::Pack: { if (Y.getKind() != TemplateArgument::Pack || X.pack_size() != Y.pack_size()) return DeducedTemplateArgument(); @@ -319,11 +362,12 @@ checkDeducedTemplateArguments(ASTContext &Context, TemplateArgument::CreatePackCopy(Context, NewPack), X.wasDeducedFromArrayBound() && Y.wasDeducedFromArrayBound()); } + } llvm_unreachable("Invalid TemplateArgument Kind!"); } -/// \brief Deduce the value of the given non-type template parameter +/// Deduce the value of the given non-type template parameter /// as the given deduced template argument. All non-type template parameter /// deduction is funneled through here. static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( @@ -371,7 +415,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound()); } -/// \brief Deduce the value of the given non-type template parameter +/// Deduce the value of the given non-type template parameter /// from the given integral constant. static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, @@ -385,7 +429,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( ValueType, Info, Deduced); } -/// \brief Deduce the value of the given non-type template parameter +/// Deduce the value of the given non-type template parameter /// from the given null pointer template argument type. static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, @@ -402,7 +446,7 @@ static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument( Value->getType(), Info, Deduced); } -/// \brief Deduce the value of the given non-type template parameter +/// Deduce the value of the given non-type template parameter /// from the given type- or value-dependent expression. /// /// \returns true if deduction succeeded, false otherwise. @@ -415,7 +459,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( Value->getType(), Info, Deduced); } -/// \brief Deduce the value of the given non-type template parameter +/// Deduce the value of the given non-type template parameter /// from the given declaration. /// /// \returns true if deduction succeeded, false otherwise. @@ -475,7 +519,7 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_NonDeducedMismatch; } -/// \brief Deduce the template arguments by comparing the template parameter +/// Deduce the template arguments by comparing the template parameter /// type (which is a template-id) with the template argument type. /// /// \param S the Sema @@ -560,7 +604,7 @@ DeduceTemplateArguments(Sema &S, Deduced, /*NumberOfArgumentsMustMatch=*/true); } -/// \brief Determines whether the given type is an opaque type that +/// Determines whether the given type is an opaque type that /// might be more qualified when instantiated. static bool IsPossiblyOpaquelyQualifiedType(QualType T) { switch (T->getTypeClass()) { @@ -584,30 +628,7 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { } } -/// \brief Retrieve the depth and index of a template parameter. -static std::pair<unsigned, unsigned> -getDepthAndIndex(NamedDecl *ND) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - -/// \brief Retrieve the depth and index of an unexpanded parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(UnexpandedParameterPack UPP) { - if (const TemplateTypeParmType *TTP - = UPP.first.dyn_cast<const TemplateTypeParmType *>()) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - return getDepthAndIndex(UPP.first.get<NamedDecl *>()); -} - -/// \brief Helper function to build a TemplateParameter when we don't +/// Helper function to build a TemplateParameter when we don't /// know its type statically. static TemplateParameter makeTemplateParameter(Decl *D) { if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) @@ -618,10 +639,21 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); } +/// If \p Param is an expanded parameter pack, get the number of expansions. +static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionTemplateParameters(); + + return None; +} + /// A pack that we're currently deducing. struct clang::DeducedPack { - DeducedPack(unsigned Index) : Index(Index), Outer(nullptr) {} - // The index of the pack. unsigned Index; @@ -636,17 +668,93 @@ struct clang::DeducedPack { SmallVector<DeducedTemplateArgument, 4> New; // The outer deduction for this pack, if any. - DeducedPack *Outer; + DeducedPack *Outer = nullptr; + + DeducedPack(unsigned Index) : Index(Index) {} }; namespace { + /// A scope in which we're performing pack deduction. class PackDeductionScope { public: + /// Prepare to deduce the packs named within Pattern. PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams, SmallVectorImpl<DeducedTemplateArgument> &Deduced, TemplateDeductionInfo &Info, TemplateArgument Pattern) : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) { + unsigned NumNamedPacks = addPacks(Pattern); + finishConstruction(NumNamedPacks); + } + + /// Prepare to directly deduce arguments of the parameter with index \p Index. + PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info, unsigned Index) + : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) { + addPack(Index); + finishConstruction(1); + } + +private: + void addPack(unsigned Index) { + // Save the deduced template argument for the parameter pack expanded + // by this pack expansion, then clear out the deduction. + DeducedPack Pack(Index); + Pack.Saved = Deduced[Index]; + Deduced[Index] = TemplateArgument(); + + // FIXME: What if we encounter multiple packs with different numbers of + // pre-expanded expansions? (This should already have been diagnosed + // during substitution.) + if (Optional<unsigned> ExpandedPackExpansions = + getExpandedPackSize(TemplateParams->getParam(Index))) + FixedNumExpansions = ExpandedPackExpansions; + + Packs.push_back(Pack); + } + + unsigned addPacks(TemplateArgument Pattern) { + // Compute the set of template parameter indices that correspond to + // parameter packs expanded by the pack expansion. + llvm::SmallBitVector SawIndices(TemplateParams->size()); + + auto AddPack = [&](unsigned Index) { + if (SawIndices[Index]) + return; + SawIndices[Index] = true; + addPack(Index); + }; + + // First look for unexpanded packs in the pattern. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == Info.getDeducedDepth()) + AddPack(Index); + } + assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); + + unsigned NumNamedPacks = Packs.size(); + + // We can also have deduced template parameters that do not actually + // appear in the pattern, but can be deduced by it (the type of a non-type + // template parameter pack, in particular). These won't have prevented us + // from partially expanding the pack. + llvm::SmallBitVector Used(TemplateParams->size()); + MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, + Info.getDeducedDepth(), Used); + for (int Index = Used.find_first(); Index != -1; + Index = Used.find_next(Index)) + if (TemplateParams->getParam(Index)->isParameterPack()) + AddPack(Index); + + return NumNamedPacks; + } + + void finishConstruction(unsigned NumNamedPacks) { // Dig out the partially-substituted pack, if there is one. const TemplateArgument *PartialPackArgs = nullptr; unsigned NumPartialPackArgs = 0; @@ -656,60 +764,29 @@ public: &PartialPackArgs, &NumPartialPackArgs)) PartialPackDepthIndex = getDepthAndIndex(Partial); - // Compute the set of template parameter indices that correspond to - // parameter packs expanded by the pack expansion. - { - llvm::SmallBitVector SawIndices(TemplateParams->size()); - - auto AddPack = [&](unsigned Index) { - if (SawIndices[Index]) - return; - SawIndices[Index] = true; - - // Save the deduced template argument for the parameter pack expanded - // by this pack expansion, then clear out the deduction. - DeducedPack Pack(Index); - Pack.Saved = Deduced[Index]; - Deduced[Index] = TemplateArgument(); - - Packs.push_back(Pack); - }; - - // First look for unexpanded packs in the pattern. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - S.collectUnexpandedParameterPacks(Pattern, Unexpanded); - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); - if (Depth == Info.getDeducedDepth()) - AddPack(Index); + // This pack expansion will have been partially or fully expanded if + // it only names explicitly-specified parameter packs (including the + // partially-substituted one, if any). + bool IsExpanded = true; + for (unsigned I = 0; I != NumNamedPacks; ++I) { + if (Packs[I].Index >= Info.getNumExplicitArgs()) { + IsExpanded = false; + IsPartiallyExpanded = false; + break; + } + if (PartialPackDepthIndex == + std::make_pair(Info.getDeducedDepth(), Packs[I].Index)) { + IsPartiallyExpanded = true; } - assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); - - // This pack expansion will have been partially expanded iff the only - // unexpanded parameter pack within it is the partially-substituted pack. - IsPartiallyExpanded = - Packs.size() == 1 && - PartialPackDepthIndex == - std::make_pair(Info.getDeducedDepth(), Packs.front().Index); - - // Skip over the pack elements that were expanded into separate arguments. - if (IsPartiallyExpanded) - PackElements += NumPartialPackArgs; - - // We can also have deduced template parameters that do not actually - // appear in the pattern, but can be deduced by it (the type of a non-type - // template parameter pack, in particular). These won't have prevented us - // from partially expanding the pack. - llvm::SmallBitVector Used(TemplateParams->size()); - MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, - Info.getDeducedDepth(), Used); - for (int Index = Used.find_first(); Index != -1; - Index = Used.find_next(Index)) - if (TemplateParams->getParam(Index)->isParameterPack()) - AddPack(Index); } + // Skip over the pack elements that were expanded into separate arguments. + // If we partially expanded, this is the number of partial arguments. + if (IsPartiallyExpanded) + PackElements += NumPartialPackArgs; + else if (IsExpanded) + PackElements += *FixedNumExpansions; + for (auto &Pack : Packs) { if (Info.PendingDeducedPacks.size() > Pack.Index) Pack.Outer = Info.PendingDeducedPacks[Pack.Index]; @@ -728,12 +805,13 @@ public: // FIXME: If we could represent a "depth i, index j, pack elem k" // parameter, we could substitute the partially-substituted pack // everywhere and avoid this. - if (Pack.New.size() > PackElements) + if (!IsPartiallyExpanded) Deduced[Pack.Index] = Pack.New[PackElements]; } } } +public: ~PackDeductionScope() { for (auto &Pack : Packs) Info.PendingDeducedPacks[Pack.Index] = Pack.Outer; @@ -743,6 +821,18 @@ public: /// sequence of (prior) function parameters / template arguments. bool isPartiallyExpanded() { return IsPartiallyExpanded; } + /// Determine whether this pack expansion scope has a known, fixed arity. + /// This happens if it involves a pack from an outer template that has + /// (notionally) already been expanded. + bool hasFixedArity() { return FixedNumExpansions.hasValue(); } + + /// Determine whether the next element of the argument is still part of this + /// pack. This is the case unless the pack is already expanded to a fixed + /// length. + bool hasNextElement() { + return !FixedNumExpansions || *FixedNumExpansions > PackElements; + } + /// Move to deducing the next element in each pack that is being deduced. void nextPackElement() { // Capture the deduced template arguments for each parameter pack expanded @@ -765,16 +855,24 @@ public: ++PackElements; } - /// \brief Finish template argument deduction for a set of argument packs, + /// Finish template argument deduction for a set of argument packs, /// producing the argument packs and checking for consistency with prior /// deductions. - Sema::TemplateDeductionResult finish() { + Sema::TemplateDeductionResult + finish(bool TreatNoDeductionsAsNonDeduced = true) { // Build argument packs for each of the parameter packs expanded by this // pack expansion. for (auto &Pack : Packs) { // Put back the old value for this pack. Deduced[Pack.Index] = Pack.Saved; + // If we are deducing the size of this pack even if we didn't deduce any + // values for it, then make sure we build a pack of the right size. + // FIXME: Should we always deduce the size, even if the pack appears in + // a non-deduced context? + if (!TreatNoDeductionsAsNonDeduced) + Pack.New.resize(PackElements); + // Build or find a new value for this pack. DeducedTemplateArgument NewPack; if (PackElements && Pack.New.empty()) { @@ -830,14 +928,24 @@ public: Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack); } + NamedDecl *Param = TemplateParams->getParam(Pack.Index); if (Result.isNull()) { - Info.Param = - makeTemplateParameter(TemplateParams->getParam(Pack.Index)); + Info.Param = makeTemplateParameter(Param); Info.FirstArg = OldPack; Info.SecondArg = NewPack; return Sema::TDK_Inconsistent; } + // If we have a pre-expanded pack and we didn't deduce enough elements + // for it, fail deduction. + if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) { + if (*Expansions != PackElements) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = Result; + return Sema::TDK_IncompletePack; + } + } + *Loc = Result; } @@ -851,12 +959,15 @@ private: TemplateDeductionInfo &Info; unsigned PackElements = 0; bool IsPartiallyExpanded = false; + /// The number of expansions, if we have a fully-expanded pack in this scope. + Optional<unsigned> FixedNumExpansions; SmallVector<DeducedPack, 2> Packs; }; + } // namespace -/// \brief Deduce the template arguments by comparing the list of parameter +/// Deduce the template arguments by comparing the list of parameter /// types to the list of argument types, as in the parameter-type-lists of /// function types (C++ [temp.deduct.type]p10). /// @@ -895,12 +1006,6 @@ DeduceTemplateArguments(Sema &S, SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, bool PartialOrdering = false) { - // Fast-path check to see if we have too many/too few arguments. - if (NumParams != NumArgs && - !(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) && - !(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1]))) - return Sema::TDK_MiscellaneousDeductionFailure; - // C++0x [temp.deduct.type]p10: // Similarly, if P has a form that contains (T), then each parameter type // Pi of the respective parameter-type- list of P is compared with the @@ -937,13 +1042,6 @@ DeduceTemplateArguments(Sema &S, continue; } - // C++0x [temp.deduct.type]p5: - // The non-deduced contexts are: - // - A function parameter pack that does not occur at the end of the - // parameter-declaration-clause. - if (ParamIdx + 1 < NumParams) - return Sema::TDK_Success; - // C++0x [temp.deduct.type]p10: // If the parameter-declaration corresponding to Pi is a function // parameter pack, then the type of its declarator- id is compared with @@ -954,15 +1052,43 @@ DeduceTemplateArguments(Sema &S, QualType Pattern = Expansion->getPattern(); PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); - for (; ArgIdx < NumArgs; ++ArgIdx) { - // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, - Args[ArgIdx], Info, Deduced, - TDF, PartialOrdering)) - return Result; + // A pack scope with fixed arity is not really a pack any more, so is not + // a non-deduced context. + if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { + for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { + // Deduce template arguments from the pattern. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, + Args[ArgIdx], Info, Deduced, + TDF, PartialOrdering)) + return Result; - PackScope.nextPackElement(); + PackScope.nextPackElement(); + } + } else { + // C++0x [temp.deduct.type]p5: + // The non-deduced contexts are: + // - A function parameter pack that does not occur at the end of the + // parameter-declaration-clause. + // + // FIXME: There is no wording to say what we should do in this case. We + // choose to resolve this by applying the same rule that is applied for a + // function call: that is, deduce all contained packs to their + // explicitly-specified values (or to <> if there is no such value). + // + // This is seemingly-arbitrarily different from the case of a template-id + // with a non-trailing pack-expansion in its arguments, which renders the + // entire template-argument-list a non-deduced context. + + // If the parameter type contains an explicitly-specified pack that we + // could not expand, skip the number of parameters notionally created + // by the expansion. + Optional<unsigned> NumExpansions = Expansion->getNumExpansions(); + if (NumExpansions && !PackScope.isPartiallyExpanded()) { + for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs; + ++I, ++ArgIdx) + PackScope.nextPackElement(); + } } // Build argument packs for each of the parameter packs expanded by this @@ -978,8 +1104,10 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_Success; } -/// \brief Determine whether the parameter has qualifiers that are either -/// inconsistent with or a superset of the argument's qualifiers. +/// Determine whether the parameter has qualifiers that the argument +/// lacks. Put another way, determine whether there is no way to add +/// a deduced set of qualifiers to the ParamType that would result in +/// its qualifiers matching those of the ArgType. static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, QualType ArgType) { Qualifiers ParamQs = ParamType.getQualifiers(); @@ -1003,13 +1131,11 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, ParamQs.hasObjCLifetime()) return true; - // CVR qualifier superset. - return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && - ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) - == ParamQs.getCVRQualifiers()); + // CVR qualifiers inconsistent or a superset. + return (ParamQs.getCVRQualifiers() & ~ArgQs.getCVRQualifiers()) != 0; } -/// \brief Compare types for equality with respect to possibly compatible +/// Compare types for equality with respect to possibly compatible /// function types (noreturn adjustment, implicit calling conventions). If any /// of parameter and argument is not a function, just perform type comparison. /// @@ -1061,7 +1187,7 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { return false; } -/// \brief Deduce the template arguments by comparing the parameter type and +/// Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// /// \param S the semantic analysis object within which we are deducing @@ -1232,6 +1358,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_Underqualified; } + // Do not match a function type with a cv-qualified type. + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584 + if (Arg->isFunctionType() && Param.hasQualifiers()) { + return Sema::TDK_NonDeducedMismatch; + } + assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); @@ -1307,6 +1439,18 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (TDF & TDF_ParamWithReferenceType) { if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) return Sema::TDK_NonDeducedMismatch; + } else if (TDF & TDF_ArgWithReferenceType) { + // C++ [temp.deduct.conv]p4: + // If the original A is a reference type, A can be more cv-qualified + // than the deduced A + if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers())) + return Sema::TDK_NonDeducedMismatch; + + // Strip out all extra qualifiers from the argument to figure out the + // type we're converting to, prior to the qualification conversion. + Qualifiers Quals; + Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); + Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers()); } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; @@ -1357,7 +1501,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::Enum: case Type::ObjCObject: case Type::ObjCInterface: - case Type::ObjCObjectPointer: { + case Type::ObjCObjectPointer: if (TDF & TDF_SkipNonDependent) return Sema::TDK_Success; @@ -1367,7 +1511,6 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, } return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; - } // _Complex T [placeholder extension] case Type::Complex: @@ -1561,7 +1704,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, "saw non-type template parameter with wrong depth"); llvm::APSInt Noexcept(1); - switch (FunctionProtoArg->canThrow(S.Context)) { + switch (FunctionProtoArg->canThrow()) { case CT_Cannot: Noexcept = 1; LLVM_FALLTHROUGH; @@ -1582,11 +1725,14 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, } } // FIXME: Detect non-deduced exception specification mismatches? + // + // Careful about [temp.deduct.call] and [temp.deduct.conv], which allow + // top-level differences in noexcept-specifications. return Sema::TDK_Success; } - case Type::InjectedClassName: { + case Type::InjectedClassName: // Treat a template's injected-class-name as if the template // specialization type had been used. Param = cast<InjectedClassNameType>(Param) @@ -1594,7 +1740,6 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, assert(isa<TemplateSpecializationType>(Param) && "injected class name is not a template specialization type"); LLVM_FALLTHROUGH; - } // template-name<T> (where template-name refers to a class template) // template-name<i> @@ -1792,6 +1937,54 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_NonDeducedMismatch; } + case Type::DependentVector: { + const auto *VectorParam = cast<DependentVectorType>(Param); + + if (const auto *VectorArg = dyn_cast<VectorType>(Arg)) { + // Perform deduction on the element types. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VectorParam->getElementType(), + VectorArg->getElementType(), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the vector size, if we can. + NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + if (!NTTP) + return Sema::TDK_Success; + + llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); + ArgSize = VectorArg->getNumElements(); + // Note that we use the "array bound" rules here; just like in that + // case, we don't have any particular type for the vector size, but + // we can provide one if necessary. + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, + S.Context.UnsignedIntTy, true, + Info, Deduced); + } + + if (const auto *VectorArg = dyn_cast<DependentVectorType>(Arg)) { + // Perform deduction on the element types. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VectorParam->getElementType(), + VectorArg->getElementType(), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the vector size, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, VectorParam->getSizeExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced); + } + + return Sema::TDK_NonDeducedMismatch; + } + // (clang extension) // // T __attribute__(((ext_vector_type(N)))) @@ -1996,7 +2189,7 @@ DeduceTemplateArguments(Sema &S, Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - case TemplateArgument::Expression: { + case TemplateArgument::Expression: if (NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) @@ -2025,7 +2218,7 @@ DeduceTemplateArguments(Sema &S, // Can't deduce anything, but that's okay. return Sema::TDK_Success; - } + case TemplateArgument::Pack: llvm_unreachable("Argument packs should be expanded by the caller!"); } @@ -2033,7 +2226,7 @@ DeduceTemplateArguments(Sema &S, llvm_unreachable("Invalid TemplateArgument Kind!"); } -/// \brief Determine whether there is a template argument to be used for +/// Determine whether there is a template argument to be used for /// deduction. /// /// This routine "expands" argument packs in-place, overriding its input @@ -2056,7 +2249,7 @@ static bool hasTemplateArgumentForDeduction(ArrayRef<TemplateArgument> &Args, return ArgIdx < Args.size(); } -/// \brief Determine whether the given set of template arguments has a pack +/// Determine whether the given set of template arguments has a pack /// expansion that is not the last template argument. static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) { bool FoundPackExpansion = false; @@ -2067,6 +2260,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) { if (A.getKind() == TemplateArgument::Pack) return hasPackExpansionBeforeEnd(A.pack_elements()); + // FIXME: If this is a fixed-arity pack expansion from an outer level of + // templates, it should not be treated as a pack expansion. if (A.isPackExpansion()) FoundPackExpansion = true; } @@ -2130,17 +2325,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // template parameter packs expanded by Pi. TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern(); - // FIXME: If there are no remaining arguments, we can bail out early - // and set any deduced parameter packs to an empty argument pack. - // The latter part of this is a (minor) correctness issue. - // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - for (; hasTemplateArgumentForDeduction(Args, ArgIdx); ++ArgIdx) { + for (; hasTemplateArgumentForDeduction(Args, ArgIdx) && + PackScope.hasNextElement(); + ++ArgIdx) { // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], @@ -2171,7 +2364,7 @@ DeduceTemplateArguments(Sema &S, /*NumberOfArgumentsMustMatch*/false); } -/// \brief Determine whether two template arguments are the same. +/// Determine whether two template arguments are the same. static bool isSameTemplateArg(ASTContext &Context, TemplateArgument X, const TemplateArgument &Y, @@ -2232,7 +2425,7 @@ static bool isSameTemplateArg(ASTContext &Context, llvm_unreachable("Invalid TemplateArgument Kind!"); } -/// \brief Allocate a TemplateArgumentLoc where all locations have +/// Allocate a TemplateArgumentLoc where all locations have /// been initialized to the given location. /// /// \param Arg The template argument we are producing template argument @@ -2307,8 +2500,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, llvm_unreachable("Invalid TemplateArgument Kind!"); } - -/// \brief Convert the given deduced template argument and add it to the set of +/// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, @@ -2413,6 +2605,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NamedDecl *Param = TemplateParams->getParam(I); + // C++0x [temp.arg.explicit]p3: + // A trailing template parameter pack (14.5.3) not otherwise deduced will + // be deduced to an empty sequence of template arguments. + // FIXME: Where did the word "trailing" come from? + if (Deduced[I].isNull() && Param->isTemplateParameterPack()) { + if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I) + .finish(/*TreatNoDeductionsAsNonDeduced*/false)) + return Result; + } + if (!Deduced[I].isNull()) { if (I < NumAlreadyConverted) { // We may have had explicitly-specified template arguments for a @@ -2447,40 +2649,6 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( continue; } - // C++0x [temp.arg.explicit]p3: - // A trailing template parameter pack (14.5.3) not otherwise deduced will - // be deduced to an empty sequence of template arguments. - // FIXME: Where did the word "trailing" come from? - if (Param->isTemplateParameterPack()) { - // We may have had explicitly-specified template arguments for this - // template parameter pack. If so, our empty deduction extends the - // explicitly-specified set (C++0x [temp.arg.explicit]p9). - const TemplateArgument *ExplicitArgs; - unsigned NumExplicitArgs; - if (CurrentInstantiationScope && - CurrentInstantiationScope->getPartiallySubstitutedPack( - &ExplicitArgs, &NumExplicitArgs) == Param) { - Builder.push_back(TemplateArgument( - llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); - - // Forget the partially-substituted pack; its substitution is now - // complete. - CurrentInstantiationScope->ResetPartiallySubstitutedPack(); - } else { - // Go through the motions of checking the empty argument pack against - // the parameter pack. - DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack()); - if (ConvertDeducedTemplateArgument(S, Param, DeducedPack, Template, - Info, IsDeduced, Builder)) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); - return Sema::TDK_SubstitutionFailure; - } - } - continue; - } - // Substitute into the default template argument, if available. bool HasDefaultArg = false; TemplateDecl *TD = dyn_cast<TemplateDecl>(Template); @@ -2663,7 +2831,7 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( } -/// \brief Perform template argument deduction to determine whether +/// Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. Sema::TemplateDeductionResult @@ -2706,7 +2874,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info); } -/// \brief Perform template argument deduction to determine whether +/// Perform template argument deduction to determine whether /// the given template arguments match the given variable template /// partial specialization per C++ [temp.class.spec.match]. Sema::TemplateDeductionResult @@ -2747,7 +2915,7 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info); } -/// \brief Determine whether the given type T is a simple-template-id type. +/// Determine whether the given type T is a simple-template-id type. static bool isSimpleTemplateIdType(QualType T) { if (const TemplateSpecializationType *Spec = T->getAs<TemplateSpecializationType>()) @@ -2767,7 +2935,7 @@ static bool isSimpleTemplateIdType(QualType T) { return false; } -/// \brief Substitute the explicitly-provided template arguments into the +/// Substitute the explicitly-provided template arguments into the /// given function template according to C++ [temp.arg.explicit]. /// /// \param FunctionTemplate the function template into which the explicit @@ -2841,7 +3009,7 @@ Sema::SubstituteExplicitTemplateArguments( Trap.hasErrorOccurred()) { unsigned Index = Builder.size(); if (Index >= TemplateParams->size()) - Index = TemplateParams->size() - 1; + return TDK_SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); return TDK_InvalidExplicitArguments; } @@ -2850,7 +3018,7 @@ Sema::SubstituteExplicitTemplateArguments( // template arguments. TemplateArgumentList *ExplicitArgumentList = TemplateArgumentList::CreateCopy(Context, Builder); - Info.reset(ExplicitArgumentList); + Info.setExplicitArgs(ExplicitArgumentList); // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit @@ -2862,14 +3030,19 @@ Sema::SubstituteExplicitTemplateArguments( // note that the template argument pack is partially substituted and record // the explicit template arguments. They'll be used as part of deduction // for this template parameter pack. - for (unsigned I = 0, N = Builder.size(); I != N; ++I) { - const TemplateArgument &Arg = Builder[I]; + unsigned PartiallySubstitutedPackIndex = -1u; + if (!Builder.empty()) { + const TemplateArgument &Arg = Builder.back(); if (Arg.getKind() == TemplateArgument::Pack) { - CurrentInstantiationScope->SetPartiallySubstitutedPack( - TemplateParams->getParam(I), - Arg.pack_begin(), - Arg.pack_size()); - break; + auto *Param = TemplateParams->getParam(Builder.size() - 1); + // If this is a fully-saturated fixed-size pack, it should be + // fully-substituted, not partially-substituted. + Optional<unsigned> Expansions = getExpandedPackSize(Param); + if (!Expansions || Arg.pack_size() < *Expansions) { + PartiallySubstitutedPackIndex = Builder.size() - 1; + CurrentInstantiationScope->SetPartiallySubstitutedPack( + Param, Arg.pack_begin(), Arg.pack_size()); + } } } @@ -2959,13 +3132,13 @@ Sema::SubstituteExplicitTemplateArguments( // case, the empty template argument list <> itself may also be omitted. // // Take all of the explicitly-specified arguments and put them into - // the set of deduced template arguments. Explicitly-specified - // parameter packs, however, will be set to NULL since the deduction - // mechanisms handle explicitly-specified argument packs directly. + // the set of deduced template arguments. The partially-substituted + // parameter pack, however, will be set to NULL since the deduction + // mechanism handles the partially-substituted argument pack directly. Deduced.reserve(TemplateParams->size()); for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) { const TemplateArgument &Arg = ExplicitArgumentList->get(I); - if (Arg.getKind() == TemplateArgument::Pack) + if (I == PartiallySubstitutedPackIndex) Deduced.push_back(DeducedTemplateArgument()); else Deduced.push_back(Arg); @@ -2974,7 +3147,7 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } -/// \brief Check whether the deduced argument type for a call to a function +/// Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. static Sema::TemplateDeductionResult CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, @@ -3084,7 +3257,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, return Sema::TDK_Success; if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && - S.IsDerivedFrom(SourceLocation(), A, DeducedA)) + S.IsDerivedFrom(Info.getLocation(), A, DeducedA)) return Sema::TDK_Success; return Failed(); @@ -3120,7 +3293,7 @@ static unsigned getPackIndexForParam(Sema &S, llvm_unreachable("parameter index would not be produced from template"); } -/// \brief Finish template argument deduction for a function template, +/// Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. /// @@ -3271,13 +3444,14 @@ static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, // We may need to deduce the return type of the function now. if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() && S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false)) - return QualType(); + return {}; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't // look like a member pointer is just invalid. - if (!R.HasFormOfMemberPointer) return QualType(); + if (!R.HasFormOfMemberPointer) + return {}; return S.Context.getMemberPointerType(Fn->getType(), S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); @@ -3326,7 +3500,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP)) return GetTypeOfFunction(S, R, Viable); - return QualType(); + return {}; } // Gather the explicit template arguments, if any. @@ -3343,7 +3517,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // function templates, the parameter is treated as a // non-deduced context. if (!Ovl->hasExplicitTemplateArgs()) - return QualType(); + return {}; // Otherwise, see if we can resolve a function type FunctionDecl *Specialization = nullptr; @@ -3383,14 +3557,15 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF); if (Result) continue; - if (!Match.isNull()) return QualType(); + if (!Match.isNull()) + return {}; Match = ArgType; } return Match; } -/// \brief Perform the adjustments to the parameter and argument types +/// Perform the adjustments to the parameter and argument types /// described in C++ [temp.deduct.call]. /// /// \returns true if the caller should not attempt to perform any template @@ -3497,7 +3672,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, bool DecomposedParam, unsigned ArgIdx, unsigned TDF); -/// \brief Attempt template argument deduction from an initializer list +/// Attempt template argument deduction from an initializer list /// deemed to be an argument in a function call. static Sema::TemplateDeductionResult DeduceFromInitializerList( Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType, @@ -3558,7 +3733,7 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( return Sema::TDK_Success; } -/// \brief Perform template argument deduction per [temp.deduct.call] for a +/// Perform template argument deduction per [temp.deduct.call] for a /// single parameter / argument pair. static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex, @@ -3591,7 +3766,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( ArgType, Info, Deduced, TDF); } -/// \brief Perform template argument deduction from a function call +/// Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// /// \param FunctionTemplate the function template for which we are performing @@ -3729,8 +3904,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // the length of the explicitly-specified pack if it's expanded by the // parameter pack and 0 otherwise, and we treat each deduction as a // non-deduced context. - if (ParamIdx + 1 == NumParamTypes) { - for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) { + if (ParamIdx + 1 == NumParamTypes || PackScope.hasFixedArity()) { + for (; ArgIdx < Args.size() && PackScope.hasNextElement(); + PackScope.nextPackElement(), ++ArgIdx) { ParamTypesForArgChecking.push_back(ParamPattern); if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx)) return Result; @@ -3757,10 +3933,16 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( return Result; } + // Capture the context in which the function call is made. This is the context + // that is needed when the accessibility of template arguments is checked. + DeclContext *CallingCtx = CurContext; + return FinishTemplateArgumentDeduction( FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - &OriginalCallArgs, PartialOverloading, - [&]() { return CheckNonDependent(ParamTypesForArgChecking); }); + &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() { + ContextRAII SavedContext(*this, CallingCtx); + return CheckNonDependent(ParamTypesForArgChecking); + }); } QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, @@ -3802,7 +3984,7 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, ArgFunctionTypeP->getParamTypes(), EPI); } -/// \brief Deduce template arguments when taking the address of a function +/// Deduce template arguments when taking the address of a function /// template (C++ [temp.deduct.funcaddr]) or matching a specialization to /// a template. /// @@ -3944,7 +4126,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( return TDK_Success; } -/// \brief Deduce template arguments for a templated conversion +/// Deduce template arguments for a templated conversion /// function (C++ [temp.deduct.conv]) and, if successful, produce a /// conversion function template specialization. Sema::TemplateDeductionResult @@ -3973,12 +4155,20 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // C++0x [temp.deduct.conv]p4: // [...] If A is a reference type, the type referred to by A is used // for type deduction. - if (const ReferenceType *ARef = A->getAs<ReferenceType>()) - A = ARef->getPointeeType().getUnqualifiedType(); + if (const ReferenceType *ARef = A->getAs<ReferenceType>()) { + A = ARef->getPointeeType(); + // We work around a defect in the standard here: cv-qualifiers are also + // removed from P and A in this case, unless P was a reference type. This + // seems to mostly match what other compilers are doing. + if (!FromType->getAs<ReferenceType>()) { + A = A.getUnqualifiedType(); + P = P.getUnqualifiedType(); + } + // C++ [temp.deduct.conv]p3: // // If A is not a reference type: - else { + } else { assert(!A->isReferenceType() && "Reference types were handled above"); // - If P is an array type, the pointer type produced by the @@ -4027,7 +4217,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // cv-qualified than the deduced A (i.e., the type referred to // by the reference) if (ToType->isReferenceType()) - TDF |= TDF_ParamWithReferenceType; + TDF |= TDF_ArgWithReferenceType; // - The deduced A can be another pointer or pointer to member // type that can be converted to A via a qualification // conversion. @@ -4054,7 +4244,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, return Result; } -/// \brief Deduce template arguments for a function template when there is +/// Deduce template arguments for a function template when there is /// nothing to deduce against (C++0x [temp.arg.explicit]p3). /// /// \param FunctionTemplate the function template for which we are performing @@ -4089,12 +4279,14 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( } namespace { + /// Substitute the 'auto' specifier or deduced template specialization type /// specifier within a type for a given replacement type. class SubstituteDeducedTypeTransform : public TreeTransform<SubstituteDeducedTypeTransform> { QualType Replacement; bool UseTypeSugar; + public: SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement, bool UseTypeSugar = true) @@ -4156,7 +4348,8 @@ namespace { return TransformType(TLB, TL); } }; -} + +} // namespace Sema::DeduceAutoResult Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, @@ -4190,7 +4383,7 @@ static bool diagnoseAutoDeductionFailure(Sema &S, } } -/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) +/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// Note that this is done even if the initializer is dependent. (This is /// necessary to support partial ordering of templates using 'auto'.) @@ -4449,7 +4642,7 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, return StillUndeduced; } -/// \brief If this is a non-static member function, +/// If this is a non-static member function, static void AddImplicitObjectParameterType(ASTContext &Context, CXXMethodDecl *Method, @@ -4471,7 +4664,7 @@ AddImplicitObjectParameterType(ASTContext &Context, ArgTypes.push_back(ArgTy); } -/// \brief Determine whether the function template \p FT1 is at least as +/// Determine whether the function template \p FT1 is at least as /// specialized as \p FT2. static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, @@ -4622,7 +4815,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, return true; } -/// \brief Determine whether this a function template whose parameter-type-list +/// Determine whether this a function template whose parameter-type-list /// ends with a function parameter pack. static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { FunctionDecl *Function = FunTmpl->getTemplatedDecl(); @@ -4643,7 +4836,7 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { return true; } -/// \brief Returns the more specialized function template according +/// Returns the more specialized function template according /// to the rules of function template partial ordering (C++ [temp.func.order]). /// /// \param FT1 the first function template @@ -4690,7 +4883,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, return nullptr; } -/// \brief Determine if the two templates are equivalent. +/// Determine if the two templates are equivalent. static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { if (T1 == T2) return true; @@ -4701,7 +4894,7 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { return T1->getCanonicalDecl() == T2->getCanonicalDecl(); } -/// \brief Retrieve the most specialized of the given function template +/// Retrieve the most specialized of the given function template /// specializations. /// /// \param SpecBegin the start iterator of the function template @@ -4860,7 +5053,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, return true; } -/// \brief Returns the more specialized class template partial specialization +/// Returns the more specialized class template partial specialization /// according to the rules of partial ordering of class template partial /// specializations (C++ [temp.class.order]). /// @@ -5015,7 +5208,7 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info); } -/// \brief Mark the template parameters that are used by the given +/// Mark the template parameters that are used by the given /// expression. static void MarkUsedTemplateParameters(ASTContext &Ctx, @@ -5029,7 +5222,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, // Skip through any implicit casts we added while type-checking, and any // substitutions performed by template alias expansion. - while (1) { + while (true) { if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExpr(); else if (const SubstNonTypeTemplateParmExpr *Subst = @@ -5059,7 +5252,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); } -/// \brief Mark the template parameters that are used by the given +/// Mark the template parameters that are used by the given /// nested name specifier. static void MarkUsedTemplateParameters(ASTContext &Ctx, @@ -5076,7 +5269,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, OnlyDeduced, Depth, Used); } -/// \brief Mark the template parameters that are used by the given +/// Mark the template parameters that are used by the given /// template name. static void MarkUsedTemplateParameters(ASTContext &Ctx, @@ -5101,7 +5294,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, Depth, Used); } -/// \brief Mark the template parameters that are used by the given +/// Mark the template parameters that are used by the given /// type. static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, @@ -5172,6 +5365,14 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, OnlyDeduced, Depth, Used); break; + case Type::DependentVector: { + const auto *VecType = cast<DependentVectorType>(T); + MarkUsedTemplateParameters(Ctx, VecType->getElementType(), OnlyDeduced, + Depth, Used); + MarkUsedTemplateParameters(Ctx, VecType->getSizeExpr(), OnlyDeduced, Depth, + Used); + break; + } case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *VecType = cast<DependentSizedExtVectorType>(T); @@ -5197,9 +5398,24 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth, Used); - for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced, - Depth, Used); + for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I) { + // C++17 [temp.deduct.type]p5: + // The non-deduced contexts are: [...] + // -- A function parameter pack that does not occur at the end of the + // parameter-declaration-list. + if (!OnlyDeduced || I + 1 == N || + !Proto->getParamType(I)->getAs<PackExpansionType>()) { + MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced, + Depth, Used); + } else { + // FIXME: C++17 [temp.deduct.call]p1: + // When a function parameter pack appears in a non-deduced context, + // the type of that pack is never deduced. + // + // We should also track a set of "never deduced" parameters, and + // subtract that from the list of deduced parameters after marking. + } + } if (auto *E = Proto->getNoexceptExpr()) MarkUsedTemplateParameters(Ctx, E, OnlyDeduced, Depth, Used); break; @@ -5354,7 +5570,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, } } -/// \brief Mark the template parameters that are used by this +/// Mark the template parameters that are used by this /// template argument. static void MarkUsedTemplateParameters(ASTContext &Ctx, @@ -5397,7 +5613,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, } } -/// \brief Mark which template parameters can be deduced from a given +/// Mark which template parameters can be deduced from a given /// template argument list. /// /// \param TemplateArgs the template argument list from which template @@ -5423,7 +5639,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, Depth, Used); } -/// \brief Marks all of the template parameters that will be deduced by a +/// 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, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index a48e2466a84d..bc2ee42400b7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -18,13 +18,14 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/LangOptions.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" -#include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallback.h" using namespace clang; using namespace sema; @@ -33,7 +34,7 @@ using namespace sema; // Template Instantiation Support //===----------------------------------------------------------------------===/ -/// \brief Retrieve the template argument list(s) that should be used to +/// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// /// \param D the declaration for which we are computing template instantiation @@ -199,6 +200,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DeclaringSpecialMember: case DefiningSynthesizedFunction: return false; + + // This function should never be called when Kind's value is Memoization. + case Memoization: + break; } llvm_unreachable("Invalid SynthesisKind!"); @@ -235,6 +240,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( !SemaRef.InstantiatingSpecializations .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) .second; + atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, Inst); } } @@ -394,8 +400,10 @@ void Sema::InstantiatingTemplate::Clear() { std::make_pair(Active.Entity, Active.Kind)); } - SemaRef.popCodeSynthesisContext(); + atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, + SemaRef.CodeSynthesisContexts.back()); + SemaRef.popCodeSynthesisContext(); Invalid = true; } } @@ -419,7 +427,7 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( return true; } -/// \brief Prints the current instantiation stack through a series of +/// Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { // Determine which template instantiations to skip, if any. @@ -626,7 +634,7 @@ void Sema::PrintInstantiationStack() { << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; break; - case CodeSynthesisContext::DefiningSynthesizedFunction: + case CodeSynthesisContext::DefiningSynthesizedFunction: { // FIXME: For synthesized members other than special members, produce a note. auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity); auto CSM = MD ? getSpecialMember(MD) : CXXInvalid; @@ -637,6 +645,10 @@ void Sema::PrintInstantiationStack() { } break; } + + case CodeSynthesisContext::Memoization: + break; + } } } @@ -682,6 +694,9 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; + + case CodeSynthesisContext::Memoization: + break; } // The inner context was transparent for SFINAE. If it occurred within a @@ -693,19 +708,6 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { return None; } -/// \brief Retrieve the depth and index of a parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(NamedDecl *ND) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - //===----------------------------------------------------------------------===/ // Template Instantiation for Types //===----------------------------------------------------------------------===/ @@ -725,20 +727,20 @@ namespace { : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), Entity(Entity) { } - /// \brief Determine whether the given type \p T has already been + /// Determine whether the given type \p T has already been /// transformed. /// /// For the purposes of template instantiation, a type has already been /// transformed if it is NULL or if it is not dependent. bool AlreadyTransformed(QualType T); - /// \brief Returns the location of the entity being instantiated, if known. + /// Returns the location of the entity being instantiated, if known. SourceLocation getBaseLocation() { return Loc; } - /// \brief Returns the name of the entity being instantiated, if any. + /// Returns the name of the entity being instantiated, if any. DeclarationName getBaseEntity() { return Entity; } - /// \brief Sets the "base" location and entity when that + /// Sets the "base" location and entity when that /// information is known based on another transformation. void setBase(SourceLocation Loc, DeclarationName Entity) { this->Loc = Loc; @@ -793,7 +795,7 @@ namespace { } } - /// \brief Transform the given declaration by instantiating a reference to + /// Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(SourceLocation Loc, Decl *D); @@ -824,15 +826,15 @@ namespace { SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } - /// \brief Transform the definition of the given declaration by + /// Transform the definition of the given declaration by /// instantiating it. Decl *TransformDefinition(SourceLocation Loc, Decl *D); - /// \brief Transform the first qualifier within a scope by instantiating the + /// Transform the first qualifier within a scope by instantiating the /// declaration. NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc); - /// \brief Rebuild the exception declaration and register the declaration + /// Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, @@ -840,12 +842,12 @@ namespace { SourceLocation NameLoc, IdentifierInfo *Name); - /// \brief Rebuild the Objective-C exception declaration and register the + /// Rebuild the Objective-C exception declaration and register the /// declaration as an instantiated local. VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *TSInfo, QualType T); - /// \brief Check for tag mismatches when instantiating an + /// Check for tag mismatches when instantiating an /// elaborated type. QualType RebuildElaboratedType(SourceLocation KeywordLoc, ElaboratedTypeKeyword Keyword, @@ -870,14 +872,14 @@ namespace { ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); - /// \brief Rebuild a DeclRefExpr for a ParmVarDecl reference. + /// Rebuild a DeclRefExpr for a ParmVarDecl reference. ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc); - /// \brief Transform a reference to a function parameter pack. + /// Transform a reference to a function parameter pack. ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, ParmVarDecl *PD); - /// \brief Transform a FunctionParmPackExpr which was built when we couldn't + /// Transform a FunctionParmPackExpr which was built when we couldn't /// expand a function parameter pack reference which refers to an expanded /// pack. ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); @@ -900,12 +902,12 @@ namespace { Optional<unsigned> NumExpansions, bool ExpectParameterPack); - /// \brief Transforms a template type parameter type by performing + /// Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL); - /// \brief Transforms an already-substituted template type parameter pack + /// Transforms an already-substituted template type parameter pack /// into either itself (if we aren't substituting into its pack expansion) /// or the appropriate substituted argument. QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, @@ -1197,11 +1199,11 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, NTTP->getDeclName()); if (TargetType.isNull()) return ExprError(); - - return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr(TargetType, - NTTP, - E->getLocation(), - Arg); + + return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr( + TargetType.getNonLValueExprType(SemaRef.Context), + TargetType->isReferenceType() ? VK_LValue : VK_RValue, NTTP, + E->getLocation(), Arg); } Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); @@ -1246,7 +1248,7 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( arg.getKind() == TemplateArgument::NullPtr) { ValueDecl *VD; if (arg.getKind() == TemplateArgument::Declaration) { - VD = cast<ValueDecl>(arg.getAsDecl()); + VD = arg.getAsDecl(); // Find the instantiation of the template argument. This is // required for nested templates. @@ -1525,7 +1527,7 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType( return Result; } -/// \brief Perform substitution on the type T with a given set of template +/// Perform substitution on the type T with a given set of template /// arguments. /// /// This routine substitutes the given template arguments into the @@ -1820,7 +1822,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, return NewParm; } -/// \brief Substitute the given template arguments into the given set of +/// Substitute the given template arguments into the given set of /// parameters, producing the set of parameter types that would be generated /// from such a substitution. bool Sema::SubstParmTypes( @@ -1840,7 +1842,7 @@ bool Sema::SubstParmTypes( Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } -/// \brief Perform substitution on the base class specifiers of the +/// Perform substitution on the base class specifiers of the /// given class template specialization. /// /// Produces a diagnostic and returns true on error, returns false and @@ -1960,7 +1962,7 @@ namespace clang { } } -/// \brief Instantiate the definition of a class from a given pattern. +/// Instantiate the definition of a class from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the /// source code. @@ -1996,7 +1998,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return true; Pattern = PatternDef; - // \brief Record the point of instantiation. + // Record the point of instantiation. if (MemberSpecializationInfo *MSInfo = Instantiation->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); @@ -2011,7 +2013,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (Inst.isInvalid()) return true; assert(!Inst.isAlreadyInstantiating() && "should have been caught by caller"); - PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating class definition"); // Enter the scope of this instantiation. We don't use @@ -2068,6 +2070,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (Member->getDeclContext() != Pattern) continue; + // BlockDecls can appear in a default-member-initializer. They must be the + // child of a BlockExpr, so we only know how to instantiate them from there. + if (isa<BlockDecl>(Member)) + continue; + if (Member->isInvalidDecl()) { Instantiation->setInvalidDecl(); continue; @@ -2110,7 +2117,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, - SourceLocation(), SourceLocation(), nullptr); + SourceLocation(), SourceLocation(), ParsedAttributesView()); CheckCompletedCXXClass(Instantiation); // Default arguments are parsed, if not instantiated. We can go instantiate @@ -2196,7 +2203,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, return Instantiation->isInvalidDecl(); } -/// \brief Instantiate the definition of an enum from a given pattern. +/// Instantiate the definition of an enum from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the /// source code. @@ -2234,7 +2241,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, return true; if (Inst.isAlreadyInstantiating()) return false; - PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating enum definition"); // The instantiation is visible here, even if it was first declared in an @@ -2262,7 +2269,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, } -/// \brief Instantiate the definition of a field from the given pattern. +/// Instantiate the definition of a field from the given pattern. /// /// \param PointOfInstantiation The point of instantiation within the /// source code. @@ -2310,7 +2317,7 @@ bool Sema::InstantiateInClassInitializer( << Instantiation; return true; } - PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating default member init"); // Enter the scope of this instantiation. We don't use PushDeclContext because @@ -2340,7 +2347,7 @@ bool Sema::InstantiateInClassInitializer( } namespace { - /// \brief A partial specialization whose template arguments have matched + /// A partial specialization whose template arguments have matched /// a given template-id. struct PartialSpecMatchResult { ClassTemplatePartialSpecializationDecl *Partial; @@ -2379,127 +2386,137 @@ getPatternForClassTemplateSpecialization( if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) return nullptr; - ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - CXXRecordDecl *Pattern = nullptr; - - // C++ [temp.class.spec.match]p1: - // When a class template is used in a context that requires an - // instantiation of the class, it is necessary to determine - // whether the instantiation is to be generated using the primary - // template or one of the partial specializations. This is done by - // matching the template arguments of the class template - // specialization with the template argument lists of the partial - // specializations. - typedef PartialSpecMatchResult MatchResult; - SmallVector<MatchResult, 4> Matched; - SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; - Template->getPartialSpecializations(PartialSpecs); - TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); - for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { - ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( - Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { - // Store the failed-deduction information for use in diagnostics, later. - // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate().set( - DeclAccessPair::make(Template, AS_public), Partial, - MakeDeductionFailureInfo(S.Context, Result, Info)); - (void)Result; - } else { - Matched.push_back(PartialSpecMatchResult()); - Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); + if (!Specialized.is<ClassTemplatePartialSpecializationDecl *>()) { + // Find best matching specialization. + ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); + + // C++ [temp.class.spec.match]p1: + // When a class template is used in a context that requires an + // instantiation of the class, it is necessary to determine + // whether the instantiation is to be generated using the primary + // template or one of the partial specializations. This is done by + // matching the template arguments of the class template + // specialization with the template argument lists of the partial + // specializations. + typedef PartialSpecMatchResult MatchResult; + SmallVector<MatchResult, 4> Matched; + SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + Template->getPartialSpecializations(PartialSpecs); + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); + if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( + Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { + // Store the failed-deduction information for use in diagnostics, later. + // TODO: Actually use the failed-deduction info? + FailedCandidates.addCandidate().set( + DeclAccessPair::make(Template, AS_public), Partial, + MakeDeductionFailureInfo(S.Context, Result, Info)); + (void)Result; + } else { + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.take(); + } } - } - // If we're dealing with a member template where the template parameters - // have been instantiated, this provides the original template parameters - // from which the member template's parameters were instantiated. + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. - if (Matched.size() >= 1) { - SmallVectorImpl<MatchResult>::iterator Best = Matched.begin(); - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - // We don't need to do anything for this. - } else { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the class template is - // ambiguous and the program is ill-formed. - for (SmallVectorImpl<MatchResult>::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (S.getMoreSpecializedPartialSpecialization( - P->Partial, Best->Partial, PointOfInstantiation) == P->Partial) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - bool Ambiguous = false; - for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && - S.getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, - PointOfInstantiation) != - Best->Partial) { - Ambiguous = true; - break; + if (Matched.size() >= 1) { + SmallVectorImpl<MatchResult>::iterator Best = Matched.begin(); + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the class template is + // ambiguous and the program is ill-formed. + for (SmallVectorImpl<MatchResult>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (S.getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, PointOfInstantiation) == + P->Partial) + Best = P; } - } - - if (Ambiguous) { - // Partial ordering did not produce a clear winner. Complain. - Inst.Clear(); - ClassTemplateSpec->setInvalidDecl(); - S.Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) - << ClassTemplateSpec; - - // Print the matching partial specializations. + + // Determine if the best partial specialization is more specialized than + // the others. + bool Ambiguous = false; for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(), PEnd = Matched.end(); - P != PEnd; ++P) - S.Diag(P->Partial->getLocation(), diag::note_partial_spec_match) - << S.getTemplateArgumentBindingsText( - P->Partial->getTemplateParameters(), *P->Args); + P != PEnd; ++P) { + if (P != Best && S.getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, + PointOfInstantiation) != Best->Partial) { + Ambiguous = true; + break; + } + } + + if (Ambiguous) { + // Partial ordering did not produce a clear winner. Complain. + Inst.Clear(); + ClassTemplateSpec->setInvalidDecl(); + S.Diag(PointOfInstantiation, + diag::err_partial_spec_ordering_ambiguous) + << ClassTemplateSpec; + + // Print the matching partial specializations. + for (SmallVectorImpl<MatchResult>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + S.Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << S.getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), *P->Args); - return nullptr; + return nullptr; + } } + + ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); + } else { + // -- If no matches are found, the instantiation is generated + // from the primary template. } - + } + + CXXRecordDecl *Pattern = nullptr; + Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); + if (auto *PartialSpec = + Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { // Instantiate using the best class template partial specialization. - ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->Partial; - while (OrigPartialSpec->getInstantiatedFromMember()) { + while (PartialSpec->getInstantiatedFromMember()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. - if (OrigPartialSpec->isMemberSpecialization()) + if (PartialSpec->isMemberSpecialization()) break; - - OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember(); + + PartialSpec = PartialSpec->getInstantiatedFromMember(); } - - Pattern = OrigPartialSpec; - ClassTemplateSpec->setInstantiationOf(Best->Partial, Best->Args); + Pattern = PartialSpec; } else { - // -- If no matches are found, the instantiation is generated - // from the primary template. - ClassTemplateDecl *OrigTemplate = Template; - while (OrigTemplate->getInstantiatedFromMemberTemplate()) { + ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); + while (Template->getInstantiatedFromMemberTemplate()) { // If we've found an explicit specialization of this class template, // stop here and use that as the pattern. - if (OrigTemplate->isMemberSpecialization()) + if (Template->isMemberSpecialization()) break; - - OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate(); + + Template = Template->getInstantiatedFromMemberTemplate(); } - - Pattern = OrigTemplate->getTemplatedDecl(); + Pattern = Template->getTemplatedDecl(); } return Pattern; @@ -2525,7 +2542,7 @@ bool Sema::InstantiateClassTemplateSpecialization( Complain); } -/// \brief Instantiates the definitions of all of the member +/// Instantiates the definitions of all of the member /// of the given class, which is an instantiation of a class template /// or a member class of a template. void @@ -2732,7 +2749,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, } } -/// \brief Instantiate the definitions of all of the members of the +/// Instantiate the definitions of all of the members of the /// given class template specialization, which was named as part of an /// explicit instantiation. void @@ -2808,7 +2825,7 @@ Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, return Instantiator.TransformNestedNameSpecifierLoc(NNS); } -/// \brief Do template substitution on declaration name info. +/// Do template substitution on declaration name info. DeclarationNameInfo Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9163fbc6f7e8..5109dc8290f9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -18,11 +18,12 @@ #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/TypeLoc.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" -#include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallback.h" using namespace clang; @@ -175,7 +176,8 @@ static void instantiateDependentAllocAlignAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const AllocAlignAttr *Align, Decl *New) { Expr *Param = IntegerLiteral::Create( - S.getASTContext(), llvm::APInt(64, Align->getParamIndex()), + S.getASTContext(), + llvm::APInt(64, Align->getParamIndex().getSourceIndex()), S.getASTContext().UnsignedLongLongTy, Align->getLocation()); S.AddAllocAlignAttr(Align->getLocation(), New, Param, Align->getSpellingListIndex()); @@ -343,14 +345,6 @@ static void instantiateOMPDeclareSimdDeclAttr( Attr.getRange()); } -static bool DeclContainsAttr(const Decl *D, const Attr *NewAttr) { - if (!D->hasAttrs() || NewAttr->duplicatesAllowed()) - return false; - return llvm::find_if(D->getAttrs(), [NewAttr](const Attr *Attr) { - return Attr->getKind() == NewAttr->getKind(); - }) != D->getAttrs().end(); -} - void Sema::InstantiateAttrsForDecl( const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -365,7 +359,7 @@ void Sema::InstantiateAttrsForDecl( Attr *NewAttr = sema::instantiateTemplateAttributeForDecl( TmplAttr, Context, *this, TemplateArgs); - if (NewAttr && !DeclContainsAttr(New, NewAttr)) + if (NewAttr) New->addAttr(NewAttr); } } @@ -470,8 +464,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs); - - if (NewAttr && !DeclContainsAttr(New, NewAttr)) + if (NewAttr) New->addAttr(NewAttr); } } @@ -749,7 +742,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (D->isNRVOVariable()) { QualType ReturnType = cast<FunctionDecl>(DC)->getReturnType(); - if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false)) + if (SemaRef.isCopyElisionCandidate(ReturnType, Var, Sema::CES_Strict)) Var->setNRVOVariable(true); } @@ -1049,8 +1042,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { SemaRef.SubstType(TI->getType(), TemplateArgs, UnderlyingLoc, DeclarationName()); SemaRef.CheckEnumRedeclaration(Def->getLocation(), Def->isScoped(), - DefnUnderlying, - /*EnumUnderlyingIsImplicit=*/false, Enum); + DefnUnderlying, /*IsFixed=*/true, Enum); } } @@ -1126,8 +1118,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( } SemaRef.ActOnEnumBody(Enum->getLocation(), Enum->getBraceRange(), Enum, - Enumerators, - nullptr, nullptr); + Enumerators, nullptr, ParsedAttributesView()); } Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { @@ -1564,7 +1555,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { return Record; } -/// \brief Adjust the given function type for an instantiation of the +/// Adjust the given function type for an instantiation of the /// given declaration, to cope with modifications to the function's type that /// aren't reflected in the type-source information. /// @@ -1661,6 +1652,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, NameInfo, T, TInfo, D->getSourceRange().getEnd()); if (DGuide->isCopyDeductionCandidate()) cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate(); + Function->setAccess(D->getAccess()); } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, @@ -1815,45 +1807,24 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // apply to non-template function declarations and definitions also apply // to these implicit definitions. if (D->isThisDeclarationADefinition()) { - // Check for a function body. - const FunctionDecl *Definition = nullptr; - if (Function->isDefined(Definition) && - Definition->getTemplateSpecializationKind() == TSK_Undeclared) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) - << Function->getDeclName(); - SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition); - } - // Check for redefinitions due to other instantiations of this or - // a similar friend function. - else for (auto R : Function->redecls()) { - if (R == Function) - continue; - - // If some prior declaration of this function has been used, we need - // to instantiate its definition. - if (!QueuedInstantiation && R->isUsed(false)) { - if (MemberSpecializationInfo *MSInfo = - Function->getMemberSpecializationInfo()) { - if (MSInfo->getPointOfInstantiation().isInvalid()) { - SourceLocation Loc = R->getLocation(); // FIXME - MSInfo->setPointOfInstantiation(Loc); - SemaRef.PendingLocalImplicitInstantiations.push_back( - std::make_pair(Function, Loc)); - QueuedInstantiation = true; - } - } - } - - // If some prior declaration of this function was a friend with an - // uninstantiated definition, reject it. - if (R->getFriendObjectKind()) { - if (const FunctionDecl *RPattern = - R->getTemplateInstantiationPattern()) { - if (RPattern->isDefined(RPattern)) { - SemaRef.Diag(Function->getLocation(), diag::err_redefinition) - << Function->getDeclName(); - SemaRef.Diag(R->getLocation(), diag::note_previous_definition); - break; + SemaRef.CheckForFunctionRedefinition(Function); + if (!Function->isInvalidDecl()) { + for (auto R : Function->redecls()) { + if (R == Function) + continue; + + // If some prior declaration of this function has been used, we need + // to instantiate its definition. + if (!QueuedInstantiation && R->isUsed(false)) { + if (MemberSpecializationInfo *MSInfo = + Function->getMemberSpecializationInfo()) { + if (MSInfo->getPointOfInstantiation().isInvalid()) { + SourceLocation Loc = R->getLocation(); // FIXME + MSInfo->setPointOfInstantiation(Loc); + SemaRef.PendingLocalImplicitInstantiations.push_back( + std::make_pair(Function, Loc)); + QueuedInstantiation = true; + } } } } @@ -2676,7 +2647,8 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl( NamedDecl *UD = SemaRef.BuildUsingDeclaration( /*Scope*/ nullptr, D->getAccess(), D->getUsingLoc(), - /*HasTypename*/ TD, TypenameLoc, SS, NameInfo, EllipsisLoc, nullptr, + /*HasTypename*/ TD, TypenameLoc, SS, NameInfo, EllipsisLoc, + ParsedAttributesView(), /*IsInstantiation*/ true); if (UD) SemaRef.Context.setInstantiatedFromUsingDecl(UD, D); @@ -2697,9 +2669,9 @@ Decl *TemplateDeclInstantiator::VisitUnresolvedUsingValueDecl( Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { SmallVector<NamedDecl*, 8> Expansions; for (auto *UD : D->expansions()) { - if (auto *NewUD = + if (NamedDecl *NewUD = SemaRef.FindInstantiatedDecl(D->getLocation(), UD, TemplateArgs)) - Expansions.push_back(cast<NamedDecl>(NewUD)); + Expansions.push_back(NewUD); else return nullptr; } @@ -2740,6 +2712,8 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( assert(Specialization && "Class scope Specialization is null"); SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); + // FIXME: If this is a definition, check for redefinition errors! + return NewFD; } @@ -2859,7 +2833,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { Decl * TemplateDeclInstantiator::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { - return VisitFunctionDecl(D, nullptr); + Decl *Inst = VisitFunctionDecl(D, nullptr); + if (Inst && !D->getDescribedFunctionTemplate()) + Owner->addDecl(Inst); + return Inst; } Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { @@ -3112,7 +3089,7 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, return Instantiator.Visit(D); } -/// \brief Instantiates a nested template parameter list in the current +/// Instantiates a nested template parameter list in the current /// instantiation context. /// /// \param L The parameter list to instantiate @@ -3148,7 +3125,14 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { return InstL; } -/// \brief Instantiate the declaration of a class template partial +TemplateParameterList * +Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); + return Instantiator.SubstTemplateParams(Params); +} + +/// Instantiate the declaration of a class template partial /// specialization. /// /// \param ClassTemplate the (instantiated) class template that is partially @@ -3282,7 +3266,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return InstPartialSpec; } -/// \brief Instantiate the declaration of a variable template partial +/// Instantiate the declaration of a variable template partial /// specialization. /// /// \param VarTemplate the (instantiated) variable template that is partially @@ -3624,7 +3608,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, TemplateArgs); } -/// \brief Initializes the common fields of an instantiation function +/// Initializes the common fields of an instantiation function /// declaration (New) from the corresponding fields of its template (Tmpl). /// /// \returns true if there was an error @@ -3657,8 +3641,10 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, assert(FunTmpl->getTemplatedDecl() == Tmpl && "Deduction from the wrong function template?"); (void) FunTmpl; + atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; + atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); } } @@ -3710,7 +3696,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, return false; } -/// \brief Initializes common fields of an instantiated method +/// Initializes common fields of an instantiated method /// declaration (New) from the corresponding fields of its template /// (Tmpl). /// @@ -3774,7 +3760,7 @@ static void InstantiateDefaultCtorDefaultArgs(Sema &S, } } -/// \brief Instantiate the definition of the given function from its +/// Instantiate the definition of the given function from its /// template. /// /// \param PointOfInstantiation the point at which the instantiation was @@ -3854,8 +3840,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { Function->setInstantiationIsPending(true); - PendingInstantiations.push_back( - std::make_pair(Function, PointOfInstantiation)); + LateParsedInstantiations.push_back( + std::make_pair(Function, PointOfInstantiation)); return; } @@ -3912,7 +3898,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) return; - PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Function, SourceLocation(), "instantiating function definition"); // The instantiation is visible here, even if it was first declared in an @@ -3957,8 +3943,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, TemplateArgs)) return; + StmtResult Body; if (PatternDecl->hasSkippedBody()) { ActOnSkippedFunctionBody(Function); + Body = nullptr; } else { if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Function)) { // If this is a constructor, instantiate the member initializers. @@ -3974,16 +3962,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } // Instantiate the function body. - StmtResult Body = SubstStmt(Pattern, TemplateArgs); + Body = SubstStmt(Pattern, TemplateArgs); if (Body.isInvalid()) Function->setInvalidDecl(); - - // FIXME: finishing the function body while in an expression evaluation - // context seems wrong. Investigate more. - ActOnFinishFunctionBody(Function, Body.get(), - /*IsInstantiation=*/true); } + // FIXME: finishing the function body while in an expression evaluation + // context seems wrong. Investigate more. + ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); PerformDependentDiagnostics(PatternDecl, TemplateArgs); @@ -4050,7 +4036,7 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( VarTemplate, FromVar, InsertPos, TemplateArgsInfo, Converted)); } -/// \brief Instantiates a variable template specialization by completing it +/// Instantiates a variable template specialization by completing it /// with appropriate type information and initializer. VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, @@ -4100,6 +4086,7 @@ void Sema::BuildVariableInstantiation( NewVar->setTSCSpec(OldVar->getTSCSpec()); NewVar->setInitStyle(OldVar->getInitStyle()); NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl()); + NewVar->setObjCForDecl(OldVar->isObjCForDecl()); NewVar->setConstexpr(OldVar->isConstexpr()); NewVar->setInitCapture(OldVar->isInitCapture()); NewVar->setPreviousDeclInSameBlockScope( @@ -4173,7 +4160,7 @@ void Sema::BuildVariableInstantiation( DiagnoseUnusedDecl(NewVar); } -/// \brief Instantiate the initializer of a variable. +/// Instantiate the initializer of a variable. void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -4219,7 +4206,9 @@ void Sema::InstantiateVariableInitializer( Var->setInvalidDecl(); } } else { - if (Var->isStaticDataMember()) { + // `inline` variables are a definition and declaration all in one; we won't + // pick up an initializer from anywhere else. + if (Var->isStaticDataMember() && !Var->isInline()) { if (!Var->isOutOfLine()) return; @@ -4230,14 +4219,17 @@ void Sema::InstantiateVariableInitializer( } // We'll add an initializer to a for-range declaration later. - if (Var->isCXXForRangeDecl()) + if (Var->isCXXForRangeDecl() || Var->isObjCForDecl()) return; ActOnUninitializedDecl(Var); } + + if (getLangOpts().CUDA) + checkAllowedCUDAInitializer(Var); } -/// \brief Instantiate the definition of the given variable from its +/// Instantiate the definition of the given variable from its /// template. /// /// \param PointOfInstantiation the point at which the instantiation was @@ -4321,7 +4313,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) return; - PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable initializer"); // The instantiation is visible here, even if it was first declared in an @@ -4434,7 +4426,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) return; - PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable definition"); // If we're performing recursive template instantiation, create our own @@ -4856,7 +4848,7 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx, return nullptr; } -/// \brief Finds the instantiation of the given declaration context +/// Finds the instantiation of the given declaration context /// within the current instantiation. /// /// \returns NULL if there was an error @@ -4868,7 +4860,7 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC, } else return DC; } -/// \brief Find the instantiation of the given declaration within the +/// Find the instantiation of the given declaration within the /// current instantiation. /// /// This routine is intended to be used when \p D is a declaration @@ -5181,7 +5173,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return D; } -/// \brief Performs template instantiation for all implicit template +/// Performs template instantiation for all implicit template /// instantiations we have seen until this point. void Sema::PerformPendingInstantiations(bool LocalOnly) { while (!PendingLocalImplicitInstantiations.empty() || @@ -5238,7 +5230,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { break; } - PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable definition"); bool DefinitionRequired = Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index d81837dad508..fc1641334273 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -26,21 +26,8 @@ using namespace clang; // Visitor that collects unexpanded parameter packs //---------------------------------------------------------------------------- -/// \brief Retrieve the depth and index of a parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(NamedDecl *ND) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - namespace { - /// \brief A class that collects unexpanded parameter packs. + /// A class that collects unexpanded parameter packs. class CollectUnexpandedParameterPacksVisitor : public RecursiveASTVisitor<CollectUnexpandedParameterPacksVisitor> { @@ -83,14 +70,14 @@ namespace { // Recording occurrences of (unexpanded) parameter packs. //------------------------------------------------------------------------ - /// \brief Record occurrences of template type parameter packs. + /// Record occurrences of template type parameter packs. bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { if (TL.getTypePtr()->isParameterPack()) addUnexpanded(TL.getTypePtr(), TL.getNameLoc()); return true; } - /// \brief Record occurrences of template type parameter packs + /// Record occurrences of template type parameter packs /// when we don't have proper source-location information for /// them. /// @@ -102,7 +89,7 @@ namespace { return true; } - /// \brief Record occurrences of function and non-type template + /// Record occurrences of function and non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { if (E->getDecl()->isParameterPack()) @@ -111,7 +98,7 @@ namespace { return true; } - /// \brief Record occurrences of template template parameter packs. + /// Record occurrences of template template parameter packs. bool TraverseTemplateName(TemplateName Template) { if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( Template.getAsTemplateDecl())) { @@ -122,7 +109,7 @@ namespace { return inherited::TraverseTemplateName(Template); } - /// \brief Suppress traversal into Objective-C container literal + /// Suppress traversal into Objective-C container literal /// elements that are pack expansions. bool TraverseObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { if (!E->containsUnexpandedParameterPack()) @@ -142,7 +129,7 @@ namespace { // Pruning the search for unexpanded parameter packs. //------------------------------------------------------------------------ - /// \brief Suppress traversal into statements and expressions that + /// Suppress traversal into statements and expressions that /// do not contain unexpanded parameter packs. bool TraverseStmt(Stmt *S) { Expr *E = dyn_cast_or_null<Expr>(S); @@ -152,7 +139,7 @@ namespace { return true; } - /// \brief Suppress traversal into types that do not contain + /// Suppress traversal into types that do not contain /// unexpanded parameter packs. bool TraverseType(QualType T) { if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda) @@ -161,7 +148,7 @@ namespace { return true; } - /// \brief Suppress traversal into types with location information + /// Suppress traversal into types with location information /// that do not contain unexpanded parameter packs. bool TraverseTypeLoc(TypeLoc TL) { if ((!TL.getType().isNull() && @@ -172,7 +159,7 @@ namespace { return true; } - /// \brief Suppress traversal of parameter packs. + /// Suppress traversal of parameter packs. bool TraverseDecl(Decl *D) { // A function parameter pack is a pack expansion, so cannot contain // an unexpanded parameter pack. Likewise for a template parameter @@ -183,7 +170,7 @@ namespace { return inherited::TraverseDecl(D); } - /// \brief Suppress traversal of pack-expanded attributes. + /// Suppress traversal of pack-expanded attributes. bool TraverseAttr(Attr *A) { if (A->isPackExpansion()) return true; @@ -191,7 +178,7 @@ namespace { return inherited::TraverseAttr(A); } - /// \brief Suppress traversal of pack expansion expressions and types. + /// Suppress traversal of pack expansion expressions and types. ///@{ bool TraversePackExpansionType(PackExpansionType *T) { return true; } bool TraversePackExpansionTypeLoc(PackExpansionTypeLoc TL) { return true; } @@ -200,7 +187,7 @@ namespace { ///@} - /// \brief Suppress traversal of using-declaration pack expansion. + /// Suppress traversal of using-declaration pack expansion. bool TraverseUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { if (D->isPackExpansion()) return true; @@ -208,7 +195,7 @@ namespace { return inherited::TraverseUnresolvedUsingValueDecl(D); } - /// \brief Suppress traversal of using-declaration pack expansion. + /// Suppress traversal of using-declaration pack expansion. bool TraverseUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { if (D->isPackExpansion()) return true; @@ -216,7 +203,7 @@ namespace { return inherited::TraverseUnresolvedUsingTypenameDecl(D); } - /// \brief Suppress traversal of template argument pack expansions. + /// Suppress traversal of template argument pack expansions. bool TraverseTemplateArgument(const TemplateArgument &Arg) { if (Arg.isPackExpansion()) return true; @@ -224,7 +211,7 @@ namespace { return inherited::TraverseTemplateArgument(Arg); } - /// \brief Suppress traversal of template argument pack expansions. + /// Suppress traversal of template argument pack expansions. bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) { if (ArgLoc.getArgument().isPackExpansion()) return true; @@ -232,7 +219,7 @@ namespace { return inherited::TraverseTemplateArgumentLoc(ArgLoc); } - /// \brief Suppress traversal of base specifier pack expansions. + /// Suppress traversal of base specifier pack expansions. bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &Base) { if (Base.isPackExpansion()) return true; @@ -240,7 +227,7 @@ namespace { return inherited::TraverseCXXBaseSpecifier(Base); } - /// \brief Suppress traversal of mem-initializer pack expansions. + /// Suppress traversal of mem-initializer pack expansions. bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { if (Init->isPackExpansion()) return true; @@ -248,7 +235,7 @@ namespace { return inherited::TraverseConstructorInitializer(Init); } - /// \brief Note whether we're traversing a lambda containing an unexpanded + /// Note whether we're traversing a lambda containing an unexpanded /// parameter pack. In this case, the unexpanded pack can occur anywhere, /// including all the places where we normally wouldn't look. Within a /// lambda, we don't propagate the 'contains unexpanded parameter pack' bit @@ -284,7 +271,7 @@ namespace { }; } -/// \brief Determine whether it's possible for an unexpanded parameter pack to +/// 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. @@ -298,7 +285,7 @@ bool Sema::isUnexpandedParameterPackPermitted() { return false; } -/// \brief Diagnose all of the unexpanded parameter packs in the given +/// Diagnose all of the unexpanded parameter packs in the given /// vector. bool Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, @@ -314,8 +301,18 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, // later. SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences; for (unsigned N = FunctionScopes.size(); N; --N) { - if (sema::LambdaScopeInfo *LSI = - dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) { + sema::FunctionScopeInfo *Func = FunctionScopes[N-1]; + // We do not permit pack expansion that would duplicate a statement + // expression, not even within a lambda. + // FIXME: We could probably support this for statement expressions that do + // not contain labels, and for pack expansions that expand both the stmt + // expr and the enclosing lambda. + if (std::any_of( + Func->CompoundScopes.begin(), Func->CompoundScopes.end(), + [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) + break; + + if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) { if (N == FunctionScopes.size()) { for (auto &Param : Unexpanded) { auto *PD = dyn_cast_or_null<ParmVarDecl>( @@ -636,7 +633,9 @@ bool Sema::CheckParameterPacksForExpansion( RetainExpansion = false; std::pair<IdentifierInfo *, SourceLocation> FirstPack; bool HaveFirstPack = false; - + Optional<unsigned> NumPartialExpansions; + SourceLocation PartiallySubstitutedPackLoc; + for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(), end = Unexpanded.end(); i != end; ++i) { @@ -701,8 +700,13 @@ bool Sema::CheckParameterPacksForExpansion( = CurrentInstantiationScope->getPartiallySubstitutedPack()){ unsigned PartialDepth, PartialIndex; std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); - if (PartialDepth == Depth && PartialIndex == Index) + if (PartialDepth == Depth && PartialIndex == Index) { RetainExpansion = true; + // We don't actually know the new pack size yet. + NumPartialExpansions = NewPackSize; + PartiallySubstitutedPackLoc = i->second; + continue; + } } } @@ -732,6 +736,28 @@ bool Sema::CheckParameterPacksForExpansion( } } + // If we're performing a partial expansion but we also have a full expansion, + // expand to the number of common arguments. For example, given: + // + // template<typename ...T> struct A { + // template<typename ...U> void f(pair<T, U>...); + // }; + // + // ... a call to 'A<int, int>().f<int>' should expand the pack once and + // retain an expansion. + if (NumPartialExpansions) { + if (NumExpansions && *NumExpansions < *NumPartialExpansions) { + NamedDecl *PartialPack = + CurrentInstantiationScope->getPartiallySubstitutedPack(); + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) + << PartialPack << *NumPartialExpansions << *NumExpansions + << SourceRange(PartiallySubstitutedPackLoc); + return true; + } + + NumExpansions = NumPartialExpansions; + } + return false; } @@ -812,6 +838,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_void: case TST_char: case TST_wchar: + case TST_char8: case TST_char16: case TST_char32: case TST_int: @@ -819,6 +846,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_half: case TST_float: case TST_double: + case TST_Accum: + case TST_Fract: case TST_Float16: case TST_float128: case TST_bool: @@ -871,14 +900,14 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { ->containsUnexpandedParameterPack()) return true; } - } else if (Chunk.Fun.getExceptionSpecType() == EST_ComputedNoexcept && + } else if (isComputedNoexcept(Chunk.Fun.getExceptionSpecType()) && Chunk.Fun.NoexceptExpr->containsUnexpandedParameterPack()) return true; if (Chunk.Fun.hasTrailingReturnType()) { QualType T = Chunk.Fun.getTrailingReturnType().get(); - if (!T.isNull() && T->containsUnexpandedParameterPack()) - return true; + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return true; } break; @@ -889,7 +918,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { break; } } - + return false; } @@ -906,7 +935,7 @@ class ParameterPackValidatorCCC : public CorrectionCandidateCallback { } -/// \brief Called when an expression computing the size of a parameter pack +/// Called when an expression computing the size of a parameter pack /// is parsed. /// /// \code @@ -951,12 +980,12 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; - + case LookupResult::Ambiguous: DiagnoseAmbiguousLookup(R); return ExprError(); } - + if (!ParameterPack || !ParameterPack->isParameterPack()) { Diag(NameLoc, diag::err_sizeof_pack_no_pack_name) << &Name; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index af060cf21b5f..ac04cecaf774 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -63,13 +64,17 @@ static bool isOmittedBlockReturnType(const Declarator &D) { /// diagnoseBadTypeAttribute - Diagnoses a type attribute which /// doesn't apply to the given type. -static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, +static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, QualType type) { TypeDiagSelector WhichType; bool useExpansionLoc = true; switch (attr.getKind()) { - case AttributeList::AT_ObjCGC: WhichType = TDS_Pointer; break; - case AttributeList::AT_ObjCOwnership: WhichType = TDS_ObjCObjOrBlock; break; + case ParsedAttr::AT_ObjCGC: + WhichType = TDS_Pointer; + break; + case ParsedAttr::AT_ObjCOwnership: + WhichType = TDS_ObjCObjOrBlock; + break; default: // Assume everything else was a function attribute. WhichType = TDS_Function; @@ -97,47 +102,48 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, // objc_gc applies to Objective-C pointers or, otherwise, to the // smallest available pointer type (i.e. 'void*' in 'void**'). -#define OBJC_POINTER_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_ObjCGC: \ - case AttributeList::AT_ObjCOwnership +#define OBJC_POINTER_TYPE_ATTRS_CASELIST \ + case ParsedAttr::AT_ObjCGC: \ + case ParsedAttr::AT_ObjCOwnership // Calling convention attributes. -#define CALLING_CONV_ATTRS_CASELIST \ - case AttributeList::AT_CDecl: \ - case AttributeList::AT_FastCall: \ - case AttributeList::AT_StdCall: \ - case AttributeList::AT_ThisCall: \ - case AttributeList::AT_RegCall: \ - case AttributeList::AT_Pascal: \ - case AttributeList::AT_SwiftCall: \ - case AttributeList::AT_VectorCall: \ - case AttributeList::AT_MSABI: \ - case AttributeList::AT_SysVABI: \ - case AttributeList::AT_Pcs: \ - case AttributeList::AT_IntelOclBicc: \ - case AttributeList::AT_PreserveMost: \ - case AttributeList::AT_PreserveAll +#define CALLING_CONV_ATTRS_CASELIST \ + case ParsedAttr::AT_CDecl: \ + case ParsedAttr::AT_FastCall: \ + case ParsedAttr::AT_StdCall: \ + case ParsedAttr::AT_ThisCall: \ + case ParsedAttr::AT_RegCall: \ + case ParsedAttr::AT_Pascal: \ + case ParsedAttr::AT_SwiftCall: \ + case ParsedAttr::AT_VectorCall: \ + case ParsedAttr::AT_MSABI: \ + case ParsedAttr::AT_SysVABI: \ + case ParsedAttr::AT_Pcs: \ + case ParsedAttr::AT_IntelOclBicc: \ + case ParsedAttr::AT_PreserveMost: \ + case ParsedAttr::AT_PreserveAll // Function type attributes. -#define FUNCTION_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_NSReturnsRetained: \ - case AttributeList::AT_NoReturn: \ - case AttributeList::AT_Regparm: \ - case AttributeList::AT_AnyX86NoCallerSavedRegisters: \ +#define FUNCTION_TYPE_ATTRS_CASELIST \ + case ParsedAttr::AT_NSReturnsRetained: \ + case ParsedAttr::AT_NoReturn: \ + case ParsedAttr::AT_Regparm: \ + case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \ + case ParsedAttr::AT_AnyX86NoCfCheck: \ CALLING_CONV_ATTRS_CASELIST // Microsoft-specific type qualifiers. -#define MS_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_Ptr32: \ - case AttributeList::AT_Ptr64: \ - case AttributeList::AT_SPtr: \ - case AttributeList::AT_UPtr +#define MS_TYPE_ATTRS_CASELIST \ + case ParsedAttr::AT_Ptr32: \ + case ParsedAttr::AT_Ptr64: \ + case ParsedAttr::AT_SPtr: \ + case ParsedAttr::AT_UPtr // Nullability qualifiers. -#define NULLABILITY_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_TypeNonNull: \ - case AttributeList::AT_TypeNullable: \ - case AttributeList::AT_TypeNullUnspecified +#define NULLABILITY_TYPE_ATTRS_CASELIST \ + case ParsedAttr::AT_TypeNonNull: \ + case ParsedAttr::AT_TypeNullable: \ + case ParsedAttr::AT_TypeNullUnspecified namespace { /// An object which stores processing state for the entire @@ -160,11 +166,11 @@ namespace { bool hasSavedAttrs; /// The original set of attributes on the DeclSpec. - SmallVector<AttributeList*, 2> savedAttrs; + SmallVector<ParsedAttr *, 2> savedAttrs; /// A list of attributes to diagnose the uselessness of when the /// processing is complete. - SmallVector<AttributeList*, 2> ignoredTypeAttrs; + SmallVector<ParsedAttr *, 2> ignoredTypeAttrs; public: TypeProcessingState(Sema &sema, Declarator &declarator) @@ -193,10 +199,10 @@ namespace { chunkIndex = idx; } - AttributeList *&getCurrentAttrListRef() const { + ParsedAttributesView &getCurrentAttributes() const { if (isProcessingDeclSpec()) - return getMutableDeclSpec().getAttributes().getListRef(); - return declarator.getTypeObject(chunkIndex).getAttrListRef(); + return getMutableDeclSpec().getAttributes(); + return declarator.getTypeObject(chunkIndex).getAttrs(); } /// Save the current set of attributes on the DeclSpec. @@ -205,16 +211,15 @@ namespace { if (hasSavedAttrs) return; DeclSpec &spec = getMutableDeclSpec(); - for (AttributeList *attr = spec.getAttributes().getList(); attr; - attr = attr->getNext()) - savedAttrs.push_back(attr); + for (ParsedAttr &AL : spec.getAttributes()) + savedAttrs.push_back(&AL); trivial &= savedAttrs.empty(); hasSavedAttrs = true; } /// Record that we had nowhere to put the given type attribute. /// We will diagnose such attributes later. - void addIgnoredTypeAttr(AttributeList &attr) { + void addIgnoredTypeAttr(ParsedAttr &attr) { ignoredTypeAttrs.push_back(&attr); } @@ -239,46 +244,18 @@ namespace { void restoreDeclSpecAttrs() { assert(hasSavedAttrs); - if (savedAttrs.empty()) { - getMutableDeclSpec().getAttributes().set(nullptr); - return; - } - - getMutableDeclSpec().getAttributes().set(savedAttrs[0]); - for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i) - savedAttrs[i]->setNext(savedAttrs[i+1]); - savedAttrs.back()->setNext(nullptr); + getMutableDeclSpec().getAttributes().clearListOnly(); + for (ParsedAttr *AL : savedAttrs) + getMutableDeclSpec().getAttributes().addAtStart(AL); } }; } // end anonymous namespace -static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) { - attr.setNext(head); - head = &attr; -} - -static void spliceAttrOutOfList(AttributeList &attr, AttributeList *&head) { - if (head == &attr) { - head = attr.getNext(); - return; - } - - AttributeList *cur = head; - while (true) { - assert(cur && cur->getNext() && "ran out of attrs?"); - if (cur->getNext() == &attr) { - cur->setNext(attr.getNext()); - return; - } - cur = cur->getNext(); - } -} - -static void moveAttrFromListToList(AttributeList &attr, - AttributeList *&fromList, - AttributeList *&toList) { - spliceAttrOutOfList(attr, fromList); - spliceAttrIntoList(attr, toList); +static void moveAttrFromListToList(ParsedAttr &attr, + ParsedAttributesView &fromList, + ParsedAttributesView &toList) { + fromList.remove(&attr); + toList.addAtStart(&attr); } /// The location of a type attribute. @@ -291,29 +268,26 @@ enum TypeAttrLocation { TAL_DeclName }; -static void processTypeAttrs(TypeProcessingState &state, - QualType &type, TypeAttrLocation TAL, - AttributeList *attrs); +static void processTypeAttrs(TypeProcessingState &state, QualType &type, + TypeAttrLocation TAL, ParsedAttributesView &attrs); -static bool handleFunctionTypeAttr(TypeProcessingState &state, - AttributeList &attr, +static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, QualType &type); static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state, - AttributeList &attr, - QualType &type); + ParsedAttr &attr, QualType &type); -static bool handleObjCGCTypeAttr(TypeProcessingState &state, - AttributeList &attr, QualType &type); +static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, + QualType &type); static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, - AttributeList &attr, QualType &type); + ParsedAttr &attr, QualType &type); static bool handleObjCPointerTypeAttr(TypeProcessingState &state, - AttributeList &attr, QualType &type) { - if (attr.getKind() == AttributeList::AT_ObjCGC) + ParsedAttr &attr, QualType &type) { + if (attr.getKind() == ParsedAttr::AT_ObjCGC) return handleObjCGCTypeAttr(state, attr, type); - assert(attr.getKind() == AttributeList::AT_ObjCOwnership); + assert(attr.getKind() == ParsedAttr::AT_ObjCOwnership); return handleObjCOwnershipTypeAttr(state, attr, type); } @@ -395,8 +369,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, /// didn't apply in whatever position it was written in, try to move /// it to a more appropriate position. static void distributeObjCPointerTypeAttr(TypeProcessingState &state, - AttributeList &attr, - QualType type) { + ParsedAttr &attr, QualType type) { Declarator &declarator = state.getDeclarator(); // Move it to the outermost normal or block pointer declarator. @@ -409,13 +382,13 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, // of a block. DeclaratorChunk *destChunk = nullptr; if (state.isProcessingDeclSpec() && - attr.getKind() == AttributeList::AT_ObjCOwnership) + attr.getKind() == ParsedAttr::AT_ObjCOwnership) destChunk = maybeMovePastReturnType(declarator, i - 1, /*onlyBlockPointers=*/true); if (!destChunk) destChunk = &chunk; - moveAttrFromListToList(attr, state.getCurrentAttrListRef(), - destChunk->getAttrListRef()); + moveAttrFromListToList(attr, state.getCurrentAttributes(), + destChunk->getAttrs()); return; } @@ -426,12 +399,12 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, // We may be starting at the return type of a block. case DeclaratorChunk::Function: if (state.isProcessingDeclSpec() && - attr.getKind() == AttributeList::AT_ObjCOwnership) { + attr.getKind() == ParsedAttr::AT_ObjCOwnership) { if (DeclaratorChunk *dest = maybeMovePastReturnType( declarator, i, /*onlyBlockPointers=*/true)) { - moveAttrFromListToList(attr, state.getCurrentAttrListRef(), - dest->getAttrListRef()); + moveAttrFromListToList(attr, state.getCurrentAttributes(), + dest->getAttrs()); return; } } @@ -451,10 +424,8 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, /// Distribute an objc_gc type attribute that was written on the /// declarator. -static void -distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, - AttributeList &attr, - QualType &declSpecType) { +static void distributeObjCPointerTypeAttrFromDeclarator( + TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // objc_gc goes on the innermost pointer to something that's not a @@ -491,8 +462,8 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, // attribute from being applied multiple times and gives // the source-location-filler something to work with. state.saveDeclSpecAttrs(); - moveAttrFromListToList(attr, declarator.getAttrListRef(), - declarator.getMutableDeclSpec().getAttributes().getListRef()); + moveAttrFromListToList(attr, declarator.getAttributes(), + declarator.getMutableDeclSpec().getAttributes()); return; } } @@ -500,13 +471,13 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, // Otherwise, if we found an appropriate chunk, splice the attribute // into it. if (innermost != -1U) { - moveAttrFromListToList(attr, declarator.getAttrListRef(), - declarator.getTypeObject(innermost).getAttrListRef()); + moveAttrFromListToList(attr, declarator.getAttributes(), + declarator.getTypeObject(innermost).getAttrs()); return; } // Otherwise, diagnose when we're done building the type. - spliceAttrOutOfList(attr, declarator.getAttrListRef()); + declarator.getAttributes().remove(&attr); state.addIgnoredTypeAttr(attr); } @@ -515,8 +486,7 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, /// that it didn't apply in whatever position it was written in, try /// to move it to a more appropriate position. static void distributeFunctionTypeAttr(TypeProcessingState &state, - AttributeList &attr, - QualType type) { + ParsedAttr &attr, QualType type) { Declarator &declarator = state.getDeclarator(); // Try to push the attribute from the return type of a function to @@ -525,8 +495,8 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state, DeclaratorChunk &chunk = declarator.getTypeObject(i-1); switch (chunk.Kind) { case DeclaratorChunk::Function: - moveAttrFromListToList(attr, state.getCurrentAttrListRef(), - chunk.getAttrListRef()); + moveAttrFromListToList(attr, state.getCurrentAttributes(), + chunk.getAttrs()); return; case DeclaratorChunk::Paren: @@ -546,11 +516,9 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state, /// Try to distribute a function type attribute to the innermost /// function chunk or type. Returns true if the attribute was /// distributed, false if no location was found. -static bool -distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, - AttributeList &attr, - AttributeList *&attrList, - QualType &declSpecType) { +static bool distributeFunctionTypeAttrToInnermost( + TypeProcessingState &state, ParsedAttr &attr, + ParsedAttributesView &attrList, QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // Put it on the innermost function chunk, if there is one. @@ -558,7 +526,7 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, DeclaratorChunk &chunk = declarator.getTypeObject(i); if (chunk.Kind != DeclaratorChunk::Function) continue; - moveAttrFromListToList(attr, attrList, chunk.getAttrListRef()); + moveAttrFromListToList(attr, attrList, chunk.getAttrs()); return true; } @@ -567,25 +535,23 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, /// A function type attribute was written in the decl spec. Try to /// apply it somewhere. -static void -distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, - AttributeList &attr, - QualType &declSpecType) { +static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, + ParsedAttr &attr, + QualType &declSpecType) { state.saveDeclSpecAttrs(); // C++11 attributes before the decl specifiers actually appertain to // the declarators. Move them straight there. We don't support the // 'put them wherever you like' semantics we allow for GNU attributes. if (attr.isCXX11Attribute()) { - moveAttrFromListToList(attr, state.getCurrentAttrListRef(), - state.getDeclarator().getAttrListRef()); + moveAttrFromListToList(attr, state.getCurrentAttributes(), + state.getDeclarator().getAttributes()); return; } // Try to distribute to the innermost. - if (distributeFunctionTypeAttrToInnermost(state, attr, - state.getCurrentAttrListRef(), - declSpecType)) + if (distributeFunctionTypeAttrToInnermost( + state, attr, state.getCurrentAttributes(), declSpecType)) return; // If that failed, diagnose the bad attribute when the declarator is @@ -595,25 +561,23 @@ distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, /// A function type attribute was written on the declarator. Try to /// apply it somewhere. -static void -distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, - AttributeList &attr, - QualType &declSpecType) { +static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, + ParsedAttr &attr, + QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // Try to distribute to the innermost. - if (distributeFunctionTypeAttrToInnermost(state, attr, - declarator.getAttrListRef(), - declSpecType)) + if (distributeFunctionTypeAttrToInnermost( + state, attr, declarator.getAttributes(), declSpecType)) return; // If that failed, diagnose the bad attribute when the declarator is // fully built. - spliceAttrOutOfList(attr, declarator.getAttrListRef()); + declarator.getAttributes().remove(&attr); state.addIgnoredTypeAttr(attr); } -/// \brief Given that there are attributes written on the declarator +/// Given that there are attributes written on the declarator /// itself, try to distribute any type attributes to the appropriate /// declarator chunk. /// @@ -625,24 +589,25 @@ distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, QualType &declSpecType) { // Collect all the type attributes from the declarator itself. - assert(state.getDeclarator().getAttributes() && "declarator has no attrs!"); - AttributeList *attr = state.getDeclarator().getAttributes(); - AttributeList *next; - do { - next = attr->getNext(); - + assert(!state.getDeclarator().getAttributes().empty() && + "declarator has no attrs!"); + // The called functions in this loop actually remove things from the current + // list, so iterating over the existing list isn't possible. Instead, make a + // non-owning copy and iterate over that. + ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()}; + for (ParsedAttr &attr : AttrsCopy) { // Do not distribute C++11 attributes. They have strict rules for what // they appertain to. - if (attr->isCXX11Attribute()) + if (attr.isCXX11Attribute()) continue; - switch (attr->getKind()) { + switch (attr.getKind()) { OBJC_POINTER_TYPE_ATTRS_CASELIST: - distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); + distributeObjCPointerTypeAttrFromDeclarator(state, attr, declSpecType); break; FUNCTION_TYPE_ATTRS_CASELIST: - distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); + distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType); break; MS_TYPE_ATTRS_CASELIST: @@ -653,13 +618,13 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, // Nullability specifiers cannot go after the declarator-id. // Objective-C __kindof does not get distributed. - case AttributeList::AT_ObjCKindOf: + case ParsedAttr::AT_ObjCKindOf: continue; default: break; } - } while ((attr = next)); + } } /// Add a synthetic '()' to a block-literal declarator if it is @@ -759,28 +724,18 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, return false; // Warn if we see type attributes for omitted return type on a block literal. - AttributeList *&attrs = - declarator.getMutableDeclSpec().getAttributes().getListRef(); - AttributeList *prev = nullptr; - for (AttributeList *cur = attrs; cur; cur = cur->getNext()) { - AttributeList &attr = *cur; - // Skip attributes that were marked to be invalid or non-type - // attributes. - if (attr.isInvalid() || !attr.isTypeAttr()) { - prev = cur; + SmallVector<ParsedAttr *, 2> ToBeRemoved; + for (ParsedAttr &AL : declarator.getMutableDeclSpec().getAttributes()) { + if (AL.isInvalid() || !AL.isTypeAttr()) continue; - } - S.Diag(attr.getLoc(), + S.Diag(AL.getLoc(), diag::warn_block_literal_attributes_on_omitted_return_type) - << attr.getName(); - // Remove cur from the list. - if (prev) { - prev->setNext(cur->getNext()); - prev = cur; - } else { - attrs = cur->getNext(); - } + << AL.getName(); + ToBeRemoved.push_back(&AL); } + // Remove bad attributes from the list. + for (ParsedAttr *AL : ToBeRemoved) + declarator.getMutableDeclSpec().getAttributes().remove(AL); // Warn if we see type qualifiers for omitted return type on a block literal. const DeclSpec &DS = declarator.getDeclSpec(); @@ -1208,22 +1163,15 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( return CreateParsedType(Result, ResultTInfo); } -static OpenCLAccessAttr::Spelling getImageAccess(const AttributeList *Attrs) { - if (Attrs) { - const AttributeList *Next = Attrs; - do { - const AttributeList &Attr = *Next; - Next = Attr.getNext(); - if (Attr.getKind() == AttributeList::AT_OpenCLAccess) { - return static_cast<OpenCLAccessAttr::Spelling>( - Attr.getSemanticSpelling()); - } - } while (Next); - } +static OpenCLAccessAttr::Spelling +getImageAccess(const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) + if (AL.getKind() == ParsedAttr::AT_OpenCLAccess) + return static_cast<OpenCLAccessAttr::Spelling>(AL.getSemanticSpelling()); return OpenCLAccessAttr::Keyword_read_only; } -/// \brief Convert the specified declspec to the appropriate type +/// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier /// to be converted, along with other associated processing state. @@ -1235,7 +1183,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Sema &S = state.getSema(); Declarator &declarator = state.getDeclarator(); - const DeclSpec &DS = declarator.getDeclSpec(); + DeclSpec &DS = declarator.getMutableDeclSpec(); SourceLocation DeclLoc = declarator.getIdentifierLoc(); if (DeclLoc.isInvalid()) DeclLoc = DS.getLocStart(); @@ -1275,6 +1223,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.getUnsignedWCharType(); } break; + case DeclSpec::TST_char8: + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && + "Unknown TSS value"); + Result = Context.Char8Ty; + break; case DeclSpec::TST_char16: assert(DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && "Unknown TSS value"); @@ -1384,6 +1337,52 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } + case DeclSpec::TST_accum: { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_short: + Result = Context.ShortAccumTy; + break; + case DeclSpec::TSW_unspecified: + Result = Context.AccumTy; + break; + case DeclSpec::TSW_long: + Result = Context.LongAccumTy; + break; + case DeclSpec::TSW_longlong: + llvm_unreachable("Unable to specify long long as _Accum width"); + } + + if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) + Result = Context.getCorrespondingUnsignedType(Result); + + if (DS.isTypeSpecSat()) + Result = Context.getCorrespondingSaturatedType(Result); + + break; + } + case DeclSpec::TST_fract: { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_short: + Result = Context.ShortFractTy; + break; + case DeclSpec::TSW_unspecified: + Result = Context.FractTy; + break; + case DeclSpec::TSW_long: + Result = Context.LongFractTy; + break; + case DeclSpec::TSW_longlong: + llvm_unreachable("Unable to specify long long as _Fract width"); + } + + if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) + Result = Context.getCorrespondingUnsignedType(Result); + + if (DS.isTypeSpecSat()) + Result = Context.getCorrespondingSaturatedType(Result); + + break; + } case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type()) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) @@ -1422,7 +1421,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_union: case DeclSpec::TST_struct: case DeclSpec::TST_interface: { - TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl()); + TagDecl *D = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; @@ -1442,7 +1441,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); + Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result, + DS.isTypeSpecOwned() ? D : nullptr); break; } case DeclSpec::TST_typename: { @@ -1528,16 +1528,19 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; -#define GENERIC_IMAGE_TYPE(ImgType, Id) \ - case DeclSpec::TST_##ImgType##_t: \ - switch (getImageAccess(DS.getAttributes().getList())) { \ - case OpenCLAccessAttr::Keyword_write_only: \ - Result = Context.Id##WOTy; break; \ - case OpenCLAccessAttr::Keyword_read_write: \ - Result = Context.Id##RWTy; break; \ - case OpenCLAccessAttr::Keyword_read_only: \ - Result = Context.Id##ROTy; break; \ - } \ +#define GENERIC_IMAGE_TYPE(ImgType, Id) \ + case DeclSpec::TST_##ImgType##_t: \ + switch (getImageAccess(DS.getAttributes())) { \ + case OpenCLAccessAttr::Keyword_write_only: \ + Result = Context.Id##WOTy; \ + break; \ + case OpenCLAccessAttr::Keyword_read_write: \ + Result = Context.Id##RWTy; \ + break; \ + case OpenCLAccessAttr::Keyword_read_only: \ + Result = Context.Id##ROTy; \ + break; \ + } \ break; #include "clang/Basic/OpenCLImageTypes.def" @@ -1551,6 +1554,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) declarator.setInvalidType(true); + bool IsFixedPointType = DS.getTypeSpecType() == DeclSpec::TST_accum || + DS.getTypeSpecType() == DeclSpec::TST_fract; + + // Only fixed point types can be saturated + if (DS.isTypeSpecSat() && !IsFixedPointType) + S.Diag(DS.getTypeSpecSatLoc(), diag::err_invalid_saturation_spec) + << DS.getSpecifierName(DS.getTypeSpecType(), + Context.getPrintingPolicy()); + // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (S.getLangOpts().Freestanding) @@ -1581,7 +1593,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // attributes are pushed around. // pipe attributes will be handled later ( at GetFullTypeForDeclarator ) if (!DS.isTypeSpecPipe()) - processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList()); + processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes()); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -1748,7 +1760,7 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, return BuildQualifiedType(T, Loc, Q, DS); } -/// \brief Build a paren type including \p T. +/// Build a paren type including \p T. QualType Sema::BuildParenType(QualType T) { return Context.getParenType(T); } @@ -1858,7 +1870,7 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, return true; } -/// \brief Build a pointer type. +/// Build a pointer type. /// /// \param T The type to which we'll be building a pointer. /// @@ -1898,7 +1910,7 @@ QualType Sema::BuildPointerType(QualType T, return Context.getPointerType(T); } -/// \brief Build a reference type. +/// Build a reference type. /// /// \param T The type to which we'll be building a reference. /// @@ -1960,7 +1972,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return Context.getRValueReferenceType(T); } -/// \brief Build a Read-only Pipe type. +/// Build a Read-only Pipe type. /// /// \param T The type to which we'll be building a Pipe. /// @@ -1972,7 +1984,7 @@ QualType Sema::BuildReadPipeType(QualType T, SourceLocation Loc) { return Context.getReadPipeType(T); } -/// \brief Build a Write-only Pipe type. +/// Build a Write-only Pipe type. /// /// \param T The type to which we'll be building a Pipe. /// @@ -2006,7 +2018,7 @@ static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { S.LangOpts.OpenCL).isInvalid(); } -/// \brief Build an array type. +/// Build an array type. /// /// \param T The type of each element in the array. /// @@ -2231,7 +2243,59 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return T; } -/// \brief Build an ext-vector type. +QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, + SourceLocation AttrLoc) { + // The base type must be integer (not Boolean or enumeration) or float, and + // can't already be a vector. + if (!CurType->isDependentType() && + (!CurType->isBuiltinType() || CurType->isBooleanType() || + (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) { + Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; + return QualType(); + } + + if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent()) + return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, + VectorType::GenericVector); + + llvm::APSInt VecSize(32); + if (!SizeExpr->isIntegerConstantExpr(VecSize, Context)) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "vector_size" << AANT_ArgumentIntegerConstant + << SizeExpr->getSourceRange(); + return QualType(); + } + + if (CurType->isDependentType()) + return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, + VectorType::GenericVector); + + unsigned VectorSize = static_cast<unsigned>(VecSize.getZExtValue() * 8); + unsigned TypeSize = static_cast<unsigned>(Context.getTypeSize(CurType)); + + if (VectorSize == 0) { + Diag(AttrLoc, diag::err_attribute_zero_size) << SizeExpr->getSourceRange(); + return QualType(); + } + + // vecSize is specified in bytes - convert to bits. + if (VectorSize % TypeSize) { + Diag(AttrLoc, diag::err_attribute_invalid_size) + << SizeExpr->getSourceRange(); + return QualType(); + } + + if (VectorType::isVectorSizeTooLarge(VectorSize / TypeSize)) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << SizeExpr->getSourceRange(); + return QualType(); + } + + return Context.getVectorType(CurType, VectorSize / TypeSize, + VectorType::GenericVector); +} + +/// Build an ext-vector type. /// /// Run the required checks for the extended vector type. QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, @@ -2402,7 +2466,7 @@ QualType Sema::BuildFunctionType(QualType T, return Context.getFunctionType(T, ParamTypes, EPI); } -/// \brief Build a member pointer type \c T Class::*. +/// Build a member pointer type \c T Class::*. /// /// \param T the type to which the member pointer refers. /// \param Class the class type into which the member pointer points. @@ -2451,7 +2515,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return Context.getMemberPointerType(T, Class.getTypePtr()); } -/// \brief Build a block pointer type. +/// Build a block pointer type. /// /// \param T The type to which we'll be building a block pointer. /// @@ -2583,9 +2647,8 @@ static void inferARCWriteback(TypeProcessingState &state, if (chunk.Kind != DeclaratorChunk::Pointer && chunk.Kind != DeclaratorChunk::BlockPointer) return; - for (const AttributeList *attr = chunk.getAttrs(); attr; - attr = attr->getNext()) - if (attr->getKind() == AttributeList::AT_ObjCOwnership) + for (const ParsedAttr &AL : chunk.getAttrs()) + if (AL.getKind() == ParsedAttr::AT_ObjCOwnership) return; transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing, @@ -2750,7 +2813,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // "void" instead. T = SemaRef.Context.VoidTy; processTypeAttrs(state, T, TAL_DeclSpec, - D.getDeclSpec().getAttributes().getList()); + D.getMutableDeclSpec().getAttributes()); break; case UnqualifiedIdKind::IK_DeductionGuideName: @@ -2767,7 +2830,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, break; } - if (D.getAttributes()) + if (!D.getAttributes().empty()) distributeTypeAttrsFromDeclarator(state, T); // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context. @@ -2851,6 +2914,14 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::BlockLiteralContext: Error = 9; // Block literal break; + case DeclaratorContext::TemplateArgContext: + // Within a template argument list, a deduced template specialization + // type will be reinterpreted as a template template argument. + if (isa<DeducedTemplateSpecializationType>(Deduced) && + !D.getNumTypeObjects() && + D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier) + break; + LLVM_FALLTHROUGH; case DeclaratorContext::TemplateTypeArgContext: Error = 10; // Template type argument break; @@ -2859,6 +2930,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 12; // Type alias break; case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::TrailingReturnVarContext: if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType) Error = 13; // Function return type break; @@ -2945,9 +3017,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, T = SemaRef.Context.IntTy; D.setInvalidType(true); - } else if (!HaveTrailing) { + } else if (!HaveTrailing && + D.getContext() != DeclaratorContext::LambdaExprContext) { // If there was a trailing return type, we already got // warn_cxx98_compat_trailing_return_type in the parser. + // If this was a lambda, we already warned on that too. SemaRef.Diag(AutoRange.getBegin(), diag::warn_cxx98_compat_auto_type_specifier) << AutoRange; @@ -2961,6 +3035,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, unsigned DiagID = 0; switch (D.getContext()) { case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::TrailingReturnVarContext: // Class and enumeration definitions are syntactically not allowed in // trailing return types. llvm_unreachable("parser should not have allowed this"); @@ -2988,6 +3063,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::CXXNewContext: case DeclaratorContext::CXXCatchContext: case DeclaratorContext::ObjCCatchContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: DiagID = diag::err_type_defined_in_type_specifier; break; @@ -3238,21 +3314,20 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { /// this is the outermost chunk, then we can determine the CC from the /// declarator context. If not, then this could be either a member function /// type or normal function type. -static CallingConv -getCCForDeclaratorChunk(Sema &S, Declarator &D, - const DeclaratorChunk::FunctionTypeInfo &FTI, - unsigned ChunkIndex) { +static CallingConv getCCForDeclaratorChunk( + Sema &S, Declarator &D, const ParsedAttributesView &AttrList, + const DeclaratorChunk::FunctionTypeInfo &FTI, unsigned ChunkIndex) { assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function); // Check for an explicit CC attribute. - for (auto Attr = FTI.AttrList; Attr; Attr = Attr->getNext()) { - switch (Attr->getKind()) { - CALLING_CONV_ATTRS_CASELIST: { + for (const ParsedAttr &AL : AttrList) { + switch (AL.getKind()) { + CALLING_CONV_ATTRS_CASELIST : { // Ignore attributes that don't validate or can't apply to the // function type. We'll diagnose the failure to apply them in // handleFunctionTypeAttr. CallingConv CC; - if (!S.CheckCallingConvAttr(*Attr, CC) && + if (!S.CheckCallingConvAttr(AL, CC) && (!FTI.isVariadic || supportsVariadicCall(CC))) { return CC; } @@ -3308,9 +3383,8 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, // convention attribute. This is the simplest place to infer // calling convention for OpenCL kernels. if (S.getLangOpts().OpenCL) { - for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); - Attr; Attr = Attr->getNext()) { - if (Attr->getKind() == AttributeList::AT_OpenCLKernel) { + for (const ParsedAttr &AL : D.getDeclSpec().getAttributes()) { + if (AL.getKind() == ParsedAttr::AT_OpenCLKernel) { CC = CC_OpenCLKernel; break; } @@ -3361,12 +3435,11 @@ IdentifierInfo *Sema::getNSErrorIdent() { /// Check whether there is a nullability attribute of any kind in the given /// attribute list. -static bool hasNullabilityAttr(const AttributeList *attrs) { - for (const AttributeList *attr = attrs; attr; - attr = attr->getNext()) { - if (attr->getKind() == AttributeList::AT_TypeNonNull || - attr->getKind() == AttributeList::AT_TypeNullable || - attr->getKind() == AttributeList::AT_TypeNullUnspecified) +static bool hasNullabilityAttr(const ParsedAttributesView &attrs) { + for (const ParsedAttr &AL : attrs) { + if (AL.getKind() == ParsedAttr::AT_TypeNonNull || + AL.getKind() == ParsedAttr::AT_TypeNullable || + AL.getKind() == ParsedAttr::AT_TypeNullUnspecified) return true; } @@ -3914,6 +3987,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::ObjCResultContext: case DeclaratorContext::PrototypeContext: case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::TrailingReturnVarContext: isFunctionOrMethod = true; LLVM_FALLTHROUGH; @@ -3967,19 +4041,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // On pointer-to-pointer parameters marked cf_returns_retained or // cf_returns_not_retained, if the outer pointer is explicit then // infer the inner pointer as _Nullable. - auto hasCFReturnsAttr = [](const AttributeList *NextAttr) -> bool { - while (NextAttr) { - if (NextAttr->getKind() == AttributeList::AT_CFReturnsRetained || - NextAttr->getKind() == AttributeList::AT_CFReturnsNotRetained) - return true; - NextAttr = NextAttr->getNext(); - } - return false; + auto hasCFReturnsAttr = + [](const ParsedAttributesView &AttrList) -> bool { + return AttrList.hasAttribute(ParsedAttr::AT_CFReturnsRetained) || + AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained); }; if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) { if (hasCFReturnsAttr(D.getAttributes()) || hasCFReturnsAttr(InnermostChunk->getAttrs()) || - hasCFReturnsAttr(D.getDeclSpec().getAttributes().getList())) { + hasCFReturnsAttr(D.getDeclSpec().getAttributes())) { inferNullability = NullabilityKind::Nullable; inferNullabilityInnerOnly = true; } @@ -4007,6 +4077,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::LambdaExprParameterContext: case DeclaratorContext::ObjCCatchContext: case DeclaratorContext::TemplateParamContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TypeNameContext: case DeclaratorContext::FunctionalCastContext: @@ -4034,10 +4105,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Local function that checks the nullability for a given pointer declarator. // Returns true if _Nonnull was inferred. - auto inferPointerNullability = [&](SimplePointerKind pointerKind, - SourceLocation pointerLoc, - SourceLocation pointerEndLoc, - AttributeList *&attrs) -> AttributeList * { + auto inferPointerNullability = + [&](SimplePointerKind pointerKind, SourceLocation pointerLoc, + SourceLocation pointerEndLoc, + ParsedAttributesView &attrs) -> ParsedAttr * { // We've seen a pointer. if (NumPointersRemaining > 0) --NumPointersRemaining; @@ -4048,18 +4119,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If we're supposed to infer nullability, do so now. if (inferNullability && !inferNullabilityInnerOnlyComplete) { - AttributeList::Syntax syntax - = inferNullabilityCS ? AttributeList::AS_ContextSensitiveKeyword - : AttributeList::AS_Keyword; - AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool() - .create( - S.getNullabilityKeyword( - *inferNullability), - SourceRange(pointerLoc), - nullptr, SourceLocation(), - nullptr, 0, syntax); - - spliceAttrIntoList(*nullabilityAttr, attrs); + ParsedAttr::Syntax syntax = inferNullabilityCS + ? ParsedAttr::AS_ContextSensitiveKeyword + : ParsedAttr::AS_Keyword; + ParsedAttr *nullabilityAttr = + state.getDeclarator().getAttributePool().create( + S.getNullabilityKeyword(*inferNullability), + SourceRange(pointerLoc), nullptr, SourceLocation(), nullptr, 0, + syntax); + + attrs.addAtStart(nullabilityAttr); if (inferNullabilityCS) { state.getDeclarator().getMutableDeclSpec().getObjCQualifiers() @@ -4114,9 +4183,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, pointerKind = SimplePointerKind::MemberPointer; if (auto *attr = inferPointerNullability( - pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), - D.getDeclSpec().getLocEnd(), - D.getMutableDeclSpec().getAttributes().getListRef())) { + pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), + D.getDeclSpec().getLocEnd(), + D.getMutableDeclSpec().getAttributes())) { T = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*inferNullability),T,T); attr->setUsedAsTypeAttr(); @@ -4154,7 +4223,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability. inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrListRef()); + DeclType.EndLoc, DeclType.getAttrs()); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) { @@ -4176,7 +4245,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrListRef()); + DeclType.EndLoc, DeclType.getAttrs()); if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); @@ -4450,20 +4519,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, SourceLocation AttrLoc; if (chunkIndex + 1 < D.getNumTypeObjects()) { DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); - for (const AttributeList *Attr = ReturnTypeChunk.getAttrs(); - Attr; Attr = Attr->getNext()) { - if (Attr->getKind() == AttributeList::AT_ObjCOwnership) { - AttrLoc = Attr->getLoc(); + for (const ParsedAttr &AL : ReturnTypeChunk.getAttrs()) { + if (AL.getKind() == ParsedAttr::AT_ObjCOwnership) { + AttrLoc = AL.getLoc(); break; } } } if (AttrLoc.isInvalid()) { - for (const AttributeList *Attr - = D.getDeclSpec().getAttributes().getList(); - Attr; Attr = Attr->getNext()) { - if (Attr->getKind() == AttributeList::AT_ObjCOwnership) { - AttrLoc = Attr->getLoc(); + for (const ParsedAttr &AL : D.getDeclSpec().getAttributes()) { + if (AL.getKind() == ParsedAttr::AT_ObjCOwnership) { + AttrLoc = AL.getLoc(); break; } } @@ -4474,7 +4540,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // the predefined // __strong/__weak/__autoreleasing/__unsafe_unretained. if (AttrLoc.isMacroID()) - AttrLoc = S.SourceMgr.getImmediateExpansionRange(AttrLoc).first; + AttrLoc = + S.SourceMgr.getImmediateExpansionRange(AttrLoc).getBegin(); S.Diag(AttrLoc, diag::warn_arc_lifetime_result_type) << T.getQualifiers().getObjCLifetime(); @@ -4502,7 +4569,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.isAmbiguous) warnAboutAmbiguousFunction(S, D, DeclType, T); - FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex)); + FunctionType::ExtInfo EI( + getCCForDeclaratorChunk(S, D, DeclType.getAttrs(), FTI, chunkIndex)); if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus && !LangOpts.OpenCL) { @@ -4512,19 +4580,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan // for this attribute now. - if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) { - bool Overloadable = false; - for (const AttributeList *Attrs = D.getAttributes(); - Attrs; Attrs = Attrs->getNext()) { - if (Attrs->getKind() == AttributeList::AT_Overloadable) { - Overloadable = true; - break; - } - } - - if (!Overloadable) + if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) + if (!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable)) S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param); - } if (FTI.NumParams && FTI.Params[0].Param == nullptr) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function @@ -4656,7 +4714,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, DynamicExceptions.push_back(FTI.Exceptions[I].Ty); DynamicExceptionRanges.push_back(FTI.Exceptions[I].Range); } - } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) { + } else if (isComputedNoexcept(FTI.getExceptionSpecType())) { NoexceptExpr = FTI.NoexceptExpr; } @@ -4679,7 +4737,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Handle pointer nullability. inferPointerNullability(SimplePointerKind::MemberPointer, DeclType.Loc, - DeclType.EndLoc, DeclType.getAttrListRef()); + DeclType.EndLoc, DeclType.getAttrs()); if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. @@ -4735,7 +4793,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorChunk::Pipe: { T = S.BuildReadPipeType(T, DeclType.Loc); processTypeAttrs(state, T, TAL_DeclSpec, - D.getDeclSpec().getAttributes().getList()); + D.getMutableDeclSpec().getAttributes()); break; } } @@ -4746,8 +4804,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // See if there are any attributes on this declarator chunk. - processTypeAttrs(state, T, TAL_DeclChunk, - const_cast<AttributeList *>(DeclType.getAttrs())); + processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs()); } // GNU warning -Wstrict-prototypes @@ -4828,6 +4885,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, !(Kind == Member && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && !IsTypedefName && + D.getContext() != DeclaratorContext::TemplateArgContext && D.getContext() != DeclaratorContext::TemplateTypeArgContext) { SourceLocation Loc = D.getLocStart(); SourceRange RemovalRange; @@ -4845,8 +4903,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, 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())); + llvm::sort(RemovalLocs.begin(), RemovalLocs.end(), + BeforeThanCompare<SourceLocation>(S.getSourceManager())); RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back()); Loc = RemovalLocs.front(); } @@ -4954,6 +5012,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::LambdaExprContext: case DeclaratorContext::ConversionIdContext: case DeclaratorContext::TrailingReturnContext: + case DeclaratorContext::TrailingReturnVarContext: + case DeclaratorContext::TemplateArgContext: case DeclaratorContext::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. @@ -5009,10 +5069,8 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, // Look for an explicit lifetime attribute. DeclaratorChunk &chunk = D.getTypeObject(chunkIndex); - for (const AttributeList *attr = chunk.getAttrs(); attr; - attr = attr->getNext()) - if (attr->getKind() == AttributeList::AT_ObjCOwnership) - return; + if (chunk.getAttrs().hasAttribute(ParsedAttr::AT_ObjCOwnership)) + return; const char *attrStr = nullptr; switch (ownership) { @@ -5031,16 +5089,15 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, // If there wasn't one, add one (with an invalid source location // so that we don't make an AttributedType for it). - AttributeList *attr = D.getAttributePool() - .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(), - /*scope*/ nullptr, SourceLocation(), - /*args*/ &Args, 1, AttributeList::AS_GNU); - spliceAttrIntoList(*attr, chunk.getAttrListRef()); - + ParsedAttr *attr = D.getAttributePool().create( + &S.Context.Idents.get("objc_ownership"), SourceLocation(), + /*scope*/ nullptr, SourceLocation(), + /*args*/ &Args, 1, ParsedAttr::AS_GNU); + chunk.getAttrs().addAtStart(attr); // TODO: mark whether we did this inference? } -/// \brief Used for transferring ownership in casts resulting in l-values. +/// Used for transferring ownership in casts resulting in l-values. static void transferARCOwnership(TypeProcessingState &state, QualType &declSpecTy, Qualifiers::ObjCLifetime ownership) { @@ -5107,110 +5164,91 @@ TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); } -/// Map an AttributedType::Kind to an AttributeList::Kind. -static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { +/// Map an AttributedType::Kind to an ParsedAttr::Kind. +static ParsedAttr::Kind getAttrListKind(AttributedType::Kind kind) { switch (kind) { case AttributedType::attr_address_space: - return AttributeList::AT_AddressSpace; + return ParsedAttr::AT_AddressSpace; case AttributedType::attr_regparm: - return AttributeList::AT_Regparm; + return ParsedAttr::AT_Regparm; case AttributedType::attr_vector_size: - return AttributeList::AT_VectorSize; + return ParsedAttr::AT_VectorSize; case AttributedType::attr_neon_vector_type: - return AttributeList::AT_NeonVectorType; + return ParsedAttr::AT_NeonVectorType; case AttributedType::attr_neon_polyvector_type: - return AttributeList::AT_NeonPolyVectorType; + return ParsedAttr::AT_NeonPolyVectorType; case AttributedType::attr_objc_gc: - return AttributeList::AT_ObjCGC; + return ParsedAttr::AT_ObjCGC; case AttributedType::attr_objc_ownership: case AttributedType::attr_objc_inert_unsafe_unretained: - return AttributeList::AT_ObjCOwnership; + return ParsedAttr::AT_ObjCOwnership; case AttributedType::attr_noreturn: - return AttributeList::AT_NoReturn; + return ParsedAttr::AT_NoReturn; + case AttributedType::attr_nocf_check: + return ParsedAttr::AT_AnyX86NoCfCheck; case AttributedType::attr_cdecl: - return AttributeList::AT_CDecl; + return ParsedAttr::AT_CDecl; case AttributedType::attr_fastcall: - return AttributeList::AT_FastCall; + return ParsedAttr::AT_FastCall; case AttributedType::attr_stdcall: - return AttributeList::AT_StdCall; + return ParsedAttr::AT_StdCall; case AttributedType::attr_thiscall: - return AttributeList::AT_ThisCall; + return ParsedAttr::AT_ThisCall; case AttributedType::attr_regcall: - return AttributeList::AT_RegCall; + return ParsedAttr::AT_RegCall; case AttributedType::attr_pascal: - return AttributeList::AT_Pascal; + return ParsedAttr::AT_Pascal; case AttributedType::attr_swiftcall: - return AttributeList::AT_SwiftCall; + return ParsedAttr::AT_SwiftCall; case AttributedType::attr_vectorcall: - return AttributeList::AT_VectorCall; + return ParsedAttr::AT_VectorCall; case AttributedType::attr_pcs: case AttributedType::attr_pcs_vfp: - return AttributeList::AT_Pcs; + return ParsedAttr::AT_Pcs; case AttributedType::attr_inteloclbicc: - return AttributeList::AT_IntelOclBicc; + return ParsedAttr::AT_IntelOclBicc; case AttributedType::attr_ms_abi: - return AttributeList::AT_MSABI; + return ParsedAttr::AT_MSABI; case AttributedType::attr_sysv_abi: - return AttributeList::AT_SysVABI; + return ParsedAttr::AT_SysVABI; case AttributedType::attr_preserve_most: - return AttributeList::AT_PreserveMost; + return ParsedAttr::AT_PreserveMost; case AttributedType::attr_preserve_all: - return AttributeList::AT_PreserveAll; + return ParsedAttr::AT_PreserveAll; case AttributedType::attr_ptr32: - return AttributeList::AT_Ptr32; + return ParsedAttr::AT_Ptr32; case AttributedType::attr_ptr64: - return AttributeList::AT_Ptr64; + return ParsedAttr::AT_Ptr64; case AttributedType::attr_sptr: - return AttributeList::AT_SPtr; + return ParsedAttr::AT_SPtr; case AttributedType::attr_uptr: - return AttributeList::AT_UPtr; + return ParsedAttr::AT_UPtr; case AttributedType::attr_nonnull: - return AttributeList::AT_TypeNonNull; + return ParsedAttr::AT_TypeNonNull; case AttributedType::attr_nullable: - return AttributeList::AT_TypeNullable; + return ParsedAttr::AT_TypeNullable; case AttributedType::attr_null_unspecified: - return AttributeList::AT_TypeNullUnspecified; + return ParsedAttr::AT_TypeNullUnspecified; case AttributedType::attr_objc_kindof: - return AttributeList::AT_ObjCKindOf; + return ParsedAttr::AT_ObjCKindOf; case AttributedType::attr_ns_returns_retained: - return AttributeList::AT_NSReturnsRetained; + return ParsedAttr::AT_NSReturnsRetained; } llvm_unreachable("unexpected attribute kind!"); } -static void fillAttributedTypeLoc(AttributedTypeLoc TL, - const AttributeList *attrs, - const AttributeList *DeclAttrs = nullptr) { - // DeclAttrs and attrs cannot be both empty. - assert((attrs || DeclAttrs) && - "no type attributes in the expected location!"); - - AttributeList::Kind parsedKind = getAttrListKind(TL.getAttrKind()); - // Try to search for an attribute of matching kind in attrs list. - while (attrs && attrs->getKind() != parsedKind) - attrs = attrs->getNext(); - if (!attrs) { - // No matching type attribute in attrs list found. - // Try searching through C++11 attributes in the declarator attribute list. - while (DeclAttrs && (!DeclAttrs->isCXX11Attribute() || - DeclAttrs->getKind() != parsedKind)) - DeclAttrs = DeclAttrs->getNext(); - attrs = DeclAttrs; - } - - assert(attrs && "no matching type attribute in expected location!"); - - TL.setAttrNameLoc(attrs->getLoc()); +static void setAttributedTypeLoc(AttributedTypeLoc TL, const ParsedAttr &attr) { + TL.setAttrNameLoc(attr.getLoc()); if (TL.hasAttrExprOperand()) { - assert(attrs->isArgExpr(0) && "mismatched attribute operand kind"); - TL.setAttrExprOperand(attrs->getArgAsExpr(0)); + assert(attr.isArgExpr(0) && "mismatched attribute operand kind"); + TL.setAttrExprOperand(attr.getArgAsExpr(0)); } else if (TL.hasAttrEnumOperand()) { - assert((attrs->isArgIdent(0) || attrs->isArgExpr(0)) && + assert((attr.isArgIdent(0) || attr.isArgExpr(0)) && "unexpected attribute operand kind"); - if (attrs->isArgIdent(0)) - TL.setAttrEnumOperandLoc(attrs->getArgAsIdent(0)->Loc); + if (attr.isArgIdent(0)) + TL.setAttrEnumOperandLoc(attr.getArgAsIdent(0)->Loc); else - TL.setAttrEnumOperandLoc(attrs->getArgAsExpr(0)->getExprLoc()); + TL.setAttrEnumOperandLoc(attr.getArgAsExpr(0)->getExprLoc()); } // FIXME: preserve this information to here. @@ -5218,6 +5256,25 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL, TL.setAttrOperandParensRange(SourceRange()); } +static void fillAttributedTypeLoc(AttributedTypeLoc TL, + const ParsedAttributesView &Attrs, + const ParsedAttributesView &DeclAttrs) { + // DeclAttrs and Attrs cannot be both empty. + assert((!Attrs.empty() || !DeclAttrs.empty()) && + "no type attributes in the expected location!"); + + ParsedAttr::Kind parsedKind = getAttrListKind(TL.getAttrKind()); + // Try to search for an attribute of matching kind in Attrs list. + for (const ParsedAttr &AL : Attrs) + if (AL.getKind() == parsedKind) + return setAttributedTypeLoc(TL, AL); + + for (const ParsedAttr &AL : DeclAttrs) + if (AL.isCXX11Attribute() || AL.getKind() == parsedKind) + return setAttributedTypeLoc(TL, AL); + llvm_unreachable("no matching type attribute in expected location!"); +} + namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { ASTContext &Context; @@ -5228,7 +5285,7 @@ namespace { : Context(Context), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { - fillAttributedTypeLoc(TL, DS.getAttributes().getList()); + fillAttributedTypeLoc(TL, DS.getAttributes(), ParsedAttributesView{}); Visit(TL.getModifiedLoc()); } void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { @@ -5400,7 +5457,7 @@ namespace { } void VisitAttributedTypeLoc(AttributedTypeLoc TL) { - fillAttributedTypeLoc(TL, Chunk.getAttrs()); + fillAttributedTypeLoc(TL, Chunk.getAttrs(), ParsedAttributesView{}); } void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing @@ -5533,19 +5590,23 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { ATL.setParensRange(SourceRange()); } -static void fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, - const AttributeList *Attrs) { - while (Attrs && Attrs->getKind() != AttributeList::AT_AddressSpace) - Attrs = Attrs->getNext(); +static void +fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, + const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) { + if (AL.getKind() == ParsedAttr::AT_AddressSpace) { + DASTL.setAttrNameLoc(AL.getLoc()); + DASTL.setAttrExprOperand(AL.getArgAsExpr(0)); + DASTL.setAttrOperandParensRange(SourceRange()); + return; + } + } - assert(Attrs && "no address_space attribute found at the expected location!"); - - DASTL.setAttrNameLoc(Attrs->getLoc()); - DASTL.setAttrExprOperand(Attrs->getArgAsExpr(0)); - DASTL.setAttrOperandParensRange(SourceRange()); + llvm_unreachable( + "no address_space attribute found at the expected location!"); } -/// \brief Create and instantiate a TypeSourceInfo with type source information. +/// Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. /// @@ -5558,7 +5619,6 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo) { TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); - const AttributeList *DeclAttrs = D.getAttributes(); // Handle parameter packs whose type is a pack expansion. if (isa<PackExpansionType>(T)) { @@ -5582,7 +5642,8 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, } while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) { - fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(), DeclAttrs); + fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs(), + D.getAttributes()); CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -5607,7 +5668,7 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, return TInfo; } -/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. +/// Create a LocInfoType to hold the given QualType and TypeSourceInfo. ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser // and Sema during declaration parsing. Try deallocating/caching them when @@ -5674,14 +5735,6 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc) { if (!AddrSpace->isValueDependent()) { - // If this type is already address space qualified, reject it. - // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified - // by qualifiers for two or more different address spaces." - if (T.getAddressSpace() != LangAS::Default) { - Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); - return QualType(); - } - llvm::APSInt addrSpace(32); if (!AddrSpace->isIntegerConstantExpr(addrSpace, Context)) { Diag(AttrLoc, diag::err_attribute_argument_type) @@ -5712,6 +5765,20 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, LangAS ASIdx = getLangASFromTargetAS(static_cast<unsigned>(addrSpace.getZExtValue())); + // If this type is already address space qualified with a different + // address space, reject it. + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified + // by qualifiers for two or more different address spaces." + if (T.getAddressSpace() != LangAS::Default) { + if (T.getAddressSpace() != ASIdx) { + Diag(AttrLoc, diag::err_attribute_address_multiple_qualifiers); + return QualType(); + } else + // Emit a warning if they are identical; it's likely unintended. + Diag(AttrLoc, + diag::warn_attribute_address_multiple_identical_qualifiers); + } + return Context.getAddrSpaceQualType(T, ASIdx); } @@ -5732,16 +5799,7 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S){ - // If this type is already address space qualified, reject it. - // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by - // qualifiers for two or more different address spaces." - if (Type.getAddressSpace() != LangAS::Default) { - S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); - Attr.setInvalid(); - return; - } - + const ParsedAttr &Attr, Sema &S) { // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "A function type shall not be // qualified by an address-space qualifier." if (Type->isFunctionType()) { @@ -5751,7 +5809,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } LangAS ASIdx; - if (Attr.getKind() == AttributeList::AT_AddressSpace) { + if (Attr.getKind() == ParsedAttr::AT_AddressSpace) { // Check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -5790,20 +5848,35 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, } else { // The keyword-based type attributes imply which address space to use. switch (Attr.getKind()) { - case AttributeList::AT_OpenCLGlobalAddressSpace: + case ParsedAttr::AT_OpenCLGlobalAddressSpace: ASIdx = LangAS::opencl_global; break; - case AttributeList::AT_OpenCLLocalAddressSpace: + case ParsedAttr::AT_OpenCLLocalAddressSpace: ASIdx = LangAS::opencl_local; break; - case AttributeList::AT_OpenCLConstantAddressSpace: + case ParsedAttr::AT_OpenCLConstantAddressSpace: ASIdx = LangAS::opencl_constant; break; - case AttributeList::AT_OpenCLGenericAddressSpace: + case ParsedAttr::AT_OpenCLGenericAddressSpace: ASIdx = LangAS::opencl_generic; break; - case AttributeList::AT_OpenCLPrivateAddressSpace: + case ParsedAttr::AT_OpenCLPrivateAddressSpace: ASIdx = LangAS::opencl_private; break; default: llvm_unreachable("Invalid address space"); } + // If this type is already address space qualified with a different + // address space, reject it. + // ISO/IEC TR 18037 S5.3 (amending C99 6.7.3): "No type shall be qualified by + // qualifiers for two or more different address spaces." + if (Type.getAddressSpace() != LangAS::Default) { + if (Type.getAddressSpace() != ASIdx) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); + Attr.setInvalid(); + return; + } else + // Emit a warning if they are identical; it's likely unintended. + S.Diag(Attr.getLoc(), + diag::warn_attribute_address_multiple_identical_qualifiers); + } + Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } } @@ -5843,8 +5916,7 @@ static bool hasDirectOwnershipQualifier(QualType type) { /// /// Returns 'true' if the attribute was handled. static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, - AttributeList &attr, - QualType &type) { + ParsedAttr &attr, QualType &type) { bool NonObjCPointer = false; if (!type->isDependentType() && !type->isUndeducedType()) { @@ -5873,7 +5945,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, Sema &S = state.getSema(); SourceLocation AttrLoc = attr.getLoc(); if (AttrLoc.isMacroID()) - AttrLoc = S.getSourceManager().getImmediateExpansionRange(AttrLoc).first; + AttrLoc = + S.getSourceManager().getImmediateExpansionRange(AttrLoc).getBegin(); if (!attr.isArgIdent(0)) { S.Diag(AttrLoc, diag::err_attribute_argument_type) @@ -6028,8 +6101,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, /// attribute on the specified type. Returns true to indicate that /// the attribute was handled, false to indicate that the type does /// not permit the attribute. -static bool handleObjCGCTypeAttr(TypeProcessingState &state, - AttributeList &attr, +static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr, QualType &type) { Sema &S = state.getSema(); @@ -6221,11 +6293,10 @@ namespace { } // end anonymous namespace static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, - AttributeList &Attr, - QualType &Type) { + ParsedAttr &Attr, QualType &Type) { Sema &S = State.getSema(); - AttributeList::Kind Kind = Attr.getKind(); + ParsedAttr::Kind Kind = Attr.getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast<AttributedType>(Type); while (AT) { @@ -6242,16 +6313,16 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // You cannot have both __sptr and __uptr on the same type, nor can you // have __ptr32 and __ptr64. if ((CurAttrKind == AttributedType::attr_ptr32 && - Kind == AttributeList::AT_Ptr64) || + Kind == ParsedAttr::AT_Ptr64) || (CurAttrKind == AttributedType::attr_ptr64 && - Kind == AttributeList::AT_Ptr32)) { + Kind == ParsedAttr::AT_Ptr32)) { S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" << "'__ptr64'"; return true; } else if ((CurAttrKind == AttributedType::attr_sptr && - Kind == AttributeList::AT_UPtr) || + Kind == ParsedAttr::AT_UPtr) || (CurAttrKind == AttributedType::attr_uptr && - Kind == AttributeList::AT_SPtr)) { + Kind == ParsedAttr::AT_SPtr)) { S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" << "'__uptr'"; return true; @@ -6276,10 +6347,18 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, AttributedType::Kind TAK; switch (Kind) { default: llvm_unreachable("Unknown attribute kind"); - case AttributeList::AT_Ptr32: TAK = AttributedType::attr_ptr32; break; - case AttributeList::AT_Ptr64: TAK = AttributedType::attr_ptr64; break; - case AttributeList::AT_SPtr: TAK = AttributedType::attr_sptr; break; - case AttributeList::AT_UPtr: TAK = AttributedType::attr_uptr; break; + case ParsedAttr::AT_Ptr32: + TAK = AttributedType::attr_ptr32; + break; + case ParsedAttr::AT_Ptr64: + TAK = AttributedType::attr_ptr64; + break; + case ParsedAttr::AT_SPtr: + TAK = AttributedType::attr_sptr; + break; + case ParsedAttr::AT_UPtr: + TAK = AttributedType::attr_uptr; + break; } Type = S.Context.getAttributedType(TAK, Type, Type); @@ -6430,15 +6509,15 @@ bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { } /// Map a nullability attribute kind to a nullability kind. -static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) { +static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { switch (kind) { - case AttributeList::AT_TypeNonNull: + case ParsedAttr::AT_TypeNonNull: return NullabilityKind::NonNull; - case AttributeList::AT_TypeNullable: + case ParsedAttr::AT_TypeNullable: return NullabilityKind::Nullable; - case AttributeList::AT_TypeNullUnspecified: + case ParsedAttr::AT_TypeNullUnspecified: return NullabilityKind::Unspecified; default: @@ -6453,15 +6532,14 @@ static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) { /// \returns true if the nullability annotation was distributed, false /// otherwise. static bool distributeNullabilityTypeAttr(TypeProcessingState &state, - QualType type, - AttributeList &attr) { + QualType type, ParsedAttr &attr) { Declarator &declarator = state.getDeclarator(); /// Attempt to move the attribute to the specified chunk. auto moveToChunk = [&](DeclaratorChunk &chunk, bool inFunction) -> bool { // If there is already a nullability attribute there, don't add // one. - if (hasNullabilityAttr(chunk.getAttrListRef())) + if (hasNullabilityAttr(chunk.getAttrs())) return false; // Complain about the nullability qualifier being in the wrong @@ -6494,8 +6572,8 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state, " " + attr.getName()->getName().str() + " "); } - moveAttrFromListToList(attr, state.getCurrentAttrListRef(), - chunk.getAttrListRef()); + moveAttrFromListToList(attr, state.getCurrentAttributes(), + chunk.getAttrs()); return true; }; @@ -6534,28 +6612,28 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state, return false; } -static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { +static AttributedType::Kind getCCTypeAttrKind(ParsedAttr &Attr) { assert(!Attr.isInvalid()); switch (Attr.getKind()) { default: llvm_unreachable("not a calling convention attribute"); - case AttributeList::AT_CDecl: + case ParsedAttr::AT_CDecl: return AttributedType::attr_cdecl; - case AttributeList::AT_FastCall: + case ParsedAttr::AT_FastCall: return AttributedType::attr_fastcall; - case AttributeList::AT_StdCall: + case ParsedAttr::AT_StdCall: return AttributedType::attr_stdcall; - case AttributeList::AT_ThisCall: + case ParsedAttr::AT_ThisCall: return AttributedType::attr_thiscall; - case AttributeList::AT_RegCall: + case ParsedAttr::AT_RegCall: return AttributedType::attr_regcall; - case AttributeList::AT_Pascal: + case ParsedAttr::AT_Pascal: return AttributedType::attr_pascal; - case AttributeList::AT_SwiftCall: + case ParsedAttr::AT_SwiftCall: return AttributedType::attr_swiftcall; - case AttributeList::AT_VectorCall: + case ParsedAttr::AT_VectorCall: return AttributedType::attr_vectorcall; - case AttributeList::AT_Pcs: { + case ParsedAttr::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, // but the form may not be. @@ -6568,15 +6646,15 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { .Case("aapcs", AttributedType::attr_pcs) .Case("aapcs-vfp", AttributedType::attr_pcs_vfp); } - case AttributeList::AT_IntelOclBicc: + case ParsedAttr::AT_IntelOclBicc: return AttributedType::attr_inteloclbicc; - case AttributeList::AT_MSABI: + case ParsedAttr::AT_MSABI: return AttributedType::attr_ms_abi; - case AttributeList::AT_SysVABI: + case ParsedAttr::AT_SysVABI: return AttributedType::attr_sysv_abi; - case AttributeList::AT_PreserveMost: + case ParsedAttr::AT_PreserveMost: return AttributedType::attr_preserve_most; - case AttributeList::AT_PreserveAll: + case ParsedAttr::AT_PreserveAll: return AttributedType::attr_preserve_all; } llvm_unreachable("unexpected attribute kind!"); @@ -6584,15 +6662,14 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { /// Process an individual function attribute. Returns true to /// indicate that the attribute was handled, false if it wasn't. -static bool handleFunctionTypeAttr(TypeProcessingState &state, - AttributeList &attr, +static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, QualType &type) { Sema &S = state.getSema(); FunctionTypeUnwrapper unwrapped(S, type); - if (attr.getKind() == AttributeList::AT_NoReturn) { - if (S.CheckNoReturnAttr(attr)) + if (attr.getKind() == ParsedAttr::AT_NoReturn) { + if (S.CheckAttrNoArgs(attr)) return true; // Delay if this is not a function type. @@ -6607,7 +6684,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, // ns_returns_retained is not always a type attribute, but if we got // here, we're treating it as one right now. - if (attr.getKind() == AttributeList::AT_NSReturnsRetained) { + if (attr.getKind() == ParsedAttr::AT_NSReturnsRetained) { if (attr.getNumArgs()) return true; // Delay if this is not a function type. @@ -6631,8 +6708,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } - if (attr.getKind() == AttributeList::AT_AnyX86NoCallerSavedRegisters) { - if (S.CheckNoCallerSavedRegsAttr(attr)) + if (attr.getKind() == ParsedAttr::AT_AnyX86NoCallerSavedRegisters) { + if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr)) return true; // Delay if this is not a function type. @@ -6645,7 +6722,28 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } - if (attr.getKind() == AttributeList::AT_Regparm) { + if (attr.getKind() == ParsedAttr::AT_AnyX86NoCfCheck) { + if (!S.getLangOpts().CFProtectionBranch) { + S.Diag(attr.getLoc(), diag::warn_nocf_check_attribute_ignored); + attr.setInvalid(); + return true; + } + + if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr)) + return true; + + // If this is not a function type, warning will be asserted by subject + // check. + if (!unwrapped.isFunctionType()) + return true; + + FunctionType::ExtInfo EI = + unwrapped.get()->getExtInfo().withNoCfCheck(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + + if (attr.getKind() == ParsedAttr::AT_Regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) return true; @@ -6802,7 +6900,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, /// The raw attribute should contain precisely 1 argument, the vector size for /// the variable, measured in bytes. If curType and rawAttr are well formed, /// this routine will return a new vector type. -static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, +static void HandleVectorSizeAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { // Check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -6811,58 +6909,35 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Attr.setInvalid(); return; } - Expr *sizeExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - llvm::APSInt vecSize(32); - if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || - !sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) - << Attr.getName() << AANT_ArgumentIntegerConstant - << sizeExpr->getSourceRange(); - Attr.setInvalid(); - return; - } - // The base type must be integer (not Boolean or enumeration) or float, and - // can't already be a vector. - if (!CurType->isBuiltinType() || CurType->isBooleanType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; - Attr.setInvalid(); - return; - } - unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); - // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); - // the vector size needs to be an integral multiple of the type size. - if (vectorSize % typeSize) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) - << sizeExpr->getSourceRange(); - Attr.setInvalid(); - return; - } - if (VectorType::isVectorSizeTooLarge(vectorSize / typeSize)) { - S.Diag(Attr.getLoc(), diag::err_attribute_size_too_large) - << sizeExpr->getSourceRange(); - Attr.setInvalid(); - return; - } - if (vectorSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) - << sizeExpr->getSourceRange(); - Attr.setInvalid(); - return; + Expr *SizeExpr; + // Special case where the argument is a template id. + if (Attr.isArgIdent(0)) { + CXXScopeSpec SS; + SourceLocation TemplateKWLoc; + UnqualifiedId Id; + Id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); + + ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, TemplateKWLoc, + Id, false, false); + + if (Size.isInvalid()) + return; + SizeExpr = Size.get(); + } else { + SizeExpr = Attr.getArgAsExpr(0); } - // Success! Instantiate the vector type, the number of elements is > 0, and - // not required to be a power of 2, unlike GCC. - CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, - VectorType::GenericVector); + QualType T = S.BuildVectorType(CurType, SizeExpr, Attr.getLoc()); + if (!T.isNull()) + CurType = T; + else + Attr.setInvalid(); } -/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on +/// Process the OpenCL-like ext_vector_type attribute when it occurs on /// a type. -static void HandleExtVectorTypeAttr(QualType &CurType, - const AttributeList &Attr, +static void HandleExtVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -6951,9 +7026,8 @@ static bool isPermittedNeonBaseType(QualType &Ty, /// the argument to these Neon attributes is the number of vector elements, /// not the vector size in bytes. The vector width and element type must /// match one of the standard Neon vector types. -static void HandleNeonVectorTypeAttr(QualType& CurType, - const AttributeList &Attr, Sema &S, - VectorType::VectorKind VecKind) { +static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, + Sema &S, VectorType::VectorKind VecKind) { // Target must have NEON if (!S.Context.getTargetInfo().hasFeature("neon")) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr.getName(); @@ -6999,7 +7073,7 @@ static void HandleNeonVectorTypeAttr(QualType& CurType, } /// Handle OpenCL Access Qualifier Attribute. -static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr, +static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { // OpenCL v2.0 s6.6 - Access qualifier can be used only for image and pipe type. if (!(CurType->isImageType() || CurType->isPipeType())) { @@ -7039,12 +7113,12 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, // Handle the cases where address space should not be deduced. // - // The pointee type of a pointer type is alwasy deduced since a pointer always + // The pointee type of a pointer type is always deduced since a pointer always // points to some memory location which should has an address space. // // There are situations that at the point of certain declarations, the address // space may be unknown and better to be left as default. For example, when - // definining a typedef or struct type, they are not associated with any + // defining a typedef or struct type, they are not associated with any // specific address space. Later on, they may be used with any address space // to declare a variable. // @@ -7089,8 +7163,9 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, // The default address space name for arguments to a function in a // program, or local variables of a function is __private. All function // arguments shall be in the __private address space. - if (State.getSema().getLangOpts().OpenCLVersion <= 120) { - ImpAddr = LangAS::opencl_private; + if (State.getSema().getLangOpts().OpenCLVersion <= 120 && + !State.getSema().getLangOpts().OpenCLCPlusPlus) { + ImpAddr = LangAS::opencl_private; } else { // If address space is not set, OpenCL 2.0 defines non private default // address spaces for some cases: @@ -7120,16 +7195,18 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, } static void processTypeAttrs(TypeProcessingState &state, QualType &type, - TypeAttrLocation TAL, AttributeList *attrs) { + TypeAttrLocation TAL, + ParsedAttributesView &attrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. - while (attrs) { - AttributeList &attr = *attrs; - attrs = attr.getNext(); // reset to the next here due to early loop continue - // stmts + // This loop modifies the list pretty frequently, but we still need to make + // sure we visit every element once. Copy the attributes list, and iterate + // over that. + ParsedAttributesView AttrsCopy{attrs}; + for (ParsedAttr &attr : AttrsCopy) { // Skip attributes that were marked to be invalid. if (attr.isInvalid()) @@ -7137,14 +7214,19 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (attr.isCXX11Attribute()) { // [[gnu::...]] attributes are treated as declaration attributes, so may - // not appertain to a DeclaratorChunk, even if we handle them as type - // attributes. + // not appertain to a DeclaratorChunk. If we handle them as type + // attributes, accept them in that position and diagnose the GCC + // incompatibility. if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) { + bool IsTypeAttr = attr.isTypeAttr(); if (TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), - diag::warn_cxx11_gnu_attribute_on_type) + IsTypeAttr + ? diag::warn_gcc_ignores_type_attr + : diag::warn_cxx11_gnu_attribute_on_type) << attr.getName(); - continue; + if (!IsTypeAttr) + continue; } } else if (TAL != TAL_DeclChunk) { // Otherwise, only consider type processing for a C++11 attribute if @@ -7165,27 +7247,27 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } break; - case AttributeList::UnknownAttribute: + case ParsedAttr::UnknownAttribute: if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) state.getSema().Diag(attr.getLoc(), diag::warn_unknown_attribute_ignored) << attr.getName(); break; - case AttributeList::IgnoredAttribute: + case ParsedAttr::IgnoredAttribute: break; - case AttributeList::AT_MayAlias: + case ParsedAttr::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_OpenCLPrivateAddressSpace: - case AttributeList::AT_OpenCLGlobalAddressSpace: - case AttributeList::AT_OpenCLLocalAddressSpace: - case AttributeList::AT_OpenCLConstantAddressSpace: - case AttributeList::AT_OpenCLGenericAddressSpace: - case AttributeList::AT_AddressSpace: + case ParsedAttr::AT_OpenCLPrivateAddressSpace: + case ParsedAttr::AT_OpenCLGlobalAddressSpace: + case ParsedAttr::AT_OpenCLLocalAddressSpace: + case ParsedAttr::AT_OpenCLConstantAddressSpace: + case ParsedAttr::AT_OpenCLGenericAddressSpace: + case ParsedAttr::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; @@ -7194,25 +7276,25 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, distributeObjCPointerTypeAttr(state, attr, type); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_VectorSize: + case ParsedAttr::AT_VectorSize: HandleVectorSizeAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_ExtVectorType: + case ParsedAttr::AT_ExtVectorType: HandleExtVectorTypeAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_NeonVectorType: + case ParsedAttr::AT_NeonVectorType: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_NeonPolyVectorType: + case ParsedAttr::AT_NeonPolyVectorType: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonPolyVector); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_OpenCLAccess: + case ParsedAttr::AT_OpenCLAccess: HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; @@ -7251,7 +7333,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } break; - case AttributeList::AT_ObjCKindOf: + case ParsedAttr::AT_ObjCKindOf: // '__kindof' must be part of the decl-specifiers. switch (TAL) { case TAL_DeclSpec: @@ -7337,7 +7419,7 @@ void Sema::completeExprArrayBound(Expr *E) { } } -/// \brief Ensure that the type of the given expression is complete. +/// Ensure that the type of the given expression is complete. /// /// This routine checks whether the expression \p E has a complete type. If the /// expression refers to an instantiable construct, that instantiation is @@ -7374,7 +7456,7 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) { return RequireCompleteExprType(E, Diagnoser); } -/// @brief Ensure that the type T is a complete type. +/// Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any /// context where a complete type is required. If @p T is a complete @@ -7413,12 +7495,13 @@ bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) { // and isolate from other C++ specific checks. StructuralEquivalenceContext Ctx( D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls, + StructuralEquivalenceKind::Default, false /*StrictTypeSpelling*/, true /*Complain*/, true /*ErrorOnTagTypeMismatch*/); - return Ctx.IsStructurallyEquivalent(D, Suggested); + return Ctx.IsEquivalent(D, Suggested); } -/// \brief Determine whether there is any declaration of \p D that was ever a +/// Determine whether there is any declaration of \p D that was ever a /// definition (perhaps before module merging) and is currently visible. /// \param D The definition of the entity. /// \param Suggested Filled in with the declaration that should be made visible @@ -7488,7 +7571,7 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, /// Locks in the inheritance model for the given class and all of its bases. static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { - RD = RD->getMostRecentDecl(); + RD = RD->getMostRecentNonInjectedDecl(); if (!RD->hasAttr<MSInheritanceAttr>()) { MSInheritanceAttr::Spelling IM; @@ -7518,7 +7601,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { } } -/// \brief The implementation of RequireCompleteType +/// The implementation of RequireCompleteType bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, TypeDiagnoser *Diagnoser) { // FIXME: Add this assertion to make sure we always get instantiation points. @@ -7529,11 +7612,17 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // assert(!T->isDependentType() && // "Can't ask whether a dependent type is complete"); - // We lock in the inheritance model once somebody has asked us to ensure - // that a pointer-to-member type is complete. - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { - if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) { - if (!MPTy->getClass()->isDependentType()) { + if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) { + if (!MPTy->getClass()->isDependentType()) { + if (getLangOpts().CompleteMemberPointers && + !MPTy->getClass()->getAsCXXRecordDecl()->isBeingDefined() && + RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), + diag::err_memptr_incomplete)) + return true; + + // We lock in the inheritance model once somebody has asked us to ensure + // that a pointer-to-member type is complete. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)isCompleteType(Loc, QualType(MPTy->getClass(), 0)); assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl()); } @@ -7557,10 +7646,18 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); - if (Diagnoser) + if (Diagnoser && SuggestedDef) diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, /*Recover*/TreatAsComplete); return !TreatAsComplete; + } else if (Def && !TemplateInstCallbacks.empty()) { + CodeSynthesisContext TempInst; + TempInst.Kind = CodeSynthesisContext::Memoization; + TempInst.Template = Def; + TempInst.Entity = Def; + TempInst.PointOfInstantiation = Loc; + atTemplateBegin(TemplateInstCallbacks, *this, TempInst); + atTemplateEnd(TemplateInstCallbacks, *this, TempInst); } return false; @@ -7689,7 +7786,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return RequireCompleteType(Loc, T, Diagnoser); } -/// \brief Get diagnostic %select index for tag kind for +/// Get diagnostic %select index for tag kind for /// literal type diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// @@ -7703,7 +7800,7 @@ static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) { } } -/// @brief Ensure that the type T is a literal type. +/// Ensure that the type T is a literal type. /// /// This routine checks whether the type @p T is a literal type. If @p T is an /// incomplete type, an attempt is made to complete it. If @p T is a literal @@ -7747,6 +7844,13 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T)) return true; + // [expr.prim.lambda]p3: + // This class type is [not] a literal type. + if (RD->isLambda() && !getLangOpts().CPlusPlus17) { + Diag(RD->getLocation(), diag::note_non_literal_lambda); + return true; + } + // If the class has virtual base classes, then it's not an aggregate, and // cannot have any constexpr constructors or a trivial default constructor, // so is non-literal. This is better to diagnose than the resulting absence @@ -7790,7 +7894,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, diag::note_non_literal_user_provided_dtor : diag::note_non_literal_nontrivial_dtor) << RD; if (!Dtor->isUserProvided()) - SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true); + SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI, + /*Diagnose*/true); } return true; @@ -7801,10 +7906,12 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID) { return RequireLiteralType(Loc, T, Diagnoser); } -/// \brief Retrieve a version of the type 'T' that is elaborated by Keyword -/// and qualified by the nested-name-specifier contained in SS. +/// Retrieve a version of the type 'T' that is elaborated by Keyword, qualified +/// by the nested-name-specifier contained in SS, and that is (re)declared by +/// OwnedTagDecl, which is nullptr if this is not a (re)declaration. QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, - const CXXScopeSpec &SS, QualType T) { + const CXXScopeSpec &SS, QualType T, + TagDecl *OwnedTagDecl) { if (T.isNull()) return T; NestedNameSpecifier *NNS; @@ -7815,7 +7922,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return T; NNS = nullptr; } - return Context.getElaboratedType(Keyword, NNS, T); + return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { @@ -7851,11 +7958,12 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // // We apply the same rules for Objective-C ivar and property references. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { - if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) - return VD->getType(); + const ValueDecl *VD = DRE->getDecl(); + return VD->getType(); } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) - return FD->getType(); + if (const ValueDecl *VD = ME->getMemberDecl()) + if (isa<FieldDecl>(VD) || isa<VarDecl>(VD)) + return VD->getType(); } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) { return IR->getDecl()->getType(); } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) { diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index 96969ea87a13..3b3953991000 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -41,7 +41,7 @@ namespace clang { using namespace sema; -/// \brief A semantic tree transformation that allows one to transform one +/// A semantic tree transformation that allows one to transform one /// abstract syntax tree into another. /// /// A new tree transformation is defined by creating a new subclass \c X of @@ -57,7 +57,7 @@ using namespace sema; /// subclasses to customize any of its operations. Thus, a subclass can /// override any of the transformation or rebuild operators by providing an /// operation with the same signature as the default implementation. The -/// overridding function should not be virtual. +/// overriding function should not be virtual. /// /// Semantic tree transformations are split into two stages, either of which /// can be replaced by a subclass. The "transform" step transforms an AST node @@ -94,7 +94,7 @@ using namespace sema; /// (\c getBaseLocation(), \c getBaseEntity()). template<typename Derived> class TreeTransform { - /// \brief Private RAII object that helps us forget and then re-remember + /// Private RAII object that helps us forget and then re-remember /// the template argument corresponding to a partially-substituted parameter /// pack. class ForgetPartiallySubstitutedPackRAII { @@ -114,19 +114,19 @@ class TreeTransform { protected: Sema &SemaRef; - /// \brief The set of local declarations that have been transformed, for + /// The set of local declarations that have been transformed, for /// cases where we are forced to build new declarations within the transformer /// rather than in the subclass (e.g., lambda closure types). llvm::DenseMap<Decl *, Decl *> TransformedLocalDecls; public: - /// \brief Initializes a new tree transformer. + /// Initializes a new tree transformer. TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } - /// \brief Retrieves a reference to the derived class. + /// Retrieves a reference to the derived class. Derived &getDerived() { return static_cast<Derived&>(*this); } - /// \brief Retrieves a reference to the derived class. + /// Retrieves a reference to the derived class. const Derived &getDerived() const { return static_cast<const Derived&>(*this); } @@ -134,11 +134,11 @@ public: static inline ExprResult Owned(Expr *E) { return E; } static inline StmtResult Owned(Stmt *S) { return S; } - /// \brief Retrieves a reference to the semantic analysis object used for + /// Retrieves a reference to the semantic analysis object used for /// this tree transform. Sema &getSema() const { return SemaRef; } - /// \brief Whether the transformation should always rebuild AST nodes, even + /// Whether the transformation should always rebuild AST nodes, even /// if none of the children have changed. /// /// Subclasses may override this function to specify when the transformation @@ -149,7 +149,7 @@ public: /// statement node appears at most once in its containing declaration. bool AlwaysRebuild() { return SemaRef.ArgumentPackSubstitutionIndex != -1; } - /// \brief Returns the location of the entity being transformed, if that + /// Returns the location of the entity being transformed, if that /// information was not available elsewhere in the AST. /// /// By default, returns no source-location information. Subclasses can @@ -157,21 +157,21 @@ public: /// information. SourceLocation getBaseLocation() { return SourceLocation(); } - /// \brief Returns the name of the entity being transformed, if that + /// Returns the name of the entity being transformed, if that /// information was not available elsewhere in the AST. /// /// By default, returns an empty name. Subclasses can provide an alternative /// implementation with a more precise name. DeclarationName getBaseEntity() { return DeclarationName(); } - /// \brief Sets the "base" location and entity when that + /// Sets the "base" location and entity when that /// information is known based on another transformation. /// /// By default, the source location and entity are ignored. Subclasses can /// override this function to provide a customized implementation. void setBase(SourceLocation Loc, DeclarationName Entity) { } - /// \brief RAII object that temporarily sets the base location and entity + /// RAII object that temporarily sets the base location and entity /// used for reporting diagnostics in types. class TemporaryBase { TreeTransform &Self; @@ -193,7 +193,7 @@ public: } }; - /// \brief Determine whether the given type \p T has already been + /// Determine whether the given type \p T has already been /// transformed. /// /// Subclasses can provide an alternative implementation of this routine @@ -204,7 +204,7 @@ public: return T.isNull(); } - /// \brief Determine whether the given call argument should be dropped, e.g., + /// Determine whether the given call argument should be dropped, e.g., /// because it is a default argument. /// /// Subclasses can provide an alternative implementation of this routine to @@ -214,7 +214,7 @@ public: return E->isDefaultArgument(); } - /// \brief Determine whether we should expand a pack expansion with the + /// Determine whether we should expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// @@ -261,7 +261,7 @@ public: return false; } - /// \brief "Forget" about the partially-substituted pack template argument, + /// "Forget" about the partially-substituted pack template argument, /// when performing an instantiation that must preserve the parameter pack /// use. /// @@ -270,18 +270,18 @@ public: return TemplateArgument(); } - /// \brief "Remember" the partially-substituted pack template argument + /// "Remember" the partially-substituted pack template argument /// after performing an instantiation that must preserve the parameter pack /// use. /// /// This routine is meant to be overridden by the template instantiator. void RememberPartiallySubstitutedPack(TemplateArgument Arg) { } - /// \brief Note to the derived class when a function parameter pack is + /// Note to the derived class when a function parameter pack is /// being expanded. void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { } - /// \brief Transforms the given type into another type. + /// Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a /// TypeSourceInfo for it and delegating to the appropriate @@ -292,7 +292,7 @@ public: /// \returns the transformed type. QualType TransformType(QualType T); - /// \brief Transforms the given type-with-location into a new + /// Transforms the given type-with-location into a new /// type-with-location. /// /// By default, this routine transforms a type by delegating to the @@ -302,13 +302,13 @@ public: /// to alter the transformation. TypeSourceInfo *TransformType(TypeSourceInfo *DI); - /// \brief Transform the given type-with-location into a new + /// Transform the given type-with-location into a new /// type, collecting location information in the given builder /// as necessary. /// QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); - /// \brief Transform a type that is permitted to produce a + /// Transform a type that is permitted to produce a /// DeducedTemplateSpecializationType. /// /// This is used in the (relatively rare) contexts where it is acceptable @@ -319,7 +319,7 @@ public: TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI); /// @} - /// \brief Transform the given statement. + /// Transform the given statement. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformXXXStmt function to transform a specific kind of @@ -330,7 +330,7 @@ public: /// \returns the transformed statement. StmtResult TransformStmt(Stmt *S); - /// \brief Transform the given statement. + /// Transform the given statement. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformOMPXXXClause function to transform a specific kind @@ -340,7 +340,7 @@ public: /// \returns the transformed OpenMP clause. OMPClause *TransformOMPClause(OMPClause *S); - /// \brief Transform the given attribute. + /// Transform the given attribute. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformXXXAttr function to transform a specific kind @@ -350,7 +350,7 @@ public: /// \returns the transformed attribute const Attr *TransformAttr(const Attr *S); -/// \brief Transform the specified attribute. +/// Transform the specified attribute. /// /// Subclasses should override the transformation of attributes with a pragma /// spelling to transform expressions stored within the attribute. @@ -361,7 +361,7 @@ public: const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; } #include "clang/Basic/AttrList.inc" - /// \brief Transform the given expression. + /// Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the /// appropriate TransformXXXExpr function to build a new expression. @@ -371,7 +371,7 @@ public: /// \returns the transformed expression. ExprResult TransformExpr(Expr *E); - /// \brief Transform the given initializer. + /// Transform the given initializer. /// /// By default, this routine transforms an initializer by stripping off the /// semantic nodes added by initialization, then passing the result to @@ -380,7 +380,7 @@ public: /// \returns the transformed initializer. ExprResult TransformInitializer(Expr *Init, bool NotCopyInit); - /// \brief Transform the given list of expressions. + /// Transform the given list of expressions. /// /// This routine transforms a list of expressions by invoking /// \c TransformExpr() for each subexpression. However, it also provides @@ -407,7 +407,7 @@ public: SmallVectorImpl<Expr *> &Outputs, bool *ArgChanged = nullptr); - /// \brief Transform the given declaration, which is referenced from a type + /// Transform the given declaration, which is referenced from a type /// or expression. /// /// By default, acts as the identity function on declarations, unless the @@ -422,7 +422,7 @@ public: return D; } - /// \brief Transform the specified condition. + /// Transform the specified condition. /// /// By default, this transforms the variable and expression and rebuilds /// the condition. @@ -430,14 +430,14 @@ public: Expr *Expr, Sema::ConditionKind Kind); - /// \brief Transform the attributes associated with the given declaration and + /// Transform the attributes associated with the given declaration and /// place them on the new declaration. /// /// By default, this operation does nothing. Subclasses may override this /// behavior to transform attributes. void transformAttrs(Decl *Old, Decl *New) { } - /// \brief Note that a local declaration has been transformed by this + /// Note that a local declaration has been transformed by this /// transformer. /// /// Local declarations are typically transformed via a call to @@ -448,7 +448,7 @@ public: TransformedLocalDecls[Old] = New; } - /// \brief Transform the definition of the given declaration. + /// Transform the definition of the given declaration. /// /// By default, invokes TransformDecl() to transform the declaration. /// Subclasses may override this function to provide alternate behavior. @@ -456,7 +456,7 @@ public: return getDerived().TransformDecl(Loc, D); } - /// \brief Transform the given declaration, which was the first part of a + /// Transform the given declaration, which was the first part of a /// nested-name-specifier in a member access expression. /// /// This specific declaration transformation only applies to the first @@ -473,7 +473,7 @@ public: bool TransformOverloadExprDecls(OverloadExpr *Old, bool RequiresADL, LookupResult &R); - /// \brief Transform the given nested-name-specifier with source-location + /// Transform the given nested-name-specifier with source-location /// information. /// /// By default, transforms all of the types and declarations within the @@ -484,7 +484,7 @@ public: QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr); - /// \brief Transform the given declaration name. + /// Transform the given declaration name. /// /// By default, transforms the types of conversion function, constructor, /// and destructor names and then (if needed) rebuilds the declaration name. @@ -493,7 +493,7 @@ public: DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); - /// \brief Transform the given template name. + /// Transform the given template name. /// /// \param SS The nested-name-specifier that qualifies the template /// name. This nested-name-specifier must already have been transformed. @@ -520,7 +520,7 @@ public: NamedDecl *FirstQualifierInScope = nullptr, bool AllowInjectedClassName = false); - /// \brief Transform the given template argument. + /// Transform the given template argument. /// /// By default, this operation transforms the type, expression, or /// declaration stored within the template argument and constructs a @@ -532,7 +532,7 @@ public: TemplateArgumentLoc &Output, bool Uneval = false); - /// \brief Transform the given set of template arguments. + /// Transform the given set of template arguments. /// /// By default, this operation transforms all of the template arguments /// in the input set using \c TransformTemplateArgument(), and appends @@ -558,7 +558,7 @@ public: Uneval); } - /// \brief Transform the given set of template arguments. + /// Transform the given set of template arguments. /// /// By default, this operation transforms all of the template arguments /// in the input set using \c TransformTemplateArgument(), and appends @@ -578,11 +578,11 @@ public: TemplateArgumentListInfo &Outputs, bool Uneval = false); - /// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument. + /// Fakes up a TemplateArgumentLoc for a given TemplateArgument. void InventTemplateArgumentLoc(const TemplateArgument &Arg, TemplateArgumentLoc &ArgLoc); - /// \brief Fakes up a TypeSourceInfo for a type. + /// Fakes up a TypeSourceInfo for a type. TypeSourceInfo *InventTypeSourceInfo(QualType T) { return SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); @@ -622,7 +622,7 @@ public: TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc); - /// \brief Transforms the parameters of a function type into the + /// Transforms the parameters of a function type into the /// given vectors. /// /// The result vectors should be kept in sync; null entries in the @@ -636,7 +636,7 @@ public: SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars, Sema::ExtParameterInfoBuilder &PInfos); - /// \brief Transforms a single function-type parameter. Return null + /// Transforms a single function-type parameter. Return null /// on error. /// /// \param indexAdjustment - A number to add to the parameter's @@ -684,7 +684,7 @@ public: OMPClause *Transform ## Class(Class *S); #include "clang/Basic/OpenMPKinds.def" - /// \brief Build a new qualified type given its unqualified type and type + /// Build a new qualified type given its unqualified type and type /// qualifiers. /// /// By default, this routine adds type qualifiers only to types that can @@ -694,19 +694,19 @@ public: QualType RebuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Quals); - /// \brief Build a new pointer type given its pointee type. + /// Build a new pointer type given its pointee type. /// /// By default, performs semantic analysis when building the pointer type. /// Subclasses may override this routine to provide different behavior. QualType RebuildPointerType(QualType PointeeType, SourceLocation Sigil); - /// \brief Build a new block pointer type given its pointee type. + /// Build a new block pointer type given its pointee type. /// /// By default, performs semantic analysis when building the block pointer /// type. Subclasses may override this routine to provide different behavior. QualType RebuildBlockPointerType(QualType PointeeType, SourceLocation Sigil); - /// \brief Build a new reference type given the type it references. + /// Build a new reference type given the type it references. /// /// By default, performs semantic analysis when building the /// reference type. Subclasses may override this routine to provide @@ -718,7 +718,7 @@ public: bool LValue, SourceLocation Sigil); - /// \brief Build a new member pointer type given the pointee type and the + /// Build a new member pointer type given the pointee type and the /// class type it refers into. /// /// By default, performs semantic analysis when building the member pointer @@ -732,7 +732,7 @@ public: ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc); - /// \brief Build an Objective-C object type. + /// Build an Objective-C object type. /// /// By default, performs semantic analysis when building the object type. /// Subclasses may override this routine to provide different behavior. @@ -746,14 +746,14 @@ public: ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc); - /// \brief Build a new Objective-C object pointer type given the pointee type. + /// Build a new Objective-C object pointer type given the pointee type. /// /// By default, directly builds the pointer type, with no additional semantic /// analysis. QualType RebuildObjCObjectPointerType(QualType PointeeType, SourceLocation Star); - /// \brief Build a new array type given the element type, size + /// Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. /// @@ -767,7 +767,7 @@ public: unsigned IndexTypeQuals, SourceRange BracketsRange); - /// \brief Build a new constant array type given the element type, size + /// Build a new constant array type given the element type, size /// modifier, (known) size of the array, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. @@ -778,7 +778,7 @@ public: unsigned IndexTypeQuals, SourceRange BracketsRange); - /// \brief Build a new incomplete array type given the element type, size + /// Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. @@ -788,7 +788,7 @@ public: unsigned IndexTypeQuals, SourceRange BracketsRange); - /// \brief Build a new variable-length array type given the element type, + /// Build a new variable-length array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. @@ -799,7 +799,7 @@ public: unsigned IndexTypeQuals, SourceRange BracketsRange); - /// \brief Build a new dependent-sized array type given the element type, + /// Build a new dependent-sized array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. @@ -810,7 +810,7 @@ public: unsigned IndexTypeQuals, SourceRange BracketsRange); - /// \brief Build a new vector type given the element type and + /// Build a new vector type given the element type and /// number of elements. /// /// By default, performs semantic analysis when building the vector type. @@ -818,7 +818,16 @@ public: QualType RebuildVectorType(QualType ElementType, unsigned NumElements, VectorType::VectorKind VecKind); - /// \brief Build a new extended vector type given the element type and + /// Build a new potentially dependently-sized extended vector type + /// given the element type and number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDependentVectorType(QualType ElementType, Expr *SizeExpr, + SourceLocation AttributeLoc, + VectorType::VectorKind); + + /// Build a new extended vector type given the element type and /// number of elements. /// /// By default, performs semantic analysis when building the vector type. @@ -826,7 +835,7 @@ public: QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements, SourceLocation AttributeLoc); - /// \brief Build a new potentially dependently-sized extended vector type + /// Build a new potentially dependently-sized extended vector type /// given the element type and number of elements. /// /// By default, performs semantic analysis when building the vector type. @@ -835,7 +844,7 @@ public: Expr *SizeExpr, SourceLocation AttributeLoc); - /// \brief Build a new DependentAddressSpaceType or return the pointee + /// Build a new DependentAddressSpaceType or return the pointee /// type variable with the correct address space (retrieved from /// AddrSpaceExpr) applied to it. The former will be returned in cases /// where the address space remains dependent. @@ -847,7 +856,7 @@ public: Expr *AddrSpaceExpr, SourceLocation AttributeLoc); - /// \brief Build a new function type. + /// Build a new function type. /// /// By default, performs semantic analysis when building the function type. /// Subclasses may override this routine to provide different behavior. @@ -855,51 +864,51 @@ public: MutableArrayRef<QualType> ParamTypes, const FunctionProtoType::ExtProtoInfo &EPI); - /// \brief Build a new unprototyped function type. + /// Build a new unprototyped function type. QualType RebuildFunctionNoProtoType(QualType ResultType); - /// \brief Rebuild an unresolved typename type, given the decl that + /// Rebuild an unresolved typename type, given the decl that /// the UnresolvedUsingTypenameDecl was transformed to. QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); - /// \brief Build a new typedef type. + /// Build a new typedef type. QualType RebuildTypedefType(TypedefNameDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); } - /// \brief Build a new class/struct/union type. + /// Build a new class/struct/union type. QualType RebuildRecordType(RecordDecl *Record) { return SemaRef.Context.getTypeDeclType(Record); } - /// \brief Build a new Enum type. + /// Build a new Enum type. QualType RebuildEnumType(EnumDecl *Enum) { return SemaRef.Context.getTypeDeclType(Enum); } - /// \brief Build a new typeof(expr) type. + /// Build a new typeof(expr) type. /// /// By default, performs semantic analysis when building the typeof type. /// Subclasses may override this routine to provide different behavior. QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc); - /// \brief Build a new typeof(type) type. + /// Build a new typeof(type) type. /// /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); - /// \brief Build a new unary transform type. + /// Build a new unary transform type. QualType RebuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); - /// \brief Build a new C++11 decltype type. + /// Build a new C++11 decltype type. /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); - /// \brief Build a new C++11 auto type. + /// Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { @@ -918,7 +927,7 @@ public: Template, Deduced, /*IsDependent*/ false); } - /// \brief Build a new template specialization type. + /// Build a new template specialization type. /// /// By default, performs semantic analysis when building the template /// specialization type. Subclasses may override this routine to provide @@ -927,7 +936,7 @@ public: SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); - /// \brief Build a new parenthesized type. + /// Build a new parenthesized type. /// /// By default, builds a new ParenType type from the inner type. /// Subclasses may override this routine to provide different behavior. @@ -935,7 +944,7 @@ public: return SemaRef.BuildParenType(InnerType); } - /// \brief Build a new qualified name type. + /// Build a new qualified name type. /// /// By default, builds a new ElaboratedType type from the keyword, /// the nested-name-specifier and the named type. @@ -949,7 +958,7 @@ public: Named); } - /// \brief Build a new typename type that refers to a template-id. + /// Build a new typename type that refers to a template-id. /// /// By default, builds a new DependentNameType type from the /// nested-name-specifier and the given type. Subclasses may override @@ -957,6 +966,7 @@ public: QualType RebuildDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, const IdentifierInfo *Name, SourceLocation NameLoc, TemplateArgumentListInfo &Args, @@ -965,9 +975,9 @@ public: // TODO: avoid TemplateName abstraction CXXScopeSpec SS; SS.Adopt(QualifierLoc); - TemplateName InstName - = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), - nullptr, AllowInjectedClassName); + TemplateName InstName = getDerived().RebuildTemplateName( + SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr, + AllowInjectedClassName); if (InstName.isNull()) return QualType(); @@ -993,7 +1003,7 @@ public: T); } - /// \brief Build a new typename type that refers to an identifier. + /// Build a new typename type that refers to an identifier. /// /// By default, performs semantic analysis when building the typename type /// (or elaborated type). Subclasses may override this routine to provide @@ -1106,7 +1116,7 @@ public: T); } - /// \brief Build a new pack expansion type. + /// Build a new pack expansion type. /// /// By default, builds a new PackExpansionType type from the given pattern. /// Subclasses may override this routine to provide different behavior. @@ -1118,17 +1128,17 @@ public: NumExpansions); } - /// \brief Build a new atomic type given its value type. + /// Build a new atomic type given its value type. /// /// By default, performs semantic analysis when building the atomic type. /// Subclasses may override this routine to provide different behavior. QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); - /// \brief Build a new pipe type given its value type. + /// Build a new pipe type given its value type. QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc, bool isReadPipe); - /// \brief Build a new template name given a nested name specifier, a flag + /// Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. /// @@ -1138,7 +1148,7 @@ public: bool TemplateKW, TemplateDecl *Template); - /// \brief Build a new template name given a nested name specifier and the + /// Build a new template name given a nested name specifier and the /// name that is referred to as a template. /// /// By default, performs semantic analysis to determine whether the name can @@ -1146,13 +1156,13 @@ public: /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, const IdentifierInfo &Name, - SourceLocation NameLoc, - QualType ObjectType, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName); - /// \brief Build a new template name given a nested name specifier and the + /// Build a new template name given a nested name specifier and the /// overloaded operator name that is referred to as a template. /// /// By default, performs semantic analysis to determine whether the name can @@ -1160,12 +1170,12 @@ public: /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, - SourceLocation NameLoc, - QualType ObjectType, + SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName); - /// \brief Build a new template name given a template template parameter pack + /// Build a new template name given a template template parameter pack /// and the /// /// By default, performs semantic analysis to determine whether the name can @@ -1177,7 +1187,7 @@ public: return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack); } - /// \brief Build a new compound statement. + /// Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1189,7 +1199,7 @@ public: IsStmtExpr); } - /// \brief Build a new case statement. + /// Build a new case statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1202,7 +1212,7 @@ public: ColonLoc); } - /// \brief Attach the body to a new case statement. + /// Attach the body to a new case statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1211,7 +1221,7 @@ public: return S; } - /// \brief Build a new default statement. + /// Build a new default statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1222,7 +1232,7 @@ public: /*CurScope=*/nullptr); } - /// \brief Build a new label statement. + /// Build a new label statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1231,7 +1241,7 @@ public: return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } - /// \brief Build a new label statement. + /// Build a new label statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1241,7 +1251,7 @@ public: return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt); } - /// \brief Build a new "if" statement. + /// Build a new "if" statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1252,7 +1262,7 @@ public: ElseLoc, Else); } - /// \brief Start building a new switch statement. + /// Start building a new switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1261,7 +1271,7 @@ public: return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond); } - /// \brief Attach the body to the switch statement. + /// Attach the body to the switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1270,7 +1280,7 @@ public: return getSema().ActOnFinishSwitchStmt(SwitchLoc, Switch, Body); } - /// \brief Build a new while statement. + /// Build a new while statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1279,7 +1289,7 @@ public: return getSema().ActOnWhileStmt(WhileLoc, Cond, Body); } - /// \brief Build a new do-while statement. + /// Build a new do-while statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1290,7 +1300,7 @@ public: Cond, RParenLoc); } - /// \brief Build a new for statement. + /// Build a new for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1302,7 +1312,7 @@ public: Inc, RParenLoc, Body); } - /// \brief Build a new goto statement. + /// Build a new goto statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1311,7 +1321,7 @@ public: return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label); } - /// \brief Build a new indirect goto statement. + /// Build a new indirect goto statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1321,7 +1331,7 @@ public: return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, Target); } - /// \brief Build a new return statement. + /// Build a new return statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1329,7 +1339,7 @@ public: return getSema().BuildReturnStmt(ReturnLoc, Result); } - /// \brief Build a new declaration statement. + /// Build a new declaration statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1339,7 +1349,7 @@ public: return getSema().ActOnDeclStmt(DG, StartLoc, EndLoc); } - /// \brief Build a new inline asm statement. + /// Build a new inline asm statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1354,7 +1364,7 @@ public: AsmString, Clobbers, RParenLoc); } - /// \brief Build a new MS style inline asm statement. + /// Build a new MS style inline asm statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1371,7 +1381,7 @@ public: Constraints, Clobbers, Exprs, EndLoc); } - /// \brief Build a new co_return statement. + /// Build a new co_return statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1380,7 +1390,7 @@ public: return getSema().BuildCoreturnStmt(CoreturnLoc, Result, IsImplicit); } - /// \brief Build a new co_await expression. + /// Build a new co_await expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -1389,7 +1399,7 @@ public: return getSema().BuildResolvedCoawaitExpr(CoawaitLoc, Result, IsImplicit); } - /// \brief Build a new co_await expression. + /// Build a new co_await expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -1399,7 +1409,7 @@ public: return getSema().BuildUnresolvedCoawaitExpr(CoawaitLoc, Result, Lookup); } - /// \brief Build a new co_yield expression. + /// Build a new co_yield expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -1411,7 +1421,7 @@ public: return getSema().BuildCoroutineBodyStmt(Args); } - /// \brief Build a new Objective-C \@try statement. + /// Build a new Objective-C \@try statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1423,7 +1433,7 @@ public: Finally); } - /// \brief Rebuild an Objective-C exception declaration. + /// Rebuild an Objective-C exception declaration. /// /// By default, performs semantic analysis to build the new declaration. /// Subclasses may override this routine to provide different behavior. @@ -1435,7 +1445,7 @@ public: ExceptionDecl->getIdentifier()); } - /// \brief Build a new Objective-C \@catch statement. + /// Build a new Objective-C \@catch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1447,7 +1457,7 @@ public: Var, Body); } - /// \brief Build a new Objective-C \@finally statement. + /// Build a new Objective-C \@finally statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1456,7 +1466,7 @@ public: return getSema().ActOnObjCAtFinallyStmt(AtLoc, Body); } - /// \brief Build a new Objective-C \@throw statement. + /// Build a new Objective-C \@throw statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1465,7 +1475,7 @@ public: return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } - /// \brief Build a new OpenMP executable directive. + /// Build a new OpenMP executable directive. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1479,7 +1489,7 @@ public: Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc); } - /// \brief Build a new OpenMP 'if' clause. + /// Build a new OpenMP 'if' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1494,7 +1504,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'final' clause. + /// Build a new OpenMP 'final' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1505,7 +1515,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'num_threads' clause. + /// Build a new OpenMP 'num_threads' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1517,7 +1527,7 @@ public: LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'safelen' clause. + /// Build a new OpenMP 'safelen' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1527,7 +1537,7 @@ public: return getSema().ActOnOpenMPSafelenClause(Len, StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'simdlen' clause. + /// Build a new OpenMP 'simdlen' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1537,7 +1547,7 @@ public: return getSema().ActOnOpenMPSimdlenClause(Len, StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'collapse' clause. + /// Build a new OpenMP 'collapse' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1548,7 +1558,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'default' clause. + /// Build a new OpenMP 'default' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1561,7 +1571,7 @@ public: StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'proc_bind' clause. + /// Build a new OpenMP 'proc_bind' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1574,7 +1584,7 @@ public: StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'schedule' clause. + /// Build a new OpenMP 'schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1588,7 +1598,7 @@ public: CommaLoc, EndLoc); } - /// \brief Build a new OpenMP 'ordered' clause. + /// Build a new OpenMP 'ordered' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1598,7 +1608,7 @@ public: return getSema().ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Num); } - /// \brief Build a new OpenMP 'private' clause. + /// Build a new OpenMP 'private' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1610,7 +1620,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'firstprivate' clause. + /// Build a new OpenMP 'firstprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1622,7 +1632,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'lastprivate' clause. + /// Build a new OpenMP 'lastprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1634,7 +1644,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'shared' clause. + /// Build a new OpenMP 'shared' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1646,7 +1656,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'reduction' clause. + /// Build a new OpenMP 'reduction' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1694,7 +1704,7 @@ public: ReductionId, UnresolvedReductions); } - /// \brief Build a new OpenMP 'linear' clause. + /// Build a new OpenMP 'linear' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1710,7 +1720,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'aligned' clause. + /// Build a new OpenMP 'aligned' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1723,7 +1733,7 @@ public: LParenLoc, ColonLoc, EndLoc); } - /// \brief Build a new OpenMP 'copyin' clause. + /// Build a new OpenMP 'copyin' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1735,7 +1745,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'copyprivate' clause. + /// Build a new OpenMP 'copyprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1747,7 +1757,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'flush' pseudo clause. + /// Build a new OpenMP 'flush' pseudo clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1759,7 +1769,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'depend' pseudo clause. + /// Build a new OpenMP 'depend' pseudo clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1772,7 +1782,7 @@ public: StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'device' clause. + /// Build a new OpenMP 'device' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1783,7 +1793,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'map' clause. + /// Build a new OpenMP 'map' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1798,7 +1808,7 @@ public: VarList, StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'num_teams' clause. + /// Build a new OpenMP 'num_teams' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1809,7 +1819,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'thread_limit' clause. + /// Build a new OpenMP 'thread_limit' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1821,7 +1831,7 @@ public: LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'priority' clause. + /// Build a new OpenMP 'priority' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1832,7 +1842,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'grainsize' clause. + /// Build a new OpenMP 'grainsize' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1843,7 +1853,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'num_tasks' clause. + /// Build a new OpenMP 'num_tasks' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1854,7 +1864,7 @@ public: EndLoc); } - /// \brief Build a new OpenMP 'hint' clause. + /// Build a new OpenMP 'hint' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1864,7 +1874,7 @@ public: return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'dist_schedule' clause. + /// Build a new OpenMP 'dist_schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. @@ -1877,7 +1887,7 @@ public: Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc); } - /// \brief Build a new OpenMP 'to' clause. + /// Build a new OpenMP 'to' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1888,7 +1898,7 @@ public: return getSema().ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); } - /// \brief Build a new OpenMP 'from' clause. + /// Build a new OpenMP 'from' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1924,7 +1934,7 @@ public: EndLoc); } - /// \brief Rebuild the operand to an Objective-C \@synchronized statement. + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1933,7 +1943,7 @@ public: return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object); } - /// \brief Build a new Objective-C \@synchronized statement. + /// Build a new Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1942,7 +1952,7 @@ public: return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body); } - /// \brief Build a new Objective-C \@autoreleasepool statement. + /// Build a new Objective-C \@autoreleasepool statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1951,7 +1961,7 @@ public: return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); } - /// \brief Build a new Objective-C fast enumeration statement. + /// Build a new Objective-C fast enumeration statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1970,7 +1980,7 @@ public: return getSema().FinishObjCForCollectionStmt(ForEachStmt.get(), Body); } - /// \brief Build a new C++ exception declaration. + /// Build a new C++ exception declaration. /// /// By default, performs semantic analysis to build the new decaration. /// Subclasses may override this routine to provide different behavior. @@ -1986,7 +1996,7 @@ public: return Var; } - /// \brief Build a new C++ catch statement. + /// Build a new C++ catch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -1997,7 +2007,7 @@ public: Handler)); } - /// \brief Build a new C++ try statement. + /// Build a new C++ try statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -2006,7 +2016,7 @@ public: return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers); } - /// \brief Build a new C++0x range-based for statement. + /// Build a new C++0x range-based for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -2040,7 +2050,7 @@ public: Sema::BFRK_Rebuild); } - /// \brief Build a new C++0x range-based for statement. + /// Build a new C++0x range-based for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. @@ -2053,7 +2063,7 @@ public: QualifierLoc, NameInfo, Nested); } - /// \brief Attach body to a C++0x range-based for statement. + /// Attach body to a C++0x range-based for statement. /// /// By default, performs semantic analysis to finish the new statement. /// Subclasses may override this routine to provide different behavior. @@ -2075,7 +2085,7 @@ public: return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block); } - /// \brief Build a new predefined expression. + /// Build a new predefined expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2084,7 +2094,7 @@ public: return getSema().BuildPredefinedExpr(Loc, IT); } - /// \brief Build a new expression that references a declaration. + /// Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2095,7 +2105,7 @@ public: } - /// \brief Build a new expression that references a declaration. + /// Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2111,7 +2121,7 @@ public: return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD); } - /// \brief Build a new expression in parentheses. + /// Build a new expression in parentheses. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2120,7 +2130,7 @@ public: return getSema().ActOnParenExpr(LParen, RParen, SubExpr); } - /// \brief Build a new pseudo-destructor expression. + /// Build a new pseudo-destructor expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2133,7 +2143,7 @@ public: SourceLocation TildeLoc, PseudoDestructorTypeStorage Destroyed); - /// \brief Build a new unary operator expression. + /// Build a new unary operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2143,7 +2153,7 @@ public: return getSema().BuildUnaryOp(/*Scope=*/nullptr, OpLoc, Opc, SubExpr); } - /// \brief Build a new builtin offsetof expression. + /// Build a new builtin offsetof expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2155,7 +2165,7 @@ public: RParenLoc); } - /// \brief Build a new sizeof, alignof or vec_step expression with a + /// Build a new sizeof, alignof or vec_step expression with a /// type argument. /// /// By default, performs semantic analysis to build the new expression. @@ -2167,7 +2177,7 @@ public: return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R); } - /// \brief Build a new sizeof, alignof or vec step expression with an + /// Build a new sizeof, alignof or vec step expression with an /// expression argument. /// /// By default, performs semantic analysis to build the new expression. @@ -2183,7 +2193,7 @@ public: return Result; } - /// \brief Build a new array subscript expression. + /// Build a new array subscript expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2196,7 +2206,7 @@ public: RBracketLoc); } - /// \brief Build a new array section expression. + /// Build a new array section expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2208,7 +2218,7 @@ public: ColonLoc, Length, RBracketLoc); } - /// \brief Build a new call expression. + /// Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2220,7 +2230,7 @@ public: Args, RParenLoc, ExecConfig); } - /// \brief Build a new member access expression. + /// Build a new member access expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2239,7 +2249,6 @@ public: // We have a reference to an unnamed field. This is always the // base of an anonymous struct/union member access, i.e. the // field is always of record type. - assert(!QualifierLoc && "Can't have an unnamed field with a qualifier!"); assert(Member->getType()->isRecordType() && "unnamed member not of record type?"); @@ -2250,11 +2259,11 @@ public: if (BaseResult.isInvalid()) return ExprError(); Base = BaseResult.get(); - ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind(); - MemberExpr *ME = new (getSema().Context) - MemberExpr(Base, isArrow, OpLoc, Member, MemberNameInfo, - cast<FieldDecl>(Member)->getType(), VK, OK_Ordinary); - return ME; + + CXXScopeSpec EmptySS; + return getSema().BuildFieldReferenceExpr( + Base, isArrow, OpLoc, EmptySS, cast<FieldDecl>(Member), + DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), MemberNameInfo); } CXXScopeSpec SS; @@ -2279,7 +2288,7 @@ public: /*S*/nullptr); } - /// \brief Build a new binary operator expression. + /// Build a new binary operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2289,7 +2298,7 @@ public: return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS); } - /// \brief Build a new conditional operator expression. + /// Build a new conditional operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2302,7 +2311,7 @@ public: LHS, RHS); } - /// \brief Build a new C-style cast expression. + /// Build a new C-style cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2314,7 +2323,7 @@ public: SubExpr); } - /// \brief Build a new compound literal expression. + /// Build a new compound literal expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2326,7 +2335,7 @@ public: Init); } - /// \brief Build a new extended vector element access expression. + /// Build a new extended vector element access expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2346,27 +2355,17 @@ public: /*S*/ nullptr); } - /// \brief Build a new initializer list expression. + /// Build a new initializer list expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildInitList(SourceLocation LBraceLoc, MultiExprArg Inits, - SourceLocation RBraceLoc, - QualType ResultTy) { - ExprResult Result - = SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc); - if (Result.isInvalid() || ResultTy->isDependentType()) - return Result; - - // Patch in the result type we were given, which may have been computed - // when the initial InitListExpr was built. - InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get()); - ILE->setType(ResultTy); - return Result; + SourceLocation RBraceLoc) { + return SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc); } - /// \brief Build a new designated initializer expression. + /// Build a new designated initializer expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2384,7 +2383,7 @@ public: return Result; } - /// \brief Build a new value-initialized expression. + /// Build a new value-initialized expression. /// /// By default, builds the implicit value initialization without performing /// any semantic analysis. Subclasses may override this routine to provide @@ -2393,7 +2392,7 @@ public: return new (SemaRef.Context) ImplicitValueInitExpr(T); } - /// \brief Build a new \c va_arg expression. + /// Build a new \c va_arg expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2405,7 +2404,7 @@ public: RParenLoc); } - /// \brief Build a new expression list in parentheses. + /// Build a new expression list in parentheses. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2415,7 +2414,7 @@ public: return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs); } - /// \brief Build a new address-of-label expression. + /// Build a new address-of-label expression. /// /// By default, performs semantic analysis, using the name of the label /// rather than attempting to map the label statement itself. @@ -2425,7 +2424,7 @@ public: return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label); } - /// \brief Build a new GNU statement expression. + /// Build a new GNU statement expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2435,7 +2434,7 @@ public: return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc); } - /// \brief Build a new __builtin_choose_expr expression. + /// Build a new __builtin_choose_expr expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2447,7 +2446,7 @@ public: RParenLoc); } - /// \brief Build a new generic selection expression. + /// Build a new generic selection expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2461,7 +2460,7 @@ public: ControllingExpr, Types, Exprs); } - /// \brief Build a new overloaded operator call expression. + /// Build a new overloaded operator call expression. /// /// By default, performs semantic analysis to build the new expression. /// The semantic analysis provides the behavior of template instantiation, @@ -2475,7 +2474,7 @@ public: Expr *First, Expr *Second); - /// \brief Build a new C++ "named" cast expression, such as static_cast or + /// Build a new C++ "named" cast expression, such as static_cast or /// reinterpret_cast. /// /// By default, this routine dispatches to one of the more-specific routines @@ -2516,7 +2515,7 @@ public: } } - /// \brief Build a new C++ static_cast expression. + /// Build a new C++ static_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2533,7 +2532,7 @@ public: SourceRange(LParenLoc, RParenLoc)); } - /// \brief Build a new C++ dynamic_cast expression. + /// Build a new C++ dynamic_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2550,7 +2549,7 @@ public: SourceRange(LParenLoc, RParenLoc)); } - /// \brief Build a new C++ reinterpret_cast expression. + /// Build a new C++ reinterpret_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2567,7 +2566,7 @@ public: SourceRange(LParenLoc, RParenLoc)); } - /// \brief Build a new C++ const_cast expression. + /// Build a new C++ const_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2584,20 +2583,21 @@ public: SourceRange(LParenLoc, RParenLoc)); } - /// \brief Build a new C++ functional-style cast expression. + /// Build a new C++ functional-style cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, Expr *Sub, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool ListInitialization) { return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc, - MultiExprArg(&Sub, 1), - RParenLoc); + MultiExprArg(&Sub, 1), RParenLoc, + ListInitialization); } - /// \brief Build a new C++ typeid(type) expression. + /// Build a new C++ typeid(type) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2610,7 +2610,7 @@ public: } - /// \brief Build a new C++ typeid(expr) expression. + /// Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2622,7 +2622,7 @@ public: RParenLoc); } - /// \brief Build a new C++ __uuidof(type) expression. + /// Build a new C++ __uuidof(type) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2634,7 +2634,7 @@ public: RParenLoc); } - /// \brief Build a new C++ __uuidof(expr) expression. + /// Build a new C++ __uuidof(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2646,7 +2646,7 @@ public: RParenLoc); } - /// \brief Build a new C++ "this" expression. + /// Build a new C++ "this" expression. /// /// By default, builds a new "this" expression without performing any /// semantic analysis. Subclasses may override this routine to provide @@ -2658,7 +2658,7 @@ public: return new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, isImplicit); } - /// \brief Build a new C++ throw expression. + /// Build a new C++ throw expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2667,7 +2667,7 @@ public: return getSema().BuildCXXThrow(ThrowLoc, Sub, IsThrownVariableInScope); } - /// \brief Build a new C++ default-argument expression. + /// Build a new C++ default-argument expression. /// /// By default, builds a new default-argument expression, which does not /// require any semantic analysis. Subclasses may override this routine to @@ -2677,7 +2677,7 @@ public: return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param); } - /// \brief Build a new C++11 default-initialization expression. + /// Build a new C++11 default-initialization expression. /// /// By default, builds a new default field initialization expression, which /// does not require any semantic analysis. Subclasses may override this @@ -2687,18 +2687,18 @@ public: return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field); } - /// \brief Build a new C++ zero-initialization expression. + /// Build a new C++ zero-initialization expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - None, RParenLoc); + return getSema().BuildCXXTypeConstructExpr( + TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false); } - /// \brief Build a new C++ "new" expression. + /// Build a new C++ "new" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2725,7 +2725,7 @@ public: Initializer); } - /// \brief Build a new C++ "delete" expression. + /// Build a new C++ "delete" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2737,7 +2737,7 @@ public: Operand); } - /// \brief Build a new type trait expression. + /// Build a new type trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2748,7 +2748,7 @@ public: return getSema().BuildTypeTrait(Trait, StartLoc, Args, RParenLoc); } - /// \brief Build a new array type trait expression. + /// Build a new array type trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2760,7 +2760,7 @@ public: return getSema().BuildArrayTypeTrait(Trait, StartLoc, TSInfo, DimExpr, RParenLoc); } - /// \brief Build a new expression trait expression. + /// Build a new expression trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2771,7 +2771,7 @@ public: return getSema().BuildExpressionTrait(Trait, StartLoc, Queried, RParenLoc); } - /// \brief Build a new (previously unresolved) declaration reference + /// Build a new (previously unresolved) declaration reference /// expression. /// /// By default, performs semantic analysis to build the new expression. @@ -2794,7 +2794,7 @@ public: SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI); } - /// \brief Build a new template-id expression. + /// Build a new template-id expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2807,7 +2807,7 @@ public: TemplateArgs); } - /// \brief Build a new object-construction expression. + /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2837,7 +2837,7 @@ public: ParenRange); } - /// \brief Build a new implicit construction via inherited constructor + /// Build a new implicit construction via inherited constructor /// expression. ExprResult RebuildCXXInheritedCtorInitExpr(QualType T, SourceLocation Loc, CXXConstructorDecl *Constructor, @@ -2847,35 +2847,33 @@ public: Loc, T, Constructor, ConstructsVBase, InheritedFromVBase); } - /// \brief Build a new object-construction expression. + /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXTemporaryObjectExpr(TypeSourceInfo *TSInfo, - SourceLocation LParenLoc, + SourceLocation LParenOrBraceLoc, MultiExprArg Args, - SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, - LParenLoc, - Args, - RParenLoc); + SourceLocation RParenOrBraceLoc, + bool ListInitialization) { + return getSema().BuildCXXTypeConstructExpr( + TSInfo, LParenOrBraceLoc, Args, RParenOrBraceLoc, ListInitialization); } - /// \brief Build a new object-construction expression. + /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXUnresolvedConstructExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, MultiExprArg Args, - SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, - LParenLoc, - Args, - RParenLoc); + SourceLocation RParenLoc, + bool ListInitialization) { + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, Args, + RParenLoc, ListInitialization); } - /// \brief Build a new member reference expression. + /// Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2899,7 +2897,7 @@ public: TemplateArgs, /*S*/nullptr); } - /// \brief Build a new member reference expression. + /// Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2921,7 +2919,7 @@ public: R, TemplateArgs, /*S*/nullptr); } - /// \brief Build a new noexcept expression. + /// Build a new noexcept expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2929,7 +2927,7 @@ public: return SemaRef.BuildCXXNoexceptExpr(Range.getBegin(), Arg, Range.getEnd()); } - /// \brief Build a new expression to compute the length of a parameter pack. + /// Build a new expression to compute the length of a parameter pack. ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, @@ -2940,7 +2938,7 @@ public: RParenLoc, Length, PartialArgs); } - /// \brief Build a new Objective-C boxed expression. + /// Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2948,7 +2946,7 @@ public: return getSema().BuildObjCBoxedExpr(SR, ValueExpr); } - /// \brief Build a new Objective-C array literal. + /// Build a new Objective-C array literal. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2966,7 +2964,7 @@ public: getterMethod, setterMethod); } - /// \brief Build a new Objective-C dictionary literal. + /// Build a new Objective-C dictionary literal. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2975,7 +2973,7 @@ public: return getSema().BuildObjCDictionaryLiteral(Range, Elements); } - /// \brief Build a new Objective-C \@encode expression. + /// Build a new Objective-C \@encode expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2985,7 +2983,7 @@ public: return SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo, RParenLoc); } - /// \brief Build a new Objective-C class message. + /// Build a new Objective-C class message. ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, ArrayRef<SourceLocation> SelectorLocs, @@ -3000,7 +2998,7 @@ public: RBracLoc, Args); } - /// \brief Build a new Objective-C instance message. + /// Build a new Objective-C instance message. ExprResult RebuildObjCMessageExpr(Expr *Receiver, Selector Sel, ArrayRef<SourceLocation> SelectorLocs, @@ -3015,7 +3013,7 @@ public: RBracLoc, Args); } - /// \brief Build a new Objective-C instance/class message to 'super'. + /// Build a new Objective-C instance/class message to 'super'. ExprResult RebuildObjCMessageExpr(SourceLocation SuperLoc, Selector Sel, ArrayRef<SourceLocation> SelectorLocs, @@ -3038,7 +3036,7 @@ public: } - /// \brief Build a new Objective-C ivar reference expression. + /// Build a new Objective-C ivar reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3058,7 +3056,7 @@ public: return Result; } - /// \brief Build a new Objective-C property reference expression. + /// Build a new Objective-C property reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3077,7 +3075,7 @@ public: /*S=*/nullptr); } - /// \brief Build a new Objective-C property reference expression. + /// Build a new Objective-C property reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3093,7 +3091,7 @@ public: PropertyLoc, Base)); } - /// \brief Build a new Objective-C "isa" expression. + /// Build a new Objective-C "isa" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3110,7 +3108,7 @@ public: /*S=*/nullptr); } - /// \brief Build a new shuffle vector expression. + /// Build a new shuffle vector expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3142,7 +3140,7 @@ public: return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.get())); } - /// \brief Build a new convert vector expression. + /// Build a new convert vector expression. ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc, Expr *SrcExpr, TypeSourceInfo *DstTInfo, SourceLocation RParenLoc) { @@ -3150,7 +3148,7 @@ public: BuiltinLoc, RParenLoc); } - /// \brief Build a new template argument pack expansion. + /// Build a new template argument pack expansion. /// /// By default, performs semantic analysis to build a new pack expansion /// for a template argument. Subclasses may override this routine to provide @@ -3198,7 +3196,7 @@ public: return TemplateArgumentLoc(); } - /// \brief Build a new expression pack expansion. + /// Build a new expression pack expansion. /// /// By default, performs semantic analysis to build a new pack expansion /// for an expression. Subclasses may override this routine to provide @@ -3208,7 +3206,7 @@ public: return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } - /// \brief Build a new C++1z fold-expression. + /// Build a new C++1z fold-expression. /// /// By default, performs semantic analysis in order to build a new fold /// expression. @@ -3220,7 +3218,7 @@ public: RHS, RParenLoc); } - /// \brief Build an empty C++1z fold-expression with the given operator. + /// 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. @@ -3229,7 +3227,7 @@ public: return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } - /// \brief Build a new atomic operation expression. + /// Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3394,11 +3392,10 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, /*IsCall*/true, NewArgs, &ArgChanged)) return ExprError(); - // If this was list initialization, revert to list form. + // If this was list initialization, revert to syntactic list form. if (Construct->isListInitialization()) return getDerived().RebuildInitList(Construct->getLocStart(), NewArgs, - Construct->getLocEnd(), - Construct->getType()); + Construct->getLocEnd()); // Build a ParenListExpr to represent anything else. SourceRange Parens = Construct->getParenOrBraceRange(); @@ -3765,8 +3762,12 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, ObjectType.isNull()) return Name; + // FIXME: Preserve the location of the "template" keyword. + SourceLocation TemplateKWLoc = NameLoc; + if (DTN->isIdentifier()) { return getDerived().RebuildTemplateName(SS, + TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType, @@ -3774,7 +3775,8 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, AllowInjectedClassName); } - return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc, + return getDerived().RebuildTemplateName(SS, TemplateKWLoc, + DTN->getOperator(), NameLoc, ObjectType, AllowInjectedClassName); } @@ -3866,6 +3868,10 @@ template<typename Derived> bool TreeTransform<Derived>::TransformTemplateArgument( const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, bool Uneval) { + EnterExpressionEvaluationContext EEEC( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, /*ExprContext=*/ + Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); const TemplateArgument &Arg = Input.getArgument(); switch (Arg.getKind()) { case TemplateArgument::Null: @@ -3933,7 +3939,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( return true; } -/// \brief Iterator adaptor that invents template argument location information +/// Iterator adaptor that invents template argument location information /// for each of the template arguments in its underlying iterator. template<typename Derived, typename InputIterator> class TemplateArgumentLocInventIterator { @@ -4353,6 +4359,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope( TemplateName Template = getDerived().RebuildTemplateName(SS, + SpecTL.getTemplateKeywordLoc(), *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup, @@ -4752,6 +4759,44 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, return Result; } +template <typename Derived> +QualType TreeTransform<Derived>::TransformDependentVectorType( + TypeLocBuilder &TLB, DependentVectorTypeLoc TL) { + const DependentVectorType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + ExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + Size = SemaRef.ActOnConstantExpression(Size); + if (Size.isInvalid()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || + Size.get() != T->getSizeExpr()) { + Result = getDerived().RebuildDependentVectorType( + ElementType, Size.get(), T->getAttributeLoc(), T->getVectorKind()); + if (Result.isNull()) + return QualType(); + } + + // Result might be dependent or not. + if (isa<DependentVectorType>(Result)) { + DependentVectorTypeLoc NewTL = + TLB.push<DependentVectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } else { + VectorTypeLoc NewTL = TLB.push<VectorTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } + + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( TypeLocBuilder &TLB, @@ -5277,30 +5322,23 @@ bool TreeTransform<Derived>::TransformExceptionSpec( assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated); // Instantiate a dynamic noexcept expression, if any. - if (ESI.Type == EST_ComputedNoexcept) { + if (isComputedNoexcept(ESI.Type)) { EnterExpressionEvaluationContext Unevaluated( getSema(), Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); if (NoexceptExpr.isInvalid()) return true; - // FIXME: This is bogus, a noexcept expression is not a condition. - NoexceptExpr = getSema().CheckBooleanCondition(Loc, NoexceptExpr.get()); + ExceptionSpecificationType EST = ESI.Type; + NoexceptExpr = + getSema().ActOnNoexceptSpec(Loc, NoexceptExpr.get(), EST); 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()) + if (ESI.NoexceptExpr != NoexceptExpr.get() || EST != ESI.Type) Changed = true; ESI.NoexceptExpr = NoexceptExpr.get(); + ESI.Type = EST; } if (ESI.Type != EST_Dynamic) @@ -5507,7 +5545,7 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, // decltype expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr, - /*IsDecltype=*/true); + Sema::ExpressionEvaluationContextRecord::EK_Decltype); ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); if (E.isInvalid()) @@ -5778,7 +5816,7 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB, return Result; } - /// \brief Simple iterator that traverses the template arguments in a + /// Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. /// /// This iterator is intended to be used with the iterator form of @@ -6158,8 +6196,8 @@ TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, return QualType(); QualType Result = getDerived().RebuildDependentTemplateSpecializationType( - T->getKeyword(), QualifierLoc, T->getIdentifier(), - TL.getTemplateNameLoc(), NewTemplateArgs, + T->getKeyword(), QualifierLoc, TL.getTemplateKeywordLoc(), + T->getIdentifier(), TL.getTemplateNameLoc(), NewTemplateArgs, /*AllowInjectedClassName*/ false); if (Result.isNull()) return QualType(); @@ -6487,13 +6525,13 @@ TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) { // Transform the left-hand case value. LHS = getDerived().TransformExpr(S->getLHS()); - LHS = SemaRef.ActOnConstantExpression(LHS); + LHS = SemaRef.ActOnCaseExpr(S->getCaseLoc(), LHS); if (LHS.isInvalid()) return StmtError(); // Transform the right-hand case value (for the GNU case-range extension). RHS = getDerived().TransformExpr(S->getRHS()); - RHS = SemaRef.ActOnConstantExpression(RHS); + RHS = SemaRef.ActOnCaseExpr(S->getCaseLoc(), RHS); if (RHS.isInvalid()) return StmtError(); } @@ -6956,6 +6994,8 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { // The new CoroutinePromise object needs to be built and put into the current // FunctionScopeInfo before any transformations or rebuilding occurs. + if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation())) + return StmtError(); auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation()); if (!Promise) return StmtError(); @@ -7046,8 +7086,6 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { Builder.ReturnStmt = Res.get(); } } - if (!Builder.buildParameterMoves()) - return StmtError(); return getDerived().RebuildCoroutineBodyStmt(Builder); } @@ -7642,11 +7680,7 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective( StmtResult Body; { Sema::CompoundScopeRAII CompoundScope(getSema()); - int ThisCaptureLevel = - Sema::getOpenMPCaptureLevels(D->getDirectiveKind()); - Stmt *CS = D->getAssociatedStmt(); - while (--ThisCaptureLevel >= 0) - CS = cast<CapturedStmt>(CS)->getCapturedStmt(); + Stmt *CS = D->getInnermostCapturedStmt()->getCapturedStmt(); Body = getDerived().TransformStmt(CS); } AssociatedStmt = @@ -8905,6 +8939,12 @@ TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { return E; } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformFixedPointLiteral( + FixedPointLiteral *E) { + return E; +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { @@ -8986,7 +9026,7 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { E->getRParen()); } -/// \brief The operand of a unary address-of operator has special rules: it's +/// The operand of a unary address-of operator has special rules: it's /// allowed to refer to a non-static member of a class even if there's no 'this' /// object available. template<typename Derived> @@ -9517,7 +9557,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { } return getDerived().RebuildInitList(E->getLBraceLoc(), Inits, - E->getRBraceLoc(), E->getType()); + E->getRBraceLoc()); } template<typename Derived> @@ -9685,7 +9725,7 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { E->getRParenLoc()); } -/// \brief Transform an address-of-label expression. +/// Transform an address-of-label expression. /// /// By default, the transformation of an address-of-label expression always /// rebuilds the expression, so that the label identifier can be resolved to @@ -9951,7 +9991,8 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return getDerived().RebuildCXXFunctionalCastExpr(Type, E->getLParenLoc(), SubExpr.get(), - E->getRParenLoc()); + E->getRParenLoc(), + E->isListInitialization()); } template<typename Derived> @@ -10403,7 +10444,7 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, // the corresponding pack is empty if (AllEmptyPacks && !RequiresADL) { getSema().Diag(Old->getNameLoc(), diag::err_using_pack_expansion_empty) - << isa<UnresolvedMemberExpr>(Old) << Old->getNameInfo().getName(); + << isa<UnresolvedMemberExpr>(Old) << Old->getName(); return true; } @@ -10814,7 +10855,7 @@ ExprResult TreeTransform<Derived>::TransformCXXInheritedCtorInitExpr( E->constructsVBase(), E->inheritedFromVBase()); } -/// \brief Transform a C++ temporary-binding expression. +/// Transform a C++ temporary-binding expression. /// /// Since CXXBindTemporaryExpr nodes are implicitly generated, we just /// transform the subexpression and return that. @@ -10824,7 +10865,7 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } -/// \brief Transform a C++ expression that contains cleanups that should +/// Transform a C++ expression that contains cleanups that should /// be run after the expression is evaluated. /// /// Since ExprWithCleanups nodes are implicitly generated, we @@ -10867,11 +10908,12 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( return SemaRef.MaybeBindToTemporary(E); } - // FIXME: Pass in E->isListInitialization(). - return getDerived().RebuildCXXTemporaryObjectExpr(T, - /*FIXME:*/T->getTypeLoc().getEndLoc(), - Args, - E->getLocEnd()); + // FIXME: We should just pass E->isListInitialization(), but we're not + // prepared to handle list-initialization without a child InitListExpr. + SourceLocation LParenLoc = T->getTypeLoc().getEndLoc(); + return getDerived().RebuildCXXTemporaryObjectExpr( + T, LParenLoc, Args, E->getLocEnd(), + /*ListInitialization=*/LParenLoc.isInvalid()); } template<typename Derived> @@ -11157,10 +11199,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( return E; // FIXME: we're faking the locations of the commas - return getDerived().RebuildCXXUnresolvedConstructExpr(T, - E->getLParenLoc(), - Args, - E->getRParenLoc()); + return getDerived().RebuildCXXUnresolvedConstructExpr( + T, E->getLParenLoc(), Args, E->getRParenLoc(), E->isListInitialization()); } template<typename Derived> @@ -11408,8 +11448,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { ArgStorage = TemplateArgument(TemplateName(TTPD), None); } else { auto *VD = cast<ValueDecl>(Pack); - ExprResult DRE = getSema().BuildDeclRefExpr(VD, VD->getType(), - VK_RValue, E->getPackLoc()); + ExprResult DRE = getSema().BuildDeclRefExpr( + VD, VD->getType().getNonLValueExprType(getSema().Context), + VD->getType()->isReferenceType() ? VK_LValue : VK_RValue, + E->getPackLoc()); if (DRE.isInvalid()) return ExprError(); ArgStorage = new (getSema().Context) PackExpansionExpr( @@ -12386,6 +12428,13 @@ TreeTransform<Derived>::RebuildVectorType(QualType ElementType, return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind); } +template <typename Derived> +QualType TreeTransform<Derived>::RebuildDependentVectorType( + QualType ElementType, Expr *SizeExpr, SourceLocation AttributeLoc, + VectorType::VectorKind VecKind) { + return SemaRef.BuildVectorType(ElementType, SizeExpr, AttributeLoc); +} + template<typename Derived> QualType TreeTransform<Derived>::RebuildExtVectorType(QualType ElementType, unsigned NumElements, @@ -12532,6 +12581,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, @@ -12540,7 +12590,6 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; - SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, TemplateName, ParsedType::make(ObjectType), @@ -12552,6 +12601,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, SourceLocation NameLoc, QualType ObjectType, @@ -12560,7 +12610,6 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, // FIXME: Bogus location information. SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); - SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, Name, @@ -12609,9 +12658,11 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // -> is never a builtin operation. return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc); } else if (Second == nullptr || isPostIncDec) { - if (!First->getType()->isOverloadableType()) { - // The argument is not of overloadable type, so try to create a - // built-in unary operation. + if (!First->getType()->isOverloadableType() || + (Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) { + // The argument is not of overloadable type, or this is an expression + // of the form &Class::member, so try to create a built-in unary + // operation. UnaryOperatorKind Opc = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h index 9c77045d2e12..a088fe9de667 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h +++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h @@ -83,7 +83,7 @@ class TypeLocBuilder { NumBytesAtAlign4 = NumBytesAtAlign8 = 0; } - /// \brief Tell the TypeLocBuilder that the type it is storing has been + /// Tell the TypeLocBuilder that the type it is storing has been /// modified in some safe way that doesn't affect type-location information. void TypeWasModifiedSafely(QualType T) { #ifndef NDEBUG @@ -112,7 +112,7 @@ class TypeLocBuilder { return DI; } - /// \brief Copies the type-location information to the given AST context and + /// Copies the type-location information to the given AST context and /// returns a \c TypeLoc referring into the AST context. TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) { #ifndef NDEBUG @@ -132,7 +132,7 @@ private: /// Grow to the given capacity. void grow(size_t NewCapacity); - /// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder + /// Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder /// object. /// /// The resulting \c TypeLoc should only be used so long as the |