diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:03:47 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:04:23 +0000 |
commit | 7fa27ce4a07f19b07799a767fc29416f3b625afb (patch) | |
tree | 27825c83636c4de341eb09a74f49f5d38a15d165 /clang/lib/Sema | |
parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) | |
download | src-7fa27ce4a07f19b07799a767fc29416f3b625afb.tar.gz src-7fa27ce4a07f19b07799a767fc29416f3b625afb.zip |
Diffstat (limited to 'clang/lib/Sema')
46 files changed, 7751 insertions, 3612 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 4530154ac944..43b13e0ec4d2 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -25,6 +26,8 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/CalledOnceCheck.h" #include "clang/Analysis/Analyses/Consumed.h" @@ -35,6 +38,7 @@ #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" @@ -43,6 +47,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -66,11 +71,17 @@ namespace { public: UnreachableCodeHandler(Sema &s) : S(s) {} - void HandleUnreachable(reachable_code::UnreachableKind UK, - SourceLocation L, - SourceRange SilenceableCondVal, - SourceRange R1, - SourceRange R2) override { + void HandleUnreachable(reachable_code::UnreachableKind UK, SourceLocation L, + SourceRange SilenceableCondVal, SourceRange R1, + SourceRange R2, bool HasFallThroughAttr) override { + // If the diagnosed code is `[[fallthrough]];` and + // `-Wunreachable-code-fallthrough` is enabled, suppress `code will never + // be executed` warning to avoid generating diagnostic twice + if (HasFallThroughAttr && + !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr, + SourceLocation())) + return; + // Avoid reporting multiple unreachable code diagnostics that are // triggered by the same conditional value. if (PreviousSilenceableCondVal.isValid() && @@ -574,6 +585,7 @@ struct CheckFallThroughDiagnostics { D.diag_AlwaysFallThrough_HasNoReturn = 0; D.diag_AlwaysFallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid_coroutine; + D.diag_NeverFallThroughOrReturn = 0; D.funMode = Coroutine; return D; } @@ -2149,9 +2161,11 @@ public: namespace { class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { Sema &S; + bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions? public: - UnsafeBufferUsageReporter(Sema &S) : S(S) {} + UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions) + : S(S), SuggestSuggestions(SuggestSuggestions) {} void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl) override { @@ -2184,25 +2198,113 @@ public: MsgParam = 1; } } else { + if (isa<CallExpr>(Operation)) { + // note_unsafe_buffer_operation doesn't have this mode yet. + assert(!IsRelatedToDecl && "Not implemented yet!"); + MsgParam = 3; + } Loc = Operation->getBeginLoc(); Range = Operation->getSourceRange(); } - if (IsRelatedToDecl) + if (IsRelatedToDecl) { + assert(!SuggestSuggestions && + "Variables blamed for unsafe buffer usage without suggestions!"); S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; - else + } else { S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range; + if (SuggestSuggestions) { + S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled); + } + } } - // FIXME: rename to handleUnsafeVariable - void handleFixableVariable(const VarDecl *Variable, + void handleUnsafeVariableGroup(const VarDecl *Variable, + const DefMapTy &VarGrpMap, FixItList &&Fixes) override { - const auto &D = - S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable); - D << Variable; - D << (Variable->getType()->isPointerType() ? 0 : 1); - D << Variable->getSourceRange(); - for (const auto &F : Fixes) - D << F; + assert(!SuggestSuggestions && + "Unsafe buffer usage fixits displayed without suggestions!"); + S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable) + << Variable << (Variable->getType()->isPointerType() ? 0 : 1) + << Variable->getSourceRange(); + if (!Fixes.empty()) { + const auto VarGroupForVD = VarGrpMap.find(Variable)->second; + unsigned FixItStrategy = 0; // For now we only have 'std::span' strategy + const auto &FD = S.Diag(Variable->getLocation(), + diag::note_unsafe_buffer_variable_fixit_group); + + FD << Variable << FixItStrategy; + std::string AllVars = ""; + if (VarGroupForVD.size() > 1) { + if (VarGroupForVD.size() == 2) { + if (VarGroupForVD[0] == Variable) { + AllVars.append("'" + VarGroupForVD[1]->getName().str() + "'"); + } else { + AllVars.append("'" + VarGroupForVD[0]->getName().str() + "'"); + } + } else { + bool first = false; + if (VarGroupForVD.size() == 3) { + for (const VarDecl * V : VarGroupForVD) { + if (V == Variable) { + continue; + } + if (!first) { + first = true; + AllVars.append("'" + V->getName().str() + "'" + " and "); + } else { + AllVars.append("'" + V->getName().str() + "'"); + } + } + } else { + for (const VarDecl * V : VarGroupForVD) { + if (V == Variable) { + continue; + } + if (VarGroupForVD.back() != V) { + AllVars.append("'" + V->getName().str() + "'" + ", "); + } else { + AllVars.append("and '" + V->getName().str() + "'"); + } + } + } + } + FD << AllVars << 1; + } else { + FD << "" << 0; + } + + for (const auto &F : Fixes) + FD << F; + } + } + + bool isSafeBufferOptOut(const SourceLocation &Loc) const override { + return S.PP.isSafeBufferOptOut(S.getSourceManager(), Loc); + } + + // Returns the text representation of clang::unsafe_buffer_usage attribute. + // `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace + // characters. + std::string + getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, + StringRef WSSuffix = "") const override { + Preprocessor &PP = S.getPreprocessor(); + TokenValue ClangUnsafeBufferUsageTokens[] = { + tok::l_square, + tok::l_square, + PP.getIdentifierInfo("clang"), + tok::coloncolon, + PP.getIdentifierInfo("unsafe_buffer_usage"), + tok::r_square, + tok::r_square}; + + StringRef MacroName; + + // The returned macro (it returns) is guaranteed not to be function-like: + MacroName = PP.getLastMacroWithSpelling(Loc, ClangUnsafeBufferUsageTokens); + if (MacroName.empty()) + MacroName = "[[clang::unsafe_buffer_usage]]"; + return MacroName.str() + WSSuffix.str(); } }; } // namespace @@ -2271,6 +2373,94 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { S.Diag(D.Loc, D.PD); } +// An AST Visitor that calls a callback function on each callable DEFINITION +// that is NOT in a dependent context: +class CallableVisitor : public RecursiveASTVisitor<CallableVisitor> { +private: + llvm::function_ref<void(const Decl *)> Callback; + +public: + CallableVisitor(llvm::function_ref<void(const Decl *)> Callback) + : Callback(Callback) {} + + bool VisitFunctionDecl(FunctionDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + // `FunctionDecl->hasBody()` returns true if the function has a body + // somewhere defined. But we want to know if this `Node` has a body + // child. So we use `doesThisDeclarationHaveABody`: + if (Node->doesThisDeclarationHaveABody()) + Callback(Node); + return true; + } + + bool VisitBlockDecl(BlockDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + Callback(Node); + return true; + } + + bool VisitObjCMethodDecl(ObjCMethodDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + if (Node->hasBody()) + Callback(Node); + return true; + } + + bool VisitLambdaExpr(LambdaExpr *Node) { + return VisitFunctionDecl(Node->getCallOperator()); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return false; } +}; + +void clang::sema::AnalysisBasedWarnings::IssueWarnings( + TranslationUnitDecl *TU) { + if (!TU) + return; // This is unexpected, give up quietly. + + DiagnosticsEngine &Diags = S.getDiagnostics(); + + if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings()) + // exit if having uncompilable errors or ignoring all warnings: + return; + + DiagnosticOptions &DiagOpts = Diags.getDiagnosticOptions(); + + // UnsafeBufferUsage analysis settings. + bool UnsafeBufferUsageCanEmitSuggestions = S.getLangOpts().CPlusPlus20; + bool UnsafeBufferUsageShouldEmitSuggestions = // Should != Can. + UnsafeBufferUsageCanEmitSuggestions && + DiagOpts.ShowSafeBufferUsageSuggestions; + bool UnsafeBufferUsageShouldSuggestSuggestions = + UnsafeBufferUsageCanEmitSuggestions && + !DiagOpts.ShowSafeBufferUsageSuggestions; + UnsafeBufferUsageReporter R(S, UnsafeBufferUsageShouldSuggestSuggestions); + + // The Callback function that performs analyses: + auto CallAnalyzers = [&](const Decl *Node) -> void { + // Perform unsafe buffer usage analysis: + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, + Node->getBeginLoc()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, + Node->getBeginLoc())) { + clang::checkUnsafeBufferUsage(Node, R, + UnsafeBufferUsageShouldEmitSuggestions); + } + + // More analysis ... + }; + // Emit per-function analysis-based warnings that require the whole-TU + // reasoning. Check if any of them is enabled at all before scanning the AST: + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) { + CallableVisitor(CallAnalyzers).TraverseTranslationUnitDecl(TU); + } +} + void clang::sema::AnalysisBasedWarnings::IssueWarnings( sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, const Decl *D, QualType BlockType) { @@ -2496,16 +2686,9 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // Check for throw out of non-throwing function. if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc())) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) + if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); - // Emit unsafe buffer usage warnings and fixits. - if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { - UnsafeBufferUsageReporter R(S); - checkUnsafeBufferUsage(D, R); - } - // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index b91291cfea0b..202417798712 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -83,6 +83,7 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_ObjCCategoryName: case CCC_IncludedFile: case CCC_Attribute: + case CCC_ObjCClassForwardDecl: return false; } @@ -166,6 +167,8 @@ StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) { return "Attribute"; case CCKind::CCC_Recovery: return "Recovery"; + case CCKind::CCC_ObjCClassForwardDecl: + return "ObjCClassForwardDecl"; } llvm_unreachable("Invalid CodeCompletionContext::Kind!"); } diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 3ff4e75b5694..f29f92aceb50 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -71,7 +71,6 @@ struct BuiltinTypeDeclBuilder { // Don't let anyone derive from built-in types. Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(), - AttributeCommonInfo::AS_Keyword, FinalAttr::Keyword_final)); } @@ -286,8 +285,7 @@ struct BuiltinTypeDeclBuilder { MethodDecl->setLexicalDeclContext(Record); MethodDecl->setAccess(AccessSpecifier::AS_public); MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit( - AST, SourceRange(), AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::CXX11_clang_always_inline)); + AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline)); Record->addDecl(MethodDecl); return *this; diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 607dc3111e9d..773cef65dcbd 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -231,9 +231,12 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) { return toIdDeclInfo(Ptr)->RemoveDecl(D); } -/// begin - Returns an iterator for decls with name 'Name'. -IdentifierResolver::iterator -IdentifierResolver::begin(DeclarationName Name) { +llvm::iterator_range<IdentifierResolver::iterator> +IdentifierResolver::decls(DeclarationName Name) { + return {begin(Name), end()}; +} + +IdentifierResolver::iterator IdentifierResolver::begin(DeclarationName Name) { if (IdentifierInfo *II = Name.getAsIdentifierInfo()) readingIdentifier(*II); diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index bd2ce9a93e7e..45ff36d5fe23 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -72,10 +72,9 @@ class JumpScopeChecker { SmallVector<Stmt*, 16> Jumps; SmallVector<Stmt*, 4> IndirectJumps; - SmallVector<Stmt*, 4> AsmJumps; + SmallVector<LabelDecl *, 4> IndirectJumpTargets; SmallVector<AttributedStmt *, 4> MustTailStmts; - SmallVector<LabelDecl*, 4> IndirectJumpTargets; - SmallVector<LabelDecl*, 4> AsmJumpTargets; + public: JumpScopeChecker(Stmt *Body, Sema &S); private: @@ -86,7 +85,7 @@ private: void BuildScopeInformation(Stmt *S, unsigned &origParentScope); void VerifyJumps(); - void VerifyIndirectOrAsmJumps(bool IsAsmGoto); + void VerifyIndirectJumps(); void VerifyMustTailStmts(); void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes); void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target, @@ -115,8 +114,7 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) // Check that all jumps we saw are kosher. VerifyJumps(); - VerifyIndirectOrAsmJumps(false); - VerifyIndirectOrAsmJumps(true); + VerifyIndirectJumps(); VerifyMustTailStmts(); } @@ -333,11 +331,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // operand (to avoid recording the address-of-label use), which // works only because of the restricted set of expressions which // we detect as constant targets. - if (cast<IndirectGotoStmt>(S)->getConstantTarget()) { - LabelAndGotoScopes[S] = ParentScope; - Jumps.push_back(S); - return; - } + if (cast<IndirectGotoStmt>(S)->getConstantTarget()) + goto RecordJumpScope; LabelAndGotoScopes[S] = ParentScope; IndirectJumps.push_back(S); @@ -354,27 +349,21 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, BuildScopeInformation(Var, ParentScope); ++StmtsToSkip; } + goto RecordJumpScope; + + case Stmt::GCCAsmStmtClass: + if (!cast<GCCAsmStmt>(S)->isAsmGoto()) + break; [[fallthrough]]; case Stmt::GotoStmtClass: + RecordJumpScope: // Remember both what scope a goto is in as well as the fact that we have // it. This makes the second scan not have to walk the AST again. LabelAndGotoScopes[S] = ParentScope; Jumps.push_back(S); break; - case Stmt::GCCAsmStmtClass: - if (auto *GS = dyn_cast<GCCAsmStmt>(S)) - if (GS->isAsmGoto()) { - // Remember both what scope a goto is in as well as the fact that we - // have it. This makes the second scan not have to walk the AST again. - LabelAndGotoScopes[S] = ParentScope; - AsmJumps.push_back(GS); - for (auto *E : GS->labels()) - AsmJumpTargets.push_back(E->getLabel()); - } - break; - case Stmt::IfStmtClass: { IfStmt *IS = cast<IfStmt>(S); if (!(IS->isConstexpr() || IS->isConsteval() || @@ -477,6 +466,21 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, return; } + case Stmt::StmtExprClass: { + // [GNU] + // Jumping into a statement expression with goto or using + // a switch statement outside the statement expression with + // a case or default label inside the statement expression is not permitted. + // Jumping out of a statement expression is permitted. + StmtExpr *SE = cast<StmtExpr>(S); + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_enters_statement_expression, + /*OutDiag=*/0, SE->getBeginLoc())); + BuildScopeInformation(SE->getSubStmt(), NewParentScope); + return; + } + case Stmt::ObjCAtTryStmtClass: { // Disallow jumps into any part of an @try statement by pushing a scope and // walking all sub-stmts in that scope. @@ -666,6 +670,22 @@ void JumpScopeChecker::VerifyJumps() { continue; } + // If an asm goto jumps to a different scope, things like destructors or + // initializers might not be run which may be suprising to users. Perhaps + // this behavior can be changed in the future, but today Clang will not + // generate such code. Produce a diagnostic instead. See also the + // discussion here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110728. + if (auto *G = dyn_cast<GCCAsmStmt>(Jump)) { + for (AddrLabelExpr *L : G->labels()) { + LabelDecl *LD = L->getLabel(); + unsigned JumpScope = LabelAndGotoScopes[G]; + unsigned TargetScope = LabelAndGotoScopes[LD->getStmt()]; + if (JumpScope != TargetScope) + DiagnoseIndirectOrAsmJump(G, JumpScope, LD, TargetScope); + } + continue; + } + // We only get indirect gotos here when they have a constant target. if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) { LabelDecl *Target = IGS->getConstantTarget(); @@ -694,17 +714,16 @@ void JumpScopeChecker::VerifyJumps() { } } -/// VerifyIndirectOrAsmJumps - Verify whether any possible indirect goto or -/// asm goto jump might cross a protection boundary. Unlike direct jumps, -/// indirect or asm goto jumps count cleanups as protection boundaries: -/// since there's no way to know where the jump is going, we can't implicitly -/// run the right cleanups the way we can with direct jumps. -/// Thus, an indirect/asm jump is "trivial" if it bypasses no -/// initializations and no teardowns. More formally, an indirect/asm jump -/// from A to B is trivial if the path out from A to DCA(A,B) is -/// trivial and the path in from DCA(A,B) to B is trivial, where -/// DCA(A,B) is the deepest common ancestor of A and B. -/// Jump-triviality is transitive but asymmetric. +/// VerifyIndirectJumps - Verify whether any possible indirect goto jump might +/// cross a protection boundary. Unlike direct jumps, indirect goto jumps +/// count cleanups as protection boundaries: since there's no way to know where +/// the jump is going, we can't implicitly run the right cleanups the way we +/// can with direct jumps. Thus, an indirect/asm jump is "trivial" if it +/// bypasses no initializations and no teardowns. More formally, an +/// indirect/asm jump from A to B is trivial if the path out from A to DCA(A,B) +/// is trivial and the path in from DCA(A,B) to B is trivial, where DCA(A,B) is +/// the deepest common ancestor of A and B. Jump-triviality is transitive but +/// asymmetric. /// /// A path in is trivial if none of the entered scopes have an InDiag. /// A path out is trivial is none of the exited scopes have an OutDiag. @@ -712,57 +731,45 @@ void JumpScopeChecker::VerifyJumps() { /// Under these definitions, this function checks that the indirect /// jump between A and B is trivial for every indirect goto statement A /// and every label B whose address was taken in the function. -void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) { - SmallVector<Stmt*, 4> GotoJumps = IsAsmGoto ? AsmJumps : IndirectJumps; - if (GotoJumps.empty()) +void JumpScopeChecker::VerifyIndirectJumps() { + if (IndirectJumps.empty()) return; - SmallVector<LabelDecl *, 4> JumpTargets = - IsAsmGoto ? AsmJumpTargets : IndirectJumpTargets; // If there aren't any address-of-label expressions in this function, // complain about the first indirect goto. - if (JumpTargets.empty()) { - assert(!IsAsmGoto &&"only indirect goto can get here"); - S.Diag(GotoJumps[0]->getBeginLoc(), + if (IndirectJumpTargets.empty()) { + S.Diag(IndirectJumps[0]->getBeginLoc(), diag::err_indirect_goto_without_addrlabel); return; } - // Collect a single representative of every scope containing an - // indirect or asm goto. For most code bases, this substantially cuts - // down on the number of jump sites we'll have to consider later. - typedef std::pair<unsigned, Stmt*> JumpScope; + // Collect a single representative of every scope containing an indirect + // goto. For most code bases, this substantially cuts down on the number of + // jump sites we'll have to consider later. + using JumpScope = std::pair<unsigned, Stmt *>; SmallVector<JumpScope, 32> JumpScopes; { llvm::DenseMap<unsigned, Stmt*> JumpScopesMap; - for (SmallVectorImpl<Stmt *>::iterator I = GotoJumps.begin(), - E = GotoJumps.end(); - I != E; ++I) { - Stmt *IG = *I; + for (Stmt *IG : IndirectJumps) { if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG))) continue; unsigned IGScope = LabelAndGotoScopes[IG]; - Stmt *&Entry = JumpScopesMap[IGScope]; - if (!Entry) Entry = IG; + if (!JumpScopesMap.contains(IGScope)) + JumpScopesMap[IGScope] = IG; } JumpScopes.reserve(JumpScopesMap.size()); - for (llvm::DenseMap<unsigned, Stmt *>::iterator I = JumpScopesMap.begin(), - E = JumpScopesMap.end(); - I != E; ++I) - JumpScopes.push_back(*I); + for (auto &Pair : JumpScopesMap) + JumpScopes.emplace_back(Pair); } // Collect a single representative of every scope containing a // label whose address was taken somewhere in the function. // For most code bases, there will be only one such scope. llvm::DenseMap<unsigned, LabelDecl*> TargetScopes; - for (SmallVectorImpl<LabelDecl *>::iterator I = JumpTargets.begin(), - E = JumpTargets.end(); - I != E; ++I) { - LabelDecl *TheLabel = *I; + for (LabelDecl *TheLabel : IndirectJumpTargets) { if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt()))) continue; unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()]; - LabelDecl *&Target = TargetScopes[LabelScope]; - if (!Target) Target = TheLabel; + if (!TargetScopes.contains(LabelScope)) + TargetScopes[LabelScope] = TheLabel; } // For each target scope, make sure it's trivially reachable from @@ -774,11 +781,7 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) { // entered, then verify that every jump scope can be trivially // exitted to reach a scope in S. llvm::BitVector Reachable(Scopes.size(), false); - for (llvm::DenseMap<unsigned,LabelDecl*>::iterator - TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) { - unsigned TargetScope = TI->first; - LabelDecl *TargetLabel = TI->second; - + for (auto [TargetScope, TargetLabel] : TargetScopes) { Reachable.reset(); // Mark all the enclosing scopes from which you can safely jump @@ -799,10 +802,8 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) { // Walk through all the jump sites, checking that they can trivially // reach this label scope. - for (SmallVectorImpl<JumpScope>::iterator - I = JumpScopes.begin(), E = JumpScopes.end(); I != E; ++I) { - unsigned Scope = I->first; - + for (auto [JumpScope, JumpStmt] : JumpScopes) { + unsigned Scope = JumpScope; // Walk out the "scope chain" for this scope, looking for a scope // we've marked reachable. For well-formed code this amortizes // to O(JumpScopes.size() / Scopes.size()): we only iterate @@ -813,7 +814,7 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) { if (Reachable.test(Scope)) { // If we find something reachable, mark all the scopes we just // walked through as reachable. - for (unsigned S = I->first; S != Scope; S = Scopes[S].ParentScope) + for (unsigned S = JumpScope; S != Scope; S = Scopes[S].ParentScope) Reachable.set(S); IsReachable = true; break; @@ -832,7 +833,7 @@ void JumpScopeChecker::VerifyIndirectOrAsmJumps(bool IsAsmGoto) { // Only diagnose if we didn't find something. if (IsReachable) continue; - DiagnoseIndirectOrAsmJump(I->second, I->first, TargetLabel, TargetScope); + DiagnoseIndirectOrAsmJump(JumpStmt, JumpScope, TargetLabel, TargetScope); } } } diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 55e015487f3b..058e22cb2b81 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -341,3 +341,9 @@ bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType( } return false; } + +void MultiplexExternalSemaSource::AssignedLambdaNumbering( + const CXXRecordDecl *Lambda) { + for (auto *Source : Sources) + Source->AssignedLambdaNumbering(Lambda); +} diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index c1e39acb14ec..d7acb589172b 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -19,15 +19,12 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/ManagedStatic.h" #include <cassert> #include <cstddef> #include <utility> using namespace clang; -LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) - IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, IdentifierInfo *Ident) { IdentifierLoc *Result = new (Ctx) IdentifierLoc; @@ -120,13 +117,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) return IgnoredParsedAttrInfo; - // Otherwise this may be an attribute defined by a plugin. First instantiate - // all plugin attributes if we haven't already done so. - static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>> - PluginAttrInstances; - if (PluginAttrInstances->empty()) - for (auto It : ParsedAttrInfoRegistry::entries()) - PluginAttrInstances->emplace_back(It.instantiate()); + // Otherwise this may be an attribute defined by a plugin. // Search for a ParsedAttrInfo whose name and syntax match. std::string FullName = A.getNormalizedFullName(); @@ -134,10 +125,9 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) SyntaxUsed = AttributeCommonInfo::AS_Keyword; - for (auto &Ptr : *PluginAttrInstances) - for (auto &S : Ptr->Spellings) - if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName) - return *Ptr; + for (auto &Ptr : getAttributePluginInstances()) + if (Ptr->hasSpelling(SyntaxUsed, FullName)) + return *Ptr; // If we failed to find a match then return a default ParsedAttrInfo. static const ParsedAttrInfo DefaultParsedAttrInfo( @@ -213,6 +203,11 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const { } bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { + if (isRegularKeywordAttribute()) + // The appurtenance rules are applied strictly for all regular keyword + // atributes. + return false; + assert(isStandardAttributeSyntax()); // We have historically allowed some type attributes with standard attribute diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index c995c7e65f4b..4570d8c615fe 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -70,8 +70,10 @@ void Scope::setFlags(Scope *parent, unsigned flags) { if (flags & BlockScope) BlockParent = this; if (flags & TemplateParamScope) TemplateParamParent = this; - // If this is a prototype scope, record that. - if (flags & FunctionPrototypeScope) PrototypeDepth++; + // If this is a prototype scope, record that. Lambdas have an extra prototype + // scope that doesn't add any depth. + if (flags & FunctionPrototypeScope && !(flags & LambdaScope)) + PrototypeDepth++; if (flags & DeclScope) { if (flags & FunctionPrototypeScope) diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index e313052b3ab3..92ce5137f4f3 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -39,6 +39,7 @@ void FunctionScopeInfo::Clear() { FirstReturnLoc = SourceLocation(); FirstCXXOrObjCTryLoc = SourceLocation(); FirstSEHTryLoc = SourceLocation(); + FoundImmediateEscalatingExpression = false; // Coroutine state FirstCoroutineStmtLoc = SourceLocation(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 0f0305422454..46ae6fba8344 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -33,6 +33,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/MultiplexExternalSemaSource.h" @@ -202,9 +203,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), - StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), - StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr), - MSVCGuidDecl(nullptr), StdSourceLocationImplDecl(nullptr), + StdInitializerList(nullptr), StdCoroutineTraitsCache(nullptr), + CXXTypeInfoDecl(nullptr), StdSourceLocationImplDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr), @@ -218,7 +218,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), - CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { + CurScope(nullptr), Ident_super(nullptr) { assert(pp.TUKind == TUKind); TUScope = nullptr; isConstantEvaluatedOverride = false; @@ -444,6 +444,13 @@ void Sema::Initialize() { #include "clang/Basic/RISCVVTypes.def" } + if (Context.getTargetInfo().getTriple().isWasm() && + Context.getTargetInfo().hasFeature("reference-types")) { +#define WASM_TYPE(Name, Id, SingletonId) \ + addImplicitTypedef(Name, Context.SingletonId); +#include "clang/Basic/WebAssemblyReferenceTypes.def" + } + if (Context.getTargetInfo().hasBuiltinMSVaList()) { DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list"); if (IdResolver.begin(MSVaList) == IdResolver.end()) @@ -778,15 +785,15 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } -static bool isFunctionOrVarDeclExternC(NamedDecl *ND) { - if (auto *FD = dyn_cast<FunctionDecl>(ND)) +static bool isFunctionOrVarDeclExternC(const NamedDecl *ND) { + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) return FD->isExternC(); return cast<VarDecl>(ND)->isExternC(); } /// Determine whether ND is an external-linkage function or variable whose /// type has no linkage. -bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) { +bool Sema::isExternalWithNoLinkageType(const ValueDecl *VD) const { // Note: it's not quite enough to check whether VD has UniqueExternalLinkage, // because we also want to catch the case where its type has VisibleNoLinkage, // which does not affect the linkage of VD. @@ -858,7 +865,7 @@ static void checkUndefinedButUsed(Sema &S) { S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; - for (auto Undef : Undefined) { + for (const auto &Undef : Undefined) { ValueDecl *VD = cast<ValueDecl>(Undef.first); SourceLocation UseLoc = Undef.second; @@ -1024,16 +1031,6 @@ void Sema::ActOnStartOfTranslationUnit() { if (getLangOpts().CPlusPlusModules && getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit) HandleStartOfHeaderUnit(); - else if (getLangOpts().ModulesTS && - (getLangOpts().getCompilingModule() == - LangOptions::CMK_ModuleInterface || - getLangOpts().getCompilingModule() == LangOptions::CMK_None)) { - // We start in an implied global module fragment. - SourceLocation StartOfTU = - SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()); - ActOnGlobalModuleFragmentDecl(StartOfTU); - ModuleScopes.back().ImplicitGlobalModuleFragment = true; - } } void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { @@ -1186,7 +1183,7 @@ void Sema::ActOnEndOfTranslationUnit() { !(isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl))) for (const auto &WI : WeakIDs.second) Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type) - << "'weak'" << ExpectedVariableOrFunction; + << "'weak'" << /*isRegularKeyword=*/0 << ExpectedVariableOrFunction; else for (const auto &WI : WeakIDs.second) Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared) @@ -1205,9 +1202,8 @@ void Sema::ActOnEndOfTranslationUnit() { // A global-module-fragment is only permitted within a module unit. bool DiagnosedMissingModuleDeclaration = false; - if (!ModuleScopes.empty() && - ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment && - !ModuleScopes.back().ImplicitGlobalModuleFragment) { + if (!ModuleScopes.empty() && ModuleScopes.back().Module->Kind == + Module::ExplicitGlobalModuleFragment) { Diag(ModuleScopes.back().BeginLoc, diag::err_module_declaration_missing_after_global_module_introducer); DiagnosedMissingModuleDeclaration = true; @@ -1244,7 +1240,8 @@ void Sema::ActOnEndOfTranslationUnit() { ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. - Stack.append(Mod->submodule_begin(), Mod->submodule_end()); + auto SubmodulesRange = Mod->submodules(); + Stack.append(SubmodulesRange.begin(), SubmodulesRange.end()); } } @@ -1350,10 +1347,14 @@ void Sema::ActOnEndOfTranslationUnit() { DiagD = FD; if (DiagD->isDeleted()) continue; // Deleted functions are supposed to be unused. + SourceRange DiagRange = DiagD->getLocation(); + if (const ASTTemplateArgumentListInfo *ASTTAL = + DiagD->getTemplateSpecializationArgsAsWritten()) + DiagRange.setEnd(ASTTAL->RAngleLoc); if (DiagD->isReferenced()) { if (isa<CXXMethodDecl>(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) - << DiagD; + << DiagD << DiagRange; else { if (FD->getStorageClass() == SC_Static && !FD->isInlineSpecified() && @@ -1361,40 +1362,46 @@ void Sema::ActOnEndOfTranslationUnit() { SourceMgr.getExpansionLoc(FD->getLocation()))) Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) - << DiagD; + << DiagD << DiagRange; else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) - << /*function*/ 0 << DiagD; + << /*function=*/0 << DiagD << DiagRange; } } else { if (FD->getDescribedFunctionTemplate()) Diag(DiagD->getLocation(), diag::warn_unused_template) - << /*function*/ 0 << DiagD; + << /*function=*/0 << DiagD << DiagRange; else Diag(DiagD->getLocation(), isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function : diag::warn_unused_function) - << DiagD; + << DiagD << DiagRange; } } else { const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); if (!DiagD) DiagD = cast<VarDecl>(*I); + SourceRange DiagRange = DiagD->getLocation(); + if (const auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(DiagD)) { + if (const ASTTemplateArgumentListInfo *ASTTAL = + VTSD->getTemplateArgsInfo()) + DiagRange.setEnd(ASTTAL->RAngleLoc); + } if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) - << /*variable*/ 1 << DiagD; + << /*variable=*/1 << DiagD << DiagRange; + } else if (DiagD->getDescribedVarTemplate()) { + Diag(DiagD->getLocation(), diag::warn_unused_template) + << /*variable=*/1 << DiagD << DiagRange; } else if (DiagD->getType().isConstQualified()) { const SourceManager &SM = SourceMgr; if (SM.getMainFileID() != SM.getFileID(DiagD->getLocation()) || !PP.getLangOpts().IsHeaderFile) Diag(DiagD->getLocation(), diag::warn_unused_const_variable) - << DiagD; + << DiagD << DiagRange; } else { - if (DiagD->getDescribedVarTemplate()) - Diag(DiagD->getLocation(), diag::warn_unused_template) - << /*variable*/ 1 << DiagD; - else - Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD; + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD << DiagRange; } } } @@ -1407,9 +1414,7 @@ void Sema::ActOnEndOfTranslationUnit() { // source. RecordCompleteMap RecordsComplete; RecordCompleteMap MNCComplete; - for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(), - E = UnusedPrivateFields.end(); I != E; ++I) { - const NamedDecl *D = *I; + for (const NamedDecl *D : UnusedPrivateFields) { const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); if (RD && !RD->isUnion() && IsRecordFullyDefined(RD, RecordsComplete, MNCComplete)) { @@ -1430,6 +1435,8 @@ void Sema::ActOnEndOfTranslationUnit() { } } + AnalysisWarnings.IssueWarnings(Context.getTranslationUnitDecl()); + // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. @@ -1445,7 +1452,7 @@ void Sema::ActOnEndOfTranslationUnit() { // Helper functions. //===----------------------------------------------------------------------===// -DeclContext *Sema::getFunctionLevelDeclContext(bool AllowLambda) { +DeclContext *Sema::getFunctionLevelDeclContext(bool AllowLambda) const { DeclContext *DC = CurContext; while (true) { @@ -1465,7 +1472,7 @@ DeclContext *Sema::getFunctionLevelDeclContext(bool AllowLambda) { /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. -FunctionDecl *Sema::getCurFunctionDecl(bool AllowLambda) { +FunctionDecl *Sema::getCurFunctionDecl(bool AllowLambda) const { DeclContext *DC = getFunctionLevelDeclContext(AllowLambda); return dyn_cast<FunctionDecl>(DC); } @@ -1477,7 +1484,7 @@ ObjCMethodDecl *Sema::getCurMethodDecl() { return dyn_cast<ObjCMethodDecl>(DC); } -NamedDecl *Sema::getCurFunctionOrMethodDecl() { +NamedDecl *Sema::getCurFunctionOrMethodDecl() const { DeclContext *DC = getFunctionLevelDeclContext(); if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC)) return cast<NamedDecl>(DC); @@ -1611,7 +1618,7 @@ bool Sema::hasUncompilableErrorOccurred() const { // Print notes showing how we can reach FD starting from an a priori // known-callable function. -static void emitCallStackNotes(Sema &S, FunctionDecl *FD) { +static void emitCallStackNotes(Sema &S, const FunctionDecl *FD) { auto FnIt = S.DeviceKnownEmittedFns.find(FD); while (FnIt != S.DeviceKnownEmittedFns.end()) { // Respect error limit. @@ -1823,7 +1830,8 @@ void Sema::emitDeferredDiags() { Sema::SemaDiagnosticBuilder::SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, - FunctionDecl *Fn, Sema &S) + const FunctionDecl *Fn, + Sema &S) : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn), ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) { switch (K) { @@ -1869,11 +1877,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } Sema::SemaDiagnosticBuilder -Sema::targetDiag(SourceLocation Loc, unsigned DiagID, FunctionDecl *FD) { +Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) { FD = FD ? FD : getCurFunctionDecl(); if (LangOpts.OpenMP) - return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID, FD) - : diagIfOpenMPHostCode(Loc, DiagID, FD); + return LangOpts.OpenMPIsTargetDevice + ? diagIfOpenMPDeviceCode(Loc, DiagID, FD) + : diagIfOpenMPHostCode(Loc, DiagID, FD); if (getLangOpts().CUDA) return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) : CUDADiagIfHostCode(Loc, DiagID); @@ -1937,8 +1946,9 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { // Try to associate errors with the lexical context, if that is a function, or // the value declaration otherwise. - FunctionDecl *FD = isa<FunctionDecl>(C) ? cast<FunctionDecl>(C) - : dyn_cast_or_null<FunctionDecl>(D); + const FunctionDecl *FD = isa<FunctionDecl>(C) + ? cast<FunctionDecl>(C) + : dyn_cast_or_null<FunctionDecl>(D); auto CheckDeviceType = [&](QualType Ty) { if (Ty->isDependentType()) @@ -1975,6 +1985,8 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { (Ty->isIbm128Type() && !Context.getTargetInfo().hasIbm128Type()) || (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && !Context.getTargetInfo().hasInt128Type()) || + (Ty->isBFloat16Type() && !Context.getTargetInfo().hasBFloat16Type() && + !LangOpts.CUDAIsDevice) || LongDoubleMismatched) { PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); if (D) @@ -1995,7 +2007,8 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { }; auto CheckType = [&](QualType Ty, bool IsRetTy = false) { - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice) || + if (LangOpts.SYCLIsDevice || + (LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice) || LangOpts.CUDAIsDevice) CheckDeviceType(Ty); @@ -2010,7 +2023,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (Diag(Loc, PD, FD) << false /*show bit size*/ << 0 << Ty << false /*return*/ - << Context.getTargetInfo().getTriple().str()) { + << TI.getTriple().str()) { if (D) D->setInvalidDecl(); } @@ -2029,7 +2042,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (Diag(Loc, PD, FD) << false /*show bit size*/ << 0 << Ty << true /*return*/ - << Context.getTargetInfo().getTriple().str()) { + << TI.getTriple().str()) { if (D) D->setInvalidDecl(); } @@ -2037,6 +2050,9 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } + if (Ty->isRVVType()) + checkRVVTypeSupport(Ty, Loc, D); + // Don't allow SVE types in functions without a SVE target. if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { llvm::StringMap<bool> CallerFeatureMap; @@ -2123,11 +2139,13 @@ void Sema::PushFunctionScope() { void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics(), BlockScope, Block)); + CapturingFunctionScopes++; } LambdaScopeInfo *Sema::PushLambdaScope() { LambdaScopeInfo *const LSI = new LambdaScopeInfo(getDiagnostics()); FunctionScopes.push_back(LSI); + CapturingFunctionScopes++; return LSI; } @@ -2154,7 +2172,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) { new (S.Context) DeclRefExpr(S.Context, VD, false, T, VK_LValue, Loc); ExprResult Result; auto IE = InitializedEntity::InitializeBlock(Loc, T); - if (S.getLangOpts().CPlusPlus2b) { + if (S.getLangOpts().CPlusPlus23) { auto *E = ImplicitCastExpr::Create(S.Context, T, CK_NoOp, VarRef, nullptr, VK_XValue, FPOptionsOverride()); Result = S.PerformCopyInitialization(IE, SourceLocation(), E); @@ -2249,6 +2267,8 @@ Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, void Sema::PoppedFunctionScopeDeleter:: operator()(sema::FunctionScopeInfo *Scope) const { + if (!Scope->isPlainFunction()) + Self->CapturingFunctionScopes--; // Stash the function scope for later reuse if it's for a normal function. if (Scope->isPlainFunction() && !Self->CachedFunctionScope) Self->CachedFunctionScope.reset(Scope); @@ -2324,7 +2344,8 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const { LambdaScopeInfo *Sema::getEnclosingLambda() const { for (auto *Scope : llvm::reverse(FunctionScopes)) { if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) { - if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) { + if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && + LSI->AfterParameterList) { // We have switched contexts due to template instantiation. // FIXME: We should swap out the FunctionScopes during code synthesis // so that we don't need to check for this. @@ -2350,8 +2371,8 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) { return nullptr; } auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I); - if (CurLSI && CurLSI->Lambda && - !CurLSI->Lambda->Encloses(CurContext)) { + if (CurLSI && CurLSI->Lambda && CurLSI->CallOperator && + !CurLSI->Lambda->Encloses(CurContext) && CurLSI->AfterParameterList) { // We have switched contexts due to template instantiation. assert(!CodeSynthesisContexts.empty()); return nullptr; @@ -2376,7 +2397,7 @@ void Sema::ActOnComment(SourceRange Comment) { SourceMgr.isInSystemHeader(Comment.getBegin())) return; RawComment RC(SourceMgr, Comment, LangOpts.CommentOpts, false); - if (RC.isAlmostTrailingComment()) { + if (RC.isAlmostTrailingComment() || RC.hasUnsupportedSplice(SourceMgr)) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); StringRef MagicMarkerText; @@ -2387,6 +2408,11 @@ void Sema::ActOnComment(SourceRange Comment) { case RawComment::RCK_OrdinaryC: MagicMarkerText = "/**<"; break; + case RawComment::RCK_Invalid: + // FIXME: are there other scenarios that could produce an invalid + // raw comment here? + Diag(Comment.getBegin(), diag::warn_splice_in_doxygen_comment); + return; default: llvm_unreachable("if this is an almost Doxygen comment, " "it should be ordinary"); @@ -2493,8 +2519,8 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, return false; } - if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) { - if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { + if (const auto *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) { + if (const auto *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { if (Fun->getMinRequiredArguments() == 0) ZeroArgCallReturnTy = Fun->getReturnType(); return true; @@ -2511,8 +2537,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, if (!FunTy) FunTy = ExprTy->getAs<FunctionType>(); - if (const FunctionProtoType *FPT = - dyn_cast_or_null<FunctionProtoType>(FunTy)) { + if (const auto *FPT = dyn_cast_if_present<FunctionProtoType>(FunTy)) { if (FPT->getNumParams() == 0) ZeroArgCallReturnTy = FunTy->getReturnType(); return true; @@ -2543,7 +2568,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, continue; } - NamedDecl *Fn = (*It)->getUnderlyingDecl(); + const 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>() && @@ -2573,7 +2598,7 @@ static void notePlausibleOverloads(Sema &S, SourceLocation Loc, UnresolvedSet<2> PlausibleOverloads; for (OverloadExpr::decls_iterator It = Overloads.begin(), DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { - const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); + const auto *OverloadDecl = cast<FunctionDecl>(*It); QualType OverloadResultTy = OverloadDecl->getReturnType(); if (IsPlausibleResult(OverloadResultTy)) PlausibleOverloads.addDecl(It.getDecl()); @@ -2585,7 +2610,7 @@ static void notePlausibleOverloads(Sema &S, SourceLocation Loc, /// putting parentheses after it. Notably, expressions with unary /// operators can't be because the unary operator will start parsing /// outside the call. -static bool IsCallableWithAppend(Expr *E) { +static bool IsCallableWithAppend(const Expr *E) { E = E->IgnoreImplicit(); return (!isa<CStyleCastExpr>(E) && !isa<UnaryOperator>(E) && @@ -2659,12 +2684,6 @@ IdentifierInfo *Sema::getSuperIdentifier() const { return Ident_super; } -IdentifierInfo *Sema::getFloat128Identifier() const { - if (!Ident___float128) - Ident___float128 = &Context.Idents.get("__float128"); - return Ident___float128; -} - void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K, unsigned OpenMPCaptureLevel) { @@ -2674,6 +2693,7 @@ void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, OpenMPCaptureLevel); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); + CapturingFunctionScopes++; } CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index cbda62497e6a..4af3c0f30a8e 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -199,6 +199,16 @@ struct AccessTarget : public AccessedEntity { : Target(S.Target), Has(S.Has) { S.Target = nullptr; } + + // The move assignment operator is defined as deleted pending further + // motivation. + SavedInstanceContext &operator=(SavedInstanceContext &&) = delete; + + // The copy constrcutor and copy assignment operator is defined as deleted + // pending further motivation. + SavedInstanceContext(const SavedInstanceContext &) = delete; + SavedInstanceContext &operator=(const SavedInstanceContext &) = delete; + ~SavedInstanceContext() { if (Target) Target->HasInstanceContext = Has; @@ -1651,7 +1661,8 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); break; - case InitializedEntity::EK_Member: { + case InitializedEntity::EK_Member: + case InitializedEntity::EK_ParenAggInitMember: { const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); PD = PDiag(diag::err_access_field_ctor); PD << Field->getType() << getSpecialMember(Constructor); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 42f582724564..6dadf01ead44 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -223,8 +223,6 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, switch (Kind) { // For most of the platforms we support, native and natural are the same. // With XL, native is the same as power, natural means something else. - // - // FIXME: This is not true on Darwin/PPC. case POAK_Native: case POAK_Power: Action = Sema::PSK_Push_Set; @@ -565,13 +563,6 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc, case PFC_Precise: NewFPFeatures.setFPPreciseEnabled(true); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); - if (PP.getCurrentFPEvalMethod() == - LangOptions::FPEvalMethodKind::FEM_Indeterminable && - PP.getLastFPEvalPragmaLocation().isValid()) - // A preceding `pragma float_control(precise,off)` has changed - // the value of the evaluation method. - // Set it back to its old value. - PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod()); break; case PFC_NoPrecise: if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict) @@ -581,10 +572,6 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc, else NewFPFeatures.setFPPreciseEnabled(false); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); - PP.setLastFPEvalMethod(PP.getCurrentFPEvalMethod()); - // `AllowFPReassoc` or `AllowReciprocal` option is enabled. - PP.setCurrentFPEvalMethod( - Loc, LangOptions::FPEvalMethodKind::FEM_Indeterminable); break; case PFC_Except: if (!isPreciseFPEnabled()) @@ -608,12 +595,6 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc, } FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); NewFPFeatures = FpPragmaStack.CurrentValue; - if (CurFPFeatures.getAllowFPReassociate() || - CurFPFeatures.getAllowReciprocal()) - // Since we are popping the pragma, we don't want to be passing - // a location here. - PP.setCurrentFPEvalMethod(SourceLocation(), - CurFPFeatures.getFPEvalMethod()); break; } CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); @@ -864,7 +845,6 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name; VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(), - AttributeCommonInfo::AS_Pragma, UnusedAttr::GNU_unused)); } @@ -880,7 +860,7 @@ void Sema::AddCFAuditedAttribute(Decl *D) { return; AttributeCommonInfo Info(Ident, SourceRange(Loc), - AttributeCommonInfo::AS_Pragma); + AttributeCommonInfo::Form::Pragma()); D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info)); } @@ -1355,6 +1335,7 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { Diag(Loc, diag::err_pragma_fenv_requires_precise); } NewFPFeatures.setAllowFEnvAccessOverride(IsEnabled); + NewFPFeatures.setRoundingMathOverride(IsEnabled); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); } diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index daa61ba45e8e..f37ba5cf4c10 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -99,34 +99,53 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (ClassTemplateDecl *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>( SpecType->getTemplateName().getAsTemplateDecl())) { - QualType ContextType - = Context.getCanonicalType(QualType(SpecType, 0)); - - // If the type of the nested name specifier is the same as the - // injected class name of the named class template, we're entering - // into that class template definition. - QualType Injected - = ClassTemplate->getInjectedClassNameSpecialization(); - if (Context.hasSameType(Injected, ContextType)) - return ClassTemplate->getTemplatedDecl(); + QualType ContextType = + Context.getCanonicalType(QualType(SpecType, 0)); + + // FIXME: The fallback on the search of partial + // specialization using ContextType should be eventually removed since + // it doesn't handle the case of constrained template parameters + // correctly. Currently removing this fallback would change the + // diagnostic output for invalid code in a number of tests. + ClassTemplatePartialSpecializationDecl *PartialSpec = nullptr; + ArrayRef<TemplateParameterList *> TemplateParamLists = + SS.getTemplateParamLists(); + if (!TemplateParamLists.empty()) { + unsigned Depth = ClassTemplate->getTemplateParameters()->getDepth(); + auto L = find_if(TemplateParamLists, + [Depth](TemplateParameterList *TPL) { + return TPL->getDepth() == Depth; + }); + if (L != TemplateParamLists.end()) { + void *Pos = nullptr; + PartialSpec = ClassTemplate->findPartialSpecialization( + SpecType->template_arguments(), *L, Pos); + } + } else { + PartialSpec = ClassTemplate->findPartialSpecialization(ContextType); + } - // If the type of the nested name specifier is the same as the - // type of one of the class template's class template partial - // specializations, we're entering into the definition of that - // class template partial specialization. - if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(ContextType)) { + if (PartialSpec) { // A declaration of the partial specialization must be visible. // We can always recover here, because this only happens when we're // entering the context, and that can't happen in a SFINAE context. - assert(!isSFINAEContext() && - "partial specialization scope specifier in SFINAE context?"); - if (!hasReachableDefinition(PartialSpec)) + assert(!isSFINAEContext() && "partial specialization scope " + "specifier in SFINAE context?"); + if (PartialSpec->hasDefinition() && + !hasReachableDefinition(PartialSpec)) diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, MissingImportKind::PartialSpecialization, - /*Recover*/true); + true); return PartialSpec; } + + // If the type of the nested name specifier is the same as the + // injected class name of the named class template, we're entering + // into that class template definition. + QualType Injected = + ClassTemplate->getInjectedClassNameSpecialization(); + if (Context.hasSameType(Injected, ContextType)) + return ClassTemplate->getTemplatedDecl(); } } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. @@ -292,6 +311,11 @@ bool Sema::ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS) { + if (getCurLambda()) { + Diag(SuperLoc, diag::err_super_in_lambda_unsupported); + return true; + } + CXXRecordDecl *RD = nullptr; for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->isFunctionScope()) { @@ -308,9 +332,6 @@ bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, if (!RD) { Diag(SuperLoc, diag::err_invalid_super_scope); return true; - } else if (RD->isLambda()) { - Diag(SuperLoc, diag::err_super_in_lambda_unsupported); - return true; } else if (RD->getNumBases() == 0) { Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); return true; @@ -394,51 +415,6 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return nullptr; } -bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, - NestedNameSpecInfo &IdInfo) { - QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); - LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, - LookupNestedNameSpecifierName); - - // Determine where to perform name lookup - DeclContext *LookupCtx = nullptr; - 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(); - } 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, false); - isDependent = isDependentScopeSpecifier(SS); - Found.setContextRange(SS.getRange()); - } - - if (LookupCtx) { - // Perform "qualified" name lookup into the declaration context we - // computed, which is either the type of the base of a member access - // expression or the declaration context associated with a prior - // nested-name-specifier. - - // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && - RequireCompleteDeclContext(SS, LookupCtx)) - return false; - - LookupQualifiedName(Found, LookupCtx); - } else if (isDependent) { - return false; - } else { - LookupName(Found, S); - } - Found.suppressDiagnostics(); - - return Found.getAsSingle<NamespaceDecl>(); -} - namespace { // Callback to only accept typo corrections that can be a valid C++ member diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 9fd9369c9641..d65ecf52c523 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include <set> using namespace clang; @@ -65,9 +66,13 @@ namespace { // If a pr-value initially has the type cv-T, where T is a // cv-unqualified non-class, non-array type, the type of the // expression is adjusted to T prior to any further analysis. + // C2x 6.5.4p6: + // Preceding an expression by a parenthesized type name converts the + // value of the expression to the unqualified, non-atomic version of + // the named type. if (!S.Context.getLangOpts().ObjC && !DestType->isRecordType() && !DestType->isArrayType()) { - DestType = DestType.getUnqualifiedType(); + DestType = DestType.getAtomicUnqualifiedType(); } if (const BuiltinType *placeholder = @@ -449,9 +454,27 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, switch (sequence.getFailureKind()) { default: return false; + case InitializationSequence::FK_ParenthesizedListInitFailed: + // In C++20, if the underlying destination type is a RecordType, Clang + // attempts to perform parentesized aggregate initialization if constructor + // overload fails: + // + // C++20 [expr.static.cast]p4: + // An expression E can be explicitly converted to a type T...if overload + // resolution for a direct-initialization...would find at least one viable + // function ([over.match.viable]), or if T is an aggregate type having a + // first element X and there is an implicit conversion sequence from E to + // the type of X. + // + // If that fails, then we'll generate the diagnostics from the failed + // previous constructor overload attempt. Array initialization, however, is + // not done after attempting constructor overloading, so we exit as there + // won't be a failed overload result. + if (destType->isArrayType()) + return false; + break; case InitializationSequence::FK_ConstructorOverloadFailed: case InitializationSequence::FK_UserConversionOverloadFailed: - case InitializationSequence::FK_ParenthesizedListInitFailed: break; } @@ -2350,6 +2373,12 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Success; } + // Allow bitcasting between SVE VLATs and VLSTs, and vice-versa. + if (Self.isValidRVVBitcast(SrcType, DestType)) { + Kind = CK_BitCast; + return TC_Success; + } + // The non-vector type, if any, must have integral type. This is // the same rule that C vector casts use; note, however, that enum // types are not integral in C++. @@ -2736,6 +2765,15 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } } + // WebAssembly tables cannot be cast. + QualType SrcType = SrcExpr.get()->getType(); + if (SrcType->isWebAssemblyTableType()) { + Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table) + << 1 << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + // C++ [expr.cast]p5: The conversions performed by // - a const_cast, // - a static_cast, @@ -2911,6 +2949,13 @@ void CastOperation::CheckCStyleCast() { return; QualType SrcType = SrcExpr.get()->getType(); + if (SrcType->isWebAssemblyTableType()) { + Self.Diag(OpRange.getBegin(), diag::err_wasm_cast_table) + << 1 << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + assert(!SrcType->isPlaceholderType()); checkAddressSpaceCast(SrcType, DestType); @@ -2937,6 +2982,13 @@ void CastOperation::CheckCStyleCast() { return; } + // Allow bitcasting between compatible RVV vector types. + if ((SrcType->isVectorType() || DestType->isVectorType()) && + Self.isValidRVVBitcast(SrcType, DestType)) { + Kind = CK_BitCast; + return; + } + if (!DestType->isScalarType() && !DestType->isVectorType() && !DestType->isMatrixType()) { const RecordType *DestRecordTy = DestType->getAs<RecordType>(); @@ -3075,20 +3127,6 @@ void CastOperation::CheckCStyleCast() { return; } - // Can't cast to or from bfloat - if (DestType->isBFloat16Type() && !SrcType->isBFloat16Type()) { - Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_to_bfloat16) - << SrcExpr.get()->getSourceRange(); - SrcExpr = ExprError(); - return; - } - if (SrcType->isBFloat16Type() && !DestType->isBFloat16Type()) { - Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_from_bfloat16) - << SrcExpr.get()->getSourceRange(); - SrcExpr = ExprError(); - return; - } - // If either type is a pointer, the other type has to be either an // integer or a pointer. if (!DestType->isArithmeticType()) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ea21171aaac6..f8e48728da66 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -72,10 +72,10 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" @@ -86,6 +86,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" #include <algorithm> #include <bitset> #include <cassert> @@ -2025,6 +2026,12 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::loongarch32: case llvm::Triple::loongarch64: return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + return CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + return CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall); } } @@ -2143,6 +2150,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; + case Builtin::BI__builtin_set_flt_rounds: + if (CheckBuiltinTargetInSupported(*this, BuiltinID, TheCall, + {llvm::Triple::x86, 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: @@ -2156,6 +2171,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinFPClassification(TheCall, 6)) return ExprError(); break; + case Builtin::BI__builtin_isfpclass: + if (SemaBuiltinFPClassification(TheCall, 2)) + return ExprError(); + break; case Builtin::BI__builtin_isfinite: case Builtin::BI__builtin_isinf: case Builtin::BI__builtin_isinf_sign: @@ -2471,6 +2490,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIaddressof: case Builtin::BI__addressof: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIas_const: { @@ -2580,6 +2600,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } + case Builtin::BI__builtin_nondeterministic_value: { + if (SemaBuiltinNonDeterministicValue(TheCall)) + return ExprError(); + break; + } + // __builtin_elementwise_abs restricts the element type to signed integers or // floating point types only. case Builtin::BI__builtin_elementwise_abs: { @@ -2604,8 +2630,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // types only. case Builtin::BI__builtin_elementwise_ceil: case Builtin::BI__builtin_elementwise_cos: + case Builtin::BI__builtin_elementwise_exp: + case Builtin::BI__builtin_elementwise_exp2: case Builtin::BI__builtin_elementwise_floor: + case Builtin::BI__builtin_elementwise_log: + case Builtin::BI__builtin_elementwise_log2: + case Builtin::BI__builtin_elementwise_log10: case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_round: + case Builtin::BI__builtin_elementwise_rint: + case Builtin::BI__builtin_elementwise_nearbyint: case Builtin::BI__builtin_elementwise_sin: case Builtin::BI__builtin_elementwise_trunc: case Builtin::BI__builtin_elementwise_canonicalize: { @@ -2613,17 +2647,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); QualType ArgTy = TheCall->getArg(0)->getType(); - QualType EltTy = ArgTy; + if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(), + ArgTy, 1)) + return ExprError(); + break; + } + case Builtin::BI__builtin_elementwise_fma: { + if (SemaBuiltinElementwiseTernaryMath(TheCall)) + return ExprError(); + break; + } - if (auto *VecTy = EltTy->getAs<VectorType>()) - EltTy = VecTy->getElementType(); - if (!EltTy->isFloatingType()) { - Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_builtin_invalid_arg_type) - << 1 << /* float ty*/ 5 << ArgTy; + // These builtins restrict the element type to floating point + // types only, and take in two arguments. + case Builtin::BI__builtin_elementwise_pow: { + if (SemaBuiltinElementwiseMath(TheCall)) + return ExprError(); + QualType ArgTy = TheCall->getArg(0)->getType(); + if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(), + ArgTy, 1) || + checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(), + ArgTy, 2)) return ExprError(); - } break; } @@ -2857,6 +2903,9 @@ bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { #define GET_SVE_IMMEDIATE_CHECK #include "clang/Basic/arm_sve_sema_rangechecks.inc" #undef GET_SVE_IMMEDIATE_CHECK +#define GET_SME_IMMEDIATE_CHECK +#include "clang/Basic/arm_sme_sema_rangechecks.inc" +#undef GET_SME_IMMEDIATE_CHECK } // Perform all the immediate checks for this builtin call. @@ -2962,6 +3011,18 @@ bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) HasError = true; break; + case SVETypeFlags::ImmCheck0_0: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_15: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_255: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) + HasError = true; + break; } } @@ -3770,7 +3831,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, return Diag(TheCall->getBeginLoc(), diag::err_loongarch_builtin_requires_la64) << TheCall->getSourceRange(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case LoongArch::BI__builtin_loongarch_cacop_w: { if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w && !TI.hasFeature("32bit")) @@ -4153,21 +4214,6 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { return false; } -static bool SemaFeatureCheck(Sema &S, CallExpr *TheCall, - StringRef FeatureToCheck, unsigned DiagID, - StringRef DiagArg = "") { - if (S.Context.getTargetInfo().hasFeature(FeatureToCheck)) - return false; - - if (DiagArg.empty()) - S.Diag(TheCall->getBeginLoc(), DiagID) << TheCall->getSourceRange(); - else - S.Diag(TheCall->getBeginLoc(), DiagID) - << DiagArg << TheCall->getSourceRange(); - - return true; -} - /// Returns true if the argument consists of one contiguous run of 1s with any /// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, @@ -4212,42 +4258,16 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); case PPC::BI__builtin_tsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7); case PPC::BI__builtin_tabortwc: case PPC::BI__builtin_tabortdc: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_tabortwci: case PPC::BI__builtin_tabortdci: - return SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm) || - (SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31)); - case PPC::BI__builtin_tabort: - case PPC::BI__builtin_tcheck: - case PPC::BI__builtin_treclaim: - case PPC::BI__builtin_trechkpt: - case PPC::BI__builtin_tendall: - case PPC::BI__builtin_tresume: - case PPC::BI__builtin_tsuspend: - case PPC::BI__builtin_get_texasr: - case PPC::BI__builtin_get_texasru: - case PPC::BI__builtin_get_tfhar: - case PPC::BI__builtin_get_tfiar: - case PPC::BI__builtin_set_texasr: - case PPC::BI__builtin_set_texasru: - case PPC::BI__builtin_set_tfhar: - case PPC::BI__builtin_set_tfiar: - case PPC::BI__builtin_ttest: - return SemaFeatureCheck(*this, TheCall, "htm", - diag::err_ppc_builtin_requires_htm); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', // __builtin_(un)pack_longdouble are available only if long double uses IBM // extended double representation. @@ -4268,26 +4288,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: return SemaBuiltinVSX(TheCall); - case PPC::BI__builtin_divwe: - case PPC::BI__builtin_divweu: - case PPC::BI__builtin_divde: - case PPC::BI__builtin_divdeu: - return SemaFeatureCheck(*this, TheCall, "extdiv", - diag::err_ppc_builtin_only_on_arch, "7"); - case PPC::BI__builtin_bpermd: - return SemaFeatureCheck(*this, TheCall, "bpermd", - diag::err_ppc_builtin_only_on_arch, "7"); case PPC::BI__builtin_unpack_vector_int128: - return SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_only_on_arch, "7") || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_pack_vector_int128: - return SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_only_on_arch, "7"); - case PPC::BI__builtin_pdepd: - case PPC::BI__builtin_pextd: - return SemaFeatureCheck(*this, TheCall, "isa-v31-instructions", - diag::err_ppc_builtin_only_on_arch, "10"); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_altivec_vgnb: return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); case PPC::BI__builtin_vsx_xxeval: @@ -4301,17 +4303,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_ppc_tw: case PPC::BI__builtin_ppc_tdw: return SemaBuiltinConstantArgRange(TheCall, 2, 1, 31); - case PPC::BI__builtin_ppc_cmpeqb: - case PPC::BI__builtin_ppc_setb: - case PPC::BI__builtin_ppc_maddhd: - case PPC::BI__builtin_ppc_maddhdu: - case PPC::BI__builtin_ppc_maddld: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_ppc_cmprb: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must // be a constant that represents a contiguous bit field. case PPC::BI__builtin_ppc_rlwnm: @@ -4320,15 +4313,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_ppc_rldimi: return SemaBuiltinConstantArg(TheCall, 2, Result) || SemaValueIsRunOfOnes(TheCall, 3); - case PPC::BI__builtin_ppc_extract_exp: - case PPC::BI__builtin_ppc_extract_sig: - case PPC::BI__builtin_ppc_insert_exp: - return SemaFeatureCheck(*this, TheCall, "power9-vector", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_ppc_addex: { - if (SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) + if (SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) return true; // Output warning for reserved values 1 to 3. int ArgValue = @@ -4350,41 +4336,19 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return SemaBuiltinConstantArgPower2(TheCall, 0); case PPC::BI__builtin_ppc_rdlam: return SemaValueIsRunOfOnes(TheCall, 2); - case PPC::BI__builtin_ppc_icbt: - case PPC::BI__builtin_ppc_sthcx: - case PPC::BI__builtin_ppc_stbcx: - case PPC::BI__builtin_ppc_lharx: - case PPC::BI__builtin_ppc_lbarx: - return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", - diag::err_ppc_builtin_only_on_arch, "8"); case PPC::BI__builtin_vsx_ldrmb: case PPC::BI__builtin_vsx_strmb: - return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", - diag::err_ppc_builtin_only_on_arch, "8") || - SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); case PPC::BI__builtin_altivec_vcntmbb: case PPC::BI__builtin_altivec_vcntmbh: case PPC::BI__builtin_altivec_vcntmbw: case PPC::BI__builtin_altivec_vcntmbd: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case PPC::BI__builtin_darn: - case PPC::BI__builtin_darn_raw: - case PPC::BI__builtin_darn_32: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9"); case PPC::BI__builtin_vsx_xxgenpcvbm: case PPC::BI__builtin_vsx_xxgenpcvhm: case PPC::BI__builtin_vsx_xxgenpcvwm: case PPC::BI__builtin_vsx_xxgenpcvdm: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); - case PPC::BI__builtin_ppc_compare_exp_uo: - case PPC::BI__builtin_ppc_compare_exp_lt: - case PPC::BI__builtin_ppc_compare_exp_gt: - case PPC::BI__builtin_ppc_compare_exp_eq: - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_requires_vsx); case PPC::BI__builtin_ppc_test_data_class: { // Check if the first argument of the __builtin_ppc_test_data_class call is // valid. The argument must be 'float' or 'double' or '__float128'. @@ -4394,11 +4358,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, ArgType != QualType(Context.Float128Ty)) return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_test_data_class_type); - return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", - diag::err_ppc_builtin_only_on_arch, "9") || - SemaFeatureCheck(*this, TheCall, "vsx", - diag::err_ppc_builtin_requires_vsx) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); } case PPC::BI__builtin_ppc_maxfe: case PPC::BI__builtin_ppc_minfe: @@ -4427,11 +4387,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; return false; } - case PPC::BI__builtin_ppc_load8r: - case PPC::BI__builtin_ppc_store8r: - return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions", - diag::err_ppc_builtin_only_on_arch, "7"); -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ case PPC::BI__builtin_##Name: \ return SemaBuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" @@ -4545,7 +4501,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, bool FeatureMissing = false; SmallVector<StringRef> ReqFeatures; StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); - Features.split(ReqFeatures, ','); + Features.split(ReqFeatures, ',', -1, false); // Check if each required feature is included for (StringRef F : ReqFeatures) { @@ -4575,7 +4531,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, std::string FeatureStr = OF.str(); FeatureStr[0] = std::toupper(FeatureStr[0]); // Combine strings. - FeatureStrs += FeatureStrs == "" ? "" : ", "; + FeatureStrs += FeatureStrs.empty() ? "" : ", "; FeatureStrs += "'"; FeatureStrs += FeatureStr; FeatureStrs += "'"; @@ -4591,6 +4547,73 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, if (FeatureMissing) return true; + // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, + // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. + switch (BuiltinID) { + default: + break; + case RISCVVector::BI__builtin_rvv_vmulhsu_vv: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_m: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_m: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulhsu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulhsu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv: + case RISCVVector::BI__builtin_rvv_vmulhu_vx: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_m: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_m: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulhu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulhu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vmulh_vv: + case RISCVVector::BI__builtin_rvv_vmulh_vx: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tu: + case RISCVVector::BI__builtin_rvv_vmulh_vv_m: + case RISCVVector::BI__builtin_rvv_vmulh_vx_m: + case RISCVVector::BI__builtin_rvv_vmulh_vv_mu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_mu: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tum: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tum: + case RISCVVector::BI__builtin_rvv_vmulh_vv_tumu: + case RISCVVector::BI__builtin_rvv_vmulh_vx_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vv: + case RISCVVector::BI__builtin_rvv_vsmul_vx: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_m: + case RISCVVector::BI__builtin_rvv_vsmul_vx_m: + case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: { + bool RequireV = false; + for (unsigned ArgNum = 0; ArgNum < TheCall->getNumArgs(); ++ArgNum) + RequireV |= TheCall->getArg(ArgNum)->getType()->isRVVType( + /* Bitwidth */ 64, /* IsFloat */ false); + + if (RequireV && !TI.hasFeature("v")) + return Diag(TheCall->getBeginLoc(), + diag::err_riscv_builtin_requires_extension) + << /* IsExtension */ false << TheCall->getSourceRange() << "v"; + + break; + } + } + switch (BuiltinID) { case RISCVVector::BI__builtin_rvv_vsetvli: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3) || @@ -4605,9 +4628,12 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, ASTContext::BuiltinVectorTypeInfo VecInfo = Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( TheCall->getArg(0)->getType().getCanonicalType().getTypePtr())); - unsigned MaxIndex = - (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / - (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); + unsigned MaxIndex; + if (VecInfo.NumVectors != 1) // vget for tuple type + MaxIndex = VecInfo.NumVectors; + else // vget for non-tuple type + MaxIndex = (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / + (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } case RISCVVector::BI__builtin_rvv_vset_v: { @@ -4617,22 +4643,679 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, ASTContext::BuiltinVectorTypeInfo VecInfo = Context.getBuiltinVectorTypeInfo(cast<BuiltinType>( TheCall->getArg(2)->getType().getCanonicalType().getTypePtr())); - unsigned MaxIndex = - (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / - (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); + unsigned MaxIndex; + if (ResVecInfo.NumVectors != 1) // vset for tuple type + MaxIndex = ResVecInfo.NumVectors; + else // vset fo non-tuple type + MaxIndex = (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / + (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8mf8: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8mf4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8m1: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8m2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8m4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8m8: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16mf4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16m1: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16m2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16m4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u16m8: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u32mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u32m1: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u32m2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u32m4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u32m8: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u64m1: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u64m2: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u64m4: + case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u64m8: + // bit_27_26, bit_24_20, bit_11_7, simm5 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_iv_se: + // bit_27_26, bit_11_7, vs2, simm5 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_v_i: + case RISCVVector::BI__builtin_rvv_sf_vc_v_i_se: + // bit_27_26, bit_24_20, simm5 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_v_iv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_iv_se: + // bit_27_26, vs2, simm5 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_ivv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_ivw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw_se: + // bit_27_26, vd, vs2, simm5 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8mf8: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8mf4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8m1: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8m2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8m4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u8m8: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16mf4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16m1: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16m2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16m4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u16m8: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u32mf2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u32m1: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u32m2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u32m4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u32m8: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u64m1: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u64m2: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u64m4: + case RISCVVector::BI__builtin_rvv_sf_vc_x_se_u64m8: + // bit_27_26, bit_24_20, bit_11_7, xs1 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case RISCVVector::BI__builtin_rvv_sf_vc_xv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_vv_se: + // bit_27_26, bit_11_7, vs2, xs1/vs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_x: + case RISCVVector::BI__builtin_rvv_sf_vc_v_x_se: + // bit_27_26, bit_24-20, xs1 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + case RISCVVector::BI__builtin_rvv_sf_vc_vvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_xvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_vvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_xvw_se: + // bit_27_26, vd, vs2, xs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_xv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vv_se: + // bit_27_26, vs2, xs1/vs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw_se: + // bit_27_26, vd, vs2, xs1/vs1 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); + case RISCVVector::BI__builtin_rvv_sf_vc_fv_se: + // bit_26, bit_11_7, vs2, fs1 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + case RISCVVector::BI__builtin_rvv_sf_vc_fvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_fvw_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv_se: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fvw_se: + // bit_26, vd, vs2, fs1 + case RISCVVector::BI__builtin_rvv_sf_vc_v_fv: + case RISCVVector::BI__builtin_rvv_sf_vc_v_fv_se: + // bit_26, vs2, fs1 + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); // Check if byteselect is in [0, 3] - case RISCV::BI__builtin_riscv_aes32dsi_32: - case RISCV::BI__builtin_riscv_aes32dsmi_32: - case RISCV::BI__builtin_riscv_aes32esi_32: - case RISCV::BI__builtin_riscv_aes32esmi_32: + case RISCV::BI__builtin_riscv_aes32dsi: + case RISCV::BI__builtin_riscv_aes32dsmi: + case RISCV::BI__builtin_riscv_aes32esi: + case RISCV::BI__builtin_riscv_aes32esmi: case RISCV::BI__builtin_riscv_sm4ks: case RISCV::BI__builtin_riscv_sm4ed: return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); // Check if rnum is in [0, 10] - case RISCV::BI__builtin_riscv_aes64ks1i_64: + case RISCV::BI__builtin_riscv_aes64ks1i: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 10); + // Check if value range for vxrm is in [0, 3] + case RISCVVector::BI__builtin_rvv_vaaddu_vv: + case RISCVVector::BI__builtin_rvv_vaaddu_vx: + case RISCVVector::BI__builtin_rvv_vaadd_vv: + case RISCVVector::BI__builtin_rvv_vaadd_vx: + case RISCVVector::BI__builtin_rvv_vasubu_vv: + case RISCVVector::BI__builtin_rvv_vasubu_vx: + case RISCVVector::BI__builtin_rvv_vasub_vv: + case RISCVVector::BI__builtin_rvv_vasub_vx: + case RISCVVector::BI__builtin_rvv_vsmul_vv: + case RISCVVector::BI__builtin_rvv_vsmul_vx: + case RISCVVector::BI__builtin_rvv_vssra_vv: + case RISCVVector::BI__builtin_rvv_vssra_vx: + case RISCVVector::BI__builtin_rvv_vssrl_vv: + case RISCVVector::BI__builtin_rvv_vssrl_vx: + case RISCVVector::BI__builtin_rvv_vnclip_wv: + case RISCVVector::BI__builtin_rvv_vnclip_wx: + case RISCVVector::BI__builtin_rvv_vnclipu_wv: + case RISCVVector::BI__builtin_rvv_vnclipu_wx: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tu: + case RISCVVector::BI__builtin_rvv_vasub_vv_tu: + case RISCVVector::BI__builtin_rvv_vasub_vx_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tu: + case RISCVVector::BI__builtin_rvv_vssra_vv_tu: + case RISCVVector::BI__builtin_rvv_vssra_vx_tu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tu: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_m: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_m: + case RISCVVector::BI__builtin_rvv_vaadd_vv_m: + case RISCVVector::BI__builtin_rvv_vaadd_vx_m: + case RISCVVector::BI__builtin_rvv_vasubu_vv_m: + case RISCVVector::BI__builtin_rvv_vasubu_vx_m: + case RISCVVector::BI__builtin_rvv_vasub_vv_m: + case RISCVVector::BI__builtin_rvv_vasub_vx_m: + case RISCVVector::BI__builtin_rvv_vsmul_vv_m: + case RISCVVector::BI__builtin_rvv_vsmul_vx_m: + case RISCVVector::BI__builtin_rvv_vssra_vv_m: + case RISCVVector::BI__builtin_rvv_vssra_vx_m: + case RISCVVector::BI__builtin_rvv_vssrl_vv_m: + case RISCVVector::BI__builtin_rvv_vssrl_vx_m: + case RISCVVector::BI__builtin_rvv_vnclip_wv_m: + case RISCVVector::BI__builtin_rvv_vnclip_wx_m: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_m: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_m: + return SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tum: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vaaddu_vv_mu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tum: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vaaddu_vx_mu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tum: + case RISCVVector::BI__builtin_rvv_vaadd_vv_tumu: + case RISCVVector::BI__builtin_rvv_vaadd_vv_mu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tum: + case RISCVVector::BI__builtin_rvv_vaadd_vx_tumu: + case RISCVVector::BI__builtin_rvv_vaadd_vx_mu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tum: + case RISCVVector::BI__builtin_rvv_vasubu_vv_tumu: + case RISCVVector::BI__builtin_rvv_vasubu_vv_mu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tum: + case RISCVVector::BI__builtin_rvv_vasubu_vx_tumu: + case RISCVVector::BI__builtin_rvv_vasubu_vx_mu: + case RISCVVector::BI__builtin_rvv_vasub_vv_tum: + case RISCVVector::BI__builtin_rvv_vasub_vv_tumu: + case RISCVVector::BI__builtin_rvv_vasub_vv_mu: + case RISCVVector::BI__builtin_rvv_vasub_vx_tum: + case RISCVVector::BI__builtin_rvv_vasub_vx_tumu: + case RISCVVector::BI__builtin_rvv_vasub_vx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_mu: + case RISCVVector::BI__builtin_rvv_vssra_vv_mu: + case RISCVVector::BI__builtin_rvv_vssra_vx_mu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_mu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_mu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_mu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_mu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_mu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_mu: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tum: + case RISCVVector::BI__builtin_rvv_vssra_vv_tum: + case RISCVVector::BI__builtin_rvv_vssra_vx_tum: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tum: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tum: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tum: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tum: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tum: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tum: + case RISCVVector::BI__builtin_rvv_vsmul_vv_tumu: + case RISCVVector::BI__builtin_rvv_vsmul_vx_tumu: + case RISCVVector::BI__builtin_rvv_vssra_vv_tumu: + case RISCVVector::BI__builtin_rvv_vssra_vx_tumu: + case RISCVVector::BI__builtin_rvv_vssrl_vv_tumu: + case RISCVVector::BI__builtin_rvv_vssrl_vx_tumu: + case RISCVVector::BI__builtin_rvv_vnclip_wv_tumu: + case RISCVVector::BI__builtin_rvv_vnclip_wx_tumu: + case RISCVVector::BI__builtin_rvv_vnclipu_wv_tumu: + case RISCVVector::BI__builtin_rvv_vnclipu_wx_tumu: + return SemaBuiltinConstantArgRange(TheCall, 4, 0, 3); + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 4); + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 4); + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_m: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_xu_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_x_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfcvt_f_xu_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwcvt_x_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwcvt_xu_f_v_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_x_f_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_xu_f_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: + return SemaBuiltinConstantArgRange(TheCall, 3, 0, 4); + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwredusum_vs_rm_tum: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_wv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwadd_wf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_wv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwsub_wf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmul_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmul_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfdiv_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfdiv_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfrdiv_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmul_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmul_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmadd_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfmsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfnmsub_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmacc_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: + return SemaBuiltinConstantArgRange(TheCall, 4, 0, 4); + case RISCV::BI__builtin_riscv_ntl_load: + case RISCV::BI__builtin_riscv_ntl_store: + DeclRefExpr *DRE = + cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + assert((BuiltinID == RISCV::BI__builtin_riscv_ntl_store || + BuiltinID == RISCV::BI__builtin_riscv_ntl_load) && + "Unexpected RISC-V nontemporal load/store builtin!"); + bool IsStore = BuiltinID == RISCV::BI__builtin_riscv_ntl_store; + unsigned NumArgs = IsStore ? 3 : 2; + + if (checkArgCount(*this, TheCall, NumArgs)) + return true; + + // Domain value should be compile-time constant. + // 2 <= domain <= 5 + if (SemaBuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) + return true; + + Expr *PointerArg = TheCall->getArg(0); + ExprResult PointerArgResult = + DefaultFunctionArrayLvalueConversion(PointerArg); + + if (PointerArgResult.isInvalid()) + return true; + PointerArg = PointerArgResult.get(); + + const PointerType *PtrType = PointerArg->getType()->getAs<PointerType>(); + if (!PtrType) { + Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer) + << PointerArg->getType() << PointerArg->getSourceRange(); + return true; + } + + QualType ValType = PtrType->getPointeeType(); + ValType = ValType.getUnqualifiedType(); + if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && + !ValType->isBlockPointerType() && !ValType->isFloatingType() && + !ValType->isVectorType() && !ValType->isRVVType()) { + Diag(DRE->getBeginLoc(), + diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector) + << PointerArg->getType() << PointerArg->getSourceRange(); + return true; + } + + if (!IsStore) { + TheCall->setType(ValType); + return false; + } + + ExprResult ValArg = TheCall->getArg(1); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, ValType, /*consume*/ false); + ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); + if (ValArg.isInvalid()) + return true; + + TheCall->setArg(1, ValArg.get()); + TheCall->setType(Context.VoidTy); + return false; } return false; @@ -4708,6 +5391,68 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u); } +bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_ref_null_extern: + return BuiltinWasmRefNullExtern(TheCall); + case WebAssembly::BI__builtin_wasm_ref_null_func: + return BuiltinWasmRefNullFunc(TheCall); + case WebAssembly::BI__builtin_wasm_table_get: + return BuiltinWasmTableGet(TheCall); + case WebAssembly::BI__builtin_wasm_table_set: + return BuiltinWasmTableSet(TheCall); + case WebAssembly::BI__builtin_wasm_table_size: + return BuiltinWasmTableSize(TheCall); + case WebAssembly::BI__builtin_wasm_table_grow: + return BuiltinWasmTableGrow(TheCall); + case WebAssembly::BI__builtin_wasm_table_fill: + return BuiltinWasmTableFill(TheCall); + case WebAssembly::BI__builtin_wasm_table_copy: + return BuiltinWasmTableCopy(TheCall); + } + + return false; +} + +void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { + const TargetInfo &TI = Context.getTargetInfo(); + // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at + // least zve64x + if ((Ty->isRVVType(/* Bitwidth */ 64, /* IsFloat */ false) || + Ty->isRVVType(/* ElementCount */ 1)) && + !TI.hasFeature("zve64x")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; + if (Ty->isRVVType(/* Bitwidth */ 16, /* IsFloat */ true) && + !TI.hasFeature("zvfh")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfh"; + if (Ty->isRVVType(/* Bitwidth */ 32, /* IsFloat */ true) && + !TI.hasFeature("zve32f")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; + if (Ty->isRVVType(/* Bitwidth */ 64, /* IsFloat */ true) && + !TI.hasFeature("zve64d")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; + // Given that caller already checked isRVVType() before calling this function, + // if we don't have at least zve32x supported, then we need to emit error. + if (!TI.hasFeature("zve32x")) + Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; +} + +bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + case NVPTX::BI__nvvm_cp_async_ca_shared_global_4: + case NVPTX::BI__nvvm_cp_async_ca_shared_global_8: + case NVPTX::BI__nvvm_cp_async_ca_shared_global_16: + case NVPTX::BI__nvvm_cp_async_cg_shared_global_16: + return checkArgCountAtMost(*this, TheCall, 3); + } + + return false; +} + /// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *). /// This checks that the target supports __builtin_cpu_supports and /// that the string argument is constant and valid. @@ -5205,6 +5950,8 @@ bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_tdpbuud: case X86::BI__builtin_ia32_tdpbf16ps: case X86::BI__builtin_ia32_tdpfp16ps: + case X86::BI__builtin_ia32_tcmmimfp16ps: + case X86::BI__builtin_ia32_tcmmrlfp16ps: return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2}); } } @@ -5569,6 +6316,7 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_pternlogq128_maskz: case X86::BI__builtin_ia32_pternlogq256_mask: case X86::BI__builtin_ia32_pternlogq256_maskz: + case X86::BI__builtin_ia32_vsm3rnds2: i = 3; l = 0; u = 255; break; case X86::BI__builtin_ia32_gatherpfdpd: @@ -6268,7 +7016,15 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; - bool IsAddSub = false; + // Bit mask for extra allowed value types other than integers for atomic + // arithmetic operations. Add/sub allow pointer and floating point. Min/max + // allow floating point. + enum ArithOpExtraValueType { + AOEVT_None = 0, + AOEVT_Pointer = 1, + AOEVT_FP = 2, + }; + unsigned ArithAllows = AOEVT_None; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -6294,18 +7050,30 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__atomic_store_n: Form = Copy; break; - case AtomicExpr::AO__hip_atomic_fetch_add: - case AtomicExpr::AO__hip_atomic_fetch_min: - case AtomicExpr::AO__hip_atomic_fetch_max: - case AtomicExpr::AO__c11_atomic_fetch_add: - case AtomicExpr::AO__c11_atomic_fetch_sub: - case AtomicExpr::AO__opencl_atomic_fetch_add: - case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_sub_fetch: - IsAddSub = true; + case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__opencl_atomic_fetch_add: + case AtomicExpr::AO__opencl_atomic_fetch_sub: + case AtomicExpr::AO__hip_atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_sub: + ArithAllows = AOEVT_Pointer | AOEVT_FP; + Form = Arithmetic; + break; + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_max_fetch: + case AtomicExpr::AO__atomic_min_fetch: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_min: + ArithAllows = AOEVT_FP; Form = Arithmetic; break; case AtomicExpr::AO__c11_atomic_fetch_and: @@ -6328,16 +7096,6 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__atomic_nand_fetch: Form = Arithmetic; break; - case AtomicExpr::AO__c11_atomic_fetch_min: - case AtomicExpr::AO__c11_atomic_fetch_max: - case AtomicExpr::AO__opencl_atomic_fetch_min: - case AtomicExpr::AO__opencl_atomic_fetch_max: - case AtomicExpr::AO__atomic_min_fetch: - case AtomicExpr::AO__atomic_max_fetch: - case AtomicExpr::AO__atomic_fetch_min: - case AtomicExpr::AO__atomic_fetch_max: - Form = Arithmetic; - break; case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__hip_atomic_exchange: @@ -6425,12 +7183,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, if (Form == Arithmetic) { // GCC does not enforce these rules for GNU atomics, but we do to help catch // trivial type errors. - auto IsAllowedValueType = [&](QualType ValType) { + auto IsAllowedValueType = [&](QualType ValType, + unsigned AllowedType) -> bool { if (ValType->isIntegerType()) return true; if (ValType->isPointerType()) - return true; - if (!ValType->isFloatingType()) + return AllowedType & AOEVT_Pointer; + if (!(ValType->isFloatingType() && (AllowedType & AOEVT_FP))) return false; // LLVM Parser does not allow atomicrmw with x86_fp80 type. if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && @@ -6439,13 +7198,13 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, return false; return true; }; - if (IsAddSub && !IsAllowedValueType(ValType)) { - Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_ptr_or_fp) - << IsC11 << Ptr->getType() << Ptr->getSourceRange(); - return ExprError(); - } - if (!IsAddSub && !ValType->isIntegerType()) { - Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int) + if (!IsAllowedValueType(ValType, ArithAllows)) { + auto DID = ArithAllows & AOEVT_FP + ? (ArithAllows & AOEVT_Pointer + ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp + : diag::err_atomic_op_needs_atomic_int_or_fp) + : diag::err_atomic_op_needs_atomic_int; + Diag(ExprRange.getBegin(), DID) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -6728,6 +7487,34 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { return false; } +bool Sema::BuiltinWasmRefNullExtern(CallExpr *TheCall) { + if (TheCall->getNumArgs() != 0) + return true; + + TheCall->setType(Context.getWebAssemblyExternrefType()); + + return false; +} + +bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) { + if (TheCall->getNumArgs() != 0) { + Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << 0 << TheCall->getNumArgs(); + return true; + } + + // This custom type checking code ensures that the nodes are as expected + // in order to later on generate the necessary builtin. + QualType Pointee = Context.getFunctionType(Context.VoidTy, {}, {}); + QualType Type = Context.getPointerType(Pointee); + Pointee = Context.getAddrSpaceQualType(Pointee, LangAS::wasm_funcref); + Type = Context.getAttributedType(attr::WebAssemblyFuncref, Type, + Context.getPointerType(Pointee)); + TheCall->setType(Type); + + return false; +} + /// We have a call to a function like __sync_fetch_and_add, which is an /// overloaded function based on the pointer type of its first argument. /// The main BuildCallExpr routines have already promoted the types of @@ -7494,9 +8281,12 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (checkArgCount(*this, TheCall, NumArgs)) return true; - // __builtin_fpclassify is the only case where NumArgs != 1, so we can count - // on all preceding parameters just being int. Try all of those. - for (unsigned i = 0; i < NumArgs - 1; ++i) { + // Find out position of floating-point argument. + unsigned FPArgNo = (NumArgs == 2) ? 0 : NumArgs - 1; + + // We can count on all parameters preceding the floating-point just being int. + // Try all of those. + for (unsigned i = 0; i < FPArgNo; ++i) { Expr *Arg = TheCall->getArg(i); if (Arg->isTypeDependent()) @@ -7509,7 +8299,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { TheCall->setArg(i, Res.get()); } - Expr *OrigArg = TheCall->getArg(NumArgs-1); + Expr *OrigArg = TheCall->getArg(FPArgNo); if (OrigArg->isTypeDependent()) return false; @@ -7521,7 +8311,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { OrigArg = UsualUnaryConversions(OrigArg).get(); else OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get(); - TheCall->setArg(NumArgs - 1, OrigArg); + TheCall->setArg(FPArgNo, OrigArg); // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) @@ -7529,6 +8319,12 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); + // __builtin_isfpclass has integer parameter that specify test mask. It is + // passed in (...), so it should be analyzed completely here. + if (NumArgs == 2) + if (SemaBuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) + return true; + return false; } @@ -7858,8 +8654,9 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { { ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg); - if (FirstArgResult.isInvalid()) + if (checkBuiltinArgument(*this, TheCall, 0)) return true; + /// In-place updation of FirstArg by checkBuiltinArgument is ignored. TheCall->setArg(0, FirstArgResult.get()); } @@ -8352,18 +9149,18 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, bool ValidString = true; if (IsARMBuiltin) { - ValidString &= Fields[0].startswith_insensitive("cp") || - Fields[0].startswith_insensitive("p"); + ValidString &= Fields[0].starts_with_insensitive("cp") || + Fields[0].starts_with_insensitive("p"); if (ValidString) Fields[0] = Fields[0].drop_front( - Fields[0].startswith_insensitive("cp") ? 2 : 1); + Fields[0].starts_with_insensitive("cp") ? 2 : 1); - ValidString &= Fields[2].startswith_insensitive("c"); + ValidString &= Fields[2].starts_with_insensitive("c"); if (ValidString) Fields[2] = Fields[2].drop_front(1); if (FiveFields) { - ValidString &= Fields[3].startswith_insensitive("c"); + ValidString &= Fields[3].starts_with_insensitive("c"); if (ValidString) Fields[3] = Fields[3].drop_front(1); } @@ -8445,29 +9242,6 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, assert((TypeStr[0] != '\0') && "Invalid types in PPC MMA builtin declaration"); - switch (BuiltinID) { - default: - // This function is called in CheckPPCBuiltinFunctionCall where the - // BuiltinID is guaranteed to be an MMA or pair vector memop builtin, here - // we are isolating the pair vector memop builtins that can be used with mma - // off so the default case is every builtin that requires mma and paired - // vector memops. - if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", - diag::err_ppc_builtin_only_on_arch, "10") || - SemaFeatureCheck(*this, TheCall, "mma", - diag::err_ppc_builtin_only_on_arch, "10")) - return true; - break; - case PPC::BI__builtin_vsx_lxvp: - case PPC::BI__builtin_vsx_stxvp: - case PPC::BI__builtin_vsx_assemble_pair: - case PPC::BI__builtin_vsx_disassemble_pair: - if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", - diag::err_ppc_builtin_only_on_arch, "10")) - return true; - break; - } - unsigned Mask = 0; unsigned ArgNum = 0; @@ -9444,13 +10218,13 @@ void CheckFormatHandler::HandlePosition(const char *startPos, getSpecifierRange(startPos, posLen)); } -void -CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen, - analyze_format_string::PositionContext p) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_positional_specifier) - << (unsigned) p, - getLocationOfByte(startPos), /*IsStringLocation*/true, - getSpecifierRange(startPos, posLen)); +void CheckFormatHandler::HandleInvalidPosition( + const char *startSpecifier, unsigned specifierLen, + analyze_format_string::PositionContext p) { + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p, + getLocationOfByte(startSpecifier), /*IsStringLocation*/ true, + getSpecifierRange(startSpecifier, specifierLen)); } void CheckFormatHandler::HandleZeroPosition(const char *startPos, @@ -9495,7 +10269,7 @@ void CheckFormatHandler::DoneProcessing() { void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr) { - assert(hasUncoveredArg() && DiagnosticExprs.size() > 0 && + assert(hasUncoveredArg() && !DiagnosticExprs.empty() && "Invalid state"); if (!ArgExpr) @@ -10392,11 +11166,18 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ImplicitMatch == ArgType::NoMatchTypeConfusion) Match = ImplicitMatch; assert(Match != ArgType::MatchPromotion); - // Look through enums to their underlying type. + // Look through unscoped enums to their underlying type. bool IsEnum = false; + bool IsScopedEnum = false; if (auto EnumTy = ExprTy->getAs<EnumType>()) { - ExprTy = EnumTy->getDecl()->getIntegerType(); - IsEnum = true; + if (EnumTy->isUnscopedEnumerationType()) { + ExprTy = EnumTy->getDecl()->getIntegerType(); + // This controls whether we're talking about the underlying type or not, + // which we only want to do when it's an unscoped enum. + IsEnum = true; + } else { + IsScopedEnum = true; + } } // %C in an Objective-C context prints a unichar, not a wchar_t. @@ -10461,7 +11242,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); - if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { + if (IntendedTy == ExprTy && !ShouldNotPrintDirectly && !IsScopedEnum) { unsigned Diag; switch (Match) { case ArgType::Match: @@ -10497,12 +11278,18 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // if necessary). SmallString<16> CastBuf; llvm::raw_svector_ostream CastFix(CastBuf); - CastFix << "("; - IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); - CastFix << ")"; + CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "("); + if (IsScopedEnum) { + CastFix << AT.getRepresentativeType(S.Context).getAsString( + S.Context.getPrintingPolicy()); + } else { + IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); + } + CastFix << (S.LangOpts.CPlusPlus ? ">" : ")"); SmallVector<FixItHint,4> Hints; - if (!AT.matchesType(S.Context, IntendedTy) || ShouldNotPrintDirectly) + if ((!AT.matchesType(S.Context, IntendedTy) && !IsScopedEnum) || + ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { @@ -10510,7 +11297,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc()); Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str())); - } else if (!requiresParensToAddCast(E)) { + } else if (!requiresParensToAddCast(E) && !S.LangOpts.CPlusPlus) { // If the expression has high enough precedence, // just write the C-style cast. Hints.push_back( @@ -12170,6 +12957,10 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, } } + if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) { + Diag(ReturnLoc, diag::err_wasm_table_art) << 1; + } + // PPC MMA non-pointer types are not allowed as return type. Checking the type // here prevent the user from using a PPC MMA type as trailing return type. if (Context.getTargetInfo().getTriple().isPPC64()) @@ -12423,7 +13214,7 @@ struct IntRange { static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) - return IntRange(value.getMinSignedBits(), false); + return IntRange(value.getSignificantBits(), false); if (value.getBitWidth() > MaxWidth) value = value.trunc(MaxWidth); @@ -13340,7 +14131,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (!Value.isSigned() || Value.isNegative()) if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not) - OriginalWidth = Value.getMinSignedBits(); + OriginalWidth = Value.getSignificantBits(); if (OriginalWidth <= FieldWidth) return false; @@ -13932,6 +14723,13 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, QualType(Source, 0)))) return; + if (Target->isRVVVLSBuiltinType() && + (S.Context.areCompatibleRVVTypes(QualType(Target, 0), + QualType(Source, 0)) || + S.Context.areLaxCompatibleRVVTypes(QualType(Target, 0), + QualType(Source, 0)))) + return; + if (!isa<VectorType>(Target)) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -14283,6 +15081,12 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (S.SourceMgr.isInSystemMacro(CC)) return; + if (SourceBT && SourceBT->isInteger() && TargetBT && + TargetBT->isInteger() && + Source->isSignedIntegerType() == Target->isSignedIntegerType()) { + return; + } + unsigned DiagID = diag::warn_impcast_integer_sign; // Traditionally, gcc has warned about this under -Wsign-compare. @@ -14330,6 +15134,9 @@ static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); + // Diagnose incomplete type for second or third operand in C. + if (!S.getLangOpts().CPlusPlus && E->getType()->isRecordType()) + S.RequireCompleteExprType(E, diag::err_incomplete_type); if (auto *CO = dyn_cast<AbstractConditionalOperator>(E)) return CheckConditionalOperator(S, CO, CC, T); @@ -14652,7 +15459,7 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, bool IsAddressOf = false; - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) { if (UO->getOpcode() != UO_AddrOf) return; IsAddressOf = true; @@ -14844,37 +15651,39 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow -void Sema::CheckForIntOverflow (Expr *E) { +void Sema::CheckForIntOverflow (const Expr *E) { // Use a work list to deal with nested struct initializers. - SmallVector<Expr *, 2> Exprs(1, E); + SmallVector<const Expr *, 2> Exprs(1, E); do { - Expr *OriginalE = Exprs.pop_back_val(); - Expr *E = OriginalE->IgnoreParenCasts(); + const Expr *OriginalE = Exprs.pop_back_val(); + const Expr *E = OriginalE->IgnoreParenCasts(); - if (isa<BinaryOperator>(E)) { + if (isa<BinaryOperator, UnaryOperator>(E)) { E->EvaluateForOverflow(Context); continue; } - if (auto InitList = dyn_cast<InitListExpr>(OriginalE)) + if (const auto *InitList = dyn_cast<InitListExpr>(OriginalE)) Exprs.append(InitList->inits().begin(), InitList->inits().end()); else if (isa<ObjCBoxedExpr>(OriginalE)) E->EvaluateForOverflow(Context); - else if (auto Call = dyn_cast<CallExpr>(E)) + else if (const auto *Call = dyn_cast<CallExpr>(E)) Exprs.append(Call->arg_begin(), Call->arg_end()); - else if (auto Message = dyn_cast<ObjCMessageExpr>(E)) + else if (const auto *Message = dyn_cast<ObjCMessageExpr>(E)) Exprs.append(Message->arg_begin(), Message->arg_end()); - else if (auto Construct = dyn_cast<CXXConstructExpr>(E)) + else if (const auto *Construct = dyn_cast<CXXConstructExpr>(E)) Exprs.append(Construct->arg_begin(), Construct->arg_end()); - else if (auto Array = dyn_cast<ArraySubscriptExpr>(E)) + else if (const auto *Temporary = dyn_cast<CXXBindTemporaryExpr>(E)) + Exprs.push_back(Temporary->getSubExpr()); + else if (const auto *Array = dyn_cast<ArraySubscriptExpr>(E)) Exprs.push_back(Array->getIdx()); - else if (auto Compound = dyn_cast<CompoundLiteralExpr>(E)) + else if (const auto *Compound = dyn_cast<CompoundLiteralExpr>(E)) Exprs.push_back(Compound->getInitializer()); - else if (auto New = dyn_cast<CXXNewExpr>(E)) { - if (New->isArray()) - if (auto ArraySize = New->getArraySize()) - Exprs.push_back(*ArraySize); + else if (const auto *New = dyn_cast<CXXNewExpr>(E); + New && New->isArray()) { + if (auto ArraySize = New->getArraySize()) + Exprs.push_back(*ArraySize); } } while (!Exprs.empty()); } @@ -15210,6 +16019,23 @@ public: Base::VisitStmt(E); } + void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *CSE) { + for (auto *Sub : CSE->children()) { + const Expr *ChildExpr = dyn_cast_or_null<Expr>(Sub); + if (!ChildExpr) + continue; + + if (ChildExpr == CSE->getOperand()) + // Do not recurse over a CoroutineSuspendExpr's operand. + // The operand is also a subexpression of getCommonExpr(), and + // recursing into it directly could confuse object management + // for the sake of sequence tracking. + continue; + + Visit(Sub); + } + } + void VisitCastExpr(const CastExpr *E) { Object O = Object(); if (E->getCastKind() == CK_LValueToRValue) @@ -15796,14 +16622,21 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, bool CheckParameterNames) { bool HasInvalidParm = false; for (ParmVarDecl *Param : Parameters) { + assert(Param && "null in a parameter list"); // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. // - // This is also C++ [dcl.fct]p6. + // C++23 [dcl.fct.def.general]/p2 + // The type of a parameter [...] for a function definition + // shall not be a (possibly cv-qualified) class type that is incomplete + // or abstract within the function body unless the function is deleted. if (!Param->isInvalidDecl() && - RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { + (RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type) || + RequireNonAbstractType(Param->getBeginLoc(), Param->getOriginalType(), + diag::err_abstract_type_in_decl, + AbstractParamType))) { Param->setInvalidDecl(); HasInvalidParm = true; } @@ -15863,6 +16696,13 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, RD, /*DeclIsField*/ false); } } + + if (!Param->isInvalidDecl() && + Param->getOriginalType()->isWebAssemblyTableType()) { + Param->setInvalidDecl(); + HasInvalidParm = true; + Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter); + } } return HasInvalidParm; @@ -15975,8 +16815,12 @@ std::optional<std::pair< if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { // FIXME: If VD is captured by copy or is an escaping __block variable, // use the alignment of VD's type. - if (!VD->getType()->isReferenceType()) + if (!VD->getType()->isReferenceType()) { + // Dependent alignment cannot be resolved -> bail out. + if (VD->hasDependentAlignment()) + break; return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero()); + } if (VD->hasInit()) return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx); } @@ -16528,14 +17372,13 @@ static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) { namespace { struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> { - ASTContext &Context; VarDecl *Variable; Expr *Capturer = nullptr; bool VarWillBeReased = false; FindCaptureVisitor(ASTContext &Context, VarDecl *variable) : EvaluatedExprVisitor<FindCaptureVisitor>(Context), - Context(Context), Variable(variable) {} + Variable(variable) {} void VisitDeclRefExpr(DeclRefExpr *ref) { if (ref->getDecl() == Variable && !Capturer) @@ -17821,6 +18664,40 @@ bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) { return false; } +bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 3)) + return true; + + Expr *Args[3]; + for (int I = 0; I < 3; ++I) { + ExprResult Converted = UsualUnaryConversions(TheCall->getArg(I)); + if (Converted.isInvalid()) + return true; + Args[I] = Converted.get(); + } + + int ArgOrdinal = 1; + for (Expr *Arg : Args) { + if (checkFPMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(), + ArgOrdinal++)) + return true; + } + + for (int I = 1; I < 3; ++I) { + if (Args[0]->getType().getCanonicalType() != + Args[I]->getType().getCanonicalType()) { + return Diag(Args[0]->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Args[0]->getType() << Args[I]->getType(); + } + + TheCall->setArg(I, Args[I]); + } + + TheCall->setType(Args[0]->getType()); + return false; +} + bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 1)) return true; @@ -17833,6 +18710,21 @@ bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { return false; } +bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 1)) + return true; + + ExprResult Arg = TheCall->getArg(0); + QualType TyArg = Arg.get()->getType(); + + if (!TyArg->isBuiltinType() && !TyArg->isVectorType()) + return Diag(TheCall->getArg(0)->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /*vector, integer or floating point ty*/ 0 << TyArg; + + TheCall->setType(TyArg); + return false; +} + ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult) { if (checkArgCount(*this, TheCall, 1)) @@ -18097,12 +18989,178 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, return CallResult; } +/// Checks the argument at the given index is a WebAssembly table and if it +/// is, sets ElTy to the element type. +static bool CheckWasmBuiltinArgIsTable(Sema &S, CallExpr *E, unsigned ArgIndex, + QualType &ElTy) { + Expr *ArgExpr = E->getArg(ArgIndex); + const auto *ATy = dyn_cast<ArrayType>(ArgExpr->getType()); + if (!ATy || !ATy->getElementType().isWebAssemblyReferenceType()) { + return S.Diag(ArgExpr->getBeginLoc(), + diag::err_wasm_builtin_arg_must_be_table_type) + << ArgIndex + 1 << ArgExpr->getSourceRange(); + } + ElTy = ATy->getElementType(); + return false; +} + +/// Checks the argument at the given index is an integer. +static bool CheckWasmBuiltinArgIsInteger(Sema &S, CallExpr *E, + unsigned ArgIndex) { + Expr *ArgExpr = E->getArg(ArgIndex); + if (!ArgExpr->getType()->isIntegerType()) { + return S.Diag(ArgExpr->getBeginLoc(), + diag::err_wasm_builtin_arg_must_be_integer_type) + << ArgIndex + 1 << ArgExpr->getSourceRange(); + } + return false; +} + +/// Check that the first argument is a WebAssembly table, and the second +/// is an index to use as index into the table. +bool Sema::BuiltinWasmTableGet(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 2)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) + return true; + + // If all is well, we set the type of TheCall to be the type of the + // element of the table. + // i.e. a table.get on an externref table has type externref, + // or whatever the type of the table element is. + TheCall->setType(ElTy); + + return false; +} + +/// Check that the first argumnet is a WebAssembly table, the second is +/// an index to use as index into the table and the third is the reference +/// type to set into the table. +bool Sema::BuiltinWasmTableSet(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 3)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) + return true; + + if (!Context.hasSameType(ElTy, TheCall->getArg(2)->getType())) + return true; + + return false; +} + +/// Check that the argument is a WebAssembly table. +bool Sema::BuiltinWasmTableSize(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 1)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is the +/// value to use for new elements (of a type matching the table type), the +/// third value is an integer. +bool Sema::BuiltinWasmTableGrow(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 3)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) + return true; + + Expr *NewElemArg = TheCall->getArg(1); + if (!Context.hasSameType(ElTy, NewElemArg->getType())) { + return Diag(NewElemArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 2 << 1 << NewElemArg->getSourceRange(); + } + + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 2)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is an +/// integer, the third is the value to use to fill the table (of a type +/// matching the table type), and the fourth is an integer. +bool Sema::BuiltinWasmTableFill(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 4)) + return true; + + QualType ElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, ElTy)) + return true; + + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 1)) + return true; + + Expr *NewElemArg = TheCall->getArg(2); + if (!Context.hasSameType(ElTy, NewElemArg->getType())) { + return Diag(NewElemArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 3 << 1 << NewElemArg->getSourceRange(); + } + + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, 3)) + return true; + + return false; +} + +/// Check that the first argument is a WebAssembly table, the second is also a +/// WebAssembly table (of the same element type), and the third to fifth +/// arguments are integers. +bool Sema::BuiltinWasmTableCopy(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 5)) + return true; + + QualType XElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 0, XElTy)) + return true; + + QualType YElTy; + if (CheckWasmBuiltinArgIsTable(*this, TheCall, 1, YElTy)) + return true; + + Expr *TableYArg = TheCall->getArg(1); + if (!Context.hasSameType(XElTy, YElTy)) { + return Diag(TableYArg->getBeginLoc(), + diag::err_wasm_builtin_arg_must_match_table_element_type) + << 2 << 1 << TableYArg->getSourceRange(); + } + + for (int I = 2; I <= 4; I++) { + if (CheckWasmBuiltinArgIsInteger(*this, TheCall, I)) + return true; + } + + return false; +} + /// \brief Enforce the bounds of a TCB /// CheckTCBEnforcement - Enforces that every function in a named TCB only /// directly calls other functions in the same TCB as marked by the enforce_tcb /// and enforce_tcb_leaf attributes. void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc, const NamedDecl *Callee) { + // This warning does not make sense in code that has no runtime behavior. + if (isUnevaluatedContext()) + return; + const NamedDecl *Caller = getCurFunctionOrMethodDecl(); if (!Caller || !Caller->hasAttr<EnforceTCBAttr>()) diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 144bbe150abb..b5d29b2e956c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4148,7 +4148,7 @@ static void AddPrettyFunctionResults(const LangOptions &LangOpts, static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, - CodeCompletionContext Context, + const CodeCompletionContext &Context, CodeCompletionResult *Results, unsigned NumResults) { if (CodeCompleter) @@ -4309,16 +4309,13 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, /*IsInclusionDirective=*/false); // Enumerate submodules. if (Mod) { - for (Module::submodule_iterator Sub = Mod->submodule_begin(), - SubEnd = Mod->submodule_end(); - Sub != SubEnd; ++Sub) { - + for (auto *Submodule : Mod->submodules()) { Builder.AddTypedTextChunk( - Builder.getAllocator().CopyString((*Sub)->Name)); + Builder.getAllocator().CopyString(Submodule->Name)); Results.AddResult(Result( Builder.TakeString(), CCP_Declaration, CXCursor_ModuleImportDecl, - (*Sub)->isAvailable() ? CXAvailability_Available - : CXAvailability_NotAvailable)); + Submodule->isAvailable() ? CXAvailability_Available + : CXAvailability_NotAvailable)); } } } @@ -6217,7 +6214,7 @@ getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate, // Look for designated initializers. // They're in their syntactic form, not yet resolved to fields. - IdentifierInfo *DesignatedFieldName = nullptr; + const IdentifierInfo *DesignatedFieldName = nullptr; unsigned ArgsAfterDesignator = 0; for (const Expr *Arg : Args) { if (const auto *DIE = dyn_cast<DesignatedInitExpr>(Arg)) { @@ -6423,7 +6420,7 @@ static QualType getDesignatedType(QualType BaseType, const Designation &Desig) { assert(D.isFieldDesignator()); auto *RD = getAsRecordDecl(BaseType); if (RD && RD->isCompleteDefinition()) { - for (const auto *Member : RD->lookup(D.getField())) + for (const auto *Member : RD->lookup(D.getFieldDecl())) if (const FieldDecl *FD = llvm::dyn_cast<FieldDecl>(Member)) { NextType = FD->getType(); break; @@ -8463,6 +8460,24 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { Results.data(), Results.size()); } +void Sema::CodeCompleteObjCClassForwardDecl(Scope *S) { + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_ObjCClassForwardDecl); + Results.EnterNewScope(); + + if (CodeCompleter->includeGlobals()) { + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + } + + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), @@ -10033,11 +10048,11 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { break; case llvm::sys::fs::file_type::regular_file: { // Only files that really look like headers. (Except in special dirs). - const bool IsHeader = Filename.endswith_insensitive(".h") || - Filename.endswith_insensitive(".hh") || - Filename.endswith_insensitive(".hpp") || - Filename.endswith_insensitive(".hxx") || - Filename.endswith_insensitive(".inc") || + const bool IsHeader = Filename.ends_with_insensitive(".h") || + Filename.ends_with_insensitive(".hh") || + Filename.ends_with_insensitive(".hpp") || + Filename.ends_with_insensitive(".hxx") || + Filename.ends_with_insensitive(".inc") || (ExtensionlessHeaders && !Filename.contains('.')); if (!IsHeader) break; @@ -10058,12 +10073,12 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { // header maps are not (currently) enumerable. break; case DirectoryLookup::LT_NormalDir: - AddFilesFromIncludeDir(IncludeDir.getDir()->getName(), IsSystem, + AddFilesFromIncludeDir(IncludeDir.getDirRef()->getName(), IsSystem, DirectoryLookup::LT_NormalDir); break; case DirectoryLookup::LT_Framework: - AddFilesFromIncludeDir(IncludeDir.getFrameworkDir()->getName(), IsSystem, - DirectoryLookup::LT_Framework); + AddFilesFromIncludeDir(IncludeDir.getFrameworkDirRef()->getName(), + IsSystem, DirectoryLookup::LT_Framework); break; } }; @@ -10075,9 +10090,8 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { using llvm::make_range; if (!Angled) { // The current directory is on the include path for "quoted" includes. - const FileEntry *CurFile = PP.getCurrentFileLexer()->getFileEntry(); - if (CurFile && CurFile->getDir()) - AddFilesFromIncludeDir(CurFile->getDir()->getName(), false, + if (auto CurFile = PP.getCurrentFileLexer()->getFileEntry()) + AddFilesFromIncludeDir(CurFile->getDir().getName(), false, DirectoryLookup::LT_NormalDir); for (const auto &D : make_range(S.quoted_dir_begin(), S.quoted_dir_end())) AddFilesFromDirLookup(D, false); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 4d4b2482d046..f24b549dd2ef 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -10,19 +10,20 @@ // //===----------------------------------------------------------------------===// -#include "TreeTransform.h" #include "clang/Sema/SemaConcept.h" -#include "clang/Sema/Sema.h" -#include "clang/Sema/SemaInternal.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "clang/Sema/TemplateDeduction.h" -#include "clang/Sema/Template.h" -#include "clang/Sema/Overload.h" -#include "clang/Sema/Initialization.h" +#include "TreeTransform.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Template.h" +#include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringExtras.h" @@ -105,27 +106,35 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, QualType Type = ConstraintExpression->getType(); auto CheckForNonPrimary = [&] { - if (PossibleNonPrimary) - *PossibleNonPrimary = - // We have the following case: - // template<typename> requires func(0) struct S { }; - // The user probably isn't aware of the parentheses required around - // the function call, and we're only going to parse 'func' as the - // primary-expression, and complain that it is of non-bool type. - (NextToken.is(tok::l_paren) && - (IsTrailingRequiresClause || - (Type->isDependentType() && - isa<UnresolvedLookupExpr>(ConstraintExpression)) || - Type->isFunctionType() || - Type->isSpecificBuiltinType(BuiltinType::Overload))) || - // We have the following case: - // template<typename T> requires size_<T> == 0 struct S { }; - // The user probably isn't aware of the parentheses required around - // the binary operator, and we're only going to parse 'func' as the - // first operand, and complain that it is of non-bool type. - getBinOpPrecedence(NextToken.getKind(), - /*GreaterThanIsOperator=*/true, - getLangOpts().CPlusPlus11) > prec::LogicalAnd; + if (!PossibleNonPrimary) + return; + + *PossibleNonPrimary = + // We have the following case: + // template<typename> requires func(0) struct S { }; + // The user probably isn't aware of the parentheses required around + // the function call, and we're only going to parse 'func' as the + // primary-expression, and complain that it is of non-bool type. + // + // However, if we're in a lambda, this might also be: + // []<typename> requires var () {}; + // Which also looks like a function call due to the lambda parentheses, + // but unlike the first case, isn't an error, so this check is skipped. + (NextToken.is(tok::l_paren) && + (IsTrailingRequiresClause || + (Type->isDependentType() && + isa<UnresolvedLookupExpr>(ConstraintExpression) && + !dyn_cast_if_present<LambdaScopeInfo>(getCurFunction())) || + Type->isFunctionType() || + Type->isSpecificBuiltinType(BuiltinType::Overload))) || + // We have the following case: + // template<typename T> requires size_<T> == 0 struct S { }; + // The user probably isn't aware of the parentheses required around + // the binary operator, and we're only going to parse 'func' as the + // first operand, and complain that it is of non-bool type. + getBinOpPrecedence(NextToken.getKind(), + /*GreaterThanIsOperator=*/true, + getLangOpts().CPlusPlus11) > prec::LogicalAnd; }; // An atomic constraint! @@ -150,11 +159,19 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, namespace { struct SatisfactionStackRAII { Sema &SemaRef; - SatisfactionStackRAII(Sema &SemaRef, llvm::FoldingSetNodeID FSNID) + bool Inserted = false; + SatisfactionStackRAII(Sema &SemaRef, const NamedDecl *ND, + const llvm::FoldingSetNodeID &FSNID) : SemaRef(SemaRef) { - SemaRef.PushSatisfactionStackEntry(FSNID); + if (ND) { + SemaRef.PushSatisfactionStackEntry(ND, FSNID); + Inserted = true; + } + } + ~SatisfactionStackRAII() { + if (Inserted) + SemaRef.PopSatisfactionStackEntry(); } - ~SatisfactionStackRAII() { SemaRef.PopSatisfactionStackEntry(); } }; } // namespace @@ -273,7 +290,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, } static bool -DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const Expr *E, +DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, + const NamedDecl *Templ, const Expr *E, const MultiLevelTemplateArgumentList &MLTAL) { E->Profile(ID, S.Context, /*Canonical=*/true); for (const auto &List : MLTAL) @@ -286,7 +304,7 @@ DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const Expr *E, // expression, or when trying to determine the constexpr-ness of special // members. Otherwise we could just use the // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function. - if (S.SatisfactionStackContains(ID)) { + if (S.SatisfactionStackContains(Templ, ID)) { S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self) << const_cast<Expr *>(E) << E->getSourceRange(); return true; @@ -317,13 +335,14 @@ static ExprResult calculateConstraintSatisfaction( return ExprError(); llvm::FoldingSetNodeID ID; - if (DiagRecursiveConstraintEval(S, ID, AtomicExpr, MLTAL)) { + if (Template && + DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) { Satisfaction.IsSatisfied = false; Satisfaction.ContainsErrors = true; return ExprEmpty(); } - SatisfactionStackRAII StackRAII(S, ID); + SatisfactionStackRAII StackRAII(S, Template, ID); // We do not want error diagnostics escaping here. Sema::SFINAETrap Trap(S); @@ -509,6 +528,48 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, .isInvalid(); } +bool Sema::addInstantiatedCapturesToScope( + FunctionDecl *Function, const FunctionDecl *PatternDecl, + LocalInstantiationScope &Scope, + const MultiLevelTemplateArgumentList &TemplateArgs) { + const auto *LambdaClass = cast<CXXMethodDecl>(Function)->getParent(); + const auto *LambdaPattern = cast<CXXMethodDecl>(PatternDecl)->getParent(); + + unsigned Instantiated = 0; + + auto AddSingleCapture = [&](const ValueDecl *CapturedPattern, + unsigned Index) { + ValueDecl *CapturedVar = LambdaClass->getCapture(Index)->getCapturedVar(); + if (cast<CXXMethodDecl>(Function)->isConst()) { + QualType T = CapturedVar->getType(); + T.addConst(); + CapturedVar->setType(T); + } + if (CapturedVar->isInitCapture()) + Scope.InstantiatedLocal(CapturedPattern, CapturedVar); + }; + + for (const LambdaCapture &CapturePattern : LambdaPattern->captures()) { + if (!CapturePattern.capturesVariable()) { + Instantiated++; + continue; + } + const ValueDecl *CapturedPattern = CapturePattern.getCapturedVar(); + if (!CapturedPattern->isParameterPack()) { + AddSingleCapture(CapturedPattern, Instantiated++); + } else { + Scope.MakeInstantiatedLocalArgPack(CapturedPattern); + std::optional<unsigned> NumArgumentsInExpansion = + getNumArgumentsInExpansion(CapturedPattern->getType(), TemplateArgs); + if (!NumArgumentsInExpansion) + continue; + for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) + AddSingleCapture(CapturedPattern, Instantiated++); + } + } + return false; +} + bool Sema::SetupConstraintScope( FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { @@ -542,6 +603,11 @@ bool Sema::SetupConstraintScope( if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL)) return true; + // Make sure the captures are also added to the instantiation scope. + if (isLambdaCallOperator(FD) && + addInstantiatedCapturesToScope(FD, FromMemTempl->getTemplatedDecl(), + Scope, MLTAL)) + return true; } return false; @@ -566,6 +632,11 @@ bool Sema::SetupConstraintScope( // child-function. if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) return true; + + // Make sure the captures are also added to the instantiation scope. + if (isLambdaCallOperator(FD) && + addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL)) + return true; } return false; @@ -608,6 +679,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, return false; } + // A lambda conversion operator has the same constraints as the call operator + // and constraints checking relies on whether we are in a lambda call operator + // (and may refer to its parameters), so check the call operator instead. + if (const auto *MD = dyn_cast<CXXConversionDecl>(FD); + MD && isLambdaConversionOperator(const_cast<CXXConversionDecl *>(MD))) + return CheckFunctionConstraints(MD->getParent()->getLambdaCallOperator(), + Satisfaction, UsageLoc, + ForOverloadResolution); + DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD); while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) { @@ -634,26 +714,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, Record = const_cast<CXXRecordDecl *>(Method->getParent()); } CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); - // We substitute with empty arguments in order to rebuild the atomic - // constraint in a constant-evaluated context. - // FIXME: Should this be a dedicated TreeTransform? - const Expr *RC = FD->getTrailingRequiresClause(); - llvm::SmallVector<Expr *, 1> Converted; - - if (CheckConstraintSatisfaction( - FD, {RC}, Converted, *MLTAL, - SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), - Satisfaction)) - return true; - - // FIXME: we need to do this for the function constraints for - // comparison of constraints to work, but do we also need to do it for - // CheckInstantiatedFunctionConstraints? That one is more difficult, but we - // seem to always just pick up the constraints from the primary template. - assert(Converted.size() <= 1 && "Got more expressions converted?"); - if (!Converted.empty() && Converted[0] != nullptr) - const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]); - return false; + return CheckConstraintSatisfaction( + FD, {FD->getTrailingRequiresClause()}, *MLTAL, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); } @@ -667,7 +731,7 @@ CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, SkipForSpecialization); - return MLTAL.getNumSubstitutedLevels(); + return MLTAL.getNumLevels(); } namespace { @@ -698,27 +762,55 @@ namespace { }; } // namespace +static const Expr *SubstituteConstraintExpression(Sema &S, const NamedDecl *ND, + const Expr *ConstrExpr) { + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + ND, /*Final=*/false, /*Innermost=*/nullptr, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, + /*SkipForSpecialization*/ false); + if (MLTAL.getNumSubstitutedLevels() == 0) + return ConstrExpr; + + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false); + + Sema::InstantiatingTemplate Inst( + S, ND->getLocation(), + Sema::InstantiatingTemplate::ConstraintNormalization{}, + const_cast<NamedDecl *>(ND), SourceRange{}); + + if (Inst.isInvalid()) + return nullptr; + + std::optional<Sema::CXXThisScopeRAII> ThisScope; + if (auto *RD = dyn_cast<CXXRecordDecl>(ND->getDeclContext())) + ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers()); + ExprResult SubstConstr = + S.SubstConstraintExpr(const_cast<clang::Expr *>(ConstrExpr), MLTAL); + if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable()) + return nullptr; + return SubstConstr.get(); +} + bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, const Expr *OldConstr, const NamedDecl *New, const Expr *NewConstr) { - if (Old && New && Old != New) { - unsigned Depth1 = CalculateTemplateDepthForConstraints( - *this, Old); - unsigned Depth2 = CalculateTemplateDepthForConstraints( - *this, New); - - // Adjust the 'shallowest' verison of this to increase the depth to match - // the 'other'. - if (Depth2 > Depth1) { - OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1) - .TransformExpr(const_cast<Expr *>(OldConstr)) - .get(); - } else if (Depth1 > Depth2) { - NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2) - .TransformExpr(const_cast<Expr *>(NewConstr)) - .get(); - } + if (OldConstr == NewConstr) + return true; + // C++ [temp.constr.decl]p4 + if (Old && New && Old != New && + Old->getLexicalDeclContext() != New->getLexicalDeclContext()) { + if (const Expr *SubstConstr = + SubstituteConstraintExpression(*this, Old, OldConstr)) + OldConstr = SubstConstr; + else + return false; + if (const Expr *SubstConstr = + SubstituteConstraintExpression(*this, New, NewConstr)) + NewConstr = SubstConstr; + else + return false; } llvm::FoldingSetNodeID ID1, ID2; @@ -1072,6 +1164,11 @@ void Sema::DiagnoseUnsatisfiedConstraint( const NormalizedConstraint * Sema::getNormalizedAssociatedConstraints( NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) { + // In case the ConstrainedDecl comes from modules, it is necessary to use + // the canonical decl to avoid different atomic constraints with the 'same' + // declarations. + ConstrainedDecl = cast<NamedDecl>(ConstrainedDecl->getCanonicalDecl()); + auto CacheEntry = NormalizationCache.find(ConstrainedDecl); if (CacheEntry == NormalizationCache.end()) { auto Normalized = @@ -1132,8 +1229,7 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, Sema::InstantiatingTemplate Inst( S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, - SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(), - ArgsAsWritten->arguments().back().getSourceRange().getEnd())); + ArgsAsWritten->arguments().front().getSourceRange()); if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; @@ -1298,7 +1394,7 @@ static NormalForm makeDNF(const NormalizedConstraint &Normalized) { } template<typename AtomicSubsumptionEvaluator> -static bool subsumes(NormalForm PDNF, NormalForm QCNF, +static bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF, AtomicSubsumptionEvaluator E) { // C++ [temp.constr.order] p2 // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 79c08adb8fab..deb67337a2ae 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -54,12 +54,10 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>(); const SourceLocation FuncLoc = FD->getLocation(); - NamespaceDecl *CoroNamespace = nullptr; ClassTemplateDecl *CoroTraits = - S.lookupCoroutineTraits(KwLoc, FuncLoc, CoroNamespace); - if (!CoroTraits) { + S.lookupCoroutineTraits(KwLoc, FuncLoc); + if (!CoroTraits) return QualType(); - } // Form template argument list for coroutine_traits<R, P1, P2, ...> according // to [dcl.fct.def.coroutine]3 @@ -117,7 +115,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, QualType PromiseType = S.Context.getTypeDeclType(Promise); auto buildElaboratedType = [&]() { - auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, CoroNamespace); + auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, S.getStdNamespace()); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); return S.Context.getElaboratedType(ETK_None, NNS, PromiseType); @@ -142,7 +140,7 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, if (PromiseType.isNull()) return QualType(); - NamespaceDecl *CoroNamespace = S.getCachedCoroNamespace(); + NamespaceDecl *CoroNamespace = S.getStdNamespace(); assert(CoroNamespace && "Should already be diagnosed"); LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"), @@ -324,7 +322,7 @@ static ExprResult buildMemberCall(Sema &S, Expr *Base, SourceLocation Loc, } // 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 +// on its address. This is to enable the support for coroutine-handle // returning await_suspend that results in a guaranteed tail call to the target // coroutine. static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, @@ -432,7 +430,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, // type Z. QualType RetType = AwaitSuspend->getCallReturnType(S.Context); - // Experimental support for coroutine_handle returning await_suspend. + // Support for coroutine_handle returning await_suspend. if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc)) // Note that we don't wrap the expression with ExprWithCleanups here @@ -1139,6 +1137,18 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { Body = CoroutineBodyStmt::Create(Context, Builder); } +static CompoundStmt *buildCoroutineBody(Stmt *Body, ASTContext &Context) { + if (auto *CS = dyn_cast<CompoundStmt>(Body)) + return CS; + + // The body of the coroutine may be a try statement if it is in + // 'function-try-block' syntax. Here we wrap it into a compound + // statement for consistency. + assert(isa<CXXTryStmt>(Body) && "Unimaged coroutine body type"); + return CompoundStmt::Create(Context, {Body}, FPOptionsOverride(), + SourceLocation(), SourceLocation()); +} + CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, sema::FunctionScopeInfo &Fn, Stmt *Body) @@ -1146,7 +1156,7 @@ CoroutineStmtBuilder::CoroutineStmtBuilder(Sema &S, FunctionDecl &FD, IsPromiseDependentType( !Fn.CoroutinePromise || Fn.CoroutinePromise->getType()->isDependentType()) { - this->Body = Body; + this->Body = buildCoroutineBody(Body, S.getASTContext()); for (auto KV : Fn.CoroutineParameterMoves) this->ParamMovesVector.push_back(KV.second); @@ -1562,7 +1572,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { const auto *OpDeleteType = OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>(); if (OpDeleteType->getNumParams() > DeleteArgs.size() && - S.getASTContext().hasSameType( + S.getASTContext().hasSameUnqualifiedType( OpDeleteType->getParamType(DeleteArgs.size()), FrameSize->getType())) DeleteArgs.push_back(FrameSize); @@ -1579,7 +1589,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // So we are not forced to pass alignment to the deallocation function. if (S.getLangOpts().CoroAlignedAllocation && OpDeleteType->getNumParams() > DeleteArgs.size() && - S.getASTContext().hasSameType( + S.getASTContext().hasSameUnqualifiedType( OpDeleteType->getParamType(DeleteArgs.size()), FrameAlignment->getType())) DeleteArgs.push_back(FrameAlignment); @@ -1732,12 +1742,22 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { assert(!FnRetType->isDependentType() && "get_return_object type must no longer be dependent"); + // The call to get_Âreturn_Âobject is sequenced before the call to + // initial_Âsuspend and is invoked at most once, but there are caveats + // regarding on whether the prvalue result object may be initialized + // directly/eager or delayed, depending on the types involved. + // + // More info at https://github.com/cplusplus/papers/issues/1414 + bool GroMatchesRetType = S.getASTContext().hasSameType(GroType, FnRetType); + if (FnRetType->isVoidType()) { ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc, /*DiscardedValue*/ false); if (Res.isInvalid()) return false; + if (!GroMatchesRetType) + this->ResultDecl = Res.get(); return true; } @@ -1750,12 +1770,61 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { return false; } - StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnValue); + StmtResult ReturnStmt; + clang::VarDecl *GroDecl = nullptr; + if (GroMatchesRetType) { + ReturnStmt = S.BuildReturnStmt(Loc, ReturnValue); + } else { + GroDecl = VarDecl::Create( + S.Context, &FD, FD.getLocation(), FD.getLocation(), + &S.PP.getIdentifierTable().get("__coro_gro"), GroType, + S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None); + GroDecl->setImplicit(); + + S.CheckVariableDeclarationType(GroDecl); + if (GroDecl->isInvalidDecl()) + return false; + + InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl); + ExprResult Res = + S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue); + if (Res.isInvalid()) + return false; + + Res = S.ActOnFinishFullExpr(Res.get(), /*DiscardedValue*/ false); + if (Res.isInvalid()) + return false; + + S.AddInitializerToDecl(GroDecl, Res.get(), + /*DirectInit=*/false); + + S.FinalizeDeclaration(GroDecl); + + // Form a declaration statement for the return declaration, so that AST + // visitors can more easily find it. + StmtResult GroDeclStmt = + S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc); + if (GroDeclStmt.isInvalid()) + return false; + + this->ResultDecl = GroDeclStmt.get(); + + ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc); + if (declRef.isInvalid()) + return false; + + ReturnStmt = S.BuildReturnStmt(Loc, declRef.get()); + } + if (ReturnStmt.isInvalid()) { noteMemberDeclaredHere(S, ReturnValue, Fn); return false; } + if (!GroMatchesRetType && + cast<clang::ReturnStmt>(ReturnStmt.get())->getNRVOCandidate() == GroDecl) + GroDecl->setNRVOVariable(true); + this->ReturnStmt = ReturnStmt.get(); return true; } @@ -1842,67 +1911,32 @@ StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) { } ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, - SourceLocation FuncLoc, - NamespaceDecl *&Namespace) { - if (!StdCoroutineTraitsCache) { - // Because coroutines moved from std::experimental in the TS to std in - // C++20, we look in both places to give users time to transition their - // TS-specific code to C++20. Diagnostics are given when the TS usage is - // discovered. - // TODO: Become stricter when <experimental/coroutine> is removed. - - IdentifierInfo const &TraitIdent = - PP.getIdentifierTable().get("coroutine_traits"); - - NamespaceDecl *StdSpace = getStdNamespace(); - LookupResult ResStd(*this, &TraitIdent, FuncLoc, LookupOrdinaryName); - bool InStd = StdSpace && LookupQualifiedName(ResStd, StdSpace); - - NamespaceDecl *ExpSpace = lookupStdExperimentalNamespace(); - LookupResult ResExp(*this, &TraitIdent, FuncLoc, LookupOrdinaryName); - bool InExp = ExpSpace && LookupQualifiedName(ResExp, ExpSpace); - - if (!InStd && !InExp) { - // The goggles, they found nothing! - Diag(KwLoc, diag::err_implied_coroutine_type_not_found) - << "std::coroutine_traits"; - return nullptr; - } + SourceLocation FuncLoc) { + if (StdCoroutineTraitsCache) + return StdCoroutineTraitsCache; - // Prefer ::std to std::experimental. - LookupResult &Result = InStd ? ResStd : ResExp; - CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace; + IdentifierInfo const &TraitIdent = + PP.getIdentifierTable().get("coroutine_traits"); - // coroutine_traits is required to be a class template. - StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>(); - if (!StdCoroutineTraitsCache) { - Result.suppressDiagnostics(); - NamedDecl *Found = *Result.begin(); - Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); - return nullptr; - } + NamespaceDecl *StdSpace = getStdNamespace(); + LookupResult Result(*this, &TraitIdent, FuncLoc, LookupOrdinaryName); + bool Found = StdSpace && LookupQualifiedName(Result, StdSpace); - if (InExp) { - // Found in std::experimental - Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) - << "coroutine_traits"; - ResExp.suppressDiagnostics(); - NamedDecl *Found = *ResExp.begin(); - Diag(Found->getLocation(), diag::note_entity_declared_at) << Found; - - if (InStd && - StdCoroutineTraitsCache != ResExp.getAsSingle<ClassTemplateDecl>()) { - // Also found something different in std - Diag(KwLoc, - diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); - Diag(StdCoroutineTraitsCache->getLocation(), - diag::note_entity_declared_at) - << StdCoroutineTraitsCache; + if (!Found) { + // The goggles, we found nothing! + Diag(KwLoc, diag::err_implied_coroutine_type_not_found) + << "std::coroutine_traits"; + return nullptr; + } - return nullptr; - } - } + // coroutine_traits is required to be a class template. + StdCoroutineTraitsCache = Result.getAsSingle<ClassTemplateDecl>(); + if (!StdCoroutineTraitsCache) { + Result.suppressDiagnostics(); + NamedDecl *Found = *Result.begin(); + Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + return nullptr; } - Namespace = CoroTraitsNamespaceCache; + return StdCoroutineTraitsCache; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e2b921bfe78f..a4bf57928470 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -46,7 +46,8 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Triple.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TargetParser/Triple.h" #include <algorithm> #include <cstring> #include <functional> @@ -1593,7 +1594,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S, - bool AllowInlineNamespace) { + bool AllowInlineNamespace) const { return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace); } @@ -1661,13 +1662,19 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { if (NewM == OldM) return false; - // Partitions are part of the module, but a partition could import another - // module, so verify that the PMIs agree. - if (NewM && OldM && - (NewM->isModulePartition() || OldM->isModulePartition()) && - NewM->getPrimaryModuleInterfaceName() == - OldM->getPrimaryModuleInterfaceName()) - return false; + if (NewM && OldM) { + // A module implementation unit has visibility of the decls in its + // implicitly imported interface. + if (NewM->isModuleImplementation() && OldM == ThePrimaryInterface) + return false; + + // Partitions are part of the module, but a partition could import another + // module, so verify that the PMIs agree. + if ((NewM->isModulePartition() || OldM->isModulePartition()) && + NewM->getPrimaryModuleInterfaceName() == + OldM->getPrimaryModuleInterfaceName()) + return false; + } bool NewIsModuleInterface = NewM && NewM->isModulePurview(); bool OldIsModuleInterface = OldM && OldM->isModulePurview(); @@ -1815,17 +1822,21 @@ bool Sema::IsRedefinitionInModule(const NamedDecl *New, return OldM == NewM; } -static bool isUsingDecl(NamedDecl *D) { +static bool isUsingDeclNotAtClassScope(NamedDecl *D) { + if (D->getDeclContext()->isFileContext()) + return false; + return isa<UsingShadowDecl>(D) || isa<UnresolvedUsingTypenameDecl>(D) || isa<UnresolvedUsingValueDecl>(D); } -/// Removes using shadow declarations from the lookup results. +/// Removes using shadow declarations not at class scope from the lookup +/// results. static void RemoveUsingDecls(LookupResult &R) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) - if (isUsingDecl(F.next())) + if (isUsingDeclNotAtClassScope(F.next())) F.erase(); F.done(); @@ -1982,7 +1993,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; } - if (D->hasAttr<UnusedAttr>() || D->hasAttr<ObjCPreciseLifetimeAttr>()) + if (D->hasAttr<UnusedAttr>() || D->hasAttr<ObjCPreciseLifetimeAttr>() || + D->hasAttr<CleanupAttr>()) return false; if (isa<LabelDecl>(D)) @@ -2085,7 +2097,7 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, if (isa<LabelDecl>(D)) { SourceLocation AfterColon = Lexer::findLocationAfterToken( D->getEndLoc(), tok::colon, Ctx.getSourceManager(), Ctx.getLangOpts(), - true); + /*SkipTrailingWhitespaceAndNewline=*/false); if (AfterColon.isInvalid()) return; Hint = FixItHint::CreateRemoval( @@ -2140,7 +2152,8 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) { else DiagID = diag::warn_unused_variable; - DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint); + SourceLocation DiagLoc = D->getLocation(); + DiagReceiver(DiagLoc, PDiag(DiagID) << D << Hint << SourceRange(DiagLoc)); } void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD, @@ -3683,10 +3696,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::ext_static_non_static) << New; - Diag(OldLocation, PrevDiag); + Diag(OldLocation, PrevDiag) << Old << Old->getType(); } else { Diag(New->getLocation(), diag::err_static_non_static) << New; - Diag(OldLocation, PrevDiag); + Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } } @@ -4373,7 +4386,7 @@ static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); - S.Diag(OldLocation, PrevDiag); + S.Diag(OldLocation, PrevDiag) << Old << Old->getType(); New->setInvalidDecl(); } @@ -4386,7 +4399,7 @@ static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { /// is attached. void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld) { - if (New->isInvalidDecl() || Old->isInvalidDecl()) + if (New->isInvalidDecl() || Old->isInvalidDecl() || New->getType()->containsErrors() || Old->getType()->containsErrors()) return; QualType MergedT; @@ -5027,7 +5040,8 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); } -static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { +static unsigned GetDiagnosticTypeSpecifierID(const DeclSpec &DS) { + DeclSpec::TST T = DS.getTypeSpecType(); switch (T) { case DeclSpec::TST_class: return 0; @@ -5038,12 +5052,17 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { case DeclSpec::TST_union: return 3; case DeclSpec::TST_enum: + if (const auto *ED = dyn_cast<EnumDecl>(DS.getRepAsDecl())) { + if (ED->isScopedUsingClassTag()) + return 5; + if (ED->isScoped()) + return 6; + } return 4; default: llvm_unreachable("unexpected type specifier"); } } - /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. @@ -5101,7 +5120,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // the declaration of a function or function template if (Tag) Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) - << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) + << GetDiagnosticTypeSpecifierID(DS) << static_cast<int>(DS.getConstexprSpecifier()); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind) @@ -5135,7 +5154,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either. Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) - << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << SS.getRange(); + << GetDiagnosticTypeSpecifierID(DS) << SS.getRange(); return nullptr; } @@ -5299,11 +5318,15 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { for (const ParsedAttr &AL : DS.getAttributes()) - Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) - << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_declspec_keyword_has_no_effect + : diag::warn_declspec_attribute_ignored) + << AL << GetDiagnosticTypeSpecifierID(DS); for (const ParsedAttr &AL : DeclAttrs) - Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) - << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_declspec_keyword_has_no_effect + : diag::warn_declspec_attribute_ignored) + << AL << GetDiagnosticTypeSpecifierID(DS); } } @@ -5694,10 +5717,10 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, SC = SC_None; } - assert(DS.getAttributes().empty() && "No attribute expected"); Anon = VarDecl::Create(Context, Owner, DS.getBeginLoc(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, SC); + ProcessDeclAttributes(S, Anon, Dc); // Default-initialize the implicit variable. This initialization will be // trivial in almost all cases, except if a union member has an in-class @@ -6366,10 +6389,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // containing the two f's declared in X, but neither of them // matches. - // C++ [dcl.meaning]p1: - // [...] the member shall not merely have been introduced by a - // using-declaration in the scope of the class or namespace nominated by - // the nested-name-specifier of the declarator-id. RemoveUsingDecls(Previous); } @@ -6746,14 +6765,26 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, if (IdentifierInfo *II = NewTD->getIdentifier()) if (!NewTD->isInvalidDecl() && NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { - if (II->isStr("FILE")) + switch (II->getInterestingIdentifierID()) { + case tok::InterestingIdentifierKind::FILE: Context.setFILEDecl(NewTD); - else if (II->isStr("jmp_buf")) + break; + case tok::InterestingIdentifierKind::jmp_buf: Context.setjmp_bufDecl(NewTD); - else if (II->isStr("sigjmp_buf")) + break; + case tok::InterestingIdentifierKind::sigjmp_buf: Context.setsigjmp_bufDecl(NewTD); - else if (II->isStr("ucontext_t")) + break; + case tok::InterestingIdentifierKind::ucontext_t: Context.setucontext_tDecl(NewTD); + break; + case tok::InterestingIdentifierKind::float_t: + case tok::InterestingIdentifierKind::double_t: + NewTD->addAttr(AvailableOnlyInDefaultEvalMethodAttr::Create(Context)); + break; + default: + break; + } } return NewTD; @@ -7674,7 +7705,12 @@ NamedDecl *Sema::ActOnVariableDeclarator( // If we have any template parameter lists that don't directly belong to // the variable (matching the scope specifier), store them. - unsigned VDTemplateParamLists = TemplateParams ? 1 : 0; + // An explicit variable template specialization does not own any template + // parameter lists. + bool IsExplicitSpecialization = + IsVariableTemplateSpecialization && !IsPartialSpecialization; + unsigned VDTemplateParamLists = + (TemplateParams && !IsExplicitSpecialization) ? 1 : 0; if (TemplateParamLists.size() > VDTemplateParamLists) NewVD->setTemplateParameterListsInfo( Context, TemplateParamLists.drop_back(VDTemplateParamLists)); @@ -7727,7 +7763,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) { - if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + if (getLangOpts().CUDA || getLangOpts().OpenMPIsTargetDevice || getLangOpts().SYCLIsDevice) { // Postpone error emission until we've collected attributes required to // figure out whether it's a host or device variable and whether the @@ -7770,9 +7806,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constinit_local_variable); else - NewVD->addAttr(ConstInitAttr::Create( - Context, D.getDeclSpec().getConstexprSpecLoc(), - AttributeCommonInfo::AS_Keyword, ConstInitAttr::Keyword_constinit)); + NewVD->addAttr( + ConstInitAttr::Create(Context, D.getDeclSpec().getConstexprSpecLoc(), + ConstInitAttr::Keyword_constinit)); break; } @@ -7833,6 +7869,18 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + // WebAssembly tables are always in address space 1 (wasm_var). Don't apply + // address space if the table has local storage (semantic checks elsewhere + // will produce an error anyway). + if (const auto *ATy = dyn_cast<ArrayType>(NewVD->getType())) { + if (ATy && ATy->getElementType().isWebAssemblyReferenceType() && + !NewVD->hasLocalStorage()) { + QualType Type = Context.getAddrSpaceQualType( + NewVD->getType(), Context.getLangASForBuiltinAddressSpace(1)); + NewVD->setType(Type); + } + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -7844,17 +7892,18 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (const auto *TT = R->getAs<TypedefType>()) copyAttrFromTypedefToDecl<AllocSizeAttr>(*this, NewVD, TT); - if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + if (getLangOpts().CUDA || getLangOpts().OpenMPIsTargetDevice || getLangOpts().SYCLIsDevice) { if (EmitTLSUnsupportedError && ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) || - (getLangOpts().OpenMPIsDevice && + (getLangOpts().OpenMPIsTargetDevice && OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD)))) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); if (EmitTLSUnsupportedError && - (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice))) + (LangOpts.SYCLIsDevice || + (LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice))) targetDiag(D.getIdentifierLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static // storage [duration]." @@ -7989,6 +8038,13 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (!IsVariableTemplateSpecialization) D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + // CheckVariableDeclaration will set NewVD as invalid if something is in + // error like WebAssembly tables being declared as arrays with a non-zero + // size, but then parsing continues and emits further errors on that line. + // To avoid that we check here if it happened and return nullptr. + if (NewVD->getType()->isWebAssemblyTableType() && NewVD->isInvalidDecl()) + return nullptr; + if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() @@ -8133,7 +8189,7 @@ NamedDecl *Sema::getShadowedDeclaration(const VarDecl *D, return nullptr; // Don't diagnose declarations at file scope. - if (D->hasGlobalStorage()) + if (D->hasGlobalStorage() && !D->isStaticLocal()) return nullptr; NamedDecl *ShadowedDecl = R.getFoundDecl(); @@ -8595,6 +8651,28 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } } + // WebAssembly tables must be static with a zero length and can't be + // declared within functions. + if (T->isWebAssemblyTableType()) { + if (getCurScope()->getParent()) { // Parent is null at top-level + Diag(NewVD->getLocation(), diag::err_wasm_table_in_function); + NewVD->setInvalidDecl(); + return; + } + if (NewVD->getStorageClass() != SC_Static) { + Diag(NewVD->getLocation(), diag::err_wasm_table_must_be_static); + NewVD->setInvalidDecl(); + return; + } + const auto *ATy = dyn_cast<ConstantArrayType>(T.getTypePtr()); + if (!ATy || ATy->getSize().getSExtValue() != 0) { + Diag(NewVD->getLocation(), + diag::err_typecheck_wasm_table_must_have_zero_length); + NewVD->setInvalidDecl(); + return; + } + } + bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || NewVD->hasAttr<BlocksAttr>()) @@ -8665,7 +8743,8 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } - if (!NewVD->hasLocalStorage() && T->isSizelessType()) { + if (!NewVD->hasLocalStorage() && T->isSizelessType() && + !T.isWebAssemblyReferenceType()) { Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T; NewVD->setInvalidDecl(); return; @@ -8693,7 +8772,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } // Check that SVE types are only used in functions with SVE available. - if (T->isSVESizelessBuiltinType() && CurContext->isFunctionOrMethod()) { + if (T->isSVESizelessBuiltinType() && isa<FunctionDecl>(CurContext)) { const FunctionDecl *FD = cast<FunctionDecl>(CurContext); llvm::StringMap<bool> CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); @@ -8704,6 +8783,9 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } } + + if (T->isRVVType()) + checkRVVTypeSupport(T, NewVD->getLocation(), cast<ValueDecl>(CurContext)); } /// Perform semantic checking on a newly-created variable @@ -9101,15 +9183,6 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, } Expr *TrailingRequiresClause = D.getTrailingRequiresClause(); - // Check that the return type is not an abstract class type. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!DC->isRecord() && - SemaRef.RequireNonAbstractType( - D.getIdentifierLoc(), R->castAs<FunctionType>()->getReturnType(), - diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType)) - D.setInvalidType(); - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && @@ -9181,8 +9254,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, SemaRef.Diag(TrailingRequiresClause->getBeginLoc(), diag::err_trailing_requires_clause_on_deduction_guide) << TrailingRequiresClause->getSourceRange(); - SemaRef.CheckDeductionGuideDeclarator(D, R, SC); - + if (SemaRef.CheckDeductionGuideDeclarator(D, R, SC)) + return nullptr; return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), ExplicitSpecifier, NameInfo, R, TInfo, D.getEndLoc()); @@ -9272,6 +9345,12 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { ParamKind == InvalidKernelParam) return ParamKind; + // OpenCL v3.0 s6.11.a: + // A restriction to pass pointers to pointers only applies to OpenCL C + // v1.2 or below. + if (S.getLangOpts().getOpenCLCompatibleVersion() > 120) + return ValidKernelParam; + return PtrPtrKernelParam; } @@ -9299,6 +9378,11 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { return InvalidKernelParam; } + // OpenCL v1.2 s6.9.p: + // A restriction to pass pointers only applies to OpenCL C v1.2 or below. + if (S.getLangOpts().getOpenCLCompatibleVersion() > 120) + return ValidKernelParam; + return PtrKernelParam; } @@ -9365,13 +9449,8 @@ static void checkIsValidOpenCLKernelParameter( // OpenCL v3.0 s6.11.a: // A kernel function argument cannot be declared as a pointer to a pointer // type. [...] This restriction only applies to OpenCL C 1.2 or below. - if (S.getLangOpts().getOpenCLCompatibleVersion() <= 120) { - S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param); - D.setInvalidType(); - return; - } - - ValidTypes.insert(PT.getTypePtr()); + S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param); + D.setInvalidType(); return; case InvalidAddrSpacePtrKernelParam: @@ -9489,7 +9568,8 @@ static void checkIsValidOpenCLKernelParameter( // OpenCL v1.2 s6.9.p: // Arguments to kernel functions that are declared to be a struct or union // do not allow OpenCL objects to be passed as elements of the struct or - // union. + // union. This restriction was lifted in OpenCL v2.0 with the introduction + // of SVM. if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam || ParamType == InvalidAddrSpacePtrKernelParam) { S.Diag(Param->getLocation(), @@ -9556,6 +9636,7 @@ static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD, case Builtin::BIaddressof: case Builtin::BI__addressof: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIas_const: { @@ -10105,9 +10186,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setParams(Params); if (D.getDeclSpec().isNoreturnSpecified()) - NewFD->addAttr(C11NoReturnAttr::Create(Context, - D.getDeclSpec().getNoreturnSpecLoc(), - AttributeCommonInfo::AS_Keyword)); + NewFD->addAttr( + C11NoReturnAttr::Create(Context, D.getDeclSpec().getNoreturnSpecLoc())); // Functions returning a variably modified type violate C99 6.7.5.2p2 // because all functions have linkage. @@ -10122,15 +10202,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, !NewFD->hasAttr<SectionAttr>()) NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit( Context, PragmaClangTextSection.SectionName, - PragmaClangTextSection.PragmaLocation, AttributeCommonInfo::AS_Pragma)); + PragmaClangTextSection.PragmaLocation)); // Apply an implicit SectionAttr if #pragma code_seg is active. if (CodeSegStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr<SectionAttr>()) { NewFD->addAttr(SectionAttr::CreateImplicit( Context, CodeSegStack.CurrentValue->getString(), - CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, - SectionAttr::Declspec_allocate)); + CodeSegStack.CurrentPragmaLocation, SectionAttr::Declspec_allocate)); if (UnifySection(CodeSegStack.CurrentValue->getString(), ASTContext::PSF_Implicit | ASTContext::PSF_Execute | ASTContext::PSF_Read, @@ -10143,8 +10222,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (StrictGuardStackCheckStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr<StrictGuardStackCheckAttr>()) NewFD->addAttr(StrictGuardStackCheckAttr::CreateImplicit( - Context, PragmaClangTextSection.PragmaLocation, - AttributeCommonInfo::AS_Pragma)); + Context, PragmaClangTextSection.PragmaLocation)); // Apply an implicit CodeSegAttr from class declspec or // apply an implicit SectionAttr from #pragma code_seg if active. @@ -10185,14 +10263,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, CheckHLSLEntryPoint(NewFD); if (!NewFD->isInvalidDecl()) { auto Env = TargetInfo.getTriple().getEnvironment(); - AttributeCommonInfo AL(NewFD->getBeginLoc()); HLSLShaderAttr::ShaderType ShaderType = static_cast<HLSLShaderAttr::ShaderType>( hlsl::getStageFromEnvironment(Env)); // To share code with HLSLShaderAttr, add HLSLShaderAttr to entry // function. - if (HLSLShaderAttr *Attr = mergeHLSLShaderAttr(NewFD, AL, ShaderType)) - NewFD->addAttr(Attr); + if (HLSLShaderAttr *NT = NewFD->getAttr<HLSLShaderAttr>()) { + if (NT->getType() != ShaderType) + Diag(NT->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch) + << NT; + } else { + NewFD->addAttr(HLSLShaderAttr::Create(Context, ShaderType, + NewFD->getBeginLoc())); + } } } // HLSL does not support specifying an address space on a function return @@ -10663,6 +10746,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } } + // WebAssembly tables can't be used as function parameters. + if (Context.getTargetInfo().getTriple().isWasm()) { + if (PT->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) { + Diag(Param->getTypeSpecStartLoc(), + diag::err_wasm_table_as_function_parameter); + D.setInvalidType(); + } + } } // Here we have an function template explicit specialization at class scope. @@ -10772,8 +10863,7 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, CodeSegStack.CurrentValue) return SectionAttr::CreateImplicit( getASTContext(), CodeSegStack.CurrentValue->getString(), - CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, - SectionAttr::Declspec_allocate); + CodeSegStack.CurrentPragmaLocation, SectionAttr::Declspec_allocate); return nullptr; } @@ -11314,8 +11404,7 @@ static bool CheckMultiVersionAdditionalDecl( if (NewMVKind == MultiVersionKind::None && OldMVKind == MultiVersionKind::TargetVersion) { NewFD->addAttr(TargetVersionAttr::CreateImplicit( - S.Context, "default", NewFD->getSourceRange(), - AttributeCommonInfo::AS_GNU)); + S.Context, "default", NewFD->getSourceRange())); NewFD->setIsMultiVersion(); NewMVKind = MultiVersionKind::TargetVersion; if (!NewTVA) { @@ -11514,6 +11603,10 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, return false; } + // Target attribute on AArch64 is not used for multiversioning + if (NewTA && S.getASTContext().getTargetInfo().getTriple().isAArch64()) + return false; + if (!OldDecl || !OldDecl->getAsFunction() || OldDecl->getDeclContext()->getRedeclContext() != NewFD->getDeclContext()->getRedeclContext()) { @@ -11532,8 +11625,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>(); if (OldTVA) { NewFD->addAttr(TargetVersionAttr::CreateImplicit( - S.Context, "default", NewFD->getSourceRange(), - AttributeCommonInfo::AS_GNU)); + S.Context, "default", NewFD->getSourceRange())); NewFD->setIsMultiVersion(); OldFD->setIsMultiVersion(); OldDecl = OldFD; @@ -11862,8 +11954,33 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // member-declarator shall be present only if the declarator declares a // templated function ([dcl.fct]). if (Expr *TRC = NewFD->getTrailingRequiresClause()) { - if (!NewFD->isTemplated() && !NewFD->isTemplateInstantiation()) + // [temp.pre]/8: + // An entity is templated if it is + // - a template, + // - an entity defined ([basic.def]) or created ([class.temporary]) in a + // templated entity, + // - a member of a templated entity, + // - an enumerator for an enumeration that is a templated entity, or + // - the closure type of a lambda-expression ([expr.prim.lambda.closure]) + // appearing in the declaration of a templated entity. [Note 6: A local + // class, a local or block variable, or a friend function defined in a + // templated entity is a templated entity. — end note] + // + // A templated function is a function template or a function that is + // templated. A templated class is a class template or a class that is + // templated. A templated variable is a variable template or a variable + // that is templated. + + if (!NewFD->getDescribedFunctionTemplate() && // -a template + // defined... in a templated entity + !(DeclIsDefn && NewFD->isTemplated()) && + // a member of a templated entity + !(isa<CXXMethodDecl>(NewFD) && NewFD->isTemplated()) && + // Don't complain about instantiations, they've already had these + // rules + others enforced. + !NewFD->isTemplateInstantiation()) { Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function); + } } if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) @@ -12584,10 +12701,9 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, if (Init) DeduceInits = Init; - if (DirectInit) { - if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init)) - DeduceInits = PL->exprs(); - } + auto *PL = dyn_cast_if_present<ParenListExpr>(Init); + if (DirectInit && PL) + DeduceInits = PL->exprs(); if (isa<DeducedTemplateSpecializationType>(Deduced)) { assert(VDecl && "non-auto type for init capture deduction?"); @@ -12597,7 +12713,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, // FIXME: Initialization should not be taking a mutable list of inits. SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end()); return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, - InitsCopy); + InitsCopy, PL); } if (DirectInit) { @@ -13024,6 +13140,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + // WebAssembly tables can't be used to initialise a variable. + if (Init && !Init->getType().isNull() && + Init->getType()->isWebAssemblyTableType()) { + Diag(Init->getExprLoc(), diag::err_wasm_table_art) << 0; + VDecl->setInvalidDecl(); + return; + } + // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (VDecl->getType()->isUndeducedType()) { // Attempt typo correction early so that the type of the init expression can @@ -13088,9 +13212,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // C++ [module.import/6] external definitions are not permitted in header // units. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && - VDecl->isThisDeclarationADefinition() && + !VDecl->isInvalidDecl() && VDecl->isThisDeclarationADefinition() && VDecl->getFormalLinkage() == Linkage::ExternalLinkage && - !VDecl->isInline()) { + !VDecl->isInline() && !VDecl->isTemplated() && + !isa<VarTemplateSpecializationDecl>(VDecl)) { Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit); VDecl->setInvalidDecl(); } @@ -13471,7 +13596,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { } if (LangOpts.OpenMP && - (LangOpts.OpenMPIsDevice || !LangOpts.OMPTargetTriples.empty()) && + (LangOpts.OpenMPIsTargetDevice || !LangOpts.OMPTargetTriples.empty()) && VDecl->isFileVarDecl()) DeclsToCheckForDeferredDiags.insert(VDecl); CheckCompleteVariableDeclaration(VDecl); @@ -13656,7 +13781,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { } if (Context.getTargetInfo().allowDebugInfoForExternalRef() && - !Var->isInvalidDecl() && !getLangOpts().CPlusPlus) + !Var->isInvalidDecl()) ExternalDeclarations.push_back(Var); return; @@ -14147,9 +14272,9 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } else if (Stack->CurrentValue) { SectionFlags |= ASTContext::PSF_Implicit; auto SectionName = Stack->CurrentValue->getString(); - var->addAttr(SectionAttr::CreateImplicit( - Context, SectionName, Stack->CurrentPragmaLocation, - AttributeCommonInfo::AS_Pragma, SectionAttr::Declspec_allocate)); + var->addAttr(SectionAttr::CreateImplicit(Context, SectionName, + Stack->CurrentPragmaLocation, + SectionAttr::Declspec_allocate)); if (UnifySection(SectionName, SectionFlags, var)) var->dropAttr<SectionAttr>(); } @@ -14159,8 +14284,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // attribute. if (CurInitSeg && var->getInit()) var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), - CurInitSegLoc, - AttributeCommonInfo::AS_Pragma)); + CurInitSegLoc)); } // All the following checks are C++ only. @@ -14262,23 +14386,19 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { if (PragmaClangBSSSection.Valid) VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit( Context, PragmaClangBSSSection.SectionName, - PragmaClangBSSSection.PragmaLocation, - AttributeCommonInfo::AS_Pragma)); + PragmaClangBSSSection.PragmaLocation)); if (PragmaClangDataSection.Valid) VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit( Context, PragmaClangDataSection.SectionName, - PragmaClangDataSection.PragmaLocation, - AttributeCommonInfo::AS_Pragma)); + PragmaClangDataSection.PragmaLocation)); if (PragmaClangRodataSection.Valid) VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit( Context, PragmaClangRodataSection.SectionName, - PragmaClangRodataSection.PragmaLocation, - AttributeCommonInfo::AS_Pragma)); + PragmaClangRodataSection.PragmaLocation)); if (PragmaClangRelroSection.Valid) VD->addAttr(PragmaClangRelroSectionAttr::CreateImplicit( Context, PragmaClangRelroSection.SectionName, - PragmaClangRelroSection.PragmaLocation, - AttributeCommonInfo::AS_Pragma)); + PragmaClangRelroSection.PragmaLocation)); } if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) { @@ -14422,6 +14542,12 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (Decl *D = Group[i]) { + // Check if the Decl has been declared in '#pragma omp declare target' + // directive and has static storage duration. + if (auto *VD = dyn_cast<VarDecl>(D); + LangOpts.OpenMP && VD && VD->hasAttr<OMPDeclareTargetDeclAttr>() && + VD->hasGlobalStorage()) + ActOnOpenMPDeclareTargetInitializer(D); // For declarators, there are some additional syntactic-ish checks we need // to perform. if (auto *DD = dyn_cast<DeclaratorDecl>(D)) { @@ -14802,14 +14928,6 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, checkNonTrivialCUnion(New->getType(), New->getLocation(), NTCUC_FunctionParam, NTCUK_Destruct|NTCUK_Copy); - // Parameters can not be abstract class types. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!CurContext->isRecord() && - RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl, - AbstractParamType)) - New->setInvalidDecl(); - // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { @@ -14830,7 +14948,11 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // OpenCL allows function arguments declared to be an array of a type // to be qualified with an address space. !(getLangOpts().OpenCL && - (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) { + (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private)) && + // WebAssembly allows reference types as parameters. Funcref in particular + // lives in a different address space. + !(T->isFunctionPointerType() && + T.getAddressSpace() == LangAS::wasm_funcref)) { Diag(NameLoc, diag::err_arg_with_address_space); New->setInvalidDecl(); } @@ -15125,6 +15247,17 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext : ExprEvalContexts.back().Context); + // Each ExpressionEvaluationContextRecord also keeps track of whether the + // context is nested in an immediate function context, so smaller contexts + // that appear inside immediate functions (like variable initializers) are + // considered to be inside an immediate function context even though by + // themselves they are not immediate function contexts. But when a new + // function is entered, we need to reset this tracking, since the entered + // function might be not an immediate function. + ExprEvalContexts.back().InImmediateFunctionContext = FD->isConsteval(); + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + getLangOpts().CPlusPlus20 && FD->isImmediateEscalating(); + // Check for defining attributes before the check for redefinition. if (const auto *Attr = FD->getAttr<AliasAttr>()) { Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 0; @@ -15201,13 +15334,19 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, } } - // The return type of a function definition must be complete (C99 6.9.1p3), - // unless the function is deleted (C++ specifc, C++ [dcl.fct.def.general]p2) + // The return type of a function definition must be complete (C99 6.9.1p3). + // C++23 [dcl.fct.def.general]/p2 + // The type of [...] the return for a function definition + // shall not be a (possibly cv-qualified) class type that is incomplete + // or abstract within the function body unless the function is deleted. QualType ResultType = FD->getReturnType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && - RequireCompleteType(FD->getLocation(), ResultType, - diag::err_func_def_incomplete_result)) + (RequireCompleteType(FD->getLocation(), ResultType, + diag::err_func_def_incomplete_result) || + RequireNonAbstractType(FD->getLocation(), FD->getReturnType(), + diag::err_abstract_type_in_decl, + AbstractReturnType))) FD->setInvalidDecl(); if (FnBodyScope) @@ -15259,9 +15398,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // FIXME: Consider an alternate location for the test where the inlined() // state is complete. if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && + !FD->isInvalidDecl() && !FD->isInlined() && + BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default && FD->getFormalLinkage() == Linkage::ExternalLinkage && - !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && - BodyKind != FnBodyKind::Default && !FD->isInlined()) { + !FD->isTemplated() && !FD->isTemplateInstantiation()) { assert(FD->isThisDeclarationADefinition()); Diag(FD->getLocation(), diag::err_extern_def_in_header_unit); FD->setInvalidDecl(); @@ -15432,10 +15572,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // one is already popped when finishing the lambda in BuildLambdaExpr(). // This is meant to pop the context added in ActOnStartOfFunctionDef(). ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); - if (FD) { FD->setBody(Body); FD->setWillHaveBody(false); + CheckImmediateEscalatingFunctionDefinition(FD, FSI); if (getLangOpts().CPlusPlus14) { if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && @@ -15821,7 +15961,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiscardCleanupsInEvaluationContext(); } - if (FD && ((LangOpts.OpenMP && (LangOpts.OpenMPIsDevice || + if (FD && ((LangOpts.OpenMP && (LangOpts.OpenMPIsTargetDevice || !LangOpts.OMPTargetTriples.empty())) || LangOpts.CUDA || LangOpts.SYCLIsDevice)) { auto ES = getEmissionStatus(FD); @@ -15867,8 +16007,14 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, while (!BlockScope->isCompoundStmtScope() && BlockScope->getParent()) BlockScope = BlockScope->getParent(); + // Loop until we find a DeclContext that is either a function/method or the + // translation unit, which are the only two valid places to implicitly define + // a function. This avoids accidentally defining the function within a tag + // declaration, for example. Scope *ContextScope = BlockScope; - while (!ContextScope->getEntity()) + while (!ContextScope->getEntity() || + (!ContextScope->getEntity()->isFunctionOrMethod() && + !ContextScope->getEntity()->isTranslationUnit())) ContextScope = ContextScope->getParent(); ContextRAII SavedContext(*this, ContextScope->getEntity()); @@ -16003,7 +16149,11 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( // indicates failure by returning a null pointer value. Any other allocation // function never returns a null pointer value and indicates failure only by // throwing an exception [...] - if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>()) + // + // However, -fcheck-new invalidates this possible assumption, so don't add + // NonNull when that is enabled. + if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>() && + !getLangOpts().CheckNew) FD->addAttr(ReturnsNonNullAttr::CreateImplicit(Context, FD->getLocation())); // C++2a [basic.stc.dynamic.allocation]p2: @@ -16196,6 +16346,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { case Builtin::BI__builtin_addressof: case Builtin::BIas_const: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: if (ParmVarDecl *P = FD->getParamDecl(0u); @@ -16616,8 +16767,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, - OffsetOfKind OOK, UsingShadowDecl *&FoundUsingShadow, - SkipBodyInfo *SkipBody) { + OffsetOfKind OOK, SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -16991,11 +17141,14 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, S = getTagInjectionScope(S, getLangOpts()); } else { assert(TUK == TUK_Friend); + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(SearchDC); + // C++ [namespace.memdef]p3: // If a friend declaration in a non-local class first declares a // class or function, the friend class or function is a member of // the innermost enclosing namespace. - SearchDC = SearchDC->getEnclosingNamespaceContext(); + SearchDC = RD->isLocalClass() ? RD->isLocalClass() + : SearchDC->getEnclosingNamespaceContext(); } // In C++, we need to do a redeclaration lookup to properly @@ -17052,7 +17205,6 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // redefinition if either context is within the other. if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { auto *OldTag = dyn_cast<TagDecl>(PrevDecl); - FoundUsingShadow = Shadow; if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) && !(OldTag && isAcceptableTagRedeclContext( @@ -17608,9 +17760,10 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, Record->markAbstract(); if (FinalLoc.isValid()) { - Record->addAttr(FinalAttr::Create( - Context, FinalLoc, AttributeCommonInfo::AS_Keyword, - static_cast<FinalAttr::Spelling>(IsFinalSpelledSealed))); + Record->addAttr(FinalAttr::Create(Context, FinalLoc, + IsFinalSpelledSealed + ? FinalAttr::Keyword_sealed + : FinalAttr::Keyword_final)); } // C++ [class]p2: // [...] The class-name is also inserted into the scope of the @@ -18871,10 +19024,24 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ProcessDeclAttributeList(S, Record, Attrs); // Check to see if a FieldDecl is a pointer to a function. - auto IsFunctionPointer = [&](const Decl *D) { + auto IsFunctionPointerOrForwardDecl = [&](const Decl *D) { const FieldDecl *FD = dyn_cast<FieldDecl>(D); - if (!FD) + if (!FD) { + // Check whether this is a forward declaration that was inserted by + // Clang. This happens when a non-forward declared / defined type is + // used, e.g.: + // + // struct foo { + // struct bar *(*f)(); + // struct bar *(*g)(); + // }; + // + // "struct bar" shows up in the decl AST as a "RecordDecl" with an + // incomplete definition. + if (const auto *TD = dyn_cast<TagDecl>(D)) + return !TD->isCompleteDefinition(); return false; + } QualType FieldType = FD->getType().getDesugaredType(Context); if (isa<PointerType>(FieldType)) { QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType(); @@ -18888,7 +19055,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (!getLangOpts().CPlusPlus && (Record->hasAttr<RandomizeLayoutAttr>() || (!Record->hasAttr<NoRandomizeLayoutAttr>() && - llvm::all_of(Record->decls(), IsFunctionPointer))) && + llvm::all_of(Record->decls(), IsFunctionPointerOrForwardDecl))) && !Record->isUnion() && !getLangOpts().RandstructSeed.empty() && !Record->isRandomized()) { SmallVector<Decl *, 32> NewDeclOrdering; @@ -19043,7 +19210,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, --BitWidth; return Value.getActiveBits() <= BitWidth; } - return Value.getMinSignedBits() <= BitWidth; + return Value.getSignificantBits() <= BitWidth; } // Given an integral type, return the next larger integral type @@ -19233,6 +19400,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!getLangOpts().CPlusPlus && !T.isNull()) Diag(IdLoc, diag::warn_enum_value_overflow); } else if (!getLangOpts().CPlusPlus && + !EltTy->isDependentType() && !isRepresentableIntegerValue(Context, EnumVal, EltTy)) { // Enforce C99 6.7.2.2p2 even when we compute the next value. Diag(IdLoc, diag::ext_enum_value_not_int) @@ -19433,7 +19601,7 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, return; } - // Constants with initalizers are handled in the next loop. + // Constants with initializers are handled in the next loop. if (ECD->getInitExpr()) continue; @@ -19578,8 +19746,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, unsigned ActiveBits = InitVal.getActiveBits(); NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u}); } else { - NumNegativeBits = std::max(NumNegativeBits, - (unsigned)InitVal.getMinSignedBits()); + NumNegativeBits = + std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits()); } } @@ -19794,7 +19962,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc), - AttributeCommonInfo::AS_Pragma); + AttributeCommonInfo::Form::Pragma()); AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit( Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info); @@ -19819,7 +19987,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { - PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma)); + PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc)); } else { (void)WeakUndeclaredIdentifiers[Name].insert(WeakInfo(nullptr, NameLoc)); } @@ -19847,7 +20015,7 @@ ObjCContainerDecl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); } -Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD, +Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD, bool Final) { assert(FD && "Expected non-null FunctionDecl"); @@ -19865,13 +20033,13 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD, // We have to check the GVA linkage of the function's *definition* -- if we // only have a declaration, we don't know whether or not the function will // be emitted, because (say) the definition could include "inline". - FunctionDecl *Def = FD->getDefinition(); + const FunctionDecl *Def = FD->getDefinition(); return Def && !isDiscardableGVALinkage( getASTContext().GetGVALinkageForFunction(Def)); }; - if (LangOpts.OpenMPIsDevice) { + if (LangOpts.OpenMPIsTargetDevice) { // In OpenMP device mode we will not emit host only functions, or functions // we don't need due to their linkage. std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a303c7f57280..ed69e802c95d 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -273,7 +273,9 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Ex template <typename AttrTy> static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *A = D->getAttr<AttrTy>()) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -283,8 +285,9 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { template <typename AttrTy> static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { if (const auto *A = D->getAttr<AttrTy>()) { - S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL - << A; + S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) + << &AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -447,7 +450,7 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { if (!CXXRecord) return false; - for (auto BaseSpecifier : CXXRecord->bases()) { + for (const auto &BaseSpecifier : CXXRecord->bases()) { if (!foundStarOperator) foundStarOperator = IsOverloadedOperatorPresent( BaseSpecifier.getType()->getAsRecordDecl(), OO_Star); @@ -1878,8 +1881,11 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Cannot have two ownership attributes of different kinds for the same // index. if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; - return; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << I + << (AL.isRegularKeywordAttribute() || + I->isRegularKeywordAttribute()); + return; } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { // A returns attribute conflicts with any other returns attribute using @@ -2033,7 +2039,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (S.Context.getTargetInfo().getTriple().isOSAIX() && - Model != "global-dynamic") { + Model != "global-dynamic" && Model != "local-exec") { S.Diag(LiteralLoc, diag::err_aix_attr_unsupported_tls_model) << Model; return; } @@ -2164,7 +2170,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // nonstatic) when in Microsoft compatibility mode. if (S.getLangOpts().MSVCCompat && isa<CXXMethodDecl>(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str) - << AL << "non-member functions"; + << AL << AL.isRegularKeywordAttribute() << "non-member functions"; return; } } @@ -2177,7 +2183,8 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attrs << ExpectedFunctionOrMethod; + << Attrs << Attrs.isRegularKeywordAttribute() + << ExpectedFunctionOrMethod; return; } @@ -2218,7 +2225,9 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_keyword_not_supported_on_target + : diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); AL.setInvalid(); return true; @@ -2238,7 +2247,8 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } } @@ -2775,7 +2785,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return V; }; AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL.getRange(), NewII, true /*Implicit*/, + ND, AL, NewII, true /*Implicit*/, MinMacCatalystVersion(Introduced.Version), MinMacCatalystVersion(Deprecated.Version), MinMacCatalystVersion(Obsoleted.Version), IsUnavailable, Str, @@ -2817,7 +2827,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return V ? *V : VersionTuple(); }; AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL.getRange(), NewII, true /*Implicit*/, + ND, AL, NewII, true /*Implicit*/, VersionOrEmptyVersion(NewIntroduced), VersionOrEmptyVersion(NewDeprecated), VersionOrEmptyVersion(NewObsoleted), /*IsUnavailable=*/false, Str, @@ -2834,7 +2844,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 4)) return; StringRef Language; @@ -2844,9 +2854,12 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1))) DefinedIn = SE->getString(); bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; + StringRef USR; + if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(3))) + USR = SE->getString(); D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration)); + S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration, USR)); } template <class T> @@ -2885,12 +2898,10 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, } // 'type_visibility' can only go on a type or namespace. - if (isTypeVisibility && - !(isa<TagDecl>(D) || - isa<ObjCInterfaceDecl>(D) || - isa<NamespaceDecl>(D))) { + if (isTypeVisibility && !(isa<TagDecl>(D) || isa<ObjCInterfaceDecl>(D) || + isa<NamespaceDecl>(D))) { S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedTypeOrNamespace; + << AL << AL.isRegularKeywordAttribute() << ExpectedTypeOrNamespace; return; } @@ -3109,12 +3120,14 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos)); @@ -3139,7 +3152,8 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { // as a function pointer. if (isa<VarDecl>(D)) S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "functions, classes, or enumerations"; + << AL << AL.isRegularKeywordAttribute() + << "functions, classes, or enumerations"; // If this is spelled as the standard C++17 attribute, but not in C++17, // warn about using it as an extension. If there are attribute arguments, @@ -3185,7 +3199,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Nothing to warn about here. } else S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedVariableOrFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedVariableOrFunction; return; } @@ -3505,6 +3519,7 @@ bool Sema::checkTargetClonesAttrString( enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; HasCommas = HasCommas || Str.contains(','); + const TargetInfo &TInfo = Context.getTargetInfo(); // Warn on empty at the beginning of a string. if (Str.size() == 0) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) @@ -3514,9 +3529,9 @@ bool Sema::checkTargetClonesAttrString( while (!Parts.second.empty()) { Parts = Parts.second.split(','); StringRef Cur = Parts.first.trim(); - SourceLocation CurLoc = Literal->getLocationOfByte( - Cur.data() - Literal->getString().data(), getSourceManager(), - getLangOpts(), Context.getTargetInfo()); + SourceLocation CurLoc = + Literal->getLocationOfByte(Cur.data() - Literal->getString().data(), + getSourceManager(), getLangOpts(), TInfo); bool DefaultIsDupe = false; bool HasCodeGenImpact = false; @@ -3524,7 +3539,7 @@ bool Sema::checkTargetClonesAttrString( return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; - if (Context.getTargetInfo().getTriple().isAArch64()) { + if (TInfo.getTriple().isAArch64()) { // AArch64 target clones specific if (Cur == "default") { DefaultIsDupe = HasDefault; @@ -3539,13 +3554,12 @@ bool Sema::checkTargetClonesAttrString( while (!CurParts.second.empty()) { CurParts = CurParts.second.split('+'); StringRef CurFeature = CurParts.first.trim(); - if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) { + if (!TInfo.validateCpuSupports(CurFeature)) { Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << CurFeature << TargetClones; continue; } - std::string Options; - if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options)) + if (TInfo.doesFeatureAffectCodeGen(CurFeature)) HasCodeGenImpact = true; CurFeatures.push_back(CurFeature); } @@ -3756,7 +3770,7 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D, /// 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 ParsedAttr &AL) { - Expr *IdxExpr = AL.getArgAsExpr(0); + const Expr *IdxExpr = AL.getArgAsExpr(0); ParamIdx Idx; if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx)) return; @@ -3831,7 +3845,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; return; } - + if (S.getLangOpts().HLSL) { S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); return; @@ -3881,7 +3895,9 @@ ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, (EA->isWarning() && NewAttr == "warning"); if (!Match) { Diag(EA->getLocation(), diag::err_attributes_are_not_compatible) - << CI << EA; + << CI << EA + << (CI.isRegularKeywordAttribute() || + EA->isRegularKeywordAttribute()); Diag(CI.getLoc(), diag::note_conflicting_attribute); return nullptr; } @@ -4198,8 +4214,8 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RD = dyn_cast<RecordDecl>(D); if (!RD || !RD->isUnion()) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL - << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedUnion; return; } @@ -4330,6 +4346,27 @@ void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) { } static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (AL.hasParsedType()) { + const ParsedType &TypeArg = AL.getTypeArg(); + TypeSourceInfo *TInfo; + (void)S.GetTypeFromParser( + ParsedType::getFromOpaquePtr(TypeArg.getAsOpaquePtr()), &TInfo); + if (AL.isPackExpansion() && + !TInfo->getType()->containsUnexpandedParameterPack()) { + S.Diag(AL.getEllipsisLoc(), + diag::err_pack_expansion_without_parameter_packs); + return; + } + + if (!AL.isPackExpansion() && + S.DiagnoseUnexpandedParameterPack(TInfo->getTypeLoc().getBeginLoc(), + TInfo, Sema::UPPC_Expression)) + return; + + S.AddAlignedAttr(D, AL, TInfo, AL.isPackExpansion()); + return; + } + // check the attribute arguments. if (AL.getNumArgs() > 1) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -4354,53 +4391,61 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.AddAlignedAttr(D, AL, E, AL.isPackExpansion()); } +/// Perform checking of type validity +/// +/// C++11 [dcl.align]p1: +/// An alignment-specifier may be applied to a variable or to a class +/// data member, but it shall not be applied to a bit-field, a function +/// parameter, the formal parameter of a catch clause, or a variable +/// declared with the register storage class specifier. An +/// alignment-specifier may also be applied to the declaration of a class +/// or enumeration type. +/// CWG 2354: +/// CWG agreed to remove permission for alignas to be applied to +/// enumerations. +/// C11 6.7.5/2: +/// An alignment attribute shall not be specified in a declaration of +/// a typedef, or a bit-field, or a function, or a parameter, or an +/// object declared with the register storage-class specifier. +static bool validateAlignasAppliedType(Sema &S, Decl *D, + const AlignedAttr &Attr, + SourceLocation AttrLoc) { + int DiagKind = -1; + if (isa<ParmVarDecl>(D)) { + DiagKind = 0; + } else if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (VD->getStorageClass() == SC_Register) + DiagKind = 1; + if (VD->isExceptionVariable()) + DiagKind = 2; + } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { + if (FD->isBitField()) + DiagKind = 3; + } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { + if (ED->getLangOpts().CPlusPlus) + DiagKind = 4; + } else if (!isa<TagDecl>(D)) { + return S.Diag(AttrLoc, diag::err_attribute_wrong_decl_type) + << &Attr << Attr.isRegularKeywordAttribute() + << (Attr.isC11() ? ExpectedVariableOrField + : ExpectedVariableFieldOrTag); + } + if (DiagKind != -1) { + return S.Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) + << &Attr << DiagKind; + } + return false; +} + void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion) { AlignedAttr TmpAttr(Context, CI, true, E); SourceLocation AttrLoc = CI.getLoc(); // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. - if (TmpAttr.isAlignas()) { - // C++11 [dcl.align]p1: - // An alignment-specifier may be applied to a variable or to a class - // data member, but it shall not be applied to a bit-field, a function - // parameter, the formal parameter of a catch clause, or a variable - // declared with the register storage class specifier. An - // alignment-specifier may also be applied to the declaration of a class - // or enumeration type. - // CWG 2354: - // CWG agreed to remove permission for alignas to be applied to - // enumerations. - // C11 6.7.5/2: - // An alignment attribute shall not be specified in a declaration of - // a typedef, or a bit-field, or a function, or a parameter, or an - // object declared with the register storage-class specifier. - int DiagKind = -1; - if (isa<ParmVarDecl>(D)) { - DiagKind = 0; - } else if (const auto *VD = dyn_cast<VarDecl>(D)) { - if (VD->getStorageClass() == SC_Register) - DiagKind = 1; - if (VD->isExceptionVariable()) - DiagKind = 2; - } else if (const auto *FD = dyn_cast<FieldDecl>(D)) { - if (FD->isBitField()) - DiagKind = 3; - } else if (const auto *ED = dyn_cast<EnumDecl>(D)) { - if (ED->getLangOpts().CPlusPlus) - DiagKind = 4; - } else if (!isa<TagDecl>(D)) { - Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr - << (TmpAttr.isC11() ? ExpectedVariableOrField - : ExpectedVariableFieldOrTag); - return; - } - if (DiagKind != -1) { - Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) - << &TmpAttr << DiagKind; - return; - } - } + if (TmpAttr.isAlignas() && + validateAlignasAppliedType(*this, D, TmpAttr, AttrLoc)) + return; if (E->isValueDependent()) { // We can't support a dependent alignment on a non-dependent type, @@ -4428,6 +4473,15 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, if (ICE.isInvalid()) return; + uint64_t MaximumAlignment = Sema::MaximumAlignment; + if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF()) + MaximumAlignment = std::min(MaximumAlignment, uint64_t(8192)); + if (Alignment > MaximumAlignment) { + Diag(AttrLoc, diag::err_attribute_aligned_too_great) + << MaximumAlignment << E->getSourceRange(); + return; + } + uint64_t AlignVal = Alignment.getZExtValue(); // C++11 [dcl.align]p2: // -- if the constant expression evaluates to zero, the alignment @@ -4442,15 +4496,6 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } } - uint64_t MaximumAlignment = Sema::MaximumAlignment; - if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF()) - MaximumAlignment = std::min(MaximumAlignment, uint64_t(8192)); - if (AlignVal > MaximumAlignment) { - Diag(AttrLoc, diag::err_attribute_aligned_too_great) - << MaximumAlignment << E->getSourceRange(); - return; - } - const auto *VD = dyn_cast<VarDecl>(D); if (VD) { unsigned MaxTLSAlign = @@ -4477,15 +4522,56 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get()); AA->setPackExpansion(IsPackExpansion); + AA->setCachedAlignmentValue( + static_cast<unsigned>(AlignVal * Context.getCharWidth())); D->addAttr(AA); } void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *TS, bool IsPackExpansion) { - // FIXME: Cache the number on the AL object if non-dependent? - // FIXME: Perform checking of type validity + AlignedAttr TmpAttr(Context, CI, false, TS); + SourceLocation AttrLoc = CI.getLoc(); + + // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. + if (TmpAttr.isAlignas() && + validateAlignasAppliedType(*this, D, TmpAttr, AttrLoc)) + return; + + if (TS->getType()->isDependentType()) { + // We can't support a dependent alignment on a non-dependent type, + // because we have no way to model that a type is "type-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) + << TS->getTypeLoc().getSourceRange(); + return; + } + } + + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS); + AA->setPackExpansion(IsPackExpansion); + D->addAttr(AA); + return; + } + + const auto *VD = dyn_cast<VarDecl>(D); + unsigned AlignVal = TmpAttr.getAlignment(Context); + // On AIX, an aligned attribute can not decrease the alignment when applied + // to a variable declaration with vector type. + if (VD && Context.getTargetInfo().getTriple().isOSAIX()) { + const Type *Ty = VD->getType().getTypePtr(); + if (Ty->isVectorType() && + Context.toCharUnitsFromBits(AlignVal).getQuantity() < 16) { + Diag(VD->getLocation(), diag::warn_aligned_attr_underaligned) + << VD->getType() << 16; + return; + } + } + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS); AA->setPackExpansion(IsPackExpansion); + AA->setCachedAlignmentValue(AlignVal); D->addAttr(AA); } @@ -4815,8 +4901,9 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << AL << AL.isRegularKeywordAttribute() + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4835,8 +4922,9 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) { // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type) - << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << &AL << AL.isRegularKeywordAttribute() + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4867,7 +4955,9 @@ SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) { if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) - << PrevSNA << &SNA; + << PrevSNA << &SNA + << (PrevSNA->isRegularKeywordAttribute() || + SNA.isRegularKeywordAttribute()); Diag(SNA.getLoc(), diag::note_conflicting_attribute); } @@ -4967,7 +5057,10 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD; - D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); + if (AL.getKind() == ParsedAttr::AT_NVPTXKernel) + D->addAttr(::new (S.Context) NVPTXKernelAttr(S.Context, AL)); + else + D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); // In host compilation the kernel is emitted as a stub function, which is // a helper function for launching the kernel. The instructions in the helper // function has nothing to do with the source code of the kernel. Do not emit @@ -5029,7 +5122,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isa<ObjCMethodDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -5160,7 +5253,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << OAttr; + << AL << OAttr + << (AL.isRegularKeywordAttribute() || + OAttr->isRegularKeywordAttribute()); S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5177,7 +5272,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << PAttr; + << AL << PAttr + << (AL.isRegularKeywordAttribute() || + PAttr->isRegularKeywordAttribute()); S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5252,6 +5349,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_AArch64SVEPcs: CC = CC_AArch64SVEPCS; break; + case ParsedAttr::AT_ArmStreaming: + CC = CC_C; // FIXME: placeholder until real SME support is added. + break; case ParsedAttr::AT_AMDGPUKernelCall: CC = CC_AMDGPUKernelCall; break; @@ -5409,7 +5509,9 @@ void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, if (auto existingAttr = D->getAttr<ParameterABIAttr>()) { if (existingAttr->getABI() != abi) { Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) - << getParameterABISpelling(abi) << existingAttr; + << getParameterABISpelling(abi) << existingAttr + << (CI.isRegularKeywordAttribute() || + existingAttr->isRegularKeywordAttribute()); Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); return; } @@ -5601,7 +5703,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, if (!isa<VarDecl>(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedVariable; + << AL << AL.isRegularKeywordAttribute() << ExpectedVariable; return; } @@ -5696,6 +5798,14 @@ static bool ArmSveAliasValid(ASTContext &Context, unsigned BuiltinID, BuiltinID <= AArch64::LastSVEBuiltin; } +static bool ArmSmeAliasValid(ASTContext &Context, unsigned BuiltinID, + StringRef AliasName) { + if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) + BuiltinID = Context.BuiltinInfo.getAuxBuiltinID(BuiltinID); + return BuiltinID >= AArch64::FirstSMEBuiltin && + BuiltinID <= AArch64::LastSMEBuiltin; +} + static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) @@ -5708,7 +5818,8 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName(); bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64(); - if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) || + if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName) && + !ArmSmeAliasValid(S.Context, BuiltinID, AliasName)) || (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) && !ArmCdeAliasValid(BuiltinID, AliasName))) { S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); @@ -5898,7 +6009,8 @@ static void handleXReturnsXRetainedAttr(Sema &S, Decl *D, break; } S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getRange() << AL << ExpectedDeclKind; + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedDeclKind; return; } @@ -6170,10 +6282,12 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (hasDeclarator(D)) return; + if (hasDeclarator(D)) + return; S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) - << AL.getRange() << AL << ExpectedVariable; + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, @@ -6666,7 +6780,8 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, Params = F->parameters(); if (!F->hasWrittenPrototype()) { - Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL + Diag(Loc, diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionWithProtoType; return false; } @@ -6787,7 +6902,7 @@ static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isa<TypedefNameDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "typedefs"; + << AL << AL.isRegularKeywordAttribute() << "typedefs"; return; } @@ -7262,7 +7377,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // a function with no parameters and void return type. if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -7335,7 +7450,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -7410,7 +7525,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { CXXMethodDecl::isStaticOverloadedOperator( cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionWithProtoType; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -7466,7 +7582,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { 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; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7479,7 +7595,7 @@ static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { 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; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7532,10 +7648,11 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag()); } -static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'export_name'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7659,7 +7776,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, if (D->getFunctionType() == nullptr) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7854,7 +7971,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -8133,7 +8250,7 @@ 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) - << AL << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a // NoSanitizeAttr object; but we need to calculate the correct spelling list @@ -8252,6 +8369,22 @@ static void handleFunctionReturnThunksAttr(Sema &S, Decl *D, D->addAttr(FunctionReturnThunksAttr::Create(S.Context, Kind, AL)); } +static void handleAvailableOnlyInDefaultEvalMethod(Sema &S, Decl *D, + const ParsedAttr &AL) { + assert(isa<TypedefNameDecl>(D) && "This attribute only applies to a typedef"); + handleSimpleAttribute<AvailableOnlyInDefaultEvalMethodAttr>(S, D, AL); +} + +static void handleNoMergeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + auto *VDecl = dyn_cast<VarDecl>(D); + if (VDecl && !VDecl->isFunctionPointerType()) { + S.Diag(AL.getLoc(), diag::warn_attribute_ignored_non_function_pointer) + << AL << VDecl; + return; + } + D->addAttr(NoMergeAttr::Create(S.Context, AL)); +} + static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The 'sycl_kernel' attribute applies only to function templates. const auto *FD = cast<FunctionDecl>(D); @@ -8446,6 +8579,11 @@ static void handleHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(Attr::Create(S.Context, Argument, AL)); } +template<typename Attr> +static void handleUnsafeBufferUsage(Sema &S, Decl *D, const ParsedAttr &AL) { + D->addAttr(Attr::Create(S.Context, AL)); +} + static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // The guard attribute takes a single identifier argument. @@ -8580,13 +8718,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, // Ignore C++11 attributes on declarator chunks: they appertain to the type // instead. - // FIXME: We currently check the attribute syntax directly instead of using - // isCXX11Attribute(), which currently erroneously classifies the C11 - // `_Alignas` attribute as a C++11 attribute. `_Alignas` can appear on the - // `DeclSpec`, so we need to let it through here to make sure it is processed - // appropriately. Once the behavior of isCXX11Attribute() is fixed, we can - // go back to using that here. - if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes) + if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes @@ -8595,7 +8727,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, if (AL.getKind() == ParsedAttr::UnknownAttribute || !AL.existsInTarget(S.Context.getTargetInfo())) { S.Diag(AL.getLoc(), - AL.isDeclspecAttribute() + AL.isRegularKeywordAttribute() + ? (unsigned)diag::err_keyword_not_supported_on_target + : AL.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); @@ -8624,7 +8758,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, if (AL.isTypeAttr()) { if (Options.IgnoreTypeAttributes) break; - if (!AL.isStandardAttributeSyntax()) { + if (!AL.isStandardAttributeSyntax() && !AL.isRegularKeywordAttribute()) { // Non-[[]] type attributes are handled in processTypeAttrs(); silently // move on. break; @@ -8689,7 +8823,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, // needed for type attributes as well as statement attributes in Attr.td // that do not list any subjects. S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl) - << AL << D->getLocation(); + << AL << AL.isRegularKeywordAttribute() << D->getLocation(); break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); @@ -8843,6 +8977,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_CalledOnce: handleCalledOnceAttr(S, D, AL); break; + case ParsedAttr::AT_NVPTXKernel: case ParsedAttr::AT_CUDAGlobal: handleGlobalAttr(S, D, AL); break; @@ -9130,6 +9265,13 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_FunctionReturnThunks: handleFunctionReturnThunksAttr(S, D, AL); break; + case ParsedAttr::AT_NoMerge: + handleNoMergeAttr(S, D, AL); + break; + + case ParsedAttr::AT_AvailableOnlyInDefaultEvalMethod: + handleAvailableOnlyInDefaultEvalMethod(S, D, AL); + break; // Microsoft attributes: case ParsedAttr::AT_LayoutVersion: @@ -9328,6 +9470,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, handleHandleAttr<ReleaseHandleAttr>(S, D, AL); break; + case ParsedAttr::AT_UnsafeBufferUsage: + handleUnsafeBufferUsage<UnsafeBufferUsageAttr>(S, D, AL); + break; + case ParsedAttr::AT_UseHandle: handleHandleAttr<UseHandleAttr>(S, D, AL); break; @@ -9395,19 +9541,19 @@ void Sema::ProcessDeclAttributeList( } else if (!D->hasAttr<CUDAGlobalAttr>()) { if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } } @@ -9542,8 +9688,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) { NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation()); NewD->addAttr( AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation())); - NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(), - AttributeCommonInfo::AS_Pragma)); + NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); WeakTopLevelDecl.push_back(NewD); // FIXME: "hideous" code from Sema::LazilyCreateBuiltin // to insert Decl at TU scope, sorry. @@ -9554,8 +9699,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) { PushOnScopeChains(NewD, S); CurContext = SavedContext; } else { // just add weak to existing - ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(), - AttributeCommonInfo::AS_Pragma)); + ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation())); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 348092fc62e8..b62f3c475c45 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -34,6 +34,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" @@ -41,10 +42,11 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/SaveAndRestore.h" #include <map> #include <optional> #include <set> @@ -761,7 +763,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // C++20 [dcl.dcl]/8: // If decl-specifier-seq contains any decl-specifier other than static, // thread_local, auto, or cv-qualifiers, the program is ill-formed. - // C++2b [dcl.pre]/6: + // C++23 [dcl.pre]/6: // Each decl-specifier in the decl-specifier-seq shall be static, // thread_local, auto (9.2.9.6 [dcl.spec.auto]), or a cv-qualifier. auto &DS = D.getDeclSpec(); @@ -1721,6 +1723,7 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, e = FT->param_type_end(); i != e; ++i, ++ArgIndex) { const ParmVarDecl *PD = FD->getParamDecl(ArgIndex); + assert(PD && "null in a parameter list"); SourceLocation ParamLoc = PD->getLocation(); if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1, @@ -1926,16 +1929,16 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, if (VD->isStaticLocal()) { if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag(VD->getLocation(), - SemaRef.getLangOpts().CPlusPlus2b + SemaRef.getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_constexpr_var : diag::ext_constexpr_static_var) << isa<CXXConstructorDecl>(Dcl) << (VD->getTLSKind() == VarDecl::TLS_Dynamic); - } else if (!SemaRef.getLangOpts().CPlusPlus2b) { + } else if (!SemaRef.getLangOpts().CPlusPlus23) { return false; } } - if (SemaRef.LangOpts.CPlusPlus2b) { + if (SemaRef.LangOpts.CPlusPlus23) { CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(), diag::warn_cxx20_compat_constexpr_var, isa<CXXConstructorDecl>(Dcl), @@ -2274,15 +2277,15 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::CheckValid) { // If this is only valid as an extension, report that we don't satisfy the // constraints of the current language. - if ((Cxx2bLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2b) || + if ((Cxx2bLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus23) || (Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; } else if (Cxx2bLoc.isValid()) { SemaRef.Diag(Cxx2bLoc, - SemaRef.getLangOpts().CPlusPlus2b + SemaRef.getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_constexpr_body_invalid_stmt - : diag::ext_constexpr_body_invalid_stmt_cxx2b) + : diag::ext_constexpr_body_invalid_stmt_cxx23) << isa<CXXConstructorDecl>(Dcl); } else if (Cxx2aLoc.isValid()) { SemaRef.Diag(Cxx2aLoc, @@ -2435,6 +2438,114 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, return true; } +bool Sema::CheckImmediateEscalatingFunctionDefinition( + FunctionDecl *FD, const sema::FunctionScopeInfo *FSI) { + if (!getLangOpts().CPlusPlus20 || !FD->isImmediateEscalating()) + return true; + FD->setBodyContainsImmediateEscalatingExpressions( + FSI->FoundImmediateEscalatingExpression); + if (FSI->FoundImmediateEscalatingExpression) { + auto it = UndefinedButUsed.find(FD->getCanonicalDecl()); + if (it != UndefinedButUsed.end()) { + Diag(it->second, diag::err_immediate_function_used_before_definition) + << it->first; + Diag(FD->getLocation(), diag::note_defined_here) << FD; + if (FD->isImmediateFunction() && !FD->isConsteval()) + DiagnoseImmediateEscalatingReason(FD); + return false; + } + } + return true; +} + +void Sema::DiagnoseImmediateEscalatingReason(FunctionDecl *FD) { + assert(FD->isImmediateEscalating() && !FD->isConsteval() && + "expected an immediate function"); + assert(FD->hasBody() && "expected the function to have a body"); + struct ImmediateEscalatingExpressionsVisitor + : public RecursiveASTVisitor<ImmediateEscalatingExpressionsVisitor> { + + using Base = RecursiveASTVisitor<ImmediateEscalatingExpressionsVisitor>; + Sema &SemaRef; + + const FunctionDecl *ImmediateFn; + bool ImmediateFnIsConstructor; + CXXConstructorDecl *CurrentConstructor = nullptr; + CXXCtorInitializer *CurrentInit = nullptr; + + ImmediateEscalatingExpressionsVisitor(Sema &SemaRef, FunctionDecl *FD) + : SemaRef(SemaRef), ImmediateFn(FD), + ImmediateFnIsConstructor(isa<CXXConstructorDecl>(FD)) {} + + bool shouldVisitImplicitCode() const { return true; } + bool shouldVisitLambdaBody() const { return false; } + + void Diag(const Expr *E, const FunctionDecl *Fn, bool IsCall) { + SourceLocation Loc = E->getBeginLoc(); + SourceRange Range = E->getSourceRange(); + if (CurrentConstructor && CurrentInit) { + Loc = CurrentConstructor->getLocation(); + Range = CurrentInit->isWritten() ? CurrentInit->getSourceRange() + : SourceRange(); + } + SemaRef.Diag(Loc, diag::note_immediate_function_reason) + << ImmediateFn << Fn << Fn->isConsteval() << IsCall + << isa<CXXConstructorDecl>(Fn) << ImmediateFnIsConstructor + << (CurrentInit != nullptr) + << (CurrentInit && !CurrentInit->isWritten()) + << (CurrentInit ? CurrentInit->getAnyMember() : nullptr) << Range; + } + bool TraverseCallExpr(CallExpr *E) { + if (const auto *DR = + dyn_cast<DeclRefExpr>(E->getCallee()->IgnoreImplicit()); + DR && DR->isImmediateEscalating()) { + Diag(E, E->getDirectCallee(), /*IsCall=*/true); + return false; + } + + for (Expr *A : E->arguments()) + if (!getDerived().TraverseStmt(A)) + return false; + + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (const auto *ReferencedFn = dyn_cast<FunctionDecl>(E->getDecl()); + ReferencedFn && E->isImmediateEscalating()) { + Diag(E, ReferencedFn, /*IsCall=*/false); + return false; + } + + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + CXXConstructorDecl *D = E->getConstructor(); + if (E->isImmediateEscalating()) { + Diag(E, D, /*IsCall=*/true); + return false; + } + return true; + } + + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { + llvm::SaveAndRestore RAII(CurrentInit, Init); + return Base::TraverseConstructorInitializer(Init); + } + + bool TraverseCXXConstructorDecl(CXXConstructorDecl *Ctr) { + llvm::SaveAndRestore RAII(CurrentConstructor, Ctr); + return Base::TraverseCXXConstructorDecl(Ctr); + } + + bool TraverseType(QualType T) { return true; } + bool VisitBlockExpr(BlockExpr *T) { return true; } + + } Visitor(*this, FD); + Visitor.TraverseDecl(FD); +} + /// 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. @@ -2608,7 +2719,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } // For the MS ABI, propagate DLL attributes to base class templates. - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isPS()) { if (Attr *ClassAttr = getDLLAttr(Class)) { if (auto *BaseTemplate = dyn_cast_or_null<ClassTemplateSpecializationDecl>( BaseType->getAsCXXRecordDecl())) { @@ -2707,10 +2819,12 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, for (const ParsedAttr &AL : Attributes) { if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) continue; - Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute - ? (unsigned)diag::warn_unknown_attribute_ignored - : (unsigned)diag::err_base_specifier_attribute) - << AL << AL.getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); + else + Diag(AL.getLoc(), diag::err_base_specifier_attribute) + << AL << AL.isRegularKeywordAttribute() << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; @@ -3230,16 +3344,6 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } -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; -} - // Check if there is a field shadowing. void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, @@ -3317,7 +3421,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isDeclarationOfFunction(); const ParsedAttr *MSPropertyAttr = - getMSPropertyAttr(D.getDeclSpec().getAttributes()); + D.getDeclSpec().getAttributes().getMSPropertyAttr(); if (cast<CXXRecordDecl>(CurContext)->isInterface()) { // The Microsoft extension __interface only permits public member functions @@ -3575,12 +3679,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } if (VS.isOverrideSpecified()) - Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc(), - AttributeCommonInfo::AS_Keyword)); + Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc())); if (VS.isFinalSpecified()) - Member->addAttr(FinalAttr::Create( - Context, VS.getFinalLoc(), AttributeCommonInfo::AS_Keyword, - static_cast<FinalAttr::Spelling>(VS.isFinalSpelledSealed()))); + Member->addAttr(FinalAttr::Create(Context, VS.getFinalLoc(), + VS.isFinalSpelledSealed() + ? FinalAttr::Keyword_sealed + : FinalAttr::Keyword_final)); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. @@ -3979,7 +4083,7 @@ namespace { } llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses; - for (auto I : RD->bases()) + for (const auto &I : RD->bases()) UninitializedBaseClasses.insert(I.getType().getCanonicalType()); if (UninitializedFields.empty() && UninitializedBaseClasses.empty()) @@ -6007,9 +6111,9 @@ void AbstractUsageInfo::CheckType(const NamedDecl *D, TypeLoc TL, /// Check for invalid uses of an abstract type in a function declaration. static void CheckAbstractClassUsage(AbstractUsageInfo &Info, FunctionDecl *FD) { - // No need to do the check on definitions, which require that - // the return/param types be complete. - if (FD->doesThisDeclarationHaveABody()) + // Only definitions are required to refer to complete and + // non-abstract types. + if (!FD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source @@ -6346,6 +6450,18 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (!ClassAttr) return; + // MSVC allows imported or exported template classes that have UniqueExternal + // linkage. This occurs when the template class has been instantiated with + // a template parameter which itself has internal linkage. + // We drop the attribute to avoid exporting or importing any members. + if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isPS()) && + (!Class->isExternallyVisible() && Class->hasExternalFormalLinkage())) { + Class->dropAttr<DLLExportAttr>(); + Class->dropAttr<DLLImportAttr>(); + return; + } + if (!Class->isExternallyVisible()) { Diag(Class->getLocation(), diag::err_attribute_dll_not_extern) << Class << ClassAttr; @@ -7512,7 +7628,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, } } - const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *Type = MD->getType()->castAs<FunctionProtoType>(); bool CanHaveConstParam = false; if (CSM == CXXCopyConstructor) @@ -7754,6 +7870,10 @@ protected: // followed by the non-static data members of C for (FieldDecl *Field : Record->fields()) { + // C++23 [class.bit]p2: + // Unnamed bit-fields are not members ... + if (Field->isUnnamedBitfield()) + continue; // Recursively expand anonymous structs. if (Field->isAnonymousStructOrUnion()) { if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(), @@ -8116,7 +8236,8 @@ private: if (Diagnose == ExplainDeleted) { S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function) - << FD << (OO == OO_ExclaimEqual) << Subobj.Kind << Subobj.Decl; + << FD << (OO == OO_EqualEqual || OO == OO_ExclaimEqual) + << Subobj.Kind << Subobj.Decl; // For a three-way comparison, list both the candidates for the // original operator and the candidates for the synthesized operator. @@ -8571,8 +8692,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // C++2a [class.compare.default]p1: // A defaulted comparison operator function for some class C shall be a // non-template function declared in the member-specification of C that is - // -- a non-static const member of C having one parameter of type - // const C&, or + // -- a non-static const non-volatile member of C having one parameter of + // type const C& and either no ref-qualifier or the ref-qualifier &, or // -- a friend of C having two parameters of type const C& or two // parameters of type C. @@ -8582,6 +8703,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, auto *MD = cast<CXXMethodDecl>(FD); assert(!MD->isStatic() && "comparison function cannot be a static member"); + if (MD->getRefQualifier() == RQ_RValue) { + Diag(MD->getLocation(), diag::err_ref_qualifier_comparison_operator); + + // Remove the ref qualifier to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.RefQualifier = RQ_None; + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + // If we're out-of-class, this is the class we're comparing. if (!RD) RD = MD->getParent(); @@ -8604,6 +8736,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, MD->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); } + + if (MD->isVolatile()) { + Diag(MD->getLocation(), diag::err_volatile_comparison_operator); + + // Remove the 'volatile' from the type to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals.removeVolatile(); + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } } if (FD->getNumParams() != (IsMethod ? 1 : 2)) { @@ -8617,8 +8760,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, const ParmVarDecl *KnownParm = nullptr; for (const ParmVarDecl *Param : FD->parameters()) { QualType ParmTy = Param->getType(); - if (ParmTy->isDependentType()) - continue; + if (!KnownParm) { auto CTy = ParmTy; // Is it `T const &`? @@ -8804,12 +8946,25 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // the requirements for a constexpr function [...] // The only relevant requirements are that the parameter and return types are // literal types. The remaining conditions are checked by the analyzer. + // + // We support P2448R2 in language modes earlier than C++23 as an extension. + // The concept of constexpr-compatible was removed. + // C++23 [dcl.fct.def.default]p3 [P2448R2] + // A function explicitly defaulted on its first declaration is implicitly + // inline, and is implicitly constexpr if it is constexpr-suitable. + // C++23 [dcl.constexpr]p3 + // A function is constexpr-suitable if + // - it is not a coroutine, and + // - if the function is a constructor or destructor, its class does not + // have any virtual base classes. if (FD->isConstexpr()) { if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) && CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) && !Info.Constexpr) { Diag(FD->getBeginLoc(), - diag::err_incorrect_defaulted_comparison_constexpr) + getLangOpts().CPlusPlus23 + ? diag::warn_cxx23_compat_defaulted_comparison_constexpr_mismatch + : diag::ext_defaulted_comparison_constexpr_mismatch) << FD->isImplicit() << (int)DCK << FD->isConsteval(); DefaultedComparisonAnalyzer(*this, RD, FD, DCK, DefaultedComparisonAnalyzer::ExplainConstexpr) @@ -9157,7 +9312,18 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( // must be accessible and non-deleted, but need not be trivial. Such a // destructor is never actually called, but is semantically checked as // if it were. - DiagKind = 4; + if (CSM == Sema::CXXDefaultConstructor) { + // [class.default.ctor]p2: + // A defaulted default constructor for class X is defined as deleted if + // - X is a union that has a variant member with a non-trivial default + // constructor and no variant member of X has a default member + // initializer + const auto *RD = cast<CXXRecordDecl>(Field->getParent()); + if (!RD->hasInClassInitializer()) + DiagKind = 4; + } else { + DiagKind = 4; + } } if (DiagKind == -1) @@ -11054,8 +11220,8 @@ struct BadSpecifierDiagnoser { /// Check the validity of a declarator that we parsed for a deduction-guide. /// These aren't actually declarators in the grammar, so we need to check that /// the user didn't specify any pieces that are not part of the deduction-guide -/// grammar. -void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, +/// grammar. Return true on invalid deduction-guide. +bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC) { TemplateName GuidedTemplate = D.getName().TemplateName.get().get(); TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl(); @@ -11105,7 +11271,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, } if (D.isInvalidType()) - return; + return true; // Check the declarator is simple enough. bool FoundFunction = false; @@ -11118,11 +11284,9 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, << D.getSourceRange(); break; } - if (!Chunk.Fun.hasTrailingReturnType()) { - Diag(D.getName().getBeginLoc(), - diag::err_deduction_guide_no_trailing_return_type); - break; - } + if (!Chunk.Fun.hasTrailingReturnType()) + return Diag(D.getName().getBeginLoc(), + diag::err_deduction_guide_no_trailing_return_type); // Check that the return type is written as a specialization of // the template specified as the deduction-guide's name. @@ -11157,13 +11321,12 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, MightInstantiateToSpecialization = true; } - if (!AcceptableReturnType) { - Diag(TSI->getTypeLoc().getBeginLoc(), - diag::err_deduction_guide_bad_trailing_return_type) - << GuidedTemplate << TSI->getType() - << MightInstantiateToSpecialization - << TSI->getTypeLoc().getSourceRange(); - } + if (!AcceptableReturnType) + return Diag(TSI->getTypeLoc().getBeginLoc(), + diag::err_deduction_guide_bad_trailing_return_type) + << GuidedTemplate << TSI->getType() + << MightInstantiateToSpecialization + << TSI->getTypeLoc().getSourceRange(); // Keep going to check that we don't have any inner declarator pieces (we // could still have a function returning a pointer to a function). @@ -11171,7 +11334,9 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, } if (D.isFunctionDefinition()) + // we can still create a valid deduction guide here. Diag(D.getIdentifierLoc(), diag::err_deduction_guide_defines_function); + return false; } //===----------------------------------------------------------------------===// @@ -11223,6 +11388,20 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, NamespaceDecl *PrevNS = nullptr; if (II) { + // C++ [namespace.std]p7: + // A translation unit shall not declare namespace std to be an inline + // namespace (9.8.2). + // + // Precondition: the std namespace is in the file scope and is declared to + // be inline + auto DiagnoseInlineStdNS = [&]() { + assert(IsInline && II->isStr("std") && + CurContext->getRedeclContext()->isTranslationUnit() && + "Precondition of DiagnoseInlineStdNS not met"); + Diag(InlineLoc, diag::err_inline_namespace_std) + << SourceRange(InlineLoc, InlineLoc.getLocWithOffset(6)); + IsInline = false; + }; // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not // have been previously defined in the declarative region in @@ -11243,7 +11422,10 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, if (PrevNS) { // This is an extended namespace definition. - if (IsInline != PrevNS->isInline()) + if (IsInline && II->isStr("std") && + CurContext->getRedeclContext()->isTranslationUnit()) + DiagnoseInlineStdNS(); + else if (IsInline != PrevNS->isInline()) DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II, &IsInline, PrevNS); } else if (PrevDecl) { @@ -11255,6 +11437,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // Continue on to push Namespc as current DeclContext and return it. } else if (II->isStr("std") && CurContext->getRedeclContext()->isTranslationUnit()) { + if (IsInline) + DiagnoseInlineStdNS(); // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. PrevNS = getStdNamespace(); @@ -11386,21 +11570,6 @@ NamespaceDecl *Sema::getStdNamespace() const { return cast_or_null<NamespaceDecl>( StdNamespace.get(Context.getExternalSource())); } - -NamespaceDecl *Sema::lookupStdExperimentalNamespace() { - if (!StdExperimentalNamespaceCache) { - if (auto Std = getStdNamespace()) { - LookupResult Result(*this, &PP.getIdentifierTable().get("experimental"), - SourceLocation(), LookupNamespaceName); - if (!LookupQualifiedName(Result, Std) || - !(StdExperimentalNamespaceCache = - Result.getAsSingle<NamespaceDecl>())) - Result.suppressDiagnostics(); - } - } - return StdExperimentalNamespaceCache; -} - namespace { enum UnsupportedSTLSelect { @@ -11549,6 +11718,10 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { &PP.getIdentifierTable().get("std"), /*PrevDecl=*/nullptr, /*Nested=*/false); getStdNamespace()->setImplicit(true); + // We want the created NamespaceDecl to be available for redeclaration + // lookups, but not for regular name lookups. + Context.getTranslationUnitDecl()->addDecl(getStdNamespace()); + getStdNamespace()->clearIdentifierNamespace(); } return getStdNamespace(); @@ -15654,9 +15827,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkFunctionReferenced(ConstructLoc, Constructor); if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) return ExprError(); - if (getLangOpts().SYCLIsDevice && - !checkSYCLDeviceFunction(ConstructLoc, Constructor)) - return ExprError(); return CheckForImmediateInvocation( CXXConstructExpr::Create( @@ -15684,7 +15854,11 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { return; CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - + // The result of `LookupDestructor` might be nullptr if the destructor is + // invalid, in which case it is marked as `IneligibleOrNotSelected` and + // will not be selected by `CXXRecordDecl::getDestructor()`. + if (!Destructor) + return; // If this is an array, we'll require the destructor during initialization, so // we can skip over this. We still want to emit exit-time destructor warnings // though. @@ -15714,7 +15888,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { } } - if (!VD->hasGlobalStorage()) return; + if (!VD->hasGlobalStorage() || !VD->needsDestruction(Context)) + return; // Emit warning for non-trivial dtor in global scope (a real global, // class-static, function-static). @@ -15971,7 +16146,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (MethodDecl->isStatic()) { if (Op == OO_Call || Op == OO_Subscript) Diag(FnDecl->getLocation(), - (LangOpts.CPlusPlus2b + (LangOpts.CPlusPlus23 ? diag::warn_cxx20_compat_operator_overload_static : diag::ext_operator_overload_static)) << FnDecl; @@ -16012,7 +16187,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { } if (FirstDefaultedParam) { if (Op == OO_Subscript) { - Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b + Diag(FnDecl->getLocation(), LangOpts.CPlusPlus23 ? diag::ext_subscript_overload : diag::error_subscript_overload) << FnDecl->getDeclName() << 1 @@ -16063,7 +16238,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { } if (Op == OO_Subscript && NumParams != 2) { - Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b + Diag(FnDecl->getLocation(), LangOpts.CPlusPlus23 ? diag::ext_subscript_overload : diag::error_subscript_overload) << FnDecl->getDeclName() << (NumParams == 1 ? 0 : 2); @@ -16319,15 +16494,18 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { } } - StringRef LiteralName - = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); - if (LiteralName[0] != '_' && + const IdentifierInfo *II = FnDecl->getDeclName().getCXXLiteralIdentifier(); + ReservedLiteralSuffixIdStatus Status = II->isReservedLiteralSuffixId(); + if (Status != ReservedLiteralSuffixIdStatus::NotReserved && !getSourceManager().isInSystemHeader(FnDecl->getLocation())) { - // C++11 [usrlit.suffix]p1: - // Literal suffix identifiers that do not start with an underscore - // are reserved for future standardization. + // C++23 [usrlit.suffix]p1: + // Literal suffix identifiers that do not start with an underscore are + // reserved for future standardization. Literal suffix identifiers that + // contain a double underscore __ are reserved for use by C++ + // implementations. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << static_cast<int>(Status) + << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName()); } return false; @@ -16343,11 +16521,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc) { StringLiteral *Lit = cast<StringLiteral>(LangStr); - if (!Lit->isOrdinary()) { - Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii) - << LangStr->getSourceRange(); - return nullptr; - } + assert(Lit->isUnevaluated() && "Unexpected string literal kind"); StringRef Lang = Lit->getString(); LinkageSpecDecl::LanguageIDs Language; @@ -16377,14 +16551,8 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, /// If the declaration is already in global module fragment, we don't /// need to attach it again. if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) { - Module *GlobalModule = - PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true); - /// According to [module.reach]p3.2, - /// The declaration in global module fragment is reachable if it is not - /// discarded. And the discarded declaration should be deleted. So it - /// doesn't matter mark the declaration in global module fragment as - /// reachable here. - D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported); + Module *GlobalModule = PushImplicitGlobalModuleFragment( + ExternLoc, /*IsExported=*/D->isInExportDeclContext()); D->setLocalOwningModule(GlobalModule); } @@ -16409,8 +16577,9 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, // LinkageSpec isn't in the module created by itself. So we don't // need to pop it. if (getLangOpts().CPlusPlusModules && getCurrentModule() && - getCurrentModule()->isGlobalModule() && getCurrentModule()->Parent) - PopGlobalModuleFragment(); + getCurrentModule()->isImplicitGlobalModule() && + getCurrentModule()->Parent) + PopImplicitGlobalModuleFragment(); PopDeclContext(); return LinkageSpec; @@ -16476,6 +16645,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; + if (!Invalid && BaseType.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reftype_tc) << 1; + Invalid = true; + } + if (!Invalid && Mode != 1 && BaseType->isSizelessType()) { Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType; Invalid = true; @@ -16618,14 +16792,11 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc) { - StringLiteral *AssertMessage = - AssertMessageExpr ? cast<StringLiteral>(AssertMessageExpr) : nullptr; - if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) return nullptr; return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr, - AssertMessage, RParenLoc, false); + AssertMessageExpr, RParenLoc, false); } /// Convert \V to a string we can present to the user in a diagnostic @@ -16723,7 +16894,8 @@ static bool UsefulToPrintExpr(const Expr *E) { /// Try to print more useful information about a failed static_assert /// with expression \E void Sema::DiagnoseStaticAssertDetails(const Expr *E) { - if (const auto *Op = dyn_cast<BinaryOperator>(E)) { + if (const auto *Op = dyn_cast<BinaryOperator>(E); + Op && Op->getOpcode() != BO_LOr) { const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts(); const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts(); @@ -16759,13 +16931,147 @@ void Sema::DiagnoseStaticAssertDetails(const Expr *E) { } } +bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message, + std::string &Result, + ASTContext &Ctx, + bool ErrorOnInvalidMessage) { + assert(Message); + assert(!Message->isTypeDependent() && !Message->isValueDependent() && + "can't evaluate a dependant static assert message"); + + if (const auto *SL = dyn_cast<StringLiteral>(Message)) { + assert(SL->isUnevaluated() && "expected an unevaluated string"); + Result.assign(SL->getString().begin(), SL->getString().end()); + return true; + } + + SourceLocation Loc = Message->getBeginLoc(); + QualType T = Message->getType().getNonReferenceType(); + auto *RD = T->getAsCXXRecordDecl(); + if (!RD) { + Diag(Loc, diag::err_static_assert_invalid_message); + return false; + } + + auto FindMember = [&](StringRef Member, bool &Empty, + bool Diag = false) -> std::optional<LookupResult> { + QualType ObjectType = Message->getType(); + Expr::Classification ObjectClassification = + Message->Classify(getASTContext()); + + DeclarationName DN = PP.getIdentifierInfo(Member); + LookupResult MemberLookup(*this, DN, Loc, Sema::LookupMemberName); + LookupQualifiedName(MemberLookup, RD); + Empty = MemberLookup.empty(); + OverloadCandidateSet Candidates(MemberLookup.getNameLoc(), + OverloadCandidateSet::CSK_Normal); + for (NamedDecl *D : MemberLookup) { + AddMethodCandidate(DeclAccessPair::make(D, D->getAccess()), ObjectType, + ObjectClassification, /*Args=*/{}, Candidates); + } + OverloadCandidateSet::iterator Best; + switch (Candidates.BestViableFunction(*this, Loc, Best)) { + case OR_Success: + return std::move(MemberLookup); + default: + if (Diag) + Candidates.NoteCandidates( + PartialDiagnosticAt( + Loc, PDiag(diag::err_static_assert_invalid_mem_fn_ret_ty) + << (Member == "data")), + *this, OCD_AllCandidates, /*Args=*/{}); + } + return std::nullopt; + }; + + bool SizeNotFound, DataNotFound; + std::optional<LookupResult> SizeMember = FindMember("size", SizeNotFound); + std::optional<LookupResult> DataMember = FindMember("data", DataNotFound); + if (SizeNotFound || DataNotFound) { + Diag(Loc, diag::err_static_assert_missing_member_function) + << ((SizeNotFound && DataNotFound) ? 2 + : SizeNotFound ? 0 + : 1); + return false; + } + + if (!SizeMember || !DataMember) { + if (!SizeMember) + FindMember("size", SizeNotFound, /*Diag=*/true); + if (!DataMember) + FindMember("data", DataNotFound, /*Diag=*/true); + return false; + } + + auto BuildExpr = [&](LookupResult &LR) { + ExprResult Res = BuildMemberReferenceExpr( + Message, Message->getType(), Message->getBeginLoc(), false, + CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr); + if (Res.isInvalid()) + return ExprError(); + Res = BuildCallExpr(nullptr, Res.get(), Loc, std::nullopt, Loc, nullptr, + false, true); + if (Res.isInvalid()) + return ExprError(); + if (Res.get()->isTypeDependent() || Res.get()->isValueDependent()) + return ExprError(); + return TemporaryMaterializationConversion(Res.get()); + }; + + ExprResult SizeE = BuildExpr(*SizeMember); + ExprResult DataE = BuildExpr(*DataMember); + + QualType SizeT = Context.getSizeType(); + QualType ConstCharPtr = + Context.getPointerType(Context.getConstType(Context.CharTy)); + + ExprResult EvaluatedSize = + SizeE.isInvalid() ? ExprError() + : BuildConvertedConstantExpression( + SizeE.get(), SizeT, CCEK_StaticAssertMessageSize); + if (EvaluatedSize.isInvalid()) { + Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*size*/ 0; + return false; + } + + ExprResult EvaluatedData = + DataE.isInvalid() + ? ExprError() + : BuildConvertedConstantExpression(DataE.get(), ConstCharPtr, + CCEK_StaticAssertMessageData); + if (EvaluatedData.isInvalid()) { + Diag(Loc, diag::err_static_assert_invalid_mem_fn_ret_ty) << /*data*/ 1; + return false; + } + + if (!ErrorOnInvalidMessage && + Diags.isIgnored(diag::warn_static_assert_message_constexpr, Loc)) + return true; + + Expr::EvalResult Status; + SmallVector<PartialDiagnosticAt, 8> Notes; + Status.Diag = &Notes; + if (!Message->EvaluateCharRangeAsString(Result, EvaluatedSize.get(), + EvaluatedData.get(), Ctx, Status) || + !Notes.empty()) { + Diag(Message->getBeginLoc(), + ErrorOnInvalidMessage ? diag::err_static_assert_message_constexpr + : diag::warn_static_assert_message_constexpr); + for (const auto &Note : Notes) + Diag(Note.first, Note.second); + return !ErrorOnInvalidMessage; + } + return true; +} + Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, - Expr *AssertExpr, - StringLiteral *AssertMessage, + Expr *AssertExpr, Expr *AssertMessage, SourceLocation RParenLoc, bool Failed) { assert(AssertExpr != nullptr && "Expected non-null condition"); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() && + (!AssertMessage || (!AssertMessage->isTypeDependent() && + !AssertMessage->isValueDependent())) && !Failed) { // In a static_assert-declaration, the constant-expression shall be a // constant expression that can be contextually converted to bool. @@ -16799,17 +17105,32 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, FoldKind).isInvalid()) Failed = true; - if (!Failed && !Cond) { + // If the static_assert passes, only verify that + // the message is grammatically valid without evaluating it. + if (!Failed && AssertMessage && Cond.getBoolValue()) { + std::string Str; + EvaluateStaticAssertMessageAsString(AssertMessage, Str, Context, + /*ErrorOnInvalidMessage=*/false); + } + + // CWG2518 + // [dcl.pre]/p10 If [...] the expression is evaluated in the context of a + // template definition, the declaration has no effect. + bool InTemplateDefinition = + getLangOpts().CPlusPlus && CurContext->isDependentContext(); + + if (!Failed && !Cond && !InTemplateDefinition) { SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); + bool HasMessage = AssertMessage; if (AssertMessage) { - const auto *MsgStr = cast<StringLiteral>(AssertMessage); - if (MsgStr->isOrdinary()) - Msg << MsgStr->getString(); - else - MsgStr->printPretty(Msg, nullptr, getPrintingPolicy()); + std::string Str; + HasMessage = + EvaluateStaticAssertMessageAsString( + AssertMessage, Str, Context, /*ErrorOnInvalidMessage=*/true) || + !Str.empty(); + Msg << Str; } - Expr *InnerCond = nullptr; std::string InnerCondDescription; std::tie(InnerCond, InnerCondDescription) = @@ -16817,20 +17138,22 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) { // Drill down into concept specialization expressions to see why they // weren't satisfied. - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed) + << !HasMessage << Msg.str() << AssertExpr->getSourceRange(); ConstraintSatisfaction Satisfaction; if (!CheckConstraintSatisfaction(InnerCond, Satisfaction)) DiagnoseUnsatisfiedConstraint(Satisfaction); } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) && !isa<IntegerLiteral>(InnerCond)) { - Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) - << InnerCondDescription << !AssertMessage - << Msg.str() << InnerCond->getSourceRange(); + Diag(InnerCond->getBeginLoc(), + diag::err_static_assert_requirement_failed) + << InnerCondDescription << !HasMessage << Msg.str() + << InnerCond->getSourceRange(); DiagnoseStaticAssertDetails(InnerCond); } else { - Diag(StaticAssertLoc, diag::err_static_assert_failed) - << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed) + << !HasMessage << Msg.str() << AssertExpr->getSourceRange(); + PrintContextStack(); } Failed = true; } @@ -16977,7 +17300,6 @@ DeclResult Sema::ActOnTemplatedFriendTag( if (SS.isEmpty()) { bool Owned = false; bool IsDependent = false; - UsingShadowDecl* FoundUsing = nullptr; return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, AS_public, /*ModulePrivateLoc=*/SourceLocation(), @@ -16986,7 +17308,7 @@ DeclResult Sema::ActOnTemplatedFriendTag( /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult(), /*IsTypeSpecifier=*/false, - /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside, FoundUsing); + /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -17935,7 +18257,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Do not mark as used if compiling for the device outside of the target // region. - if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice && !isInOpenMPDeclareTargetContext() && !isInOpenMPTargetExecutionDirective()) { if (!DefinitionRequired) @@ -17983,7 +18305,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // immediately. For all other classes, we mark their virtual members // at the end of the translation unit. if (Class->isLocalClass()) - MarkVirtualMembersReferenced(Loc, Class); + MarkVirtualMembersReferenced(Loc, Class->getDefinition()); else VTableUses.push_back(std::make_pair(Class, Loc)); } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a5a57c38bb48..9b7ff5ff8251 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -172,6 +172,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; + // WebAssembly reference types can't be used in exception specifications. + if (PointeeT.isWebAssemblyReferenceType()) { + Diag(Range.getBegin(), diag::err_wasm_reftype_exception_spec); + return true; + } + // The MSVC compatibility mode doesn't extend to sizeless types, // so diagnose them separately. if (PointeeT->isSizelessType() && Kind != 1) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2842add2cc4a..2716b6677105 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -41,6 +41,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" @@ -308,8 +309,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; - if (getLangOpts().SYCLIsDevice && !checkSYCLDeviceFunction(Loc, FD)) - return true; } if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -375,10 +374,21 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); + if (D->hasAttr<AvailableOnlyInDefaultEvalMethodAttr>()) { + if (getLangOpts().getFPEvalMethod() != + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine && + PP.getLastFPEvalPragmaLocation().isValid() && + PP.getCurrentFPEvalMethod() != getLangOpts().getFPEvalMethod()) + Diag(D->getLocation(), + diag::err_type_available_only_in_default_eval_method) + << D->getName(); + } + if (auto *VD = dyn_cast<ValueDecl>(D)) checkTypeSupport(VD->getType(), Loc, VD); - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) { + if (LangOpts.SYCLIsDevice || + (LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice)) { if (!Context.getTargetInfo().isTLSSupported()) if (const auto *VD = dyn_cast<VarDecl>(D)) if (VD->getTLSKind() != VarDecl::TLS_None) @@ -940,6 +950,11 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) return VAK_Invalid; + if (Context.getTargetInfo().getTriple().isWasm() && + Ty.isWebAssemblyReferenceType()) { + return VAK_Invalid; + } + if (Ty.isCXX98PODType(Context)) return VAK_Valid; @@ -1607,13 +1622,10 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, //===----------------------------------------------------------------------===// -ExprResult -Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - Expr *ControllingExpr, - ArrayRef<ParsedType> ArgTypes, - ArrayRef<Expr *> ArgExprs) { +ExprResult Sema::ActOnGenericSelectionExpr( + SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool PredicateIsExpr, void *ControllingExprOrType, + ArrayRef<ParsedType> ArgTypes, ArrayRef<Expr *> ArgExprs) { unsigned NumAssocs = ArgTypes.size(); assert(NumAssocs == ArgExprs.size()); @@ -1625,42 +1637,64 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, Types[i] = nullptr; } - ExprResult ER = - CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr, - llvm::ArrayRef(Types, NumAssocs), ArgExprs); + // If we have a controlling type, we need to convert it from a parsed type + // into a semantic type and then pass that along. + if (!PredicateIsExpr) { + TypeSourceInfo *ControllingType; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(ControllingExprOrType), + &ControllingType); + assert(ControllingType && "couldn't get the type out of the parser"); + ControllingExprOrType = ControllingType; + } + + ExprResult ER = CreateGenericSelectionExpr( + KeyLoc, DefaultLoc, RParenLoc, PredicateIsExpr, ControllingExprOrType, + llvm::ArrayRef(Types, NumAssocs), ArgExprs); delete [] Types; return ER; } -ExprResult -Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - Expr *ControllingExpr, - ArrayRef<TypeSourceInfo *> Types, - ArrayRef<Expr *> Exprs) { +ExprResult Sema::CreateGenericSelectionExpr( + SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool PredicateIsExpr, void *ControllingExprOrType, + ArrayRef<TypeSourceInfo *> Types, ArrayRef<Expr *> Exprs) { unsigned NumAssocs = Types.size(); assert(NumAssocs == Exprs.size()); - - // Decay and strip qualifiers for the controlling expression type, and handle - // placeholder type replacement. See committee discussion from WG14 DR423. - { + assert(ControllingExprOrType && + "Must have either a controlling expression or a controlling type"); + + Expr *ControllingExpr = nullptr; + TypeSourceInfo *ControllingType = nullptr; + if (PredicateIsExpr) { + // Decay and strip qualifiers for the controlling expression type, and + // handle placeholder type replacement. See committee discussion from WG14 + // DR423. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr); + ExprResult R = DefaultFunctionArrayLvalueConversion( + reinterpret_cast<Expr *>(ControllingExprOrType)); if (R.isInvalid()) return ExprError(); ControllingExpr = R.get(); + } else { + // The extension form uses the type directly rather than converting it. + ControllingType = reinterpret_cast<TypeSourceInfo *>(ControllingExprOrType); + if (!ControllingType) + return ExprError(); } bool TypeErrorFound = false, - IsResultDependent = ControllingExpr->isTypeDependent(), - ContainsUnexpandedParameterPack - = ControllingExpr->containsUnexpandedParameterPack(); + IsResultDependent = ControllingExpr + ? ControllingExpr->isTypeDependent() + : ControllingType->getType()->isDependentType(), + ContainsUnexpandedParameterPack = + ControllingExpr + ? ControllingExpr->containsUnexpandedParameterPack() + : ControllingType->getType()->containsUnexpandedParameterPack(); // The controlling expression is an unevaluated operand, so side effects are // likely unintended. - if (!inTemplateInstantiation() && !IsResultDependent && + if (!inTemplateInstantiation() && !IsResultDependent && ControllingExpr && ControllingExpr->HasSideEffects(Context, false)) Diag(ControllingExpr->getExprLoc(), diag::warn_side_effects_unevaluated_context); @@ -1676,16 +1710,24 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, if (Types[i]->getType()->isDependentType()) { IsResultDependent = true; } else { + // We relax the restriction on use of incomplete types and non-object + // types with the type-based extension of _Generic. Allowing incomplete + // objects means those can be used as "tags" for a type-safe way to map + // to a value. Similarly, matching on function types rather than + // function pointer types can be useful. However, the restriction on VM + // types makes sense to retain as there are open questions about how + // the selection can be made at compile time. + // // C11 6.5.1.1p2 "The type name in a generic association shall specify a // complete object type other than a variably modified type." unsigned D = 0; - if (Types[i]->getType()->isIncompleteType()) + if (ControllingExpr && Types[i]->getType()->isIncompleteType()) D = diag::err_assoc_type_incomplete; - else if (!Types[i]->getType()->isObjectType()) + else if (ControllingExpr && !Types[i]->getType()->isObjectType()) D = diag::err_assoc_type_nonobject; else if (Types[i]->getType()->isVariablyModifiedType()) D = diag::err_assoc_type_variably_modified; - else { + else if (ControllingExpr) { // Because the controlling expression undergoes lvalue conversion, // array conversion, and function conversion, an association which is // of array type, function type, or is qualified can never be @@ -1700,6 +1742,10 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // The result of these rules is that all qualified types in an // association in C are unreachable, and in C++, only qualified non- // class types are unreachable. + // + // NB: this does not apply when the first operand is a type rather + // than an expression, because the type form does not undergo + // conversion. unsigned Reason = 0; QualType QT = Types[i]->getType(); if (QT->isArrayType()) @@ -1746,10 +1792,15 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // If we determined that the generic selection is result-dependent, don't // try to compute the result expression. - if (IsResultDependent) - return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types, + if (IsResultDependent) { + if (ControllingExpr) + return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, + Types, Exprs, DefaultLoc, RParenLoc, + ContainsUnexpandedParameterPack); + return GenericSelectionExpr::Create(Context, KeyLoc, ControllingType, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack); + } SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; @@ -1759,22 +1810,42 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, for (unsigned i = 0; i < NumAssocs; ++i) { if (!Types[i]) DefaultIndex = i; - else if (Context.typesAreCompatible( + else if (ControllingExpr && + Context.typesAreCompatible( ControllingExpr->getType().getCanonicalType(), - Types[i]->getType())) + Types[i]->getType())) + CompatIndices.push_back(i); + else if (ControllingType && + Context.typesAreCompatible( + ControllingType->getType().getCanonicalType(), + Types[i]->getType())) CompatIndices.push_back(i); } + auto GetControllingRangeAndType = [](Expr *ControllingExpr, + TypeSourceInfo *ControllingType) { + // We strip parens here because the controlling expression is typically + // parenthesized in macro definitions. + if (ControllingExpr) + ControllingExpr = ControllingExpr->IgnoreParens(); + + SourceRange SR = ControllingExpr + ? ControllingExpr->getSourceRange() + : ControllingType->getTypeLoc().getSourceRange(); + QualType QT = ControllingExpr ? ControllingExpr->getType() + : ControllingType->getType(); + + return std::make_pair(SR, QT); + }; + // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have // type compatible with at most one of the types named in its generic // association list." if (CompatIndices.size() > 1) { - // We strip parens here because the controlling expression is typically - // parenthesized in macro definitions. - ControllingExpr = ControllingExpr->IgnoreParens(); - Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_multi_match) - << ControllingExpr->getSourceRange() << ControllingExpr->getType() - << (unsigned)CompatIndices.size(); + auto P = GetControllingRangeAndType(ControllingExpr, ControllingType); + SourceRange SR = P.first; + Diag(SR.getBegin(), diag::err_generic_sel_multi_match) + << SR << P.second << (unsigned)CompatIndices.size(); for (unsigned I : CompatIndices) { Diag(Types[I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) @@ -1788,11 +1859,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, // its controlling expression shall have type compatible with exactly one of // the types named in its generic association list." if (DefaultIndex == -1U && CompatIndices.size() == 0) { - // We strip parens here because the controlling expression is typically - // parenthesized in macro definitions. - ControllingExpr = ControllingExpr->IgnoreParens(); - Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_no_match) - << ControllingExpr->getSourceRange() << ControllingExpr->getType(); + auto P = GetControllingRangeAndType(ControllingExpr, ControllingType); + SourceRange SR = P.first; + Diag(SR.getBegin(), diag::err_generic_sel_no_match) << SR << P.second; return ExprError(); } @@ -1804,8 +1873,13 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, unsigned ResultIndex = CompatIndices.size() ? CompatIndices[0] : DefaultIndex; + if (ControllingExpr) { + return GenericSelectionExpr::Create( + Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, + ContainsUnexpandedParameterPack, ResultIndex); + } return GenericSelectionExpr::Create( - Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, + Context, KeyLoc, ControllingType, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); } @@ -1848,6 +1922,30 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); } +ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks) { + StringLiteralParser Literal(StringToks, PP, + StringLiteralEvalMethod::Unevaluated); + if (Literal.hadError) + return ExprError(); + + SmallVector<SourceLocation, 4> StringTokLocs; + for (const Token &Tok : StringToks) + StringTokLocs.push_back(Tok.getLocation()); + + StringLiteral *Lit = StringLiteral::Create( + Context, Literal.GetString(), StringLiteral::Unevaluated, false, {}, + &StringTokLocs[0], StringTokLocs.size()); + + if (!Literal.getUDSuffix().empty()) { + SourceLocation UDSuffixLoc = + getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()], + Literal.getUDSuffixOffset()); + return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl)); + } + + return Lit; +} + /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from @@ -2102,9 +2200,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, // b) if the function is a defaulted comparison, we can use the body we // build when defining it as input to the exception specification // computation rather than computing a new body. - if (auto *FPT = Ty->getAs<FunctionProtoType>()) { + if (const auto *FPT = Ty->getAs<FunctionProtoType>()) { if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { - if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) + if (const auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); } } @@ -2114,8 +2212,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) getCurFunction()->recordUseOfWeak(E); - FieldDecl *FD = dyn_cast<FieldDecl>(D); - if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) + const auto *FD = dyn_cast<FieldDecl>(D); + if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) FD = IFD->getAnonField(); if (FD) { UnusedPrivateFields.remove(FD); @@ -2126,8 +2224,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier // designates a bit-field. - if (auto *BD = dyn_cast<BindingDecl>(D)) - if (auto *BE = BD->getBinding()) + if (const auto *BD = dyn_cast<BindingDecl>(D)) + if (const auto *BE = BD->getBinding()) E->setObjectKind(BE->getObjectKind()); return E; @@ -2206,7 +2304,7 @@ static void emitEmptyLookupTypoDiagnostic( /// /// Return \c true if the error is unrecoverable, or \c false if the caller /// should attempt to recover using these lookup results. -bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { +bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) { // During a default argument instantiation the CurContext points // to a CXXMethodDecl; but we can't apply a this-> fixit inside a // function parameter list, hence add an explicit check. @@ -2214,7 +2312,7 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { !CodeSynthesisContexts.empty() && CodeSynthesisContexts.back().Kind == CodeSynthesisContext::DefaultFunctionArgumentInstantiation; - CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); + const auto *CurMethod = dyn_cast<CXXMethodDecl>(CurContext); bool isInstance = CurMethod && CurMethod->isInstance() && R.getNamingClass() == CurMethod->getParent() && !isDefaultArgument; @@ -2246,7 +2344,7 @@ bool Sema::DiagnoseDependentMemberLookup(LookupResult &R) { Diag(R.getNameLoc(), DiagID) << R.getLookupName(); } - for (NamedDecl *D : R) + for (const NamedDecl *D : R) Diag(D->getLocation(), NoteID); // Return true if we are inside a default argument instantiation @@ -3004,7 +3102,7 @@ Sema::PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member) { - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); + const auto *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) return From; @@ -3029,7 +3127,7 @@ Sema::PerformObjectMemberConversion(Expr *From, DestType = DestRecordType; FromRecordType = FromType; } - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { + } else if (const auto *Method = dyn_cast<CXXMethodDecl>(Member)) { if (Method->isStatic()) return From; @@ -3149,7 +3247,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // Turn off ADL when we find certain kinds of declarations during // normal lookup: - for (NamedDecl *D : R) { + for (const NamedDecl *D : R) { // C++0x [basic.lookup.argdep]p3: // -- a declaration of a class member // Since using decls preserve this property, we check this on the @@ -3172,9 +3270,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // -- a declaration that is neither a function or a function // template // And also for builtin functions. - if (isa<FunctionDecl>(D)) { - FunctionDecl *FDecl = cast<FunctionDecl>(D); - + if (const auto *FDecl = dyn_cast<FunctionDecl>(D)) { // But also builtin functions. if (FDecl->getBuiltinID() && FDecl->isImplicit()) return false; @@ -3308,10 +3404,10 @@ ExprResult Sema::BuildDeclarationNameExpr( // Handle members of anonymous structs and unions. If we got here, // and the reference is to a class member indirect field, then this // must be the subject of a pointer-to-member expression. - if (IndirectFieldDecl *indirectField = dyn_cast<IndirectFieldDecl>(VD)) - if (!indirectField->isCXXClassMember()) - return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), - indirectField); + if (auto *IndirectField = dyn_cast<IndirectFieldDecl>(VD); + IndirectField && !IndirectField->isCXXClassMember()) + return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), + IndirectField); QualType type = VD->getType(); if (type.isNull()) @@ -3577,7 +3673,8 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, } } - return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); + return PredefinedExpr::Create(Context, Loc, ResTy, IK, LangOpts.MicrosoftExt, + SL); } ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, @@ -3774,7 +3871,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Literal.hasUDSuffix()) { // We're building a user-defined literal. - IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); + const IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); SourceLocation UDSuffixLoc = getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset()); @@ -3953,13 +4050,13 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { QualType Ty; - // 'z/uz' literals are a C++2b feature. + // 'z/uz' literals are a C++23 feature. if (Literal.isSizeT) Diag(Tok.getLocation(), getLangOpts().CPlusPlus - ? getLangOpts().CPlusPlus2b + ? getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_size_t_suffix - : diag::ext_cxx2b_size_t_suffix - : diag::err_cxx2b_size_t_suffix); + : diag::ext_cxx23_size_t_suffix + : diag::err_cxx23_size_t_suffix); // 'wb/uwb' literals are a C2x feature. We support _BitInt as a type in C++, // but we do not currently support the suffix in C++ mode because it's not @@ -4039,7 +4136,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Ty = Context.getBitIntType(Literal.isUnsigned, Width); } - // Check C++2b size_t literals. + // Check C++23 size_t literals. if (Literal.isSizeT) { assert(!Literal.MicrosoftInteger && "size_t literals can't be Microsoft literals"); @@ -4237,13 +4334,13 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, /// 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) { + const Expr *E) { // Don't warn if the operation changed the type. if (T != E->getType()) return; // Now look for array decays. - ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E); + const auto *ICE = dyn_cast<ImplicitCastExpr>(E); if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay) return; @@ -4294,6 +4391,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, E->getSourceRange(), ExprKind)) return false; + // WebAssembly tables are always illegal operands to unary expressions and + // type traits. + if (Context.getTargetInfo().getTriple().isWasm() && + E->getType()->isWebAssemblyTableType()) { + Diag(E->getExprLoc(), diag::err_wasm_table_invalid_uett_operand) + << getTraitSpelling(ExprKind); + return true; + } + // 'alignof' applied to an expression only requires the base element type of // the expression to be complete. 'sizeof' requires the expression's type to // be complete (and will attempt to complete it if it's an array of unknown @@ -4326,8 +4432,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return true; if (ExprKind == UETT_SizeOf) { - if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { - if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { + if (const auto *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (const auto *PVD = dyn_cast<ParmVarDecl>(DeclRef->getFoundDecl())) { QualType OType = PVD->getOriginalType(); QualType Type = PVD->getType(); if (Type->isPointerType() && OType->isArrayType()) { @@ -4341,7 +4447,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array // decays into a pointer and returns an unintended result. This is most // likely a typo for "sizeof(array) op x". - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) { + if (const auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) { warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), BO->getLHS()); warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), @@ -4352,70 +4458,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return false; } -/// Check the constraints on operands to unary expression and type -/// traits. -/// -/// This will complete any types necessary, and validate the various constraints -/// on those operands. -/// -/// The UsualUnaryConversions() function is *not* called by this routine. -/// C99 6.3.2.1p[2-4] all state: -/// Except when it is the operand of the sizeof operator ... -/// -/// C++ [expr.sizeof]p4 -/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer -/// standard conversions are not applied to the operand of sizeof. -/// -/// This policy is followed for all of the unary trait expressions. -bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, - SourceLocation OpLoc, - SourceRange ExprRange, - UnaryExprOrTypeTrait ExprKind) { - if (ExprType->isDependentType()) - return false; - - // C++ [expr.sizeof]p2: - // When applied to a reference or a reference type, the result - // is the size of the referenced type. - // C++11 [expr.alignof]p3: - // When alignof is applied to a reference type, the result - // shall be the alignment of the referenced type. - if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) - ExprType = Ref->getPointeeType(); - - // C11 6.5.3.4/3, C++11 [expr.alignof]p3: - // When alignof or _Alignof is applied to an array type, the result - // is the alignment of the element type. - if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || - ExprKind == UETT_OpenMPRequiredSimdAlign) - ExprType = Context.getBaseElementType(ExprType); - - if (ExprKind == UETT_VecStep) - return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); - - // Explicitly list some types as extensions. - if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, - ExprKind)) - return false; - - if (RequireCompleteSizedType( - OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, - getTraitSpelling(ExprKind), ExprRange)) - return true; - - if (ExprType->isFunctionType()) { - Diag(OpLoc, diag::err_sizeof_alignof_function_type) - << getTraitSpelling(ExprKind) << ExprRange; - return true; - } - - if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, - ExprKind)) - return true; - - return false; -} - static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) @@ -4593,23 +4635,78 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, } while (!T.isNull() && T->isVariablyModifiedType()); } -/// Build a sizeof or alignof expression given a type operand. -ExprResult -Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, - SourceRange R) { - if (!TInfo) - return ExprError(); +/// Check the constraints on operands to unary expression and type +/// traits. +/// +/// This will complete any types necessary, and validate the various constraints +/// on those operands. +/// +/// The UsualUnaryConversions() function is *not* called by this routine. +/// C99 6.3.2.1p[2-4] all state: +/// Except when it is the operand of the sizeof operator ... +/// +/// C++ [expr.sizeof]p4 +/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer +/// standard conversions are not applied to the operand of sizeof. +/// +/// This policy is followed for all of the unary trait expressions. +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, + SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind, + StringRef KWName) { + if (ExprType->isDependentType()) + return false; - QualType T = TInfo->getType(); + // C++ [expr.sizeof]p2: + // When applied to a reference or a reference type, the result + // is the size of the referenced type. + // C++11 [expr.alignof]p3: + // When alignof is applied to a reference type, the result + // shall be the alignment of the referenced type. + if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>()) + ExprType = Ref->getPointeeType(); - if (!T->isDependentType() && - CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) - return ExprError(); + // C11 6.5.3.4/3, C++11 [expr.alignof]p3: + // When alignof or _Alignof is applied to an array type, the result + // is the alignment of the element type. + if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || + ExprKind == UETT_OpenMPRequiredSimdAlign) + ExprType = Context.getBaseElementType(ExprType); + + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); + + // Explicitly list some types as extensions. + if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, + ExprKind)) + return false; + + if (RequireCompleteSizedType( + OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, + KWName, ExprRange)) + return true; - if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { - if (auto *TT = T->getAs<TypedefType>()) { + if (ExprType->isFunctionType()) { + Diag(OpLoc, diag::err_sizeof_alignof_function_type) << KWName << ExprRange; + return true; + } + + // WebAssembly tables are always illegal operands to unary expressions and + // type traits. + if (Context.getTargetInfo().getTriple().isWasm() && + ExprType->isWebAssemblyTableType()) { + Diag(OpLoc, diag::err_wasm_table_invalid_uett_operand) + << getTraitSpelling(ExprKind); + return true; + } + + if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, + ExprKind)) + return true; + + if (ExprType->isVariablyModifiedType() && FunctionScopes.size() > 1) { + if (auto *TT = ExprType->getAs<TypedefType>()) { for (auto I = FunctionScopes.rbegin(), E = std::prev(FunctionScopes.rend()); I != E; ++I) { @@ -4626,17 +4723,37 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, if (DC) { if (DC->containsDecl(TT->getDecl())) break; - captureVariablyModifiedType(Context, T, CSI); + captureVariablyModifiedType(Context, ExprType, CSI); } } } } - // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. + return false; +} + +/// Build a sizeof or alignof expression given a type operand. +ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { + if (!TInfo) + return ExprError(); + + QualType T = TInfo->getType(); + + if (!T->isDependentType() && + CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind, + getTraitSpelling(ExprKind))) + return ExprError(); + + // Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to + // properly deal with VLAs in nested calls of sizeof and typeof. if (isUnevaluatedContext() && ExprKind == UETT_SizeOf && TInfo->getType()->isVariablyModifiedType()) TInfo = TransformToPotentiallyEvaluated(TInfo); + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); } @@ -4705,6 +4822,29 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, return Result; } +bool Sema::CheckAlignasTypeArgument(StringRef KWName, TypeSourceInfo *TInfo, + SourceLocation OpLoc, SourceRange R) { + if (!TInfo) + return true; + return CheckUnaryExprOrTypeTraitOperand(TInfo->getType(), OpLoc, R, + UETT_AlignOf, KWName); +} + +/// ActOnAlignasTypeArgument - Handle @c alignas(type-id) and @c +/// _Alignas(type-name) . +/// [dcl.align] An alignment-specifier of the form +/// alignas(type-id) has the same effect as alignas(alignof(type-id)). +/// +/// [N1570 6.7.5] _Alignas(type-name) is equivalent to +/// _Alignas(_Alignof(type-name)). +bool Sema::ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty, + SourceLocation OpLoc, SourceRange R) { + TypeSourceInfo *TInfo; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(Ty.getAsOpaquePtr()), + &TInfo); + return CheckAlignasTypeArgument(KWName, TInfo, OpLoc, R); +} + static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, bool IsReal) { if (V.get()->isTypeDependent()) @@ -4850,7 +4990,8 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, }; // The matrix subscript operator ([][])is considered a single operator. // Separating the index expressions by parenthesis is not allowed. - if (base->hasPlaceholderType(BuiltinType::IncompleteMatrixIdx) && + if (base && !base->getType().isNull() && + base->hasPlaceholderType(BuiltinType::IncompleteMatrixIdx) && !isa<MatrixSubscriptExpr>(base)) { Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index) << SourceRange(base->getBeginLoc(), rbLoc); @@ -4870,6 +5011,11 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, matSubscriptE->getRowIdx(), ArgExprs.front(), rbLoc); } + if (base->getType()->isWebAssemblyTableType()) { + Diag(base->getExprLoc(), diag::err_wasm_table_art) + << SourceRange(base->getBeginLoc(), rbLoc) << 3; + return ExprError(); + } // Handle any non-overload placeholder types in the base and index // expressions. We can't handle overloads here because the other @@ -4921,7 +5067,8 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, // Build an unanalyzed expression if either operand is type-dependent. if (getLangOpts().CPlusPlus && ArgExprs.size() == 1 && (base->isTypeDependent() || - Expr::hasAnyTypeDependentArguments(ArgExprs))) { + Expr::hasAnyTypeDependentArguments(ArgExprs)) && + !isa<PackExpansionExpr>(ArgExprs[0])) { return new (Context) ArraySubscriptExpr( base, ArgExprs.front(), getDependentArraySubscriptType(base, ArgExprs.front(), getASTContext()), @@ -4955,7 +5102,8 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, // to overload resolution and so should not take this path. if (getLangOpts().CPlusPlus && !base->getType()->isObjCObjectPointerType() && ((base->getType()->isRecordType() || - (ArgExprs.size() != 1 || ArgExprs[0]->getType()->isRecordType())))) { + (ArgExprs.size() != 1 || isa<PackExpansionExpr>(ArgExprs[0]) || + ArgExprs[0]->getType()->isRecordType())))) { return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs); } @@ -5826,6 +5974,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, if (!ResultType.hasQualifiers()) VK = VK_PRValue; } else if (!ResultType->isDependentType() && + !ResultType.isWebAssemblyReferenceType() && RequireCompleteSizedType( LLoc, ResultType, diag::err_subscript_incomplete_or_sizeless_type, BaseExpr)) @@ -5912,22 +6061,34 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, assert(!InitWithCleanup->getNumObjects() && "default argument expression has capturing blocks?"); } + // C++ [expr.const]p15.1: + // An expression or conversion is in an immediate function context if it is + // potentially evaluated and [...] its innermost enclosing non-block scope + // is a function parameter scope of an immediate function. EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + *this, + FD->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : ExpressionEvaluationContext::PotentiallyEvaluated, + Param); ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = SkipImmediateInvocations; - MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true); + runWithSufficientStackSpace(CallLoc, [&] { + MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables=*/true); + }); return false; } struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> { - bool HasImmediateCalls = false; + const ASTContext &Context; + ImmediateCallVisitor(const ASTContext &Ctx) : Context(Ctx) {} + bool HasImmediateCalls = false; bool shouldVisitImplicitCode() const { return true; } bool VisitCallExpr(CallExpr *E) { if (const FunctionDecl *FD = E->getDirectCallee()) - HasImmediateCalls |= FD->isConsteval(); + HasImmediateCalls |= FD->isImmediateFunction(); return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E); } @@ -6000,8 +6161,16 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // Mark that we are replacing a default argument first. // If we are instantiating a template we won't have to // retransform immediate calls. + // C++ [expr.const]p15.1: + // An expression or conversion is in an immediate function context if it + // is potentially evaluated and [...] its innermost enclosing non-block + // scope is a function parameter scope of an immediate function. EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + *this, + FD->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : ExpressionEvaluationContext::PotentiallyEvaluated, + Param); if (Param->hasUninstantiatedDefaultArg()) { if (InstantiateDefaultArgument(CallLoc, FD, Param)) @@ -6011,15 +6180,18 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // An immediate invocation that is not evaluated where it appears is // evaluated and checked for whether it is a constant expression at the // point where the enclosing initializer is used in a function call. - ImmediateCallVisitor V; + ImmediateCallVisitor V(getASTContext()); if (!NestedDefaultChecking) V.TraverseDecl(Param); if (V.HasImmediateCalls) { ExprEvalContexts.back().DelayedDefaultInitializationContext = { CallLoc, Param, CurContext}; EnsureImmediateInvocationInDefaultArgs Immediate(*this); - ExprResult Res = Immediate.TransformInitializer(Param->getInit(), - /*NotCopy=*/false); + ExprResult Res; + runWithSufficientStackSpace(CallLoc, [&] { + Res = Immediate.TransformInitializer(Param->getInit(), + /*NotCopy=*/false); + }); if (Res.isInvalid()) return ExprError(); Res = ConvertParamDefaultArgument(Param, Res.get(), @@ -6046,6 +6218,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { if (Field->isInvalidDecl()) return ExprError(); + CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers()); + auto *ParentRD = cast<CXXRecordDecl>(Field->getParent()); std::optional<ExpressionEvaluationContextRecord::InitializationContext> @@ -6089,7 +6263,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // evaluated and checked for whether it is a constant expression at the // point where the enclosing initializer is used in a [...] a constructor // definition, or an aggregate initialization. - ImmediateCallVisitor V; + ImmediateCallVisitor V(getASTContext()); if (!NestedDefaultChecking) V.TraverseDecl(Field); if (V.HasImmediateCalls) { @@ -6099,10 +6273,11 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { NestedDefaultChecking; EnsureImmediateInvocationInDefaultArgs Immediate(*this); - - ExprResult Res = - Immediate.TransformInitializer(Field->getInClassInitializer(), - /*CXXDirectInit=*/false); + ExprResult Res; + runWithSufficientStackSpace(Loc, [&] { + Res = Immediate.TransformInitializer(Field->getInClassInitializer(), + /*CXXDirectInit=*/false); + }); if (!Res.isInvalid()) Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc); if (Res.isInvalid()) { @@ -6115,7 +6290,9 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { if (Field->getInClassInitializer()) { Expr *E = Init ? Init : Field->getInClassInitializer(); if (!NestedDefaultChecking) - MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false); + runWithSufficientStackSpace(Loc, [&] { + MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false); + }); // C++11 [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. @@ -6296,7 +6473,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) + << FDecl << FDecl->getParametersSourceRange(); return true; } @@ -6341,7 +6519,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) + << FDecl << FDecl->getParametersSourceRange(); // This deletes the extra arguments. Call->shrinkNumArgs(NumParams); @@ -6567,6 +6746,8 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" +#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/WebAssemblyReferenceTypes.def" #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) #define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: #include "clang/AST/BuiltinTypes.def" @@ -6655,10 +6836,10 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, return nullptr; Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); - if (!ParamType->isPointerType() || - ParamType.hasAddressSpace() || + if (!ParamType->isPointerType() || ParamType.hasAddressSpace() || !ArgType->isPointerType() || - !ArgType->getPointeeType().hasAddressSpace()) { + !ArgType->getPointeeType().hasAddressSpace() || + isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { OverloadParams.push_back(ParamType); continue; } @@ -7071,13 +7252,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, llvm::any_of(ArgExprs, [](clang::Expr *E) { return E->containsErrors(); })) && "should only occur in error-recovery path."); - QualType ReturnType = - llvm::isa_and_nonnull<FunctionDecl>(NDecl) - ? cast<FunctionDecl>(NDecl)->getCallResultType() - : Context.DependentTy; - return CallExpr::Create(Context, Fn, ArgExprs, ReturnType, - Expr::getValueKindForType(ReturnType), RParenLoc, - CurFPFeatureOverrides()); + return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, + VK_PRValue, RParenLoc, CurFPFeatureOverrides()); } return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc, ExecConfig, IsExecConfig); @@ -7329,6 +7505,16 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall->setType(FuncT->getCallResultType(Context)); TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType())); + // WebAssembly tables can't be used as arguments. + if (Context.getTargetInfo().getTriple().isWasm()) { + for (const Expr *Arg : Args) { + if (Arg && Arg->getType()->isWebAssemblyTableType()) { + return ExprError(Diag(Arg->getExprLoc(), + diag::err_wasm_table_as_function_parameter)); + } + } + } + if (Proto) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc, IsExecConfig)) @@ -7469,10 +7655,23 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) { - if (!tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, - diag::err_variable_object_no_init)) { + // C2x 6.7.9p4: An entity of variable length array type shall not be + // initialized except by an empty initializer. + // + // The C extension warnings are issued from ParseBraceInitializer() and + // do not need to be issued here. However, we continue to issue an error + // in the case there are initializers or we are compiling C++. We allow + // use of VLAs in C++, but it's not clear we want to allow {} to zero + // init a VLA in C++ in all cases (such as with non-trivial constructors). + // FIXME: should we allow this construct in C++ when it makes sense to do + // so? + std::optional<unsigned> NumInits; + if (const auto *ILE = dyn_cast<InitListExpr>(LiteralExpr)) + NumInits = ILE->getNumInits(); + if ((LangOpts.CPlusPlus || NumInits.value_or(0)) && + !tryToFixVariablyModifiedVarType(TInfo, literalType, LParenLoc, + diag::err_variable_object_no_init)) return ExprError(); - } } } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, @@ -7930,7 +8129,7 @@ bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) { assert(srcTy->isVectorType() || destTy->isVectorType()); auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { - if (!FirstType->isSizelessBuiltinType()) + if (!FirstType->isSVESizelessBuiltinType()) return false; const auto *VecTy = SecondType->getAs<VectorType>(); @@ -7942,6 +8141,28 @@ bool Sema::isValidSveBitcast(QualType srcTy, QualType destTy) { ValidScalableConversion(destTy, srcTy); } +/// Are the two types RVV-bitcast-compatible types? I.e. is bitcasting from the +/// first RVV type (e.g. an RVV scalable type) to the second type (e.g. an RVV +/// VLS type) allowed? +/// +/// This will also return false if the two given types do not make sense from +/// the perspective of RVV bitcasts. +bool Sema::isValidRVVBitcast(QualType srcTy, QualType destTy) { + assert(srcTy->isVectorType() || destTy->isVectorType()); + + auto ValidScalableConversion = [](QualType FirstType, QualType SecondType) { + if (!FirstType->isRVVSizelessBuiltinType()) + return false; + + const auto *VecTy = SecondType->getAs<VectorType>(); + return VecTy && + VecTy->getVectorKind() == VectorType::RVVFixedLengthDataVector; + }; + + return ValidScalableConversion(srcTy, destTy) || + ValidScalableConversion(destTy, srcTy); +} + /// Are the two types matrix types and do they have the same dimensions i.e. /// do they have the same number of rows and the same number of columns? bool Sema::areMatrixTypesOfTheSameDimension(QualType srcTy, QualType destTy) { @@ -7980,30 +8201,24 @@ bool Sema::anyAltivecTypes(QualType SrcTy, QualType DestTy) { "expected at least one type to be a vector here"); bool IsSrcTyAltivec = - SrcTy->isVectorType() && (SrcTy->castAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector); + SrcTy->isVectorType() && ((SrcTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecVector) || + (SrcTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecBool) || + (SrcTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecPixel)); + bool IsDestTyAltivec = DestTy->isVectorType() && - (DestTy->castAs<VectorType>()->getVectorKind() == - VectorType::AltiVecVector); + ((DestTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecVector) || + (DestTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecBool) || + (DestTy->castAs<VectorType>()->getVectorKind() == + VectorType::AltiVecPixel)); return (IsSrcTyAltivec || IsDestTyAltivec); } -// This returns true if both vectors have the same element type. -bool Sema::areSameVectorElemTypes(QualType SrcTy, QualType DestTy) { - assert((DestTy->isVectorType() || SrcTy->isVectorType()) && - "expected at least one type to be a vector here"); - - uint64_t SrcLen, DestLen; - QualType SrcEltTy, DestEltTy; - if (!breakDownVectorType(SrcTy, SrcLen, SrcEltTy)) - return false; - if (!breakDownVectorType(DestTy, DestLen, DestEltTy)) - return false; - - return (SrcEltTy == DestEltTy); -} - /// Are the two types lax-compatible vector types? That is, given /// that one of them is a vector, do they have equal storage sizes, /// where the storage size is the number of elements times the element @@ -8892,8 +9107,14 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); + // WebAssembly tables are not allowed as conditional LHS or RHS. QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); + if (LHSTy->isWebAssemblyTableType() || RHSTy->isWebAssemblyTableType()) { + Diag(QuestionLoc, diag::err_wasm_table_conditional_expression) + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } // Diagnose attempts to convert between __ibm128, __float128 and long double // where such conversions currently can't be handled. @@ -9840,8 +10061,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // The default for lax vector conversions with Altivec vectors will // change, so if we are converting between vector types where // at least one is an Altivec vector, emit a warning. - if (anyAltivecTypes(RHSType, LHSType) && - !areSameVectorElemTypes(RHSType, LHSType)) + if (Context.getTargetInfo().getTriple().isPPC() && + anyAltivecTypes(RHSType, LHSType) && + !Context.areCompatibleVectorTypes(RHSType, LHSType)) Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all) << RHSType << LHSType; Kind = CK_BitCast; @@ -9857,7 +10079,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, const VectorType *VecType = RHSType->getAs<VectorType>(); if (VecType && VecType->getNumElements() == 1 && isLaxVectorConversion(RHSType, LHSType)) { - if (VecType->getVectorKind() == VectorType::AltiVecVector) + if (Context.getTargetInfo().getTriple().isPPC() && + (VecType->getVectorKind() == VectorType::AltiVecVector || + VecType->getVectorKind() == VectorType::AltiVecBool || + VecType->getVectorKind() == VectorType::AltiVecPixel)) Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all) << RHSType << LHSType; ExprResult *VecExpr = &RHS; @@ -9868,14 +10093,24 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Allow assignments between fixed-length and sizeless SVE vectors. - if ((LHSType->isSizelessBuiltinType() && RHSType->isVectorType()) || - (LHSType->isVectorType() && RHSType->isSizelessBuiltinType())) + if ((LHSType->isSVESizelessBuiltinType() && RHSType->isVectorType()) || + (LHSType->isVectorType() && RHSType->isSVESizelessBuiltinType())) if (Context.areCompatibleSveTypes(LHSType, RHSType) || Context.areLaxCompatibleSveTypes(LHSType, RHSType)) { Kind = CK_BitCast; return Compatible; } + // Allow assignments between fixed-length and sizeless RVV vectors. + if ((LHSType->isRVVSizelessBuiltinType() && RHSType->isVectorType()) || + (LHSType->isVectorType() && RHSType->isRVVSizelessBuiltinType())) { + if (Context.areCompatibleRVVTypes(LHSType, RHSType) || + Context.areLaxCompatibleRVVTypes(LHSType, RHSType)) { + Kind = CK_BitCast; + return Compatible; + } + } + return Incompatible; } @@ -10045,6 +10280,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } + // Conversion to nullptr_t (C2x only) + if (getLangOpts().C2x && LHSType->isNullPtrType() && + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) { + // null -> nullptr_t + Kind = CK_NullToPointer; + return Compatible; + } + // Conversions from pointers that are not covered by the above. if (isa<PointerType>(RHSType)) { // T* -> _Bool @@ -10257,12 +10501,18 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, return Incompatible; } + // The constraints are expressed in terms of the atomic, qualified, or + // unqualified type of the LHS. + QualType LHSTypeAfterConversion = LHSType.getAtomicUnqualifiedType(); + // C99 6.5.16.1p1: the left operand is a pointer and the right is - // a null pointer constant. - if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() || - LHSType->isBlockPointerType()) && - RHS.get()->isNullPointerConstant(Context, - Expr::NPC_ValueDependentIsNull)) { + // a null pointer constant <C2x>or its type is nullptr_t;</C2x>. + if ((LHSTypeAfterConversion->isPointerType() || + LHSTypeAfterConversion->isObjCObjectPointerType() || + LHSTypeAfterConversion->isBlockPointerType()) && + ((getLangOpts().C2x && RHS.get()->getType()->isNullPtrType()) || + RHS.get()->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull))) { if (Diagnose || ConvertRHS) { CastKind Kind; CXXCastPath Path; @@ -10273,6 +10523,26 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, } return Compatible; } + // C2x 6.5.16.1p1: the left operand has type atomic, qualified, or + // unqualified bool, and the right operand is a pointer or its type is + // nullptr_t. + if (getLangOpts().C2x && LHSType->isBooleanType() && + RHS.get()->getType()->isNullPtrType()) { + // NB: T* -> _Bool is handled in CheckAssignmentConstraints, this only + // only handles nullptr -> _Bool due to needing an extra conversion + // step. + // We model this by converting from nullptr -> void * and then let the + // conversion from void * -> _Bool happen naturally. + if (Diagnose || ConvertRHS) { + CastKind Kind; + CXXCastPath Path; + CheckPointerConversion(RHS.get(), Context.VoidPtrTy, Kind, Path, + /*IgnoreBaseAccess=*/false, Diagnose); + if (ConvertRHS) + RHS = ImpCastExprToType(RHS.get(), Context.VoidPtrTy, Kind, VK_PRValue, + &Path); + } + } // OpenCL queue_t type assignment. if (LHSType->isQueueT() && RHS.get()->isNullPointerConstant( @@ -10495,7 +10765,7 @@ static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, // bits that the vector element type, reject it. llvm::APSInt Result = EVResult.Val.getInt(); unsigned NumBits = IntSigned - ? (Result.isNegative() ? Result.getMinSignedBits() + ? (Result.isNegative() ? Result.getSignificantBits() : Result.getActiveBits()) : Result.getActiveBits(); if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits) @@ -10645,11 +10915,9 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, return true; // Adjust scalar if desired. - if (Scalar) { - if (ScalarCast != CK_NoOp) - *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); - *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); - } + if (ScalarCast != CK_NoOp) + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); + *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); return false; } @@ -10677,10 +10945,6 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, const VectorType *RHSVecType = RHSType->getAs<VectorType>(); assert(LHSVecType || RHSVecType); - if ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) || - (RHSVecType && RHSVecType->getElementType()->isBFloat16Type())) - return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); - // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && @@ -10732,41 +10996,74 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, } } - // Expressions containing fixed-length and sizeless SVE vectors are invalid - // since the ambiguity can affect the ABI. - auto IsSveConversion = [](QualType FirstType, QualType SecondType) { + // Expressions containing fixed-length and sizeless SVE/RVV vectors are + // invalid since the ambiguity can affect the ABI. + auto IsSveRVVConversion = [](QualType FirstType, QualType SecondType, + unsigned &SVEorRVV) { const VectorType *VecType = SecondType->getAs<VectorType>(); - return FirstType->isSizelessBuiltinType() && VecType && - (VecType->getVectorKind() == VectorType::SveFixedLengthDataVector || - VecType->getVectorKind() == - VectorType::SveFixedLengthPredicateVector); + SVEorRVV = 0; + if (FirstType->isSizelessBuiltinType() && VecType) { + if (VecType->getVectorKind() == VectorType::SveFixedLengthDataVector || + VecType->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + return true; + if (VecType->getVectorKind() == VectorType::RVVFixedLengthDataVector) { + SVEorRVV = 1; + return true; + } + } + + return false; }; - if (IsSveConversion(LHSType, RHSType) || IsSveConversion(RHSType, LHSType)) { - Diag(Loc, diag::err_typecheck_sve_ambiguous) << LHSType << RHSType; + unsigned SVEorRVV; + if (IsSveRVVConversion(LHSType, RHSType, SVEorRVV) || + IsSveRVVConversion(RHSType, LHSType, SVEorRVV)) { + Diag(Loc, diag::err_typecheck_sve_rvv_ambiguous) + << SVEorRVV << LHSType << RHSType; return QualType(); } - // Expressions containing GNU and SVE (fixed or sizeless) vectors are invalid - // since the ambiguity can affect the ABI. - auto IsSveGnuConversion = [](QualType FirstType, QualType SecondType) { + // Expressions containing GNU and SVE or RVV (fixed or sizeless) vectors are + // invalid since the ambiguity can affect the ABI. + auto IsSveRVVGnuConversion = [](QualType FirstType, QualType SecondType, + unsigned &SVEorRVV) { const VectorType *FirstVecType = FirstType->getAs<VectorType>(); const VectorType *SecondVecType = SecondType->getAs<VectorType>(); - if (FirstVecType && SecondVecType) - return FirstVecType->getVectorKind() == VectorType::GenericVector && - (SecondVecType->getVectorKind() == - VectorType::SveFixedLengthDataVector || - SecondVecType->getVectorKind() == - VectorType::SveFixedLengthPredicateVector); + SVEorRVV = 0; + if (FirstVecType && SecondVecType) { + if (FirstVecType->getVectorKind() == VectorType::GenericVector) { + if (SecondVecType->getVectorKind() == + VectorType::SveFixedLengthDataVector || + SecondVecType->getVectorKind() == + VectorType::SveFixedLengthPredicateVector) + return true; + if (SecondVecType->getVectorKind() == + VectorType::RVVFixedLengthDataVector) { + SVEorRVV = 1; + return true; + } + } + return false; + } - return FirstType->isSizelessBuiltinType() && SecondVecType && - SecondVecType->getVectorKind() == VectorType::GenericVector; + if (SecondVecType && + SecondVecType->getVectorKind() == VectorType::GenericVector) { + if (FirstType->isSVESizelessBuiltinType()) + return true; + if (FirstType->isRVVSizelessBuiltinType()) { + SVEorRVV = 1; + return true; + } + } + + return false; }; - if (IsSveGnuConversion(LHSType, RHSType) || - IsSveGnuConversion(RHSType, LHSType)) { - Diag(Loc, diag::err_typecheck_sve_gnu_ambiguous) << LHSType << RHSType; + if (IsSveRVVGnuConversion(LHSType, RHSType, SVEorRVV) || + IsSveRVVGnuConversion(RHSType, LHSType, SVEorRVV)) { + Diag(Loc, diag::err_typecheck_sve_rvv_gnu_ambiguous) + << SVEorRVV << LHSType << RHSType; return QualType(); } @@ -10805,8 +11102,9 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, QualType OtherType = LHSVecType ? RHSType : LHSType; ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS; if (isLaxVectorConversion(OtherType, VecType)) { - if (anyAltivecTypes(RHSType, LHSType) && - !areSameVectorElemTypes(RHSType, LHSType)) + if (Context.getTargetInfo().getTriple().isPPC() && + anyAltivecTypes(RHSType, LHSType) && + !Context.areCompatibleVectorTypes(RHSType, LHSType)) Diag(Loc, diag::warn_deprecated_lax_vec_conv_all) << RHSType << LHSType; // If we're allowing lax vector conversions, only the total (data) size // needs to be the same. For non compound assignment, if one of the types is @@ -11738,7 +12036,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, } llvm::APInt ResultBits = - static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits(); + static_cast<llvm::APInt &>(Right) + Left.getSignificantBits(); if (LeftBits.uge(ResultBits)) return; llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue()); @@ -11761,9 +12059,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) - << HexResult.str() << Result.getMinSignedBits() << LHSType - << Left.getBitWidth() << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); + << HexResult.str() << Result.getSignificantBits() << LHSType + << Left.getBitWidth() << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); } /// Return the resulting type when a vector is shifted @@ -11876,14 +12174,14 @@ static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, return QualType(); QualType LHSType = LHS.get()->getType(); - const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>(); + const BuiltinType *LHSBuiltinTy = LHSType->castAs<BuiltinType>(); QualType LHSEleType = LHSType->isVLSTBuiltinType() ? LHSBuiltinTy->getSveEltType(S.getASTContext()) : LHSType; // Note that RHS might not be a vector QualType RHSType = RHS.get()->getType(); - const BuiltinType *RHSBuiltinTy = RHSType->getAs<BuiltinType>(); + const BuiltinType *RHSBuiltinTy = RHSType->castAs<BuiltinType>(); QualType RHSEleType = RHSType->isVLSTBuiltinType() ? RHSBuiltinTy->getSveEltType(S.getASTContext()) : RHSType; @@ -12288,6 +12586,11 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, S.inTemplateInstantiation()) return; + // WebAssembly Tables cannot be compared, therefore shouldn't emit + // Tautological diagnostics. + if (LHSType->isWebAssemblyTableType() || RHSType->isWebAssemblyTableType()) + return; + // 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()) @@ -12674,6 +12977,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, (RHSType->isArithmeticType() || RHSType->isEnumeralType())) return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); + if ((LHSType->isPointerType() && + LHSType->getPointeeType().isWebAssemblyReferenceType()) || + (RHSType->isPointerType() && + RHSType->getPointeeType().isWebAssemblyReferenceType())) + return InvalidOperands(Loc, LHS, RHS); + const Expr::NullPointerConstantKind LHSNullKind = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); const Expr::NullPointerConstantKind RHSNullKind = @@ -13571,47 +13880,39 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, return InvalidOperands(Loc, LHS, RHS); } -// C99 6.5.[13,14] -inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, +// Diagnose cases where the user write a logical and/or but probably meant a +// bitwise one. We do this when one of the operands is a non-bool integer and +// the other is a constant. +void Sema::diagnoseLogicalInsteadOfBitwise(Expr *Op1, Expr *Op2, SourceLocation Loc, BinaryOperatorKind Opc) { - // Check vector operands differently. - if (LHS.get()->getType()->isVectorType() || - RHS.get()->getType()->isVectorType()) - return CheckVectorLogicalOperands(LHS, RHS, Loc); - - bool EnumConstantInBoolContext = false; - for (const ExprResult &HS : {LHS, RHS}) { - if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) { - const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl()); - if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1) - EnumConstantInBoolContext = true; - } - } - - if (EnumConstantInBoolContext) - Diag(Loc, diag::warn_enum_constant_in_bool_context); - - // Diagnose cases where the user write a logical and/or but probably meant a - // bitwise one. We do this when the LHS is a non-bool integer and the RHS - // is a constant. - if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() && - !LHS.get()->getType()->isBooleanType() && - RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && + if (Op1->getType()->isIntegerType() && !Op1->getType()->isBooleanType() && + Op2->getType()->isIntegerType() && !Op2->isValueDependent() && // Don't warn in macros or template instantiations. - !Loc.isMacroID() && !inTemplateInstantiation()) { + !Loc.isMacroID() && !inTemplateInstantiation() && + !Op2->getExprLoc().isMacroID() && + !Op1->getExprLoc().isMacroID()) { + bool IsOp1InMacro = Op1->getExprLoc().isMacroID(); + bool IsOp2InMacro = Op2->getExprLoc().isMacroID(); + + // Exclude the specific expression from triggering the warning. + if (!(IsOp1InMacro && IsOp2InMacro && Op1->getSourceRange() == Op2->getSourceRange())) { + // If the RHS can be constant folded, and if it constant folds to something + // that isn't 0 or 1 (which indicate a potential logical operation that + // happened to fold to true/false) then warn. + // Parens on the RHS are ignored. // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. // Parens on the RHS are ignored. Expr::EvalResult EVResult; - if (RHS.get()->EvaluateAsInt(EVResult, Context)) { + if (Op2->EvaluateAsInt(EVResult, Context)) { llvm::APSInt Result = EVResult.Val.getInt(); - if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() && - !RHS.get()->getExprLoc().isMacroID()) || + if ((getLangOpts().Bool && !Op2->getType()->isBooleanType() && + !Op2->getExprLoc().isMacroID()) || (Result != 0 && Result != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) - << RHS.get()->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||"); + << Op2->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||"); // Suggest replacing the logical operator with the bitwise version Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator) << (Opc == BO_LAnd ? "&" : "|") @@ -13621,12 +13922,51 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, if (Opc == BO_LAnd) // Suggest replacing "Foo() && kNonZero" with "Foo()" Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant) - << FixItHint::CreateRemoval( - SourceRange(getLocForEndOfToken(LHS.get()->getEndLoc()), - RHS.get()->getEndLoc())); + << FixItHint::CreateRemoval(SourceRange( + getLocForEndOfToken(Op1->getEndLoc()), Op2->getEndLoc())); } } } + } +} + +// C99 6.5.[13,14] +inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc) { + // Check vector operands differently. + if (LHS.get()->getType()->isVectorType() || + RHS.get()->getType()->isVectorType()) + return CheckVectorLogicalOperands(LHS, RHS, Loc); + + bool EnumConstantInBoolContext = false; + for (const ExprResult &HS : {LHS, RHS}) { + if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) { + const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl()); + if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1) + EnumConstantInBoolContext = true; + } + } + + // WebAssembly tables can't be used with logical operators. + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); + const auto *LHSATy = dyn_cast<ArrayType>(LHSTy); + const auto *RHSATy = dyn_cast<ArrayType>(RHSTy); + if ((LHSATy && LHSATy->getElementType().isWebAssemblyReferenceType()) || + (RHSATy && RHSATy->getElementType().isWebAssemblyReferenceType())) { + return InvalidOperands(Loc, LHS, RHS); + } + + if (EnumConstantInBoolContext) { + // Warn when converting the enum constant to a boolean + Diag(Loc, diag::warn_enum_constant_in_bool_context); + } else { + // Diagnose cases where the user write a logical and/or but probably meant a + // bitwise one. + diagnoseLogicalInsteadOfBitwise(LHS.get(), RHS.get(), Loc, Opc); + diagnoseLogicalInsteadOfBitwise(RHS.get(), LHS.get(), Loc, Opc); + } if (!Context.getLangOpts().CPlusPlus) { // OpenCL v1.1 s6.3.g: The logical operators and (&&), or (||) do @@ -14133,6 +14473,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, return QualType(); } + // WebAssembly tables can't be used on RHS of an assignment expression. + if (RHSType->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_art) << 0; + return QualType(); + } + AssignConvertType ConvTy; if (CompoundType.isNull()) { Expr *RHSCheck = RHS.get(); @@ -14740,6 +15086,21 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + // Cannot take the address of WebAssembly references or tables. + if (Context.getTargetInfo().getTriple().isWasm()) { + QualType OpTy = op->getType(); + if (OpTy.isWebAssemblyReferenceType()) { + Diag(OpLoc, diag::err_wasm_ca_reference) + << 1 << OrigOp.get()->getSourceRange(); + return QualType(); + } + if (OpTy->isWebAssemblyTableType()) { + Diag(OpLoc, diag::err_wasm_table_pr) + << 1 << OrigOp.get()->getSourceRange(); + return QualType(); + } + } + CheckAddressOfPackedMember(op); return Context.getPointerType(op->getType()); @@ -14808,7 +15169,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, // be a pointer to an object type, or a pointer to a function type LangOptions LO = S.getLangOpts(); if (LO.CPlusPlus) - S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer_cpp) + S.Diag(OpLoc, diag::err_typecheck_indirection_through_void_pointer_cpp) << OpTy << Op->getSourceRange(); else if (!(LO.C99 && IsAfterAmp) && !S.isUnevaluatedContext()) S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) @@ -15603,13 +15964,22 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, Expr *LHS, Expr *RHS) { switch (Opc) { case BO_Assign: + // In the non-overloaded case, we warn about self-assignment (x = x) for + // both simple assignment and certain compound assignments where algebra + // tells us the operation yields a constant result. When the operator is + // overloaded, we can't do the latter because we don't want to assume that + // those algebraic identities still apply; for example, a path-building + // library might use operator/= to append paths. But it's still reasonable + // to assume that simple assignment is just moving/copying values around + // and so self-assignment is likely a bug. + DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); + [[fallthrough]]; 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: @@ -15913,6 +16283,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = Context.FloatTy; } + // WebAsembly tables can't be used in unary expressions. + if (resultType->isPointerType() && + resultType->getPointeeType().isWebAssemblyReferenceType()) { + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + } + if (resultType->isDependentType()) break; if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) { @@ -16121,6 +16498,8 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, void Sema::ActOnStartStmtExpr() { PushExpressionEvaluationContext(ExprEvalContexts.back().Context); + // Make sure we diagnose jumping into a statement expression. + setFunctionHasBranchProtectedScope(); } void Sema::ActOnStmtExprError() { @@ -16569,6 +16948,9 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, PushOnScopeChains(AI, CurBlock->TheScope); } + + if (AI->isInvalidDecl()) + CurBlock->TheDecl->setInvalidDecl(); } } @@ -16769,6 +17151,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (getCurFunction()) getCurFunction()->addBlock(BD); + if (BD->isInvalidDecl()) + return CreateRecoveryExpr(Result->getBeginLoc(), Result->getEndLoc(), + {Result}, Result->getType()); return Result; } @@ -16795,7 +17180,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, } // NVPTX does not support va_arg expression. - if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice && Context.getTargetInfo().getTriple().isNVPTX()) targetDiag(E->getBeginLoc(), diag::err_va_arg_in_device); @@ -17022,7 +17407,9 @@ ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, QualType ResultTy; switch (Kind) { case SourceLocExpr::File: - case SourceLocExpr::Function: { + case SourceLocExpr::FileName: + case SourceLocExpr::Function: + case SourceLocExpr::FuncSig: { QualType ArrTy = Context.getStringLiteralArrayType(Context.CharTy, 0); ResultTy = Context.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType()); @@ -17685,9 +18072,17 @@ Sema::PushExpressionEvaluationContext( ExprEvalContexts.back().InDiscardedStatement = ExprEvalContexts[ExprEvalContexts.size() - 2] .isDiscardedStatementContext(); + + // C++23 [expr.const]/p15 + // An expression or conversion is in an immediate function context if [...] + // it is a subexpression of a manifestly constant-evaluated expression or + // conversion. + const auto &Prev = ExprEvalContexts[ExprEvalContexts.size() - 2]; ExprEvalContexts.back().InImmediateFunctionContext = - ExprEvalContexts[ExprEvalContexts.size() - 2] - .isImmediateFunctionContext(); + Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated(); + + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + Prev.InImmediateEscalatingFunctionContext; Cleanup.reset(); if (!MaybeODRUseExprs.empty()) @@ -17766,9 +18161,30 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { } } +void Sema::MarkExpressionAsImmediateEscalating(Expr *E) { + assert(!FunctionScopes.empty() && "Expected a function scope"); + assert(getLangOpts().CPlusPlus20 && + ExprEvalContexts.back().InImmediateEscalatingFunctionContext && + "Cannot mark an immediate escalating expression outside of an " + "immediate escalating context"); + if (auto *Call = dyn_cast<CallExpr>(E->IgnoreImplicit()); + Call && Call->getCallee()) { + if (auto *DeclRef = + dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) + DeclRef->setIsImmediateEscalating(true); + } else if (auto *Ctr = dyn_cast<CXXConstructExpr>(E->IgnoreImplicit())) { + Ctr->setIsImmediateEscalating(true); + } else if (auto *DeclRef = dyn_cast<DeclRefExpr>(E->IgnoreImplicit())) { + DeclRef->setIsImmediateEscalating(true); + } else { + assert(false && "expected an immediately escalating expression"); + } + getCurFunction()->FoundImmediateEscalatingExpression = true; +} + ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (isUnevaluatedContext() || !E.isUsable() || !Decl || - !Decl->isConsteval() || isConstantEvaluated() || + !Decl->isImmediateFunction() || isConstantEvaluated() || isCheckingDefaultArgumentOrInitializer() || RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; @@ -17782,13 +18198,59 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); - E = MaybeCreateExprWithCleanups(E); + // C++23 [expr.const]/p16 + // An expression or conversion is immediate-escalating if it is not initially + // in an immediate function context and it is [...] an immediate invocation + // that is not a constant expression and is not a subexpression of an + // immediate invocation. + APValue Cached; + auto CheckConstantExpressionAndKeepResult = [&]() { + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + Expr::EvalResult Eval; + Eval.Diag = &Notes; + bool Res = E.get()->EvaluateAsConstantExpr( + Eval, getASTContext(), ConstantExprKind::ImmediateInvocation); + if (Res && Notes.empty()) { + Cached = std::move(Eval.Val); + return true; + } + return false; + }; + + if (!E.get()->isValueDependent() && + ExprEvalContexts.back().InImmediateEscalatingFunctionContext && + !CheckConstantExpressionAndKeepResult()) { + MarkExpressionAsImmediateEscalating(E.get()); + return E; + } + + if (Cleanup.exprNeedsCleanups()) { + // Since an immediate invocation is a full expression itself - it requires + // an additional ExprWithCleanups node, but it can participate to a bigger + // full expression which actually requires cleanups to be run after so + // create ExprWithCleanups without using MaybeCreateExprWithCleanups as it + // may discard cleanups for outer expression too early. + + // Note that ExprWithCleanups created here must always have empty cleanup + // objects: + // - compound literals do not create cleanup objects in C++ and immediate + // invocations are C++-only. + // - blocks are not allowed inside constant expressions and compiler will + // issue an error if they appear there. + // + // Hence, in correct code any cleanup objects created inside current + // evaluation context must be outside the immediate invocation. + E = ExprWithCleanups::Create(getASTContext(), E.get(), + Cleanup.cleanupsHaveSideEffects(), {}); + } ConstantExpr *Res = ConstantExpr::Create( getASTContext(), E.get(), ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), getASTContext()), /*IsImmediateInvocation*/ true); + if (Cached.hasValue()) + Res->MoveIntoResult(Cached, getASTContext()); /// Value-dependent constant expressions should not be immediately /// evaluated until they are instantiated. if (!Res->isValueDependent()) @@ -17805,6 +18267,7 @@ static void EvaluateAndDiagnoseImmediateInvocation( bool Result = CE->EvaluateAsConstantExpr( Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation); if (!Result || !Notes.empty()) { + SemaRef.FailedImmediateInvocations.insert(CE); Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit(); if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr)) InnerExpr = FunctionalCast->getSubExpr(); @@ -17815,14 +18278,17 @@ static void EvaluateAndDiagnoseImmediateInvocation( FD = Call->getConstructor(); else llvm_unreachable("unhandled decl kind"); - assert(FD && FD->isConsteval()); - SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD; + assert(FD && FD->isImmediateFunction()); + SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) + << FD << FD->isConsteval(); if (auto Context = SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) { SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer) << Context->Decl; SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at); } + if (!FD->isConsteval()) + SemaRef.DiagnoseImmediateEscalatingReason(FD); for (auto &Note : Notes) SemaRef.Diag(Note.first, Note.second); return; @@ -17849,10 +18315,16 @@ static void RemoveNestedImmediateInvocation( [E](Sema::ImmediateInvocationCandidate Elem) { return Elem.getPointer() == E; }); - assert(It != IISet.rend() && - "ConstantExpr marked IsImmediateInvocation should " - "be present"); - It->setInt(1); // Mark as deleted + // It is possible that some subexpression of the current immediate + // invocation was handled from another expression evaluation context. Do + // not handle the current immediate invocation if some of its + // subexpressions failed before. + if (It == IISet.rend()) { + if (SemaRef.FailedImmediateInvocations.contains(E)) + CurrentII->setInt(1); + } else { + It->setInt(1); // Mark as deleted + } } ExprResult TransformConstantExpr(ConstantExpr *E) { if (!E->isImmediateInvocation()) @@ -17925,10 +18397,13 @@ HandleImmediateInvocations(Sema &SemaRef, SemaRef.RebuildingImmediateInvocation) return; - /// When we have more then 1 ImmediateInvocationCandidates we need to check - /// for nested ImmediateInvocationCandidates. when we have only 1 we only - /// need to remove ReferenceToConsteval in the immediate invocation. - if (Rec.ImmediateInvocationCandidates.size() > 1) { + /// When we have more than 1 ImmediateInvocationCandidates or previously + /// failed immediate invocations, we need to check for nested + /// ImmediateInvocationCandidates in order to avoid duplicate diagnostics. + /// Otherwise we only need to remove ReferenceToConsteval in the immediate + /// invocation. + if (Rec.ImmediateInvocationCandidates.size() > 1 || + !SemaRef.FailedImmediateInvocations.empty()) { /// Prevent sema calls during the tree transform from adding pointers that /// are already in the sets. @@ -17959,10 +18434,48 @@ HandleImmediateInvocations(Sema &SemaRef, if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); for (auto *DR : Rec.ReferenceToConsteval) { + // If the expression is immediate escalating, it is not an error; + // The outer context itself becomes immediate and further errors, + // if any, will be handled by DiagnoseImmediateEscalatingReason. + if (DR->isImmediateEscalating()) + continue; auto *FD = cast<FunctionDecl>(DR->getDecl()); - SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) - << FD; - SemaRef.Diag(FD->getLocation(), diag::note_declared_at); + const NamedDecl *ND = FD; + if (const auto *MD = dyn_cast<CXXMethodDecl>(ND); + MD && (MD->isLambdaStaticInvoker() || isLambdaCallOperator(MD))) + ND = MD->getParent(); + + // C++23 [expr.const]/p16 + // An expression or conversion is immediate-escalating if it is not + // initially in an immediate function context and it is [...] a + // potentially-evaluated id-expression that denotes an immediate function + // that is not a subexpression of an immediate invocation. + bool ImmediateEscalating = false; + bool IsPotentiallyEvaluated = + Rec.Context == + Sema::ExpressionEvaluationContext::PotentiallyEvaluated || + Rec.Context == + Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed; + if (SemaRef.inTemplateInstantiation() && IsPotentiallyEvaluated) + ImmediateEscalating = Rec.InImmediateEscalatingFunctionContext; + + if (!Rec.InImmediateEscalatingFunctionContext || + (SemaRef.inTemplateInstantiation() && !ImmediateEscalating)) { + SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) + << ND << isa<CXXRecordDecl>(ND) << FD->isConsteval(); + SemaRef.Diag(ND->getLocation(), diag::note_declared_at); + if (auto Context = + SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) { + SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer) + << Context->Decl; + SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at); + } + if (FD->isImmediateEscalating() && !FD->isConsteval()) + SemaRef.DiagnoseImmediateEscalatingReason(FD); + + } else { + SemaRef.MarkExpressionAsImmediateEscalating(DR); + } } } @@ -18295,9 +18808,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); - if (getLangOpts().SYCLIsDevice) - checkSYCLDeviceFunction(Loc, Func); - // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { runWithSufficientStackSpace(Loc, [&] { @@ -18411,9 +18921,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // or of another default member initializer (ie a PotentiallyEvaluatedIfUsed // context), its initializers may not be referenced yet. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { + EnterExpressionEvaluationContext EvalContext( + *this, + Constructor->isImmediateFunction() + ? ExpressionEvaluationContext::ImmediateFunctionContext + : ExpressionEvaluationContext::PotentiallyEvaluated, + Constructor); for (CXXCtorInitializer *Init : Constructor->inits()) { if (Init->isInClassMemberInitializer()) - MarkDeclarationsReferencedInExpr(Init->getInit()); + runWithSufficientStackSpace(Init->getSourceLocation(), [&]() { + MarkDeclarationsReferencedInExpr(Init->getInit()); + }); } } @@ -18851,6 +19369,12 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, Invalid = true; } + if (BuildAndDiagnose && S.Context.getTargetInfo().getTriple().isWasm() && + CaptureType.getNonReferenceType().isWebAssemblyReferenceType()) { + S.Diag(Loc, diag::err_wasm_ca_reference) << 0; + Invalid = true; + } + // Compute the type of the field that will capture this variable. if (ByRef) { // C++11 [expr.prim.lambda]p15: @@ -19040,6 +19564,15 @@ bool Sema::tryCaptureVariable( // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. DeclContext *VarDC = Var->getDeclContext(); + DeclContext *DC = CurContext; + + // tryCaptureVariable is called every time a DeclRef is formed, + // it can therefore have non-negigible impact on performances. + // For local variables and when there is no capturing scope, + // we can bailout early. + if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC)) + return true; + const auto *VD = dyn_cast<VarDecl>(Var); if (VD) { if (VD->isInitCapture()) @@ -19049,7 +19582,6 @@ bool Sema::tryCaptureVariable( } assert(VD && "Cannot capture a null variable"); - DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // We need to sync up the Declaration Context with the @@ -19062,11 +19594,6 @@ bool Sema::tryCaptureVariable( } } - - // If the variable is declared in the current context, there is no need to - // capture it. - if (VarDC == DC) return true; - // Capture global variables if it is required to use private copy of this // variable. bool IsGlobal = !VD->hasLocalStorage(); @@ -19092,12 +19619,41 @@ bool Sema::tryCaptureVariable( bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { + + LambdaScopeInfo *LSI = nullptr; + if (!FunctionScopes.empty()) + LSI = dyn_cast_or_null<LambdaScopeInfo>( + FunctionScopes[FunctionScopesIndex]); + + bool IsInScopeDeclarationContext = + !LSI || LSI->AfterParameterList || CurContext == LSI->CallOperator; + + if (LSI && !LSI->AfterParameterList) { + // This allows capturing parameters from a default value which does not + // seems correct + if (isa<ParmVarDecl>(Var) && !Var->getDeclContext()->isFunctionOrMethod()) + return true; + } + // If the variable is declared in the current context, there is no need to + // capture it. + if (IsInScopeDeclarationContext && + FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC) + return true; + + // When evaluating some attributes (like enable_if) we might refer to a + // function parameter appertaining to the same declaration as that + // attribute. + if (const auto *Parm = dyn_cast<ParmVarDecl>(Var); + Parm && Parm->getDeclContext() == DC) + return true; + // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. - DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var, - ExprLoc, - BuildAndDiagnose, - *this); + DeclContext *ParentDC = + !IsInScopeDeclarationContext + ? DC->getParent() + : getParentOfCapturingContextOrNull(DC, Var, ExprLoc, + BuildAndDiagnose, *this); // We need to check for the parent *first* because, if we *have* // private-captured a global variable, we need to recursively capture it in // intermediate blocks, lambdas, etc. @@ -19112,7 +19668,6 @@ bool Sema::tryCaptureVariable( FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FSI); - // Check whether we've already captured it. if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, DeclRefType)) { @@ -19228,10 +19783,10 @@ bool Sema::tryCaptureVariable( } return true; } - - FunctionScopesIndex--; - DC = ParentDC; Explicit = false; + FunctionScopesIndex--; + if (IsInScopeDeclarationContext) + DC = ParentDC; } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) @@ -19583,9 +20138,15 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, } } + void *ExOrTy = nullptr; + bool IsExpr = GSE->isExprPredicate(); + if (IsExpr) + ExOrTy = GSE->getControllingExpr(); + else + ExOrTy = GSE->getControllingType(); return AnyChanged ? S.CreateGenericSelectionExpr( GSE->getGenericLoc(), GSE->getDefaultLoc(), - GSE->getRParenLoc(), GSE->getControllingExpr(), + GSE->getRParenLoc(), IsExpr, ExOrTy, GSE->getAssocTypeSourceInfos(), AssocExprs) : ExprEmpty(); } @@ -19833,14 +20394,31 @@ static void DoMarkVarDeclReferenced( DRE->setDecl(DRE->getDecl()); else if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) ME->setMemberDecl(ME->getMemberDecl()); - } else if (FirstInstantiation || - isa<VarTemplateSpecializationDecl>(Var)) { + } else if (FirstInstantiation) { + SemaRef.PendingInstantiations + .push_back(std::make_pair(Var, PointOfInstantiation)); + } else { + bool Inserted = false; + for (auto &I : SemaRef.SavedPendingInstantiations) { + auto Iter = llvm::find_if( + I, [Var](const Sema::PendingImplicitInstantiation &P) { + return P.first == Var; + }); + if (Iter != I.end()) { + SemaRef.PendingInstantiations.push_back(*Iter); + I.erase(Iter); + Inserted = true; + break; + } + } + // FIXME: For a specialization of a variable template, we don't // distinguish between "declaration and type implicitly instantiated" // and "implicit instantiation of definition requested", so we have // no direct way to avoid enqueueing the pending instantiation // multiple times. - SemaRef.PendingInstantiations + if (isa<VarTemplateSpecializationDecl>(Var) && !Inserted) + SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } } @@ -19987,12 +20565,14 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; - if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) + if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) { if (!isUnevaluatedContext() && !isConstantEvaluated() && !isImmediateFunctionContext() && - !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() && - !RebuildingImmediateInvocation && !FD->isDependentContext()) + !isCheckingDefaultArgumentOrInitializer() && + FD->isImmediateFunction() && !RebuildingImmediateInvocation && + !FD->isDependentContext()) ExprEvalContexts.back().ReferenceToConsteval.insert(E); + } MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); } @@ -21096,6 +21676,8 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" +#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/WebAssemblyReferenceTypes.def" #define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id: #define PLACEHOLDER_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index e3eef9323b2f..423d5372a6f6 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -31,6 +31,7 @@ #include "clang/Basic/TypeTraits.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" @@ -42,6 +43,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TypeSize.h" #include <optional> @@ -391,7 +393,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // // also looks for type-name in the scope. Unfortunately, we can't // reasonably apply this fallback for dependent nested-name-specifiers. - if (SS.getScopeRep()->getPrefix()) { + if (SS.isValid() && SS.getScopeRep()->getPrefix()) { if (ParsedType T = LookupInScope()) { Diag(SS.getEndLoc(), diag::ext_qualified_dtor_named_in_lexical_scope) << FixItHint::CreateRemoval(SS.getRange()); @@ -500,13 +502,16 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); - if (isReservedInAllContexts(Status) && - !PP.getSourceManager().isInSystemHeader(Loc)) { - Diag(Loc, diag::warn_reserved_extern_symbol) - << II << static_cast<int>(Status) - << FixItHint::CreateReplacement( - Name.getSourceRange(), - (StringRef("operator\"\"") + II->getName()).str()); + if (!PP.getSourceManager().isInSystemHeader(Loc)) { + if (auto Hint = FixItHint::CreateReplacement( + Name.getSourceRange(), + (StringRef("operator\"\"") + II->getName()).str()); + isReservedInAllContexts(Status)) { + Diag(Loc, diag::warn_reserved_extern_symbol) + << II << static_cast<int>(Status) << Hint; + } else { + Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint; + } } } @@ -975,6 +980,19 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Ty = Ptr->getPointeeType(); isPointer = true; } + + // Cannot throw WebAssembly reference type. + if (Ty.isWebAssemblyReferenceType()) { + Diag(ThrowLoc, diag::err_wasm_reftype_tc) << 0 << E->getSourceRange(); + return true; + } + + // Cannot throw WebAssembly table. + if (isPointer && Ty.isWebAssemblyReferenceType()) { + Diag(ThrowLoc, diag::err_wasm_table_art) << 2 << E->getSourceRange(); + return true; + } + if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, isPointer ? diag::err_throw_incomplete_ptr @@ -1135,8 +1153,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { - ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); - if (CurLSI->CallOperator->isConst()) + if (!CurLSI->Mutable) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } @@ -1175,7 +1192,6 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( while (Closure && IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) { if (IsByCopyCapture) { - ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (IsConstCapture) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); @@ -1362,15 +1378,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). - QualType CaptureType = ThisTy; - if (ByCopy) { - // If we are capturing the object referred to by '*this' by copy, ignore - // any cv qualifiers inherited from the type of the member function for - // the type of the closure-type's corresponding data member and any use - // of 'this'. - CaptureType = ThisTy->getPointeeType(); - CaptureType.removeLocalCVRQualifiers(Qualifiers::CVRMask); - } + QualType CaptureType = ByCopy ? ThisTy->getPointeeType() : ThisTy; bool isNested = NumCapturingClosures > 1; CSI->addThisCapture(isNested, Loc, CaptureType, ByCopy); @@ -1476,20 +1484,21 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, : InitializationKind::CreateValue(TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc); - // C++1z [expr.type.conv]p1: + // C++17 [expr.type.conv]p1: // If the type is a placeholder for a deduced class type, [...perform class // template argument deduction...] - // C++2b: + // C++23: // Otherwise, if the type contains a placeholder type, it is replaced by the // type determined by placeholder type deduction. DeducedType *Deduced = Ty->getContainedDeducedType(); - if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { + if (Deduced && !Deduced->isDeduced() && + isa<DeducedTemplateSpecializationType>(Deduced)) { Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, Kind, Exprs); if (Ty.isNull()) return ExprError(); Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); - } else if (Deduced) { + } else if (Deduced && !Deduced->isDeduced()) { MultiExprArg Inits = Exprs; if (ListInitialization) { auto *ILE = cast<InitListExpr>(Exprs[0]); @@ -1505,7 +1514,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, diag::err_auto_expr_init_multiple_expressions) << Ty << FullRange); } - if (getLangOpts().CPlusPlus2b) { + if (getLangOpts().CPlusPlus23) { if (Ty->getAs<AutoType>()) Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange; } @@ -1531,16 +1540,10 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } - if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { - // 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, Ty.getNonReferenceType(), - TInfo, Locs.getBegin(), Exprs, - Locs.getEnd()); - } + if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) + return CXXUnresolvedConstructExpr::Create( + Context, Ty.getNonReferenceType(), TInfo, LParenOrBraceLoc, Exprs, + RParenOrBraceLoc, ListInitialization); // C++ [expr.type.conv]p1: // If the expression list is a parenthesized single expression, the type @@ -1589,6 +1592,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, Expr *Inner = Result.get(); if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner)) Inner = BTE->getSubExpr(); + if (auto *CE = dyn_cast<ConstantExpr>(Inner); + CE && CE->isImmediateInvocation()) + Inner = CE->getSubExpr(); if (!isa<CXXTemporaryObjectExpr>(Inner) && !isa<CXXScalarValueInitExpr>(Inner)) { // If we created a CXXTemporaryObjectExpr, that node also represents the @@ -2016,7 +2022,8 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. auto *Deduced = AllocType->getContainedDeducedType(); - if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { + if (Deduced && !Deduced->isDeduced() && + isa<DeducedTemplateSpecializationType>(Deduced)) { if (ArraySize) return ExprError( Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), @@ -2030,7 +2037,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, AllocTypeInfo, Entity, Kind, Exprs); if (AllocType.isNull()) return ExprError(); - } else if (Deduced) { + } else if (Deduced && !Deduced->isDeduced()) { MultiExprArg Inits = Exprs; bool Braced = (initStyle == CXXNewExpr::ListInit); if (Braced) { @@ -2650,11 +2657,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? // FIXME: Using a dummy value will interact poorly with attribute enable_if. - IntegerLiteral Size( - Context, - llvm::APInt::getZero( - Context.getTargetInfo().getPointerWidth(LangAS::Default)), - Context.getSizeType(), SourceLocation()); + QualType SizeTy = Context.getSizeType(); + unsigned SizeTyWidth = Context.getTypeSize(SizeTy); + IntegerLiteral Size(Context, llvm::APInt::getZero(SizeTyWidth), SizeTy, + SourceLocation()); AllocArgs.push_back(&Size); QualType AlignValT = Context.VoidTy; @@ -2977,7 +2983,7 @@ void Sema::DeclareGlobalNewDelete() { // functions are replaceable ([new.delete]); these are attached to the // global module ([module.unit]). if (getLangOpts().CPlusPlusModules && getCurrentModule()) - PushGlobalModuleFragment(SourceLocation(), /*IsImplicit=*/true); + PushGlobalModuleFragment(SourceLocation()); // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are @@ -3021,10 +3027,10 @@ void Sema::DeclareGlobalNewDelete() { // The implicitly declared "std::bad_alloc" should live in global module // fragment. - if (GlobalModuleFragment) { + if (TheGlobalModuleFragment) { getStdBadAlloc()->setModuleOwnershipKind( Decl::ModuleOwnershipKind::ReachableWhenImported); - getStdBadAlloc()->setLocalOwningModule(GlobalModuleFragment); + getStdBadAlloc()->setLocalOwningModule(TheGlobalModuleFragment); } } if (!StdAlignValT && getLangOpts().AlignedAllocation) { @@ -3036,10 +3042,10 @@ void Sema::DeclareGlobalNewDelete() { // The implicitly declared "std::align_val_t" should live in global module // fragment. - if (GlobalModuleFragment) { + if (TheGlobalModuleFragment) { AlignValT->setModuleOwnershipKind( Decl::ModuleOwnershipKind::ReachableWhenImported); - AlignValT->setLocalOwningModule(GlobalModuleFragment); + AlignValT->setLocalOwningModule(TheGlobalModuleFragment); } AlignValT->setIntegerType(Context.getSizeType()); @@ -3154,7 +3160,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); - if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible) + if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible && + !getLangOpts().CheckNew) Alloc->addAttr( ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); @@ -3168,10 +3175,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // module all the time. But in the implementation, the global module // is only meaningful when we're in a module unit. So here we attach // these allocation functions to global module conditionally. - if (GlobalModuleFragment) { + if (TheGlobalModuleFragment) { Alloc->setModuleOwnershipKind( Decl::ModuleOwnershipKind::ReachableWhenImported); - Alloc->setLocalOwningModule(GlobalModuleFragment); + Alloc->setLocalOwningModule(TheGlobalModuleFragment); } Alloc->addAttr(VisibilityAttr::CreateImplicit( @@ -4032,7 +4039,7 @@ ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) { // The value of a condition that is an expression is the value of the // expression, implicitly converted to bool. // - // C++2b 8.5.2p2 + // C++23 8.5.2p2 // If the if statement is of the form if constexpr, the value of the condition // is contextually converted to bool and the converted expression shall be // a constant expression. @@ -4083,6 +4090,9 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { case StringLiteral::Wide: return Context.typesAreCompatible(Context.getWideCharType(), QualType(ToPointeeType, 0)); + case StringLiteral::Unevaluated: + assert(false && "Unevaluated string literal in expression"); + break; } } } @@ -4576,6 +4586,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, break; case ICK_SVE_Vector_Conversion: + case ICK_RVV_Vector_Conversion: From = ImpCastExprToType(From, ToType, CK_BitCast, VK_PRValue, /*BasePath=*/nullptr, CCK) .get(); @@ -4881,8 +4892,11 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: - // By analogy, is_trivially_relocatable imposes the same constraints. + // By analogy, is_trivially_relocatable and is_trivially_equality_comparable + // impose the same constraints. case UTT_IsTriviallyRelocatable: + case UTT_IsTriviallyEqualityComparable: + case UTT_CanPassInRegs: // Per the GCC type traits documentation, T shall be a complete type, cv void, // or an array of unknown bound. But GCC actually imposes the same constraints // as above. @@ -5371,15 +5385,27 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return T.isTriviallyRelocatableType(C); case UTT_IsReferenceable: return T.isReferenceable(); + case UTT_CanPassInRegs: + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl(); RD && !T.hasQualifiers()) + return RD->canPassInRegisters(); + Self.Diag(KeyLoc, diag::err_builtin_pass_in_regs_non_class) << T; + return false; + case UTT_IsTriviallyEqualityComparable: + return T.isTriviallyEqualityComparableType(C); } } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc); -static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, - ArrayRef<TypeSourceInfo *> Args, - SourceLocation RParenLoc) { +static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, + SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool IsDependent) { + if (IsDependent) + return false; + if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); @@ -5547,12 +5573,19 @@ bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) { return true; } +enum class TypeTraitReturnType { + Bool, +}; + +static TypeTraitReturnType GetReturnType(TypeTrait Kind) { + return TypeTraitReturnType::Bool; +} + ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc) { if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size())) return ExprError(); - QualType ResultType = Context.getLogicalOperationType(); if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( *this, Kind, KWLoc, Args[0]->getType())) @@ -5568,12 +5601,15 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, } } - bool Result = false; - if (!Dependent) - Result = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc); - - return TypeTraitExpr::Create(Context, ResultType, KWLoc, Kind, Args, - RParenLoc, Result); + switch (GetReturnType(Kind)) { + case TypeTraitReturnType::Bool: { + bool Result = EvaluateBooleanTypeTrait(*this, Kind, KWLoc, Args, RParenLoc, + Dependent); + return TypeTraitExpr::Create(Context, Context.getLogicalOperationType(), + KWLoc, Kind, Args, RParenLoc, Result); + } + } + llvm_unreachable("unhandled type trait return type"); } ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, @@ -6561,6 +6597,13 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (IsSizelessVectorConditional) return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); + // WebAssembly tables are not allowed as conditional LHS or RHS. + if (LTy->isWebAssemblyTableType() || RTy->isWebAssemblyTableType()) { + Diag(QuestionLoc, diag::err_wasm_table_conditional_expression) + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } + // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and // either has (cv) class type [...] an attempt is made to convert each of @@ -8231,12 +8274,12 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, const VarDecl *DefVD = nullptr; // If there is no initializer - this can not be a constant expression. - if (!Var->getAnyInitializer(DefVD)) return true; + const Expr *Init = Var->getAnyInitializer(DefVD); + if (!Init) + return true; assert(DefVD); - if (DefVD->isWeak()) return false; - EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt(); - - Expr *Init = cast<Expr>(Eval->Value); + if (DefVD->isWeak()) + return false; if (Var->getType()->isDependentType() || Init->isValueDependent()) { // FIXME: Teach the constant evaluator to deal with the non-dependent parts diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index a3420ac6fdd2..3d14ca3859bb 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -161,10 +161,13 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, } CXXRecordDecl *contextClass; - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) + if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) contextClass = MD->getParent()->getCanonicalDecl(); + else if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) + contextClass = RD; else - contextClass = cast<CXXRecordDecl>(DC); + return AbstractInstanceResult ? AbstractInstanceResult + : IMA_Error_StaticContext; // [class.mfct.non-static]p3: // ...is used in the body of a non-static member function of class X, @@ -764,7 +767,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, QualType RecordTy = BaseType; if (IsArrow) RecordTy = RecordTy->castAs<PointerType>()->getPointeeType(); if (LookupMemberExprInRecord( - *this, R, nullptr, RecordTy->getAs<RecordType>(), OpLoc, IsArrow, + *this, R, nullptr, RecordTy->castAs<RecordType>(), OpLoc, IsArrow, SS, TemplateArgs != nullptr, TemplateKWLoc, TE)) return ExprError(); if (TE) diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index a4372349fff7..5df830e5bee6 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2438,6 +2438,9 @@ ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, if (!ReceiverType.isNull()) receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType); + assert(((isSuperReceiver && Loc.isValid()) || receiverTypeInfo) && + "Either the super receiver location needs to be valid or the receiver " + "needs valid type source information"); return BuildClassMessage(receiverTypeInfo, ReceiverType, /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(), Sel, Method, Loc, Loc, Loc, Args, @@ -4551,6 +4554,7 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { CurFPFeatureOverrides()); } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { assert(!gse->isResultDependent()); + assert(!gse->isTypePredicate()); unsigned n = gse->getNumAssocs(); SmallVector<Expr *, 4> subExprs; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index ddb2b5cf5cd1..32c9215184eb 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -20,12 +20,16 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -139,6 +143,9 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, if (IsWideCharCompatible(ElemTy, Context)) return SIF_IncompatWideStringIntoWideChar; return SIF_Other; + case StringLiteral::Unevaluated: + assert(false && "Unevaluated string literal in initialization"); + break; } llvm_unreachable("missed a StringLiteral kind?"); @@ -173,6 +180,8 @@ static void updateStringLiteralType(Expr *E, QualType Ty) { E = GSE->getResultExpr(); } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(E)) { E = CE->getChosenSubExpr(); + } else if (PredefinedExpr *PE = dyn_cast<PredefinedExpr>(E)) { + E = PE->getFunctionName(); } else { llvm_unreachable("unexpected expr in string literal init"); } @@ -301,6 +310,7 @@ class InitListChecker { bool InOverloadResolution; InitListExpr *FullyStructuredList = nullptr; NoInitExpr *DummyExpr = nullptr; + SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr; NoInitExpr *getDummyInit() { if (!DummyExpr) @@ -350,7 +360,7 @@ class InitListChecker { unsigned &StructuredIndex); void CheckStructUnionTypes(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, - CXXRecordDecl::base_class_range Bases, + CXXRecordDecl::base_class_const_range Bases, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, @@ -387,18 +397,22 @@ class InitListChecker { unsigned ExpectedNumInits); int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); + static RecordDecl *getRecordDecl(QualType DeclType); ExprResult PerformEmptyInit(SourceLocation Loc, const InitializedEntity &Entity); /// Diagnose that OldInit (or part thereof) has been overridden by NewInit. void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange, + bool UnionOverride = false, bool FullyOverwritten = true) { // Overriding an initializer via a designator is valid with C99 designated // initializers, but ill-formed with C++20 designated initializers. - unsigned DiagID = SemaRef.getLangOpts().CPlusPlus - ? diag::ext_initializer_overrides - : diag::warn_initializer_overrides; + unsigned DiagID = + SemaRef.getLangOpts().CPlusPlus + ? (UnionOverride ? diag::ext_initializer_union_overrides + : diag::ext_initializer_overrides) + : diag::warn_initializer_overrides; if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) { // In overload resolution, we have to strictly enforce the rules, and so @@ -486,9 +500,19 @@ class InitListChecker { SourceLocation Loc); public: + InitListChecker( + Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, + bool VerifyOnly, bool TreatUnavailableAsInvalid, + bool InOverloadResolution = false, + SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr); InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, - QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid, - bool InOverloadResolution = false); + QualType &T, + SmallVectorImpl<QualType> &AggrDeductionCandidateParamTypes) + : InitListChecker(S, Entity, IL, T, /*VerifyOnly=*/true, + /*TreatUnavailableAsInvalid=*/false, + /*InOverloadResolution=*/false, + &AggrDeductionCandidateParamTypes){}; + bool HadError() { return hadError; } // Retrieves the fully-structured initializer list used for @@ -805,7 +829,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, // order to leave them uninitialized, the ILE is expanded and the extra // fields are then filled with NoInitExpr. unsigned NumElems = numStructUnionElements(ILE->getType()); - if (RDecl->hasFlexibleArrayMember()) + if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember()) ++NumElems; if (!VerifyOnly && ILE->getNumInits() < NumElems) ILE->resizeInits(SemaRef.Context, NumElems); @@ -948,18 +972,19 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, static bool hasAnyDesignatedInits(const InitListExpr *IL) { for (const Stmt *Init : *IL) - if (Init && isa<DesignatedInitExpr>(Init)) + if (isa_and_nonnull<DesignatedInitExpr>(Init)) return true; return false; } -InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T, bool VerifyOnly, - bool TreatUnavailableAsInvalid, - bool InOverloadResolution) +InitListChecker::InitListChecker( + Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, + bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution, + SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes) : SemaRef(S), VerifyOnly(VerifyOnly), TreatUnavailableAsInvalid(TreatUnavailableAsInvalid), - InOverloadResolution(InOverloadResolution) { + InOverloadResolution(InOverloadResolution), + AggrDeductionCandidateParamTypes(AggrDeductionCandidateParamTypes) { if (!VerifyOnly || hasAnyDesignatedInits(IL)) { FullyStructuredList = createInitListExpr(T, IL->getSourceRange(), IL->getNumInits()); @@ -973,7 +998,7 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, CheckExplicitInitList(Entity, IL, T, FullyStructuredList, /*TopLevelObject=*/true); - if (!hadError && FullyStructuredList) { + if (!hadError && !AggrDeductionCandidateParamTypes && FullyStructuredList) { bool RequiresSecondPass = false; FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass, /*OuterILE=*/nullptr, /*OuterIndex=*/0); @@ -1009,6 +1034,14 @@ int InitListChecker::numStructUnionElements(QualType DeclType) { return InitializableMembers - structDecl->hasFlexibleArrayMember(); } +RecordDecl *InitListChecker::getRecordDecl(QualType DeclType) { + if (const auto *RT = DeclType->getAs<RecordType>()) + return RT->getDecl(); + if (const auto *Inject = DeclType->getAs<InjectedClassNameType>()) + return Inject->getDecl(); + return nullptr; +} + /// Determine whether Entity is an entity for which it is idiomatic to elide /// the braces in aggregate initialization. static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { @@ -1152,6 +1185,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_TemplateParameter: case InitializedEntity::EK_Result: + case InitializedEntity::EK_ParenAggInitMember: // Extra braces here are suspicious. DiagID = diag::warn_braces_around_init; break; @@ -1302,15 +1336,18 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isVectorType()) { CheckVectorType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); - } else if (DeclType->isRecordType()) { - assert(DeclType->isAggregateType() && - "non-aggregate records should be handed in CheckSubElementType"); - RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); + } else if (const RecordDecl *RD = getRecordDecl(DeclType)) { auto Bases = - CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), - CXXRecordDecl::base_class_iterator()); - if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) - Bases = CXXRD->bases(); + CXXRecordDecl::base_class_const_range(CXXRecordDecl::base_class_const_iterator(), + CXXRecordDecl::base_class_const_iterator()); + if (DeclType->isRecordType()) { + assert(DeclType->isAggregateType() && + "non-aggregate records should be handed in CheckSubElementType"); + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + Bases = CXXRD->bases(); + } else { + Bases = cast<CXXRecordDecl>(RD)->bases(); + } CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(), SubobjectIsDesignatorContext, Index, StructuredList, StructuredIndex, TopLevelObject); @@ -1340,6 +1377,13 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, // Checks for scalar type are sufficient for these types too. CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); + } else if (DeclType->isDependentType()) { + // C++ [over.match.class.deduct]p1.5: + // brace elision is not considered for any aggregate element that has a + // dependent non-array type or an array type with a value-dependent bound + ++Index; + assert(AggrDeductionCandidateParamTypes); + AggrDeductionCandidateParamTypes->push_back(DeclType); } else { if (!VerifyOnly) SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type) @@ -1397,31 +1441,46 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, ? InitializedEntity::InitializeTemporary(ElemType) : Entity; - InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr, - /*TopLevelOfInitList*/ true); + if (TmpEntity.getType()->isDependentType()) { + // C++ [over.match.class.deduct]p1.5: + // brace elision is not considered for any aggregate element that has a + // dependent non-array type or an array type with a value-dependent + // bound + assert(AggrDeductionCandidateParamTypes); + if (!isa_and_nonnull<ConstantArrayType>( + SemaRef.Context.getAsArrayType(ElemType))) { + ++Index; + AggrDeductionCandidateParamTypes->push_back(ElemType); + return; + } + } else { + InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr, + /*TopLevelOfInitList*/ true); + // C++14 [dcl.init.aggr]p13: + // If the assignment-expression can initialize a member, the member is + // initialized. Otherwise [...] brace elision is assumed + // + // Brace elision is never performed if the element is not an + // assignment-expression. + if (Seq || isa<InitListExpr>(expr)) { + if (!VerifyOnly) { + ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr); + if (Result.isInvalid()) + hadError = true; - // C++14 [dcl.init.aggr]p13: - // If the assignment-expression can initialize a member, the member is - // initialized. Otherwise [...] brace elision is assumed - // - // Brace elision is never performed if the element is not an - // assignment-expression. - if (Seq || isa<InitListExpr>(expr)) { - if (!VerifyOnly) { - ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr); - if (Result.isInvalid()) + UpdateStructuredListElement(StructuredList, StructuredIndex, + Result.getAs<Expr>()); + } else if (!Seq) { hadError = true; - - UpdateStructuredListElement(StructuredList, StructuredIndex, - Result.getAs<Expr>()); - } else if (!Seq) { - hadError = true; - } else if (StructuredList) { - UpdateStructuredListElement(StructuredList, StructuredIndex, - getDummyInit()); + } else if (StructuredList) { + UpdateStructuredListElement(StructuredList, StructuredIndex, + getDummyInit()); + } + ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(ElemType); + return; } - ++Index; - return; } // Fall through for subaggregate initialization @@ -1536,7 +1595,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity, // the element type of the complex type. The first element initializes // the real part, and the second element intitializes the imaginary part. - if (IList->getNumInits() != 2) + if (IList->getNumInits() < 2) return CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); @@ -1565,20 +1624,23 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { if (!VerifyOnly) { - if (DeclType->isSizelessBuiltinType()) - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_sizeless_initializer - : diag::err_empty_sizeless_initializer) - << DeclType << IList->getSourceRange(); - else - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_scalar_initializer - : diag::err_empty_scalar_initializer) - << IList->getSourceRange(); + if (SemaRef.getLangOpts().CPlusPlus) { + if (DeclType->isSizelessBuiltinType()) + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_sizeless_initializer + : diag::err_empty_sizeless_initializer) + << DeclType << IList->getSourceRange(); + else + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_scalar_initializer + : diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + } } - hadError = !SemaRef.getLangOpts().CPlusPlus11; + hadError = + SemaRef.getLangOpts().CPlusPlus && !SemaRef.getLangOpts().CPlusPlus11; ++Index; ++StructuredIndex; return; @@ -1634,6 +1696,8 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, } UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(DeclType); } void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, @@ -1689,6 +1753,8 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, UpdateStructuredListElement(StructuredList, StructuredIndex, expr); ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(DeclType); } void InitListChecker::CheckVectorType(const InitializedEntity &Entity, @@ -1740,6 +1806,8 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, } UpdateStructuredListElement(StructuredList, StructuredIndex, ResultExpr); ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(elementType); return; } @@ -1901,6 +1969,8 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, StructuredList->resizeInits(SemaRef.Context, StructuredIndex); } ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(DeclType); return; } } @@ -1908,11 +1978,24 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for VLAs; in standard C it would be possible to check this // earlier, but I don't know where clang accepts VLAs (gcc accepts // them in all sorts of strange places). - if (!VerifyOnly) - SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(), - diag::err_variable_object_no_init) - << VAT->getSizeExpr()->getSourceRange(); - hadError = true; + bool HasErr = IList->getNumInits() != 0 || SemaRef.getLangOpts().CPlusPlus; + if (!VerifyOnly) { + // C2x 6.7.9p4: An entity of variable length array type shall not be + // initialized except by an empty initializer. + // + // The C extension warnings are issued from ParseBraceInitializer() and + // do not need to be issued here. However, we continue to issue an error + // in the case there are initializers or we are compiling C++. We allow + // use of VLAs in C++, but it's not clear we want to allow {} to zero + // init a VLA in C++ in all cases (such as with non-trivial constructors). + // FIXME: should we allow this construct in C++ when it makes sense to do + // so? + if (HasErr) + SemaRef.Diag(VAT->getSizeExpr()->getBeginLoc(), + diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); + } + hadError = HasErr; ++Index; ++StructuredIndex; return; @@ -2043,24 +2126,22 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity, void InitListChecker::CheckStructUnionTypes( const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, - CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field, + CXXRecordDecl::base_class_const_range Bases, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex, bool TopLevelObject) { - RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl(); + const RecordDecl *RD = getRecordDecl(DeclType); // If the record is invalid, some of it's members are invalid. To avoid // confusion, we forgo checking the initializer for the entire record. - if (structDecl->isInvalidDecl()) { + if (RD->isInvalidDecl()) { // Assume it was supposed to consume a single initializer. ++Index; hadError = true; return; } - if (DeclType->isUnionType() && IList->getNumInits() == 0) { - RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); - + if (RD->isUnion() && IList->getNumInits() == 0) { if (!VerifyOnly) for (FieldDecl *FD : RD->fields()) { QualType ET = SemaRef.Context.getBaseElementType(FD->getType()); @@ -2104,7 +2185,8 @@ void InitListChecker::CheckStructUnionTypes( bool InitializedSomething = false; // If we have any base classes, they are initialized prior to the fields. - for (auto &Base : Bases) { + for (auto I = Bases.begin(), E = Bases.end(); I != E; ++I) { + auto &Base = *I; Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr; // Designated inits always initialize fields, so if we see one, all @@ -2112,6 +2194,34 @@ void InitListChecker::CheckStructUnionTypes( if (Init && isa<DesignatedInitExpr>(Init)) Init = nullptr; + // C++ [over.match.class.deduct]p1.6: + // each non-trailing aggregate element that is a pack expansion is assumed + // to correspond to no elements of the initializer list, and (1.7) a + // trailing aggregate element that is a pack expansion is assumed to + // correspond to all remaining elements of the initializer list (if any). + + // C++ [over.match.class.deduct]p1.9: + // ... except that additional parameter packs of the form P_j... are + // inserted into the parameter list in their original aggregate element + // position corresponding to each non-trailing aggregate element of + // type P_j that was skipped because it was a parameter pack, and the + // trailing sequence of parameters corresponding to a trailing + // aggregate element that is a pack expansion (if any) is replaced + // by a single parameter of the form T_n.... + if (AggrDeductionCandidateParamTypes && Base.isPackExpansion()) { + AggrDeductionCandidateParamTypes->push_back( + SemaRef.Context.getPackExpansionType(Base.getType(), std::nullopt)); + + // Trailing pack expansion + if (I + 1 == E && RD->field_empty()) { + if (Index < IList->getNumInits()) + Index = IList->getNumInits(); + return; + } + + continue; + } + SourceLocation InitLoc = Init ? Init->getBeginLoc() : IList->getEndLoc(); InitializedEntity BaseEntity = InitializedEntity::InitializeBase( SemaRef.Context, &Base, false, &Entity); @@ -2134,7 +2244,6 @@ void InitListChecker::CheckStructUnionTypes( // anything except look at designated initializers; That's okay, // because an error should get printed out elsewhere. It might be // worthwhile to skip over the rest of the initializer, though. - RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa<FieldDecl>(D) || isa<RecordDecl>(D); @@ -2218,7 +2327,7 @@ void InitListChecker::CheckStructUnionTypes( } // We've already initialized a member of a union. We're done. - if (InitializedSomething && DeclType->isUnionType()) + if (InitializedSomething && RD->isUnion()) break; // If we've hit the flexible array member at the end, we're done. @@ -2259,7 +2368,7 @@ void InitListChecker::CheckStructUnionTypes( StructuredList, StructuredIndex); InitializedSomething = true; - if (DeclType->isUnionType() && StructuredList) { + if (RD->isUnion() && StructuredList) { // Initialize the first field within the union. StructuredList->setInitializedFieldInUnion(*Field); } @@ -2270,7 +2379,7 @@ void InitListChecker::CheckStructUnionTypes( // Emit warnings for missing struct field initializers. if (!VerifyOnly && InitializedSomething && CheckForMissingFields && Field != FieldEnd && !Field->getType()->isIncompleteArrayType() && - !DeclType->isUnionType()) { + !RD->isUnion()) { // It is possible we have one or more unnamed bitfields remaining. // Find first (if any) named field and emit warning. for (RecordDecl::field_iterator it = Field, end = RD->field_end(); @@ -2285,7 +2394,7 @@ void InitListChecker::CheckStructUnionTypes( // Check that any remaining fields can be value-initialized if we're not // building a structured list. (If we are, we'll check this later.) - if (!StructuredList && Field != FieldEnd && !DeclType->isUnionType() && + if (!StructuredList && Field != FieldEnd && !RD->isUnion() && !Field->getType()->isIncompleteArrayType()) { for (; Field != FieldEnd && !hadError; ++Field) { if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) @@ -2324,7 +2433,8 @@ void InitListChecker::CheckStructUnionTypes( InitializedEntity MemberEntity = InitializedEntity::InitializeMember(*Field, &Entity); - if (isa<InitListExpr>(IList->getInit(Index))) + if (isa<InitListExpr>(IList->getInit(Index)) || + AggrDeductionCandidateParamTypes) CheckSubElementType(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); else @@ -2347,14 +2457,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(), PE = IndirectField->chain_end(); PI != PE; ++PI) { if (PI + 1 == PE) - Replacements.push_back(Designator((IdentifierInfo *)nullptr, - DIE->getDesignator(DesigIdx)->getDotLoc(), - DIE->getDesignator(DesigIdx)->getFieldLoc())); + Replacements.push_back(Designator::CreateFieldDesignator( + (IdentifierInfo *)nullptr, DIE->getDesignator(DesigIdx)->getDotLoc(), + DIE->getDesignator(DesigIdx)->getFieldLoc())); else - Replacements.push_back(Designator((IdentifierInfo *)nullptr, - SourceLocation(), SourceLocation())); + Replacements.push_back(Designator::CreateFieldDesignator( + (IdentifierInfo *)nullptr, SourceLocation(), SourceLocation())); assert(isa<FieldDecl>(*PI)); - Replacements.back().setField(cast<FieldDecl>(*PI)); + Replacements.back().setFieldDecl(cast<FieldDecl>(*PI)); } // Expand the current designator into the set of replacement @@ -2382,7 +2492,7 @@ namespace { // the given struct or union. class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback { public: - explicit FieldInitializerValidatorCCC(RecordDecl *RD) + explicit FieldInitializerValidatorCCC(const RecordDecl *RD) : Record(RD) {} bool ValidateCandidate(const TypoCorrection &candidate) override { @@ -2395,7 +2505,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback { } private: - RecordDecl *Record; + const RecordDecl *Record; }; } // end anonymous namespace @@ -2471,6 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, Result.get()); } ++Index; + if (AggrDeductionCandidateParamTypes) + AggrDeductionCandidateParamTypes->push_back(CurrentObjectType); return !Seq; } @@ -2528,6 +2640,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // subobject [0].b. diagnoseInitOverride(ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()), + /*UnionOverride=*/false, /*FullyOverwritten=*/false); if (!VerifyOnly) { @@ -2563,8 +2676,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // then the current object (defined below) shall have // structure or union type and the identifier shall be the // name of a member of that type. - const RecordType *RT = CurrentObjectType->getAs<RecordType>(); - if (!RT) { + RecordDecl *RD = getRecordDecl(CurrentObjectType); + if (!RD) { SourceLocation Loc = D->getDotLoc(); if (Loc.isInvalid()) Loc = D->getFieldLoc(); @@ -2575,10 +2688,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return true; } - FieldDecl *KnownField = D->getField(); + FieldDecl *KnownField = D->getFieldDecl(); if (!KnownField) { - IdentifierInfo *FieldName = D->getFieldName(); - DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName); + const IdentifierInfo *FieldName = D->getFieldName(); + DeclContext::lookup_result Lookup = RD->lookup(FieldName); for (NamedDecl *ND : Lookup) { if (auto *FD = dyn_cast<FieldDecl>(ND)) { KnownField = FD; @@ -2612,11 +2725,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Name lookup didn't find anything. // Determine whether this was a typo for another field name. - FieldInitializerValidatorCCC CCC(RT->getDecl()); + FieldInitializerValidatorCCC CCC(RD); if (TypoCorrection Corrected = SemaRef.CorrectTypo( DeclarationNameInfo(FieldName, D->getFieldLoc()), Sema::LookupMemberName, /*Scope=*/nullptr, /*SS=*/nullptr, CCC, - Sema::CTK_ErrorRecovery, RT->getDecl())) { + Sema::CTK_ErrorRecovery, RD)) { SemaRef.diagnoseTypo( Corrected, SemaRef.PDiag(diag::err_field_designator_unknown_suggest) @@ -2625,8 +2738,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, hadError = true; } else { // Typo correction didn't find anything. - SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) - << FieldName << CurrentObjectType; + SourceLocation Loc = D->getFieldLoc(); + + // The loc can be invalid with a "null" designator (i.e. an anonymous + // union/struct). Do our best to approximate the location. + if (Loc.isInvalid()) + Loc = IList->getBeginLoc(); + + SemaRef.Diag(Loc, diag::err_field_designator_unknown) + << FieldName << CurrentObjectType << DIE->getSourceRange(); ++Index; return true; } @@ -2634,12 +2754,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } unsigned NumBases = 0; - if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl())) + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) NumBases = CXXRD->getNumBases(); unsigned FieldIndex = NumBases; - for (auto *FI : RT->getDecl()->fields()) { + for (auto *FI : RD->fields()) { if (FI->isUnnamedBitfield()) continue; if (declaresSameEntity(KnownField, FI)) { @@ -2654,7 +2774,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // All of the fields of a union are located at the same place in // the initializer list. - if (RT->getDecl()->isUnion()) { + if (RD->isUnion()) { FieldIndex = 0; if (StructuredList) { FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); @@ -2666,7 +2786,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (ExistingInit) { // We're about to throw away an initializer, emit warning. diagnoseInitOverride( - ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc())); + ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()), + /*UnionOverride=*/true, + /*FullyOverwritten=*/SemaRef.getLangOpts().CPlusPlus ? false + : true); } // remove existing initializer @@ -2706,15 +2829,14 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // cases where a designator takes us backwards too. if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus && NextField && - (*NextField == RT->getDecl()->field_end() || + (*NextField == RD->field_end() || (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) { // Find the field that we just initialized. FieldDecl *PrevField = nullptr; - for (auto FI = RT->getDecl()->field_begin(); - FI != RT->getDecl()->field_end(); ++FI) { + for (auto FI = RD->field_begin(); FI != RD->field_end(); ++FI) { if (FI->isUnnamedBitfield()) continue; - if (*NextField != RT->getDecl()->field_end() && + if (*NextField != RD->field_end() && declaresSameEntity(*FI, **NextField)) break; PrevField = *FI; @@ -2725,7 +2847,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered) << KnownField << PrevField << DIE->getSourceRange(); - unsigned OldIndex = NumBases + PrevField->getFieldIndex(); + unsigned OldIndex = StructuredIndex - 1; if (StructuredList && OldIndex <= StructuredList->getNumInits()) { if (Expr *PrevInit = StructuredList->getInit(OldIndex)) { SemaRef.Diag(PrevInit->getBeginLoc(), @@ -2739,7 +2861,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Update the designator with the field declaration. if (!VerifyOnly) - D->setField(*Field); + D->setFieldDecl(*Field); // Make sure that our non-designated initializer list has space // for a subobject corresponding to this field. @@ -2829,8 +2951,12 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // If this the first designator, our caller will continue checking // the rest of this struct/class/union subobject. if (IsFirstDesignator) { + if (Field != RD->field_end() && Field->isUnnamedBitfield()) + ++Field; + if (NextField) *NextField = Field; + StructuredIndex = FieldIndex; return false; } @@ -2839,7 +2965,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, return false; // We've already initialized something in the union; we're done. - if (RT->getDecl()->isUnion()) + if (RD->isUnion()) return hadError; // Check the remaining fields within this class/struct/union subobject. @@ -3147,6 +3273,8 @@ InitListChecker::createInitListExpr(QualType CurrentObjectType, NumElements = VType->getNumElements(); } else if (CurrentObjectType->isRecordType()) { NumElements = numStructUnionElements(CurrentObjectType); + } else if (CurrentObjectType->isDependentType()) { + NumElements = 1; } Result->reserveInits(SemaRef.Context, NumElements); @@ -3225,13 +3353,11 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, // Build designators and check array designator expressions. for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) { const Designator &D = Desig.getDesignator(Idx); - switch (D.getKind()) { - case Designator::FieldDesignator: - Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(), - D.getFieldLoc())); - break; - case Designator::ArrayDesignator: { + if (D.isFieldDesignator()) { + Designators.push_back(ASTDesignator::CreateFieldDesignator( + D.getFieldDecl(), D.getDotLoc(), D.getFieldLoc())); + } else if (D.isArrayDesignator()) { Expr *Index = static_cast<Expr *>(D.getArrayIndex()); llvm::APSInt IndexValue; if (!Index->isTypeDependent() && !Index->isValueDependent()) @@ -3239,15 +3365,11 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, if (!Index) Invalid = true; else { - Designators.push_back(ASTDesignator(InitExpressions.size(), - D.getLBracketLoc(), - D.getRBracketLoc())); + Designators.push_back(ASTDesignator::CreateArrayDesignator( + InitExpressions.size(), D.getLBracketLoc(), D.getRBracketLoc())); InitExpressions.push_back(Index); } - break; - } - - case Designator::ArrayRangeDesignator: { + } else if (D.isArrayRangeDesignator()) { Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart()); Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd()); llvm::APSInt StartValue; @@ -3279,25 +3401,19 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, << StartIndex->getSourceRange() << EndIndex->getSourceRange(); Invalid = true; } else { - Designators.push_back(ASTDesignator(InitExpressions.size(), - D.getLBracketLoc(), - D.getEllipsisLoc(), - D.getRBracketLoc())); + Designators.push_back(ASTDesignator::CreateArrayRangeDesignator( + InitExpressions.size(), D.getLBracketLoc(), D.getEllipsisLoc(), + D.getRBracketLoc())); InitExpressions.push_back(StartIndex); InitExpressions.push_back(EndIndex); } } - break; - } } } if (Invalid || Init.isInvalid()) return ExprError(); - // Clear out the expressions within the designation. - Desig.ClearExprs(*this); - return DesignatedInitExpr::Create(Context, Designators, InitExpressions, EqualOrColonLoc, GNUSyntax, Init.getAs<Expr>()); @@ -3348,6 +3464,7 @@ DeclarationName InitializedEntity::getName() const { case EK_Variable: case EK_Member: + case EK_ParenAggInitMember: case EK_Binding: case EK_TemplateParameter: return Variable.VariableOrMember->getDeclName(); @@ -3379,6 +3496,7 @@ ValueDecl *InitializedEntity::getDecl() const { switch (getKind()) { case EK_Variable: case EK_Member: + case EK_ParenAggInitMember: case EK_Binding: case EK_TemplateParameter: return Variable.VariableOrMember; @@ -3420,6 +3538,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Parameter_CF_Audited: case EK_TemplateParameter: case EK_Member: + case EK_ParenAggInitMember: case EK_Binding: case EK_New: case EK_Temporary: @@ -3454,7 +3573,10 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { 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_Member: + case EK_ParenAggInitMember: + OS << "Member"; + break; case EK_Binding: OS << "Binding"; break; case EK_New: OS << "New"; break; case EK_Temporary: OS << "Temporary"; break; @@ -3591,6 +3713,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ExplicitConstructor: case FK_AddressOfUnaddressableFunction: case FK_ParenthesizedListInitFailed: + case FK_DesignatedInitForNonAggregate: return false; case FK_ReferenceInitOverloadFailed: @@ -4428,6 +4551,22 @@ static void TryListInitialization(Sema &S, return; } + // C++20 [dcl.init.list]p3: + // - If the braced-init-list contains a designated-initializer-list, T shall + // be an aggregate class. [...] Aggregate initialization is performed. + // + // We allow arrays here too in order to support array designators. + // + // FIXME: This check should precede the handling of reference initialization. + // We follow other compilers in allowing things like 'Aggr &&a = {.x = 1};' + // as a tentative DR resolution. + bool IsDesignatedInit = InitList->hasDesignatedInit(); + if (!DestType->isAggregateType() && IsDesignatedInit) { + Sequence.SetFailed( + InitializationSequence::FK_DesignatedInitForNonAggregate); + return; + } + // C++11 [dcl.init.list]p3, per DR1467: // - If T is a class type and the initializer list has a single element of // type cv U, where U is T or a class derived from T, the object is @@ -4439,7 +4578,8 @@ static void TryListInitialization(Sema &S, // (8.5.2 [dcl.init.string]), initialization is performed as described // in that section. // - Otherwise, if T is an aggregate, [...] (continue below). - if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1) { + if (S.getLangOpts().CPlusPlus11 && InitList->getNumInits() == 1 && + !IsDesignatedInit) { if (DestType->isRecordType()) { QualType InitType = InitList->getInit(0)->getType(); if (S.Context.hasSameUnqualifiedType(InitType, DestType) || @@ -4481,7 +4621,7 @@ static void TryListInitialization(Sema &S, // - If T is an aggregate, aggregate initialization is performed. if ((DestType->isRecordType() && !DestType->isAggregateType()) || (S.getLangOpts().CPlusPlus11 && - S.isStdInitializerList(DestType, nullptr))) { + S.isStdInitializerList(DestType, nullptr) && !IsDesignatedInit)) { if (S.getLangOpts().CPlusPlus11) { // - Otherwise, if the initializer list has no elements and T is a // class type with a default constructor, the object is @@ -5274,176 +5414,225 @@ static void TryOrBuildParenListInitialization( Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly, ExprResult *Result = nullptr) { - unsigned ArgIndexToProcess = 0; + unsigned EntityIndexToProcess = 0; SmallVector<Expr *, 4> InitExprs; QualType ResultType; Expr *ArrayFiller = nullptr; FieldDecl *InitializedFieldInUnion = nullptr; - // Process entities (i.e. array members, base classes, or class fields) by - // adding an initialization expression to InitExprs for each entity to - // initialize. - auto ProcessEntities = [&](auto Range) -> bool { - bool IsUnionType = Entity.getType()->isUnionType(); - for (InitializedEntity SubEntity : Range) { - // Unions should only have one initializer expression. - // If there are more initializers than it will be caught when we check - // whether Index equals Args.size(). - if (ArgIndexToProcess == 1 && IsUnionType) - return true; - - bool IsMember = SubEntity.getKind() == InitializedEntity::EK_Member; - - // Unnamed bitfields should not be initialized at all, either with an arg - // or by default. - if (IsMember && cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield()) - continue; - - if (ArgIndexToProcess < Args.size()) { - // There are still expressions in Args that haven't been processed. - // Let's match them to the current entity to initialize. - Expr *E = Args[ArgIndexToProcess++]; - - // Incomplete array types indicate flexible array members. Do not allow - // paren list initializations of structs with these members, as GCC - // doesn't either. - if (IsMember) { - auto *FD = cast<FieldDecl>(SubEntity.getDecl()); - if (FD->getType()->isIncompleteArrayType()) { - if (!VerifyOnly) { - S.Diag(E->getBeginLoc(), diag::err_flexible_array_init) - << SourceRange(E->getBeginLoc(), E->getEndLoc()); - S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD; - } - Sequence.SetFailed( - InitializationSequence::FK_ParenthesizedListInitFailed); - return false; - } - } - - InitializationKind SubKind = InitializationKind::CreateForInit( - E->getExprLoc(), /*isDirectInit=*/false, E); - InitializationSequence SubSeq(S, SubEntity, SubKind, E); - - if (SubSeq.Failed()) { - if (!VerifyOnly) - SubSeq.Diagnose(S, SubEntity, SubKind, E); - else - Sequence.SetFailed( - InitializationSequence::FK_ParenthesizedListInitFailed); + auto HandleInitializedEntity = [&](const InitializedEntity &SubEntity, + const InitializationKind &SubKind, + Expr *Arg, Expr **InitExpr = nullptr) { + InitializationSequence IS = [&]() { + if (Arg) + return InitializationSequence(S, SubEntity, SubKind, Arg); + return InitializationSequence(S, SubEntity, SubKind, std::nullopt); + }(); - return false; - } - if (!VerifyOnly) { - ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E); - InitExprs.push_back(ER.get()); - if (IsMember && IsUnionType) - InitializedFieldInUnion = cast<FieldDecl>(SubEntity.getDecl()); - } + if (IS.Failed()) { + if (!VerifyOnly) { + if (Arg) + IS.Diagnose(S, SubEntity, SubKind, Arg); + else + IS.Diagnose(S, SubEntity, SubKind, std::nullopt); } else { - // We've processed all of the args, but there are still entities that - // have to be initialized. - if (IsMember) { - // C++ [dcl.init]p17.6.2.2 - // The remaining elements are initialized with their default member - // initializers, if any - auto *FD = cast<FieldDecl>(SubEntity.getDecl()); - if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) { - ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD); - if (DIE.isInvalid()) - return false; - S.checkInitializerLifetime(SubEntity, DIE.get()); - InitExprs.push_back(DIE.get()); - continue; - }; - } - // Remaining class elements without default member initializers and - // array elements are value initialized: - // - // C++ [dcl.init]p17.6.2.2 - // The remaining elements...otherwise are value initialzed - // - // C++ [dcl.init]p17.5 - // if the destination type is an array, the object is initialized as - // . follows. Let x1, . . . , xk be the elements of the expression-list - // ...Let n denote the array size...the ith array element is...value- - // initialized for each k < i <= n. - InitializationKind SubKind = InitializationKind::CreateValue( - Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true); - InitializationSequence SubSeq(S, SubEntity, SubKind, std::nullopt); - if (SubSeq.Failed()) { - if (!VerifyOnly) - SubSeq.Diagnose(S, SubEntity, SubKind, std::nullopt); - return false; - } - if (!VerifyOnly) { - ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, std::nullopt); - if (SubEntity.getKind() == InitializedEntity::EK_ArrayElement) { - ArrayFiller = ER.get(); - return true; - } - InitExprs.push_back(ER.get()); - } + Sequence.SetFailed( + InitializationSequence::FK_ParenthesizedListInitFailed); } + + return false; + } + if (!VerifyOnly) { + ExprResult ER; + if (Arg) + ER = IS.Perform(S, SubEntity, SubKind, Arg); + else + ER = IS.Perform(S, SubEntity, SubKind, std::nullopt); + if (InitExpr) + *InitExpr = ER.get(); + else + InitExprs.push_back(ER.get()); } return true; }; if (const ArrayType *AT = S.getASTContext().getAsArrayType(Entity.getType())) { - SmallVector<InitializedEntity, 4> ElementEntities; uint64_t ArrayLength; - // C++ [dcl.init]p17.5 + // C++ [dcl.init]p16.5 // if the destination type is an array, the object is initialized as // follows. Let x1, . . . , xk be the elements of the expression-list. If - // the destination type is an array of unknown bound, it is define as + // the destination type is an array of unknown bound, it is defined as // having k elements. if (const ConstantArrayType *CAT = - S.getASTContext().getAsConstantArrayType(Entity.getType())) + S.getASTContext().getAsConstantArrayType(Entity.getType())) { ArrayLength = CAT->getSize().getZExtValue(); - else + ResultType = Entity.getType(); + } else if (const VariableArrayType *VAT = + S.getASTContext().getAsVariableArrayType(Entity.getType())) { + // Braced-initialization of variable array types is not allowed, even if + // the size is greater than or equal to the number of args, so we don't + // allow them to be initialized via parenthesized aggregate initialization + // either. + const Expr *SE = VAT->getSizeExpr(); + S.Diag(SE->getBeginLoc(), diag::err_variable_object_no_init) + << SE->getSourceRange(); + return; + } else { + assert(isa<IncompleteArrayType>(Entity.getType())); ArrayLength = Args.size(); + } + EntityIndexToProcess = ArrayLength; - if (ArrayLength >= Args.size()) { - for (uint64_t I = 0; I < ArrayLength; ++I) - ElementEntities.push_back( - InitializedEntity::InitializeElement(S.getASTContext(), I, Entity)); - - if (!ProcessEntities(ElementEntities)) + // ...the ith array element is copy-initialized with xi for each + // 1 <= i <= k + for (Expr *E : Args) { + InitializedEntity SubEntity = InitializedEntity::InitializeElement( + S.getASTContext(), EntityIndexToProcess, Entity); + InitializationKind SubKind = InitializationKind::CreateForInit( + E->getExprLoc(), /*isDirectInit=*/false, E); + if (!HandleInitializedEntity(SubEntity, SubKind, E)) + return; + } + // ...and value-initialized for each k < i <= n; + if (ArrayLength > Args.size()) { + InitializedEntity SubEntity = InitializedEntity::InitializeElement( + S.getASTContext(), Args.size(), Entity); + InitializationKind SubKind = InitializationKind::CreateValue( + Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true); + if (!HandleInitializedEntity(SubEntity, SubKind, nullptr, &ArrayFiller)) return; + } + if (ResultType.isNull()) { ResultType = S.Context.getConstantArrayType( AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength), - nullptr, ArrayType::Normal, 0); + /*SizeExpr=*/nullptr, ArrayType::Normal, 0); } } else if (auto *RT = Entity.getType()->getAs<RecordType>()) { + bool IsUnion = RT->isUnionType(); const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - auto BaseRange = map_range(RD->bases(), [&S](auto &base) { - return InitializedEntity::InitializeBase(S.getASTContext(), &base, false); - }); - auto FieldRange = map_range(RD->fields(), [](auto *field) { - return InitializedEntity::InitializeMember(field); - }); + if (!IsUnion) { + for (const CXXBaseSpecifier &Base : RD->bases()) { + InitializedEntity SubEntity = InitializedEntity::InitializeBase( + S.getASTContext(), &Base, false, &Entity); + if (EntityIndexToProcess < Args.size()) { + // C++ [dcl.init]p16.6.2.2. + // ...the object is initialized is follows. Let e1, ..., en be the + // elements of the aggregate([dcl.init.aggr]). Let x1, ..., xk be + // the elements of the expression-list...The element ei is + // copy-initialized with xi for 1 <= i <= k. + Expr *E = Args[EntityIndexToProcess]; + InitializationKind SubKind = InitializationKind::CreateForInit( + E->getExprLoc(), /*isDirectInit=*/false, E); + if (!HandleInitializedEntity(SubEntity, SubKind, E)) + return; + } else { + // We've processed all of the args, but there are still base classes + // that have to be initialized. + // C++ [dcl.init]p17.6.2.2 + // The remaining elements...otherwise are value initialzed + InitializationKind SubKind = InitializationKind::CreateValue( + Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), + /*IsImplicit=*/true); + if (!HandleInitializedEntity(SubEntity, SubKind, nullptr)) + return; + } + EntityIndexToProcess++; + } + } - if (!ProcessEntities(BaseRange)) - return; + for (FieldDecl *FD : RD->fields()) { + // Unnamed bitfields should not be initialized at all, either with an arg + // or by default. + if (FD->isUnnamedBitfield()) + continue; - if (!ProcessEntities(FieldRange)) - return; + InitializedEntity SubEntity = + InitializedEntity::InitializeMemberFromParenAggInit(FD); + + if (EntityIndexToProcess < Args.size()) { + // ...The element ei is copy-initialized with xi for 1 <= i <= k. + Expr *E = Args[EntityIndexToProcess]; + + // Incomplete array types indicate flexible array members. Do not allow + // paren list initializations of structs with these members, as GCC + // doesn't either. + if (FD->getType()->isIncompleteArrayType()) { + if (!VerifyOnly) { + S.Diag(E->getBeginLoc(), diag::err_flexible_array_init) + << SourceRange(E->getBeginLoc(), E->getEndLoc()); + S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD; + } + Sequence.SetFailed( + InitializationSequence::FK_ParenthesizedListInitFailed); + return; + } + InitializationKind SubKind = InitializationKind::CreateForInit( + E->getExprLoc(), /*isDirectInit=*/false, E); + if (!HandleInitializedEntity(SubEntity, SubKind, E)) + return; + + // Unions should have only one initializer expression, so we bail out + // after processing the first field. If there are more initializers then + // it will be caught when we later check whether EntityIndexToProcess is + // less than Args.size(); + if (IsUnion) { + InitializedFieldInUnion = FD; + EntityIndexToProcess = 1; + break; + } + } else { + // We've processed all of the args, but there are still members that + // have to be initialized. + if (FD->hasInClassInitializer()) { + if (!VerifyOnly) { + // C++ [dcl.init]p16.6.2.2 + // The remaining elements are initialized with their default + // member initializers, if any + ExprResult DIE = S.BuildCXXDefaultInitExpr( + Kind.getParenOrBraceRange().getEnd(), FD); + if (DIE.isInvalid()) + return; + S.checkInitializerLifetime(SubEntity, DIE.get()); + InitExprs.push_back(DIE.get()); + } + } else { + // C++ [dcl.init]p17.6.2.2 + // The remaining elements...otherwise are value initialzed + if (FD->getType()->isReferenceType()) { + Sequence.SetFailed( + InitializationSequence::FK_ParenthesizedListInitFailed); + if (!VerifyOnly) { + SourceRange SR = Kind.getParenOrBraceRange(); + S.Diag(SR.getEnd(), diag::err_init_reference_member_uninitialized) + << FD->getType() << SR; + S.Diag(FD->getLocation(), diag::note_uninit_reference_member); + } + return; + } + InitializationKind SubKind = InitializationKind::CreateValue( + Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true); + if (!HandleInitializedEntity(SubEntity, SubKind, nullptr)) + return; + } + } + EntityIndexToProcess++; + } ResultType = Entity.getType(); } // Not all of the args have been processed, so there must've been more args - // then were required to initialize the element. - if (ArgIndexToProcess < Args.size()) { + // than were required to initialize the element. + if (EntityIndexToProcess < Args.size()) { Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed); if (!VerifyOnly) { QualType T = Entity.getType(); int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4; - SourceRange ExcessInitSR(Args[ArgIndexToProcess]->getBeginLoc(), + SourceRange ExcessInitSR(Args[EntityIndexToProcess]->getBeginLoc(), Args.back()->getEndLoc()); S.Diag(Kind.getLocation(), diag::err_excess_initializers) << InitKind << ExcessInitSR; @@ -6152,6 +6341,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // We're at the end of the line for C: it's either a write-back conversion // or it's a C assignment. There's no need to check anything else. if (!S.getLangOpts().CPlusPlus) { + assert(Initializer && "Initializer must be non-null"); // If allowed, check whether this is an Objective-C writeback conversion. if (allowObjCWritebackConversion && tryObjCWritebackConversion(S, *this, Entity, Initializer)) { @@ -6178,7 +6368,8 @@ void InitializationSequence::InitializeFrom(Sema &S, if (Kind.getKind() == InitializationKind::IK_Direct || (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || - S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) { + (Initializer && S.IsDerivedFrom(Initializer->getBeginLoc(), + SourceType, DestType))))) { TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType, *this); @@ -6222,6 +6413,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // function is used) to a derived class thereof are enumerated as // described in 13.3.1.4, and the best one is chosen through // overload resolution (13.3). + assert(Initializer && "Initializer must be non-null"); TryUserDefinedConversion(S, DestType, Kind, Initializer, *this, TopLevelOfInitList); } @@ -6273,6 +6465,7 @@ void InitializationSequence::InitializeFrom(Sema &S, // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. if (!SourceType.isNull() && SourceType->isRecordType()) { + assert(Initializer && "Initializer must be non-null"); // For a conversion to _Atomic(T) from either T or a class type derived // from T, initialize the T object then convert to _Atomic type. bool NeedAtomicConversion = false; @@ -6409,6 +6602,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { return Sema::AA_Converting; case InitializedEntity::EK_Member: + case InitializedEntity::EK_ParenAggInitMember: case InitializedEntity::EK_Binding: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: @@ -6429,6 +6623,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: + case InitializedEntity::EK_ParenAggInitMember: case InitializedEntity::EK_Result: case InitializedEntity::EK_StmtExprResult: case InitializedEntity::EK_New: @@ -6473,6 +6668,7 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) { return false; case InitializedEntity::EK_Member: + case InitializedEntity::EK_ParenAggInitMember: case InitializedEntity::EK_Binding: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: @@ -6509,6 +6705,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: + case InitializedEntity::EK_ParenAggInitMember: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_TemplateParameter: @@ -6856,7 +7053,7 @@ PerformConstructorInitialization(Sema &S, if (isExplicitTemporary(Entity, Kind, NumArgs)) { // An explicitly-constructed temporary, e.g., X(1, 2). - if (S.DiagnoseUseOfDecl(Constructor, Loc)) + if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc)) return ExprError(); TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); @@ -6871,8 +7068,6 @@ PerformConstructorInitialization(Sema &S, if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>( Step.Function.FoundDecl.getDecl())) { CalleeDecl = S.findInheritingConstructor(Loc, Constructor, Shadow); - if (S.DiagnoseUseOfDecl(CalleeDecl, Loc)) - return ExprError(); } S.MarkFunctionReferenced(Loc, CalleeDecl); @@ -7077,7 +7272,15 @@ static LifetimeResult getEntityLifetime( case InitializedEntity::EK_Exception: // FIXME: Can we diagnose lifetime problems with exceptions? return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_ParenAggInitMember: + // -- A temporary object bound to a reference element of an aggregate of + // class type initialized from a parenthesized expression-list + // [dcl.init, 9.3] persists until the completion of the full-expression + // containing the expression-list. + return {nullptr, LK_FullExpression}; } + llvm_unreachable("unknown entity kind"); } @@ -8088,7 +8291,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, case IndirectLocalPathEntry::DefaultInit: { auto *FD = cast<FieldDecl>(Elem.D); - Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer) + Diag(FD->getLocation(), diag::note_init_with_default_member_initializer) << FD << nextPathEntryRange(Path, I + 1, L); break; } @@ -8406,6 +8609,15 @@ ExprResult InitializationSequence::Perform(Sema &S, << Init->getSourceRange(); } + if (S.getLangOpts().MicrosoftExt && Args.size() == 1 && + isa<PredefinedExpr>(Args[0]) && Entity.getType()->isArrayType()) { + // Produce a Microsoft compatibility warning when initializing from a + // predefined expression since MSVC treats predefined expressions as string + // literals. + Expr *Init = Args[0]; + S.Diag(Init->getBeginLoc(), diag::ext_init_from_predefined) << Init; + } + // OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope QualType ETy = Entity.getType(); bool HasGlobalAS = ETy.hasAddressSpace() && @@ -9180,30 +9392,34 @@ ExprResult InitializationSequence::Perform(Sema &S, /*VerifyOnly=*/false, &CurInit); if (CurInit.get() && ResultType) *ResultType = CurInit.get()->getType(); + if (shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.get()); break; } } } + Expr *Init = CurInit.get(); + if (!Init) + return ExprError(); + // 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); + S.checkInitializerLifetime(Entity, Init); // Diagnose non-fatal problems with the completed initialization. - if (Entity.getKind() == InitializedEntity::EK_Member && + if (InitializedEntity::EntityKind EK = Entity.getKind(); + (EK == InitializedEntity::EK_Member || + EK == InitializedEntity::EK_ParenAggInitMember) && cast<FieldDecl>(Entity.getDecl())->isBitField()) S.CheckBitFieldInitialization(Kind.getLocation(), - cast<FieldDecl>(Entity.getDecl()), - CurInit.get()); + cast<FieldDecl>(Entity.getDecl()), Init); // Check for std::move on construction. - if (const Expr *E = CurInit.get()) { - CheckMoveOnConstruction(S, E, - Entity.getKind() == InitializedEntity::EK_Result); - } + CheckMoveOnConstruction(S, Init, + Entity.getKind() == InitializedEntity::EK_Result); - return CurInit; + return Init; } /// Somewhere within T there is an uninitialized reference subobject. @@ -9645,7 +9861,8 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_No_Viable_Function: if (Kind.getKind() == InitializationKind::IK_Default && (Entity.getKind() == InitializedEntity::EK_Base || - Entity.getKind() == InitializedEntity::EK_Member) && + Entity.getKind() == InitializedEntity::EK_Member || + Entity.getKind() == InitializedEntity::EK_ParenAggInitMember) && isa<CXXConstructorDecl>(S.CurContext)) { // This is implicit default initialization of a member or // base within a constructor. If no viable function was @@ -9788,6 +10005,12 @@ bool InitializationSequence::Diagnose(Sema &S, TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this, /*VerifyOnly=*/false); break; + + case FK_DesignatedInitForNonAggregate: + InitListExpr *InitList = cast<InitListExpr>(Args[0]); + S.Diag(Kind.getLocation(), diag::err_designated_init_for_non_aggregate) + << Entity.getType() << InitList->getSourceRange(); + break; } PrintInitLocationNote(S, Entity); @@ -9958,6 +10181,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { case FK_ParenthesizedListInitFailed: OS << "parenthesized list initialization failed"; break; + + case FK_DesignatedInitForNonAggregate: + OS << "designated initializer for non-aggregate type"; + break; } OS << '\n'; return; @@ -10330,7 +10557,7 @@ static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD, QualType Sema::DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TSInfo, const InitializedEntity &Entity, - const InitializationKind &Kind, MultiExprArg Inits) { + const InitializationKind &Kind, MultiExprArg Inits, ParenListExpr *PL) { auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>( TSInfo->getType()->getContainedDeducedType()); assert(DeducedTST && "not a deduced template specialization type"); @@ -10400,13 +10627,137 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( OverloadCandidateSet::CSK_Normal); OverloadCandidateSet::iterator Best; - bool HasAnyDeductionGuide = false; bool AllowExplicit = !Kind.isCopyInit() || ListInit; - auto tryToResolveOverload = + // Return true is the candidate is added successfully, false otherwise. + auto addDeductionCandidate = [&](FunctionTemplateDecl *TD, + CXXDeductionGuideDecl *GD, + DeclAccessPair FoundDecl, + bool OnlyListConstructors, + bool AllowAggregateDeductionCandidate) { + // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class) + // For copy-initialization, the candidate functions are all the + // converting constructors (12.3.1) of that class. + // C++ [over.match.copy]p1: (non-list copy-initialization from class) + // The converting constructors of T are candidate functions. + if (!AllowExplicit) { + // Overload resolution checks whether the deduction guide is declared + // explicit for us. + + // When looking for a converting constructor, deduction guides that + // could never be called with one argument are not interesting to + // check or note. + if (GD->getMinRequiredArguments() > 1 || + (GD->getNumParams() == 0 && !GD->isVariadic())) + return; + } + + // C++ [over.match.list]p1.1: (first phase list initialization) + // Initially, the candidate functions are the initializer-list + // constructors of the class T + if (OnlyListConstructors && !isInitListConstructor(GD)) + return; + + if (!AllowAggregateDeductionCandidate && + GD->getDeductionCandidateKind() == DeductionCandidate::Aggregate) + return; + + // C++ [over.match.list]p1.2: (second phase list initialization) + // the candidate functions are all the constructors of the class T + // C++ [over.match.ctor]p1: (all other cases) + // the candidate functions are all the constructors of the class of + // the object being initialized + + // C++ [over.best.ics]p4: + // When [...] the constructor [...] is a candidate by + // - [over.match.copy] (in all cases) + // FIXME: The "second phase of [over.match.list] case can also + // theoretically happen here, but it's not clear whether we can + // ever have a parameter of the right type. + bool SuppressUserConversions = Kind.isCopyInit(); + + if (TD) { + SmallVector<Expr *, 8> TmpInits; + for (Expr *E : Inits) + if (auto *DI = dyn_cast<DesignatedInitExpr>(E)) + TmpInits.push_back(DI->getInit()); + else + TmpInits.push_back(E); + AddTemplateOverloadCandidate( + TD, FoundDecl, /*ExplicitArgs=*/nullptr, TmpInits, Candidates, + SuppressUserConversions, + /*PartialOverloading=*/false, AllowExplicit, ADLCallKind::NotADL, + /*PO=*/{}, AllowAggregateDeductionCandidate); + } else { + AddOverloadCandidate(GD, FoundDecl, Inits, Candidates, + SuppressUserConversions, + /*PartialOverloading=*/false, AllowExplicit); + } + }; + + bool FoundDeductionGuide = false; + + auto TryToResolveOverload = [&](bool OnlyListConstructors) -> OverloadingResult { Candidates.clear(OverloadCandidateSet::CSK_Normal); - HasAnyDeductionGuide = false; + bool HasAnyDeductionGuide = false; + + auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) { + auto *RD = cast<CXXRecordDecl>(Template->getTemplatedDecl()); + if (!(RD->getDefinition() && RD->isAggregate())) + return; + QualType Ty = Context.getRecordType(RD); + SmallVector<QualType, 8> ElementTypes; + + InitListChecker CheckInitList(*this, Entity, ListInit, Ty, ElementTypes); + if (!CheckInitList.HadError()) { + // C++ [over.match.class.deduct]p1.8: + // if e_i is of array type and x_i is a braced-init-list, T_i is an + // rvalue reference to the declared type of e_i and + // C++ [over.match.class.deduct]p1.9: + // if e_i is of array type and x_i is a bstring-literal, T_i is an + // lvalue reference to the const-qualified declared type of e_i and + // C++ [over.match.class.deduct]p1.10: + // otherwise, T_i is the declared type of e_i + for (int I = 0, E = ListInit->getNumInits(); + I < E && !isa<PackExpansionType>(ElementTypes[I]); ++I) + if (ElementTypes[I]->isArrayType()) { + if (isa<InitListExpr>(ListInit->getInit(I))) + ElementTypes[I] = Context.getRValueReferenceType(ElementTypes[I]); + else if (isa<StringLiteral>( + ListInit->getInit(I)->IgnoreParenImpCasts())) + ElementTypes[I] = + Context.getLValueReferenceType(ElementTypes[I].withConst()); + } + + llvm::FoldingSetNodeID ID; + ID.AddPointer(Template); + for (auto &T : ElementTypes) + T.getCanonicalType().Profile(ID); + unsigned Hash = ID.ComputeHash(); + if (AggregateDeductionCandidates.count(Hash) == 0) { + if (FunctionTemplateDecl *TD = + DeclareImplicitDeductionGuideFromInitList( + Template, ElementTypes, + TSInfo->getTypeLoc().getEndLoc())) { + auto *GD = cast<CXXDeductionGuideDecl>(TD->getTemplatedDecl()); + GD->setDeductionCandidateKind(DeductionCandidate::Aggregate); + AggregateDeductionCandidates[Hash] = GD; + addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public), + OnlyListConstructors, + /*AllowAggregateDeductionCandidate=*/true); + } + } else { + CXXDeductionGuideDecl *GD = AggregateDeductionCandidates[Hash]; + FunctionTemplateDecl *TD = GD->getDescribedFunctionTemplate(); + assert(TD && "aggregate deduction candidate is function template"); + addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public), + OnlyListConstructors, + /*AllowAggregateDeductionCandidate=*/true); + } + HasAnyDeductionGuide = true; + } + }; for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); @@ -10414,7 +10765,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( continue; auto *TD = dyn_cast<FunctionTemplateDecl>(D); - auto *GD = dyn_cast_or_null<CXXDeductionGuideDecl>( + auto *GD = dyn_cast_if_present<CXXDeductionGuideDecl>( TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D)); if (!GD) continue; @@ -10422,53 +10773,30 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( if (!GD->isImplicit()) HasAnyDeductionGuide = true; - // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class) - // For copy-initialization, the candidate functions are all the - // converting constructors (12.3.1) of that class. - // C++ [over.match.copy]p1: (non-list copy-initialization from class) - // The converting constructors of T are candidate functions. - if (!AllowExplicit) { - // Overload resolution checks whether the deduction guide is declared - // explicit for us. - - // When looking for a converting constructor, deduction guides that - // could never be called with one argument are not interesting to - // check or note. - if (GD->getMinRequiredArguments() > 1 || - (GD->getNumParams() == 0 && !GD->isVariadic())) - continue; + addDeductionCandidate(TD, GD, I.getPair(), OnlyListConstructors, + /*AllowAggregateDeductionCandidate=*/false); + } + + // C++ [over.match.class.deduct]p1.4: + // if C is defined and its definition satisfies the conditions for an + // aggregate class ([dcl.init.aggr]) with the assumption that any + // dependent base class has no virtual functions and no virtual base + // classes, and the initializer is a non-empty braced-init-list or + // parenthesized expression-list, and there are no deduction-guides for + // C, the set contains an additional function template, called the + // aggregate deduction candidate, defined as follows. + if (getLangOpts().CPlusPlus20 && !HasAnyDeductionGuide) { + if (ListInit && ListInit->getNumInits()) { + SynthesizeAggrGuide(ListInit); + } else if (PL && PL->getNumExprs()) { + InitListExpr TempListInit(getASTContext(), PL->getLParenLoc(), + PL->exprs(), PL->getRParenLoc()); + SynthesizeAggrGuide(&TempListInit); } + } - // C++ [over.match.list]p1.1: (first phase list initialization) - // Initially, the candidate functions are the initializer-list - // constructors of the class T - if (OnlyListConstructors && !isInitListConstructor(GD)) - continue; + FoundDeductionGuide = FoundDeductionGuide || HasAnyDeductionGuide; - // C++ [over.match.list]p1.2: (second phase list initialization) - // the candidate functions are all the constructors of the class T - // C++ [over.match.ctor]p1: (all other cases) - // the candidate functions are all the constructors of the class of - // the object being initialized - - // C++ [over.best.ics]p4: - // When [...] the constructor [...] is a candidate by - // - [over.match.copy] (in all cases) - // FIXME: The "second phase of [over.match.list] case can also - // theoretically happen here, but it's not clear whether we can - // ever have a parameter of the right type. - bool SuppressUserConversions = Kind.isCopyInit(); - - if (TD) - AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr, - Inits, Candidates, SuppressUserConversions, - /*PartialOverloading*/ false, - AllowExplicit); - else - AddOverloadCandidate(GD, I.getPair(), Inits, Candidates, - SuppressUserConversions, - /*PartialOverloading*/ false, AllowExplicit); - } return Candidates.BestViableFunction(*this, Kind.getLocation(), Best); }; @@ -10504,7 +10832,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( } if (TryListConstructors) - Result = tryToResolveOverload(/*OnlyListConstructor*/true); + Result = TryToResolveOverload(/*OnlyListConstructor*/true); // Then unwrap the initializer list and try again considering all // constructors. Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits()); @@ -10513,7 +10841,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // If list-initialization fails, or if we're doing any other kind of // initialization, we (eventually) consider constructors. if (Result == OR_No_Viable_Function) - Result = tryToResolveOverload(/*OnlyListConstructor*/false); + Result = TryToResolveOverload(/*OnlyListConstructor*/false); switch (Result) { case OR_Ambiguous: @@ -10567,7 +10895,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // Make sure we didn't select an unusable deduction guide, and mark it // as referenced. - DiagnoseUseOfDecl(Best->Function, Kind.getLocation()); + DiagnoseUseOfDecl(Best->FoundDecl, Kind.getLocation()); MarkFunctionReferenced(Kind.getLocation(), Best->Function); break; } @@ -10583,7 +10911,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // Warn if CTAD was used on a type that does not have any user-defined // deduction guides. - if (!HasAnyDeductionGuide) { + if (!FoundDeductionGuide) { Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_ctad_maybe_unsupported) << TemplateName; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 00ab6ba580bf..06fc53591a76 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -247,8 +247,9 @@ Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); - bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(), - *this); + + bool IsGenericLambda = + Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this); // Start constructing the lambda class. CXXRecordDecl *Class = CXXRecordDecl::CreateLambda( Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind, @@ -282,12 +283,14 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { Normal, DefaultArgument, DataMember, - StaticDataMember, InlineVariable, - VariableTemplate, + TemplatedVariable, Concept } Kind = Normal; + bool IsInNonspecializedTemplate = + inTemplateInstantiation() || CurContext->isDependentContext(); + // Default arguments of member function parameters that appear in a class // definition, as well as the initializers of data members, receive special // treatment. Identify them. @@ -298,15 +301,15 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { if (LexicalDC->isRecord()) Kind = DefaultArgument; } else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) { - if (Var->getDeclContext()->isRecord()) - Kind = StaticDataMember; - else if (Var->getMostRecentDecl()->isInline()) + if (Var->getMostRecentDecl()->isInline()) Kind = InlineVariable; + else if (Var->getDeclContext()->isRecord() && IsInNonspecializedTemplate) + Kind = TemplatedVariable; else if (Var->getDescribedVarTemplate()) - Kind = VariableTemplate; + Kind = TemplatedVariable; else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) { if (!VTS->isExplicitSpecialization()) - Kind = VariableTemplate; + Kind = TemplatedVariable; } } else if (isa<FieldDecl>(ManglingContextDecl)) { Kind = DataMember; @@ -318,12 +321,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { // Itanium ABI [5.1.7]: // In the following contexts [...] the one-definition rule requires closure // types in different translation units to "correspond": - bool IsInNonspecializedTemplate = - inTemplateInstantiation() || CurContext->isDependentContext(); switch (Kind) { case Normal: { - // -- the bodies of non-exported nonspecialized template functions - // -- the bodies of inline functions + // -- the bodies of inline or templated functions if ((IsInNonspecializedTemplate && !(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) || isInInlineFunction(CurContext)) { @@ -340,21 +340,13 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { // however the ManglingContextDecl is important for the purposes of // re-forming the template argument list of the lambda for constraint // evaluation. - case StaticDataMember: - // -- the initializers of nonspecialized static members of template classes - if (!IsInNonspecializedTemplate) - return std::make_tuple(nullptr, ManglingContextDecl); - // Fall through to get the current context. - [[fallthrough]]; - case DataMember: - // -- the in-class initializers of class members + // -- default member initializers case DefaultArgument: // -- default arguments appearing in class definitions case InlineVariable: - // -- the initializers of inline variables - case VariableTemplate: - // -- the initializers of templated variables + case TemplatedVariable: + // -- the initializers of inline or templated variables return std::make_tuple( &Context.getManglingNumberContext(ASTContext::NeedExtraManglingDecl, ManglingContextDecl), @@ -364,14 +356,13 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { llvm_unreachable("unexpected context"); } -CXXMethodDecl *Sema::startLambdaDefinition( - CXXRecordDecl *Class, SourceRange IntroducerRange, - TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, - ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind, - StorageClass SC, Expr *TrailingRequiresClause) { +static QualType +buildTypeForLambdaCallOperator(Sema &S, clang::CXXRecordDecl *Class, + TemplateParameterList *TemplateParams, + TypeSourceInfo *MethodTypeInfo) { + assert(MethodTypeInfo && "expected a non null type"); + QualType MethodType = MethodTypeInfo->getType(); - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(getCurLambda(), *this); // If a lambda appears in a dependent context or is a generic lambda (has // template parameters) and has an 'auto' return type, deduce it to a // dependent type. @@ -379,75 +370,24 @@ CXXMethodDecl *Sema::startLambdaDefinition( const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = SubstAutoTypeDependent(Result); - MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), - FPT->getExtProtoInfo()); + Result = S.SubstAutoTypeDependent(Result); + MethodType = S.Context.getFunctionType(Result, FPT->getParamTypes(), + FPT->getExtProtoInfo()); } } - - // C++11 [expr.prim.lambda]p5: - // The closure type for a lambda-expression has a public inline function - // call operator (13.5.4) whose parameters and return type are described by - // the lambda-expression's parameter-declaration-clause and - // trailing-return-type respectively. - DeclarationName MethodName - = Context.DeclarationNames.getCXXOperatorName(OO_Call); - DeclarationNameLoc MethodNameLoc = - DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange); - CXXMethodDecl *Method = CXXMethodDecl::Create( - Context, Class, EndLoc, - DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), - MethodNameLoc), - MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); - Method->setAccess(AS_public); - if (!TemplateParams) - Class->addDecl(Method); - - // Temporarily set the lexical declaration context to the current - // context, so that the Scope stack matches the lexical nesting. - Method->setLexicalDeclContext(CurContext); - // Create a function template if we have a template parameter list - FunctionTemplateDecl *const TemplateMethod = TemplateParams ? - FunctionTemplateDecl::Create(Context, Class, - Method->getLocation(), MethodName, - TemplateParams, - Method) : nullptr; - if (TemplateMethod) { - TemplateMethod->setAccess(AS_public); - Method->setDescribedFunctionTemplate(TemplateMethod); - Class->addDecl(TemplateMethod); - TemplateMethod->setLexicalDeclContext(CurContext); - } - - // Add parameters. - if (!Params.empty()) { - Method->setParams(Params); - CheckParmsForFunctionDef(Params, - /*CheckParameterNames=*/false); - - for (auto *P : Method->parameters()) - P->setOwningFunction(Method); - } - - return Method; + return MethodType; } void Sema::handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, - std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) { - if (Mangling) { - bool HasKnownInternalLinkage; - unsigned ManglingNumber, DeviceManglingNumber; - Decl *ManglingContextDecl; - std::tie(HasKnownInternalLinkage, ManglingNumber, DeviceManglingNumber, - ManglingContextDecl) = *Mangling; - Class->setLambdaMangling(ManglingNumber, ManglingContextDecl, - HasKnownInternalLinkage); - Class->setDeviceLambdaManglingNumber(DeviceManglingNumber); + std::optional<CXXRecordDecl::LambdaNumbering> NumberingOverride) { + if (NumberingOverride) { + Class->setLambdaNumbering(*NumberingOverride); return; } + ContextRAII ManglingContext(*this, Class->getDeclContext()); + auto getMangleNumberingContext = [this](CXXRecordDecl *Class, Decl *ManglingContextDecl) -> MangleNumberingContext * { @@ -462,11 +402,10 @@ void Sema::handleLambdaNumbering( return &Context.getManglingNumberContext(DC); }; + CXXRecordDecl::LambdaNumbering Numbering; MangleNumberingContext *MCtx; - Decl *ManglingContextDecl; - std::tie(MCtx, ManglingContextDecl) = + std::tie(MCtx, Numbering.ContextDecl) = getCurrentMangleNumberContext(Class->getDeclContext()); - bool HasKnownInternalLinkage = false; if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice || getLangOpts().SYCLIsHost)) { // Force lambda numbering in CUDA/HIP as we need to name lambdas following @@ -476,26 +415,41 @@ void Sema::handleLambdaNumbering( // Also force for SYCL, since we need this for the // __builtin_sycl_unique_stable_name implementation, which depends on lambda // mangling. - MCtx = getMangleNumberingContext(Class, ManglingContextDecl); + MCtx = getMangleNumberingContext(Class, Numbering.ContextDecl); assert(MCtx && "Retrieving mangle numbering context failed!"); - HasKnownInternalLinkage = true; + Numbering.HasKnownInternalLinkage = true; } if (MCtx) { - unsigned ManglingNumber = MCtx->getManglingNumber(Method); - Class->setLambdaMangling(ManglingNumber, ManglingContextDecl, - HasKnownInternalLinkage); - Class->setDeviceLambdaManglingNumber(MCtx->getDeviceManglingNumber(Method)); + Numbering.IndexInContext = MCtx->getNextLambdaIndex(); + Numbering.ManglingNumber = MCtx->getManglingNumber(Method); + Numbering.DeviceManglingNumber = MCtx->getDeviceManglingNumber(Method); + Class->setLambdaNumbering(Numbering); + + if (auto *Source = + dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) + Source->AssignedLambdaNumbering(Class); + } +} + +static void buildLambdaScopeReturnType(Sema &S, LambdaScopeInfo *LSI, + CXXMethodDecl *CallOperator, + bool ExplicitResultType) { + if (ExplicitResultType) { + LSI->HasImplicitReturnType = false; + LSI->ReturnType = CallOperator->getReturnType(); + if (!LSI->ReturnType->isDependentType() && !LSI->ReturnType->isVoidType()) + S.RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType, + diag::err_lambda_incomplete_result); + } else { + LSI->HasImplicitReturnType = true; } } -void Sema::buildLambdaScope(LambdaScopeInfo *LSI, - CXXMethodDecl *CallOperator, - SourceRange IntroducerRange, - LambdaCaptureDefault CaptureDefault, - SourceLocation CaptureDefaultLoc, - bool ExplicitParams, - bool ExplicitResultType, - bool Mutable) { +void Sema::buildLambdaScope(LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, + bool ExplicitParams, bool Mutable) { LSI->CallOperator = CallOperator; CXXRecordDecl *LambdaClass = CallOperator->getParent(); LSI->Lambda = LambdaClass; @@ -507,30 +461,16 @@ void Sema::buildLambdaScope(LambdaScopeInfo *LSI, LSI->IntroducerRange = IntroducerRange; LSI->ExplicitParams = ExplicitParams; LSI->Mutable = Mutable; - - if (ExplicitResultType) { - LSI->ReturnType = CallOperator->getReturnType(); - - if (!LSI->ReturnType->isDependentType() && - !LSI->ReturnType->isVoidType()) { - if (RequireCompleteType(CallOperator->getBeginLoc(), LSI->ReturnType, - diag::err_lambda_incomplete_result)) { - // Do nothing. - } - } - } else { - LSI->HasImplicitReturnType = true; - } } void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) { LSI->finishedExplicitCaptures(); } -void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, - ArrayRef<NamedDecl *> TParams, - SourceLocation RAngleLoc, - ExprResult RequiresClause) { +void Sema::ActOnLambdaExplicitTemplateParameterList( + LambdaIntroducer &Intro, SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> TParams, SourceLocation RAngleLoc, + ExprResult RequiresClause) { LambdaScopeInfo *LSI = getCurLambda(); assert(LSI && "Expected a lambda scope"); assert(LSI->NumExplicitTemplateParams == 0 && @@ -546,35 +486,6 @@ void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, LSI->RequiresClause = RequiresClause; } -void Sema::addLambdaParameters( - ArrayRef<LambdaIntroducer::LambdaCapture> Captures, - CXXMethodDecl *CallOperator, Scope *CurScope) { - // Introduce our parameters into the function scope - for (unsigned p = 0, NumParams = CallOperator->getNumParams(); - p < NumParams; ++p) { - ParmVarDecl *Param = CallOperator->getParamDecl(p); - - // If this has an identifier, add it to the scope stack. - if (CurScope && Param->getIdentifier()) { - bool Error = false; - // Resolution of CWG 2211 in C++17 renders shadowing ill-formed, but we - // retroactively apply it. - for (const auto &Capture : Captures) { - if (Capture.Id == Param->getIdentifier()) { - Error = true; - Diag(Param->getLocation(), diag::err_parameter_shadow_capture); - Diag(Capture.Loc, diag::note_var_explicitly_captured_here) - << Capture.Id << true; - } - } - if (!Error) - CheckShadow(CurScope, Param); - - PushOnScopeChains(Param, CurScope); - } - } -} - /// If this expression is an enumerator-like expression of some type /// T, return the type T; otherwise, return null. /// @@ -861,11 +772,9 @@ QualType Sema::buildLambdaInitCaptureInitialization( return DeducedType; } -VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, - QualType InitCaptureType, - SourceLocation EllipsisLoc, - IdentifierInfo *Id, - unsigned InitStyle, Expr *Init) { +VarDecl *Sema::createLambdaInitCaptureVarDecl( + SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc, + IdentifierInfo *Id, unsigned InitStyle, Expr *Init, DeclContext *DeclCtx) { // FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization // rather than reconstructing it here. TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc); @@ -876,8 +785,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, // used as a variable, and only exists as a way to name and refer to the // init-capture. // FIXME: Pass in separate source locations for '&' and identifier. - VarDecl *NewVD = VarDecl::Create(Context, CurContext, Loc, - Loc, Id, InitCaptureType, TSI, SC_Auto); + VarDecl *NewVD = VarDecl::Create(Context, DeclCtx, Loc, Loc, Id, + InitCaptureType, TSI, SC_Auto); NewVD->setInitCapture(true); NewVD->setReferenced(true); // FIXME: Pass in a VarDecl::InitializationStyle. @@ -889,43 +798,53 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, return NewVD; } -void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var, - bool isReferenceType) { +void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var, bool ByRef) { assert(Var->isInitCapture() && "init capture flag should be set"); - LSI->addCapture(Var, /*isBlock*/ false, isReferenceType, - /*isNested*/ false, Var->getLocation(), SourceLocation(), - Var->getType(), /*Invalid*/ false); + LSI->addCapture(Var, /*isBlock=*/false, ByRef, + /*isNested=*/false, Var->getLocation(), SourceLocation(), + Var->getType(), /*Invalid=*/false); } -void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, - Declarator &ParamInfo, - Scope *CurScope) { - LambdaScopeInfo *const LSI = getCurLambda(); - assert(LSI && "LambdaScopeInfo should be on stack!"); +// Unlike getCurLambda, getCurrentLambdaScopeUnsafe doesn't +// check that the current lambda is in a consistent or fully constructed state. +static LambdaScopeInfo *getCurrentLambdaScopeUnsafe(Sema &S) { + assert(!S.FunctionScopes.empty()); + return cast<LambdaScopeInfo>(S.FunctionScopes[S.FunctionScopes.size() - 1]); +} - // Determine if we're within a context where we know that the lambda will - // be dependent, because there are template parameters in scope. - CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind = - CXXRecordDecl::LDK_Unknown; - if (LSI->NumExplicitTemplateParams > 0) { - auto *TemplateParamScope = CurScope->getTemplateParamParent(); - assert(TemplateParamScope && - "Lambda with explicit template param list should establish a " - "template param scope"); - assert(TemplateParamScope->getParent()); - if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr) - LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; - } else if (CurScope->getTemplateParamParent() != nullptr) { - LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; - } +static TypeSourceInfo * +getDummyLambdaType(Sema &S, SourceLocation Loc = SourceLocation()) { + // C++11 [expr.prim.lambda]p4: + // If a lambda-expression does not include a lambda-declarator, it is as + // if the lambda-declarator were (). + FunctionProtoType::ExtProtoInfo EPI(S.Context.getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true)); + EPI.HasTrailingReturn = true; + EPI.TypeQuals.addConst(); + LangAS AS = S.getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + EPI.TypeQuals.addAddressSpace(AS); + + // C++1y [expr.prim.lambda]: + // The lambda return type is 'auto', which is replaced by the + // trailing-return type if provided and/or deduced from 'return' + // statements + // We don't do this before C++1y, because we don't support deduced return + // types there. + QualType DefaultTypeForNoTrailingReturn = S.getLangOpts().CPlusPlus14 + ? S.Context.getAutoDeductType() + : S.Context.DependentTy; + QualType MethodTy = S.Context.getFunctionType(DefaultTypeForNoTrailingReturn, + std::nullopt, EPI); + return S.Context.getTrivialTypeSourceInfo(MethodTy, Loc); +} - // Determine the signature of the call operator. - TypeSourceInfo *MethodTyInfo; - bool ExplicitParams = true; - bool ExplicitResultType = true; - bool ContainsUnexpandedParameterPack = false; - SourceLocation EndLoc; - SmallVector<ParmVarDecl *, 8> Params; +static TypeSourceInfo *getLambdaType(Sema &S, LambdaIntroducer &Intro, + Declarator &ParamInfo, Scope *CurScope, + SourceLocation Loc, + bool &ExplicitResultType) { + + ExplicitResultType = false; assert( (ParamInfo.getDeclSpec().getStorageClassSpec() == @@ -935,146 +854,172 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, bool IsLambdaStatic = ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static; + TypeSourceInfo *MethodTyInfo; + if (ParamInfo.getNumTypeObjects() == 0) { - // C++11 [expr.prim.lambda]p4: - // If a lambda-expression does not include a lambda-declarator, it is as - // if the lambda-declarator were (). - FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention( - /*IsVariadic=*/false, /*IsCXXMethod=*/true)); - EPI.HasTrailingReturn = true; - EPI.TypeQuals.addConst(); - LangAS AS = getDefaultCXXMethodAddrSpace(); - if (AS != LangAS::Default) - EPI.TypeQuals.addAddressSpace(AS); - - // C++1y [expr.prim.lambda]: - // The lambda return type is 'auto', which is replaced by the - // trailing-return type if provided and/or deduced from 'return' - // statements - // We don't do this before C++1y, because we don't support deduced return - // types there. - QualType DefaultTypeForNoTrailingReturn = - getLangOpts().CPlusPlus14 ? Context.getAutoDeductType() - : Context.DependentTy; - QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn, - std::nullopt, EPI); - MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); - ExplicitParams = false; - ExplicitResultType = false; - EndLoc = Intro.Range.getEnd(); + MethodTyInfo = getDummyLambdaType(S, Loc); } else { - assert(ParamInfo.isFunctionDeclarator() && - "lambda-declarator is a function"); DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo(); - - // C++11 [expr.prim.lambda]p5: - // This function call operator is declared const (9.3.1) if and only if - // the lambda-expression's parameter-declaration-clause is not followed - // by mutable. It is neither virtual nor declared volatile. [...] - if (!FTI.hasMutableQualifier() && !IsLambdaStatic) { - FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, - SourceLocation()); - } - - MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); - assert(MethodTyInfo && "no type from lambda-declarator"); - EndLoc = ParamInfo.getSourceRange().getEnd(); - ExplicitResultType = FTI.hasTrailingReturnType(); + if (!FTI.hasMutableQualifier() && !IsLambdaStatic) + FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, Loc); - if (ExplicitResultType && getLangOpts().HLSL) { + if (ExplicitResultType && S.getLangOpts().HLSL) { QualType RetTy = FTI.getTrailingReturnType().get(); if (!RetTy.isNull()) { // HLSL does not support specifying an address space on a lambda return // type. LangAS AddressSpace = RetTy.getAddressSpace(); if (AddressSpace != LangAS::Default) - Diag(FTI.getTrailingReturnTypeLoc(), - diag::err_return_value_with_address_space); + S.Diag(FTI.getTrailingReturnTypeLoc(), + diag::err_return_value_with_address_space); } } - if (FTIHasNonVoidParameters(FTI)) { - Params.reserve(FTI.NumParams); - for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) - Params.push_back(cast<ParmVarDecl>(FTI.Params[i].Param)); - } + MethodTyInfo = S.GetTypeForDeclarator(ParamInfo, CurScope); + assert(MethodTyInfo && "no type from lambda-declarator"); // Check for unexpanded parameter packs in the method type. if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) - DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, - UPPC_DeclarationType); + S.DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo, + S.UPPC_DeclarationType); } + return MethodTyInfo; +} - CXXRecordDecl *Class = createLambdaClosureType( - Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default); - CXXMethodDecl *Method = - startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, - ParamInfo.getDeclSpec().getConstexprSpecifier(), - IsLambdaStatic ? SC_Static : SC_None, - ParamInfo.getTrailingRequiresClause()); - if (ExplicitParams) - CheckCXXDefaultArguments(Method); +CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange, + CXXRecordDecl *Class) { + + // C++20 [expr.prim.lambda.closure]p3: + // The closure type for a lambda-expression has a public inline function + // call operator (for a non-generic lambda) or function call operator + // template (for a generic lambda) whose parameters and return type are + // described by the lambda-expression's parameter-declaration-clause + // and trailing-return-type respectively. + DeclarationName MethodName = + Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclarationNameLoc MethodNameLoc = + DeclarationNameLoc::makeCXXOperatorNameLoc(IntroducerRange.getBegin()); + CXXMethodDecl *Method = CXXMethodDecl::Create( + Context, Class, SourceLocation(), + DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), + MethodNameLoc), + QualType(), /*Tinfo=*/nullptr, SC_None, + getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(), + /*TrailingRequiresClause=*/nullptr); + Method->setAccess(AS_public); + return Method; +} - // This represents the function body for the lambda function, check if we - // have to apply optnone due to a pragma. - AddRangeBasedOptnone(Method); +void Sema::CompleteLambdaCallOperator( + CXXMethodDecl *Method, SourceLocation LambdaLoc, + SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause, + TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind, + StorageClass SC, ArrayRef<ParmVarDecl *> Params, + bool HasExplicitResultType) { - // code_seg attribute on lambda apply to the method. - if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true)) - Method->addAttr(A); + LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); - // Attributes on the lambda apply to the method. - ProcessDeclAttributes(CurScope, Method, ParamInfo); + if (TrailingRequiresClause) + Method->setTrailingRequiresClause(TrailingRequiresClause); - // CUDA lambdas get implicit host and device attributes. - if (getLangOpts().CUDA) - CUDASetLambdaAttrs(Method); + TemplateParameterList *TemplateParams = + getGenericLambdaTemplateParameterList(LSI, *this); + + DeclContext *DC = Method->getLexicalDeclContext(); + Method->setLexicalDeclContext(LSI->Lambda); + if (TemplateParams) { + FunctionTemplateDecl *TemplateMethod = FunctionTemplateDecl::Create( + Context, LSI->Lambda, Method->getLocation(), Method->getDeclName(), + TemplateParams, Method); + TemplateMethod->setAccess(AS_public); + Method->setDescribedFunctionTemplate(TemplateMethod); + LSI->Lambda->addDecl(TemplateMethod); + TemplateMethod->setLexicalDeclContext(DC); + } else { + LSI->Lambda->addDecl(Method); + } + LSI->Lambda->setLambdaIsGeneric(TemplateParams); + LSI->Lambda->setLambdaTypeInfo(MethodTyInfo); + + Method->setLexicalDeclContext(DC); + Method->setLocation(LambdaLoc); + Method->setInnerLocStart(CallOperatorLoc); + Method->setTypeSourceInfo(MethodTyInfo); + Method->setType(buildTypeForLambdaCallOperator(*this, LSI->Lambda, + TemplateParams, MethodTyInfo)); + Method->setConstexprKind(ConstexprKind); + Method->setStorageClass(SC); + if (!Params.empty()) { + CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); + Method->setParams(Params); + for (auto P : Method->parameters()) { + assert(P && "null in a parameter list"); + P->setOwningFunction(Method); + } + } - // OpenMP lambdas might get assumumption attributes. - if (LangOpts.OpenMP) - ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method); + buildLambdaScopeReturnType(*this, LSI, Method, HasExplicitResultType); +} - // Number the lambda for linkage purposes if necessary. - handleLambdaNumbering(Class, Method); +void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, + Scope *CurrentScope) { - // Introduce the function call operator as the current declaration context. - PushDeclContext(CurScope, Method); + LambdaScopeInfo *LSI = getCurLambda(); + assert(LSI && "LambdaScopeInfo should be on stack!"); - // Build the lambda scope. - buildLambdaScope(LSI, Method, Intro.Range, Intro.Default, Intro.DefaultLoc, - ExplicitParams, ExplicitResultType, !Method->isConst()); + if (Intro.Default == LCD_ByCopy) + LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; + else if (Intro.Default == LCD_ByRef) + LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref; + LSI->CaptureDefaultLoc = Intro.DefaultLoc; + LSI->IntroducerRange = Intro.Range; + LSI->AfterParameterList = false; - // C++11 [expr.prim.lambda]p9: - // A lambda-expression whose smallest enclosing scope is a block scope is a - // local lambda expression; any other lambda expression shall not have a - // capture-default or simple-capture in its lambda-introducer. - // - // For simple-captures, this is covered by the check below that any named - // entity is a variable that can be captured. - // - // For DR1632, we also allow a capture-default in any context where we can - // odr-use 'this' (in particular, in a default initializer for a non-static - // data member). - if (Intro.Default != LCD_None && !Class->getParent()->isFunctionOrMethod() && - (getCurrentThisType().isNull() || - CheckCXXThisCapture(SourceLocation(), /*Explicit*/true, - /*BuildAndDiagnose*/false))) - Diag(Intro.DefaultLoc, diag::err_capture_default_non_local); + assert(LSI->NumExplicitTemplateParams == 0); + + // Determine if we're within a context where we know that the lambda will + // be dependent, because there are template parameters in scope. + CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind = + CXXRecordDecl::LDK_Unknown; + if (LSI->NumExplicitTemplateParams > 0) { + Scope *TemplateParamScope = CurScope->getTemplateParamParent(); + assert(TemplateParamScope && + "Lambda with explicit template param list should establish a " + "template param scope"); + assert(TemplateParamScope->getParent()); + if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr) + LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; + } else if (CurScope->getTemplateParamParent() != nullptr) { + LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent; + } + + CXXRecordDecl *Class = createLambdaClosureType( + Intro.Range, /*Info=*/nullptr, LambdaDependencyKind, Intro.Default); + LSI->Lambda = Class; + + CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class); + LSI->CallOperator = Method; + Method->setLexicalDeclContext(CurContext); + + PushDeclContext(CurScope, Method); + + bool ContainsUnexpandedParameterPack = false; // Distinct capture names, for diagnostics. - llvm::SmallSet<IdentifierInfo*, 8> CaptureNames; + llvm::DenseMap<IdentifierInfo *, ValueDecl *> CaptureNames; // Handle explicit captures. - SourceLocation PrevCaptureLoc - = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; + SourceLocation PrevCaptureLoc = + Intro.Default == LCD_None ? Intro.Range.getBegin() : Intro.DefaultLoc; for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; PrevCaptureLoc = C->Loc, ++C) { if (C->Kind == LCK_This || C->Kind == LCK_StarThis) { if (C->Kind == LCK_StarThis) Diag(C->Loc, !getLangOpts().CPlusPlus17 - ? diag::ext_star_this_lambda_capture_cxx17 - : diag::warn_cxx14_compat_star_this_lambda_capture); + ? diag::ext_star_this_lambda_capture_cxx17 + : diag::warn_cxx14_compat_star_this_lambda_capture); // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a @@ -1087,7 +1032,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // C++2a [expr.prim.lambda]p8: + // C++20 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is =, // each simple-capture of that lambda-capture shall be of the form // "&identifier", "this", or "* this". [ Note: The form [&,this] is @@ -1153,13 +1098,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(), C->EllipsisLoc, C->Id, InitStyle, - C->Init.get()); - // C++1y [expr.prim.lambda]p11: - // An init-capture behaves as if it declares and explicitly - // captures a variable [...] whose declarative region is the - // lambda-expression's compound-statement - if (Var) - PushOnScopeChains(Var, CurScope, false); + C->Init.get(), Method); + assert(Var && "createLambdaInitCaptureVarDecl returned a null VarDecl?"); + if (auto *V = dyn_cast<VarDecl>(Var)) + CheckShadow(CurrentScope, V); + PushOnScopeChains(Var, CurrentScope, false); } else { assert(C->InitKind == LambdaCaptureInitKind::NoInit && "init capture has valid but null init?"); @@ -1205,31 +1148,33 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + // C++11 [expr.prim.lambda]p10: + // [...] each such lookup shall find a variable with automatic storage + // duration declared in the reaching scope of the local lambda expression. + // Note that the 'reaching scope' check happens in tryCaptureVariable(). + if (!Var) { + Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; + continue; + } + // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. - if (!CaptureNames.insert(C->Id).second) { - if (Var && LSI->isCaptured(Var)) { + if (auto [It, Inserted] = CaptureNames.insert(std::pair{C->Id, Var}); + !Inserted) { + if (C->InitKind == LambdaCaptureInitKind::NoInit && + !Var->isInitCapture()) { Diag(C->Loc, diag::err_capture_more_than_once) - << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) + << C->Id << It->second->getBeginLoc() << FixItHint::CreateRemoval( SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); } else // Previous capture captured something different (one or both was - // an init-cpature): no fixit. + // an init-capture): no fixit. Diag(C->Loc, diag::err_capture_more_than_once) << C->Id; continue; } - // C++11 [expr.prim.lambda]p10: - // [...] each such lookup shall find a variable with automatic storage - // duration declared in the reaching scope of the local lambda expression. - // Note that the 'reaching scope' check happens in tryCaptureVariable(). - if (!Var) { - Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; - continue; - } - // Ignore invalid decls; they'll just confuse the code later. if (Var->isInvalidDecl()) continue; @@ -1261,20 +1206,214 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (C->Init.isUsable()) { addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef); + PushOnScopeChains(Var, CurScope, false); } else { - TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : - TryCapture_ExplicitByVal; + TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef + : TryCapture_ExplicitByVal; tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc); } if (!LSI->Captures.empty()) LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange; } finishLambdaExplicitCaptures(LSI); - LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; + PopDeclContext(); +} + +void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro, + SourceLocation MutableLoc) { + + LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); + LSI->Mutable = MutableLoc.isValid(); + ContextRAII Context(*this, LSI->CallOperator, /*NewThisContext*/ false); + + // C++11 [expr.prim.lambda]p9: + // A lambda-expression whose smallest enclosing scope is a block scope is a + // local lambda expression; any other lambda expression shall not have a + // capture-default or simple-capture in its lambda-introducer. + // + // For simple-captures, this is covered by the check below that any named + // entity is a variable that can be captured. + // + // For DR1632, we also allow a capture-default in any context where we can + // odr-use 'this' (in particular, in a default initializer for a non-static + // data member). + if (Intro.Default != LCD_None && + !LSI->Lambda->getParent()->isFunctionOrMethod() && + (getCurrentThisType().isNull() || + CheckCXXThisCapture(SourceLocation(), /*Explicit=*/true, + /*BuildAndDiagnose=*/false))) + Diag(Intro.DefaultLoc, diag::err_capture_default_non_local); +} - // Add lambda parameters into scope. - addLambdaParameters(Intro.Captures, Method, CurScope); +void Sema::ActOnLambdaClosureParameters( + Scope *LambdaScope, MutableArrayRef<DeclaratorChunk::ParamInfo> Params) { + LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); + PushDeclContext(LambdaScope, LSI->CallOperator); + + for (const DeclaratorChunk::ParamInfo &P : Params) { + auto *Param = cast<ParmVarDecl>(P.Param); + Param->setOwningFunction(LSI->CallOperator); + if (Param->getIdentifier()) + PushOnScopeChains(Param, LambdaScope, false); + } + + LSI->AfterParameterList = true; +} + +void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, + const DeclSpec &DS) { + + LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this); + LSI->CallOperator->setConstexprKind(DS.getConstexprSpecifier()); + + SmallVector<ParmVarDecl *, 8> Params; + bool ExplicitResultType; + + SourceLocation TypeLoc, CallOperatorLoc; + if (ParamInfo.getNumTypeObjects() == 0) { + CallOperatorLoc = TypeLoc = Intro.Range.getEnd(); + } else { + unsigned Index; + ParamInfo.isFunctionDeclarator(Index); + const auto &Object = ParamInfo.getTypeObject(Index); + TypeLoc = + Object.Loc.isValid() ? Object.Loc : ParamInfo.getSourceRange().getEnd(); + CallOperatorLoc = ParamInfo.getSourceRange().getEnd(); + } + + CXXRecordDecl *Class = LSI->Lambda; + CXXMethodDecl *Method = LSI->CallOperator; + + TypeSourceInfo *MethodTyInfo = getLambdaType( + *this, Intro, ParamInfo, getCurScope(), TypeLoc, ExplicitResultType); + + LSI->ExplicitParams = ParamInfo.getNumTypeObjects() != 0; + + if (ParamInfo.isFunctionDeclarator() != 0 && + !FTIHasSingleVoidParameter(ParamInfo.getFunctionTypeInfo())) { + const auto &FTI = ParamInfo.getFunctionTypeInfo(); + Params.reserve(Params.size()); + for (unsigned I = 0; I < FTI.NumParams; ++I) { + auto *Param = cast<ParmVarDecl>(FTI.Params[I].Param); + Param->setScopeInfo(0, Params.size()); + Params.push_back(Param); + } + } + + bool IsLambdaStatic = + ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static; + + CompleteLambdaCallOperator( + Method, Intro.Range.getBegin(), CallOperatorLoc, + ParamInfo.getTrailingRequiresClause(), MethodTyInfo, + ParamInfo.getDeclSpec().getConstexprSpecifier(), + IsLambdaStatic ? SC_Static : SC_None, Params, ExplicitResultType); + + 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); + + // CUDA lambdas get implicit host and device attributes. + if (getLangOpts().CUDA) + CUDASetLambdaAttrs(Method); + + // OpenMP lambdas might get assumumption attributes. + if (LangOpts.OpenMP) + ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Method); + + handleLambdaNumbering(Class, Method); + + for (auto &&C : LSI->Captures) { + if (!C.isVariableCapture()) + continue; + ValueDecl *Var = C.getVariable(); + if (Var && Var->isInitCapture()) { + PushOnScopeChains(Var, CurScope, false); + } + } + + auto CheckRedefinition = [&](ParmVarDecl *Param) { + for (const auto &Capture : Intro.Captures) { + if (Capture.Id == Param->getIdentifier()) { + Diag(Param->getLocation(), diag::err_parameter_shadow_capture); + Diag(Capture.Loc, diag::note_var_explicitly_captured_here) + << Capture.Id << true; + return false; + } + } + return true; + }; + + for (ParmVarDecl *P : Params) { + if (!P->getIdentifier()) + continue; + if (CheckRedefinition(P)) + CheckShadow(CurScope, P); + PushOnScopeChains(P, CurScope); + } + + // C++23 [expr.prim.lambda.capture]p5: + // If an identifier in a capture appears as the declarator-id of a parameter + // of the lambda-declarator's parameter-declaration-clause or as the name of a + // template parameter of the lambda-expression's template-parameter-list, the + // program is ill-formed. + TemplateParameterList *TemplateParams = + getGenericLambdaTemplateParameterList(LSI, *this); + if (TemplateParams) { + for (const auto *TP : TemplateParams->asArray()) { + if (!TP->getIdentifier()) + continue; + for (const auto &Capture : Intro.Captures) { + if (Capture.Id == TP->getIdentifier()) { + Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id; + Diag(TP->getLocation(), diag::note_template_param_here); + } + } + } + } + + // C++20: dcl.decl.general p4: + // The optional requires-clause ([temp.pre]) in an init-declarator or + // member-declarator shall be present only if the declarator declares a + // templated function ([dcl.fct]). + if (Expr *TRC = Method->getTrailingRequiresClause()) { + // [temp.pre]/8: + // An entity is templated if it is + // - a template, + // - an entity defined ([basic.def]) or created ([class.temporary]) in a + // templated entity, + // - a member of a templated entity, + // - an enumerator for an enumeration that is a templated entity, or + // - the closure type of a lambda-expression ([expr.prim.lambda.closure]) + // appearing in the declaration of a templated entity. [Note 6: A local + // class, a local or block variable, or a friend function defined in a + // templated entity is a templated entity. — end note] + // + // A templated function is a function template or a function that is + // templated. A templated class is a class template or a class that is + // templated. A templated variable is a variable template or a variable + // that is templated. + + // Note: we only have to check if this is defined in a template entity, OR + // if we are a template, since the rest don't apply. The requires clause + // applies to the call operator, which we already know is a member function, + // AND defined. + if (!Method->getDescribedFunctionTemplate() && !Method->isTemplated()) { + Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function); + } + } // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. @@ -1282,6 +1421,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, LSI->CallOperator->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext : ExpressionEvaluationContext::PotentiallyEvaluated); + ExprEvalContexts.back().InImmediateFunctionContext = + LSI->CallOperator->isConsteval(); + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = + getLangOpts().CPlusPlus20 && LSI->CallOperator->isImmediateEscalating(); } void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, @@ -1490,6 +1633,11 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, Conversion->setAccess(AS_public); Conversion->setImplicit(true); + // A non-generic lambda may still be a templated entity. We need to preserve + // constraints when converting the lambda to a function pointer. See GH63181. + if (Expr *Requires = CallOperator->getTrailingRequiresClause()) + Conversion->setTrailingRequiresClause(Requires); + if (Class->isGenericLambda()) { // Create a template version of the conversion operator, using the template // parameter list of the function call operator. @@ -1529,7 +1677,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc), InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static, S.getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprSpecKind::Unspecified, + /*isInline=*/true, CallOperator->getConstexprKind(), CallOperator->getBody()->getEndLoc()); for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) InvokerParams[I]->setOwningFunction(Invoke); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index b2e943699c5f..c4f4edb6666c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -199,7 +199,7 @@ namespace { const_iterator end() const { return list.end(); } llvm::iterator_range<const_iterator> - getNamespacesFor(DeclContext *DC) const { + getNamespacesFor(const DeclContext *DC) const { return llvm::make_range(std::equal_range(begin(), end(), DC->getPrimaryContext(), UnqualUsingEntry::Comparator())); @@ -351,12 +351,12 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Get a representative context for a declaration such that two declarations /// will have the same context if they were found within the same scope. -static DeclContext *getContextForScopeMatching(Decl *D) { +static const DeclContext *getContextForScopeMatching(const Decl *D) { // For function-local declarations, use that function as the context. This // doesn't account for scopes within the function; the caller must deal with // those. - DeclContext *DC = D->getLexicalDeclContext(); - if (DC->isFunctionOrMethod()) + if (const DeclContext *DC = D->getLexicalDeclContext(); + DC->isFunctionOrMethod()) return DC; // Otherwise, look at the semantic context of the declaration. The @@ -367,15 +367,16 @@ static DeclContext *getContextForScopeMatching(Decl *D) { /// 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) { + const NamedDecl *D, + const NamedDecl *Existing) { // When looking up redeclarations of a using declaration, prefer a using // shadow declaration over any other declaration of the same entity. if (Kind == Sema::LookupUsingDeclName && isa<UsingShadowDecl>(D) && !isa<UsingShadowDecl>(Existing)) return true; - auto *DUnderlying = D->getUnderlyingDecl(); - auto *EUnderlying = Existing->getUnderlyingDecl(); + const auto *DUnderlying = D->getUnderlyingDecl(); + const auto *EUnderlying = Existing->getUnderlyingDecl(); // If they have different underlying declarations, prefer a typedef over the // original type (this happens when two type declarations denote the same @@ -397,8 +398,8 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, // FIXME: In the presence of ambiguous default arguments, we should keep both, // so we can diagnose the ambiguity if the default argument is needed. // See C++ [over.match.best]p3. - if (auto *DFD = dyn_cast<FunctionDecl>(DUnderlying)) { - auto *EFD = cast<FunctionDecl>(EUnderlying); + if (const auto *DFD = dyn_cast<FunctionDecl>(DUnderlying)) { + const auto *EFD = cast<FunctionDecl>(EUnderlying); unsigned DMin = DFD->getMinRequiredArguments(); unsigned EMin = EFD->getMinRequiredArguments(); // If D has more default arguments, it is preferred. @@ -409,8 +410,8 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, } // Pick the template with more default template arguments. - if (auto *DTD = dyn_cast<TemplateDecl>(DUnderlying)) { - auto *ETD = cast<TemplateDecl>(EUnderlying); + if (const auto *DTD = dyn_cast<TemplateDecl>(DUnderlying)) { + const auto *ETD = cast<TemplateDecl>(EUnderlying); unsigned DMin = DTD->getTemplateParameters()->getMinRequiredArguments(); unsigned EMin = ETD->getTemplateParameters()->getMinRequiredArguments(); // If D has more default arguments, it is preferred. Note that default @@ -433,8 +434,8 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, // VarDecl can have incomplete array types, prefer the one with more complete // array type. - if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) { - VarDecl *EVD = cast<VarDecl>(EUnderlying); + if (const auto *DVD = dyn_cast<VarDecl>(DUnderlying)) { + const auto *EVD = cast<VarDecl>(EUnderlying); if (EVD->getType()->isIncompleteType() && !DVD->getType()->isIncompleteType()) { // Prefer the decl with a more complete type if visible. @@ -451,7 +452,7 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, } // Pick the newer declaration; it might have a more precise type. - for (Decl *Prev = DUnderlying->getPreviousDecl(); Prev; + for (const Decl *Prev = DUnderlying->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) if (Prev == EUnderlying) return true; @@ -459,7 +460,7 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, } /// Determine whether \p D can hide a tag declaration. -static bool canHideTag(NamedDecl *D) { +static bool canHideTag(const NamedDecl *D) { // C++ [basic.scope.declarative]p4: // Given a set of declarations in a single declarative region [...] // exactly one declaration shall declare a class name or enumeration name @@ -492,7 +493,7 @@ void LookupResult::resolveKind() { // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { - NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); + const NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); if (isa<FunctionTemplateDecl>(D)) ResultKind = FoundOverloaded; else if (isa<UnresolvedUsingValueDecl>(D)) @@ -503,37 +504,58 @@ void LookupResult::resolveKind() { // Don't do any extra resolution if we've already resolved as ambiguous. if (ResultKind == Ambiguous) return; - llvm::SmallDenseMap<NamedDecl*, unsigned, 16> Unique; + llvm::SmallDenseMap<const NamedDecl *, unsigned, 16> Unique; llvm::SmallDenseMap<QualType, unsigned, 16> UniqueTypes; bool Ambiguous = false; bool HasTag = false, HasFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; - NamedDecl *HasNonFunction = nullptr; - - llvm::SmallVector<NamedDecl*, 4> EquivalentNonFunctions; + const NamedDecl *HasNonFunction = nullptr; - unsigned UniqueTagIndex = 0; + llvm::SmallVector<const NamedDecl *, 4> EquivalentNonFunctions; + llvm::BitVector RemovedDecls(N); - unsigned I = 0; - while (I < N) { - NamedDecl *D = Decls[I]->getUnderlyingDecl(); + for (unsigned I = 0; I < N; I++) { + const NamedDecl *D = Decls[I]->getUnderlyingDecl(); D = cast<NamedDecl>(D->getCanonicalDecl()); // Ignore an invalid declaration unless it's the only one left. // Also ignore HLSLBufferDecl which not have name conflict with other Decls. - if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) { - Decls[I] = Decls[--N]; + if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && + N - RemovedDecls.count() > 1) { + RemovedDecls.set(I); continue; } + // C++ [basic.scope.hiding]p2: + // A class name or enumeration name can be hidden by the name of + // an object, function, or enumerator declared in the same + // scope. If a class or enumeration name and an object, function, + // or enumerator are declared in the same scope (in any order) + // with the same name, the class or enumeration name is hidden + // wherever the object, function, or enumerator name is visible. + if (HideTags && isa<TagDecl>(D)) { + bool Hidden = false; + for (auto *OtherDecl : Decls) { + if (canHideTag(OtherDecl) && + getContextForScopeMatching(OtherDecl)->Equals( + getContextForScopeMatching(Decls[I]))) { + RemovedDecls.set(I); + Hidden = true; + break; + } + } + if (Hidden) + continue; + } + std::optional<unsigned> ExistingI; // Redeclarations of types via typedef can occur both within a scope // and, through using declarations and directives, across scopes. There is // no ambiguity if they all refer to the same type, so unique based on the // canonical type. - if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) { + if (const auto *TD = dyn_cast<TypeDecl>(D)) { QualType T = getSema().Context.getTypeDeclType(TD); auto UniqueResult = UniqueTypes.insert( std::make_pair(getSema().Context.getCanonicalType(T), I)); @@ -559,7 +581,7 @@ void LookupResult::resolveKind() { if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I], Decls[*ExistingI])) Decls[*ExistingI] = Decls[I]; - Decls[I] = Decls[--N]; + RemovedDecls.set(I); continue; } @@ -570,7 +592,6 @@ void LookupResult::resolveKind() { } else if (isa<TagDecl>(D)) { if (HasTag) Ambiguous = true; - UniqueTagIndex = I; HasTag = true; } else if (isa<FunctionTemplateDecl>(D)) { HasFunction = true; @@ -586,7 +607,7 @@ void LookupResult::resolveKind() { if (getSema().isEquivalentInternalLinkageDeclaration(HasNonFunction, D)) { EquivalentNonFunctions.push_back(D); - Decls[I] = Decls[--N]; + RemovedDecls.set(I); continue; } @@ -594,28 +615,6 @@ void LookupResult::resolveKind() { } HasNonFunction = D; } - I++; - } - - // C++ [basic.scope.hiding]p2: - // A class name or enumeration name can be hidden by the name of - // an object, function, or enumerator declared in the same - // scope. If a class or enumeration name and an object, function, - // or enumerator are declared in the same scope (in any order) - // with the same name, the class or enumeration name is hidden - // wherever the object, function, or enumerator name is visible. - // But it's still an error if there are distinct tag types found, - // even if they're not visible. (ref?) - if (N > 1 && HideTags && HasTag && !Ambiguous && - (HasFunction || HasNonFunction || HasUnresolved)) { - NamedDecl *OtherDecl = Decls[UniqueTagIndex ? 0 : N - 1]; - if (isa<TagDecl>(Decls[UniqueTagIndex]->getUnderlyingDecl()) && - getContextForScopeMatching(Decls[UniqueTagIndex])->Equals( - getContextForScopeMatching(OtherDecl)) && - canHideTag(OtherDecl)) - Decls[UniqueTagIndex] = Decls[--N]; - else - Ambiguous = true; } // FIXME: This diagnostic should really be delayed until we're done with @@ -624,9 +623,15 @@ void LookupResult::resolveKind() { getSema().diagnoseEquivalentInternalLinkageDeclarations( getNameLoc(), HasNonFunction, EquivalentNonFunctions); + // Remove decls by replacing them with decls from the end (which + // means that we need to iterate from the end) and then truncating + // to the new size. + for (int I = RemovedDecls.find_last(); I >= 0; I = RemovedDecls.find_prev(I)) + Decls[I] = Decls[--N]; Decls.truncate(N); - if (HasNonFunction && (HasFunction || HasUnresolved)) + if ((HasNonFunction && (HasFunction || HasUnresolved)) || + (HideTags && HasTag && (HasFunction || HasNonFunction || HasUnresolved))) Ambiguous = true; if (Ambiguous) @@ -932,10 +937,12 @@ bool Sema::LookupBuiltin(LookupResult &R) { } } - if (DeclareRISCVVBuiltins) { + if (DeclareRISCVVBuiltins || DeclareRISCVSiFiveVectorBuiltins) { if (!RVIntrinsicManager) RVIntrinsicManager = CreateRISCVIntrinsicManager(*this); + RVIntrinsicManager->InitIntrinsicList(); + if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP)) return true; } @@ -1197,9 +1204,9 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { } // Performs C++ unqualified lookup into the given file context. -static bool -CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, - DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { +static bool CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, + const DeclContext *NS, + UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); @@ -1333,8 +1340,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) - if (CXXRecordDecl *Record = - dyn_cast_or_null<CXXRecordDecl>(S->getEntity())) + if (auto *Record = dyn_cast_if_present<CXXRecordDecl>(S->getEntity())) R.setNamingClass(Record); return true; } @@ -1579,7 +1585,8 @@ bool Sema::isUsableModule(const Module *M) { // [module.global.frag]p1: // The global module fragment can be used to provide declarations that are // attached to the global module and usable within the module unit. - if (M == GlobalModuleFragment || + if (M == TheGlobalModuleFragment || M == TheImplicitGlobalModuleFragment || + M == TheExportedImplicitGlobalModuleFragment || // If M is the module we're parsing, it should be usable. This covers the // private module fragment. The private module fragment is usable only if // it is within the current module unit. And it must be the current @@ -1602,14 +1609,14 @@ bool Sema::isUsableModule(const Module *M) { return false; } -bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { +bool Sema::hasVisibleMergedDefinition(const NamedDecl *Def) { for (const Module *Merged : Context.getModulesWithMergedDefinition(Def)) if (isModuleVisible(Merged)) return true; return false; } -bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) { +bool Sema::hasMergedDefinitionInCurrentModule(const NamedDecl *Def) { for (const Module *Merged : Context.getModulesWithMergedDefinition(Def)) if (isUsableModule(Merged)) return true; @@ -1858,19 +1865,6 @@ bool LookupResult::isAcceptableSlow(Sema &SemaRef, NamedDecl *D, } bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) { - // [module.global.frag]p2: - // A global-module-fragment specifies the contents of the global module - // fragment for a module unit. The global module fragment can be used to - // provide declarations that are attached to the global module and usable - // within the module unit. - // - // Global module fragment is special. Global Module fragment is only usable - // within the module unit it got defined [module.global.frag]p2. So here we - // check if the Module is the global module fragment in current translation - // unit. - if (M->isGlobalModule() && M != this->GlobalModuleFragment) - return false; - // The module might be ordinarily visible. For a module-private query, that // means it is part of the current module. if (ModulePrivate && isUsableModule(M)) @@ -1893,6 +1887,12 @@ bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) { if (LookupModules.count(M)) return true; + // The global module fragments are visible to its corresponding module unit. + // So the global module fragment should be visible if the its corresponding + // module unit is visible. + if (M->isGlobalModule() && LookupModules.count(M->getTopLevelModule())) + return true; + // For a module-private query, that's everywhere we get to look. if (ModulePrivate) return false; @@ -1911,14 +1911,11 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); - // Entities in module map modules are reachable only if they're visible. - if (DeclModule->isModuleMapModule()) + // Entities in header like modules are reachable only if they're visible. + if (DeclModule->isHeaderLikeModule()) return false; - // If D comes from a module and SemaRef doesn't own a module, it implies D - // comes from another TU. In case SemaRef owns a module, we could judge if D - // comes from another TU by comparing the module unit. - if (SemaRef.isModuleUnitOfCurrentTU(DeclModule)) + if (!D->isInAnotherModuleUnit()) return true; // [module.reach]/p3: @@ -2433,8 +2430,9 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool oldVal; DeclContext *Context; // Set flag in DeclContext informing debugger that we're looking for qualified name - QualifiedLookupInScope(DeclContext *ctx) : Context(ctx) { - oldVal = ctx->setUseQualifiedLookup(); + QualifiedLookupInScope(DeclContext *ctx) + : oldVal(ctx->shouldUseQualifiedLookup()), Context(ctx) { + ctx->setUseQualifiedLookup(); } ~QualifiedLookupInScope() { Context->setUseQualifiedLookup(oldVal); @@ -3767,8 +3765,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, // operator template, but not both. if (FoundRaw && FoundTemplate) { Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - NoteOverloadCandidate(*I, (*I)->getUnderlyingDecl()->getAsFunction()); + for (const NamedDecl *D : R) + NoteOverloadCandidate(D, D->getUnderlyingDecl()->getAsFunction()); return LOLR_Error; } @@ -3883,10 +3881,14 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, if (isVisible(D)) { Visible = true; break; - } else if (getLangOpts().CPlusPlusModules && - D->isInExportDeclContext()) { - // C++20 [basic.lookup.argdep] p4.3 .. are exported ... + } + + if (!getLangOpts().CPlusPlusModules) + continue; + + if (D->isInExportDeclContext()) { Module *FM = D->getOwningModule(); + // C++20 [basic.lookup.argdep] p4.3 .. are exported ... // exports are only valid in module purview and outside of any // PMF (although a PMF should not even be present in a module // with an import). @@ -3894,14 +3896,12 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, "bad export context"); // .. are attached to a named module M, do not appear in the // translation unit containing the point of the lookup.. - if (!isModuleUnitOfCurrentTU(FM) && + if (D->isInAnotherModuleUnit() && llvm::any_of(AssociatedClasses, [&](auto *E) { // ... and have the same innermost enclosing non-inline // namespace scope as a declaration of an associated entity // attached to M - if (!E->hasOwningModule() || - E->getOwningModule()->getTopLevelModuleName() != - FM->getTopLevelModuleName()) + if (E->getOwningModule() != FM) return false; // TODO: maybe this could be cached when generating the // associated namespaces / entities. @@ -4155,22 +4155,21 @@ private: // Enumerate all of the results in this context. for (DeclContextLookupResult R : Load ? Ctx->lookups() - : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { - for (auto *D : R) { - if (auto *ND = Result.getAcceptableDecl(D)) { - // Rather than visit immediately, we put ND into a vector and visit - // all decls, in order, outside of this loop. The reason is that - // Consumer.FoundDecl() may invalidate the iterators used in the two - // loops above. - DeclsToVisit.push_back(ND); - } + : Ctx->noload_lookups(/*PreserveInternalState=*/false)) + for (auto *D : R) + // Rather than visit immediately, we put ND into a vector and visit + // all decls, in order, outside of this loop. The reason is that + // Consumer.FoundDecl() and LookupResult::getAcceptableDecl(D) + // may invalidate the iterators used in the two + // loops above. + DeclsToVisit.push_back(D); + + for (auto *D : DeclsToVisit) + if (auto *ND = Result.getAcceptableDecl(D)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); + Visited.add(ND); } - } - for (auto *ND : DeclsToVisit) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); - Visited.add(ND); - } DeclsToVisit.clear(); // Traverse using directives for qualified name lookup. @@ -5615,15 +5614,15 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { // unless the method being corrected--or the current DeclContext, if the // function being corrected is not a method--is a method in the same class // or a descendent class of the candidate's parent class. - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MemberFn || !MD->isStatic()) { - CXXMethodDecl *CurMD = + const auto *CurMD = MemberFn - ? dyn_cast_or_null<CXXMethodDecl>(MemberFn->getMemberDecl()) - : dyn_cast_or_null<CXXMethodDecl>(CurContext); - CXXRecordDecl *CurRD = + ? dyn_cast_if_present<CXXMethodDecl>(MemberFn->getMemberDecl()) + : dyn_cast_if_present<CXXMethodDecl>(CurContext); + const CXXRecordDecl *CurRD = CurMD ? CurMD->getParent()->getCanonicalDecl() : nullptr; - CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); + const CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); if (!CurRD || (CurRD != RD && !CurRD->isDerivedFrom(RD))) continue; } @@ -5642,28 +5641,28 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, /// Find which declaration we should import to provide the definition of /// the given declaration. -static NamedDecl *getDefinitionToImport(NamedDecl *D) { - if (VarDecl *VD = dyn_cast<VarDecl>(D)) +static const NamedDecl *getDefinitionToImport(const NamedDecl *D) { + if (const auto *VD = dyn_cast<VarDecl>(D)) return VD->getDefinition(); - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (const auto *FD = dyn_cast<FunctionDecl>(D)) return FD->getDefinition(); - if (TagDecl *TD = dyn_cast<TagDecl>(D)) + if (const auto *TD = dyn_cast<TagDecl>(D)) return TD->getDefinition(); - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) return ID->getDefinition(); - if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) + if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D)) return PD->getDefinition(); - if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) - if (NamedDecl *TTD = TD->getTemplatedDecl()) + if (const auto *TD = dyn_cast<TemplateDecl>(D)) + if (const NamedDecl *TTD = TD->getTemplatedDecl()) return getDefinitionToImport(TTD); return nullptr; } -void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, +void Sema::diagnoseMissingImport(SourceLocation Loc, const NamedDecl *Decl, MissingImportKind MIK, bool Recover) { // Suggest importing a module providing the definition of this entity, if // possible. - NamedDecl *Def = getDefinitionToImport(Decl); + const NamedDecl *Def = getDefinitionToImport(Decl); if (!Def) Def = Decl; @@ -5689,7 +5688,7 @@ static std::string getHeaderNameForHeader(Preprocessor &PP, const FileEntry *E, return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"'); } -void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, +void Sema::diagnoseMissingImport(SourceLocation UseLoc, const NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef<Module *> Modules, MissingImportKind MIK, bool Recover) { @@ -5740,7 +5739,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, if (Modules.size() > 1) { std::string ModuleList; unsigned N = 0; - for (Module *M : Modules) { + for (const auto *M : Modules) { ModuleList += "\n "; if (++N == 5 && N != Modules.size()) { ModuleList += "[...]"; @@ -5843,3 +5842,7 @@ void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) { LookupName(R, S); R.dump(); } + +void Sema::ActOnPragmaDump(Expr *E) { + E->dump(); +} diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index f52c0247f01c..cd38cd4cf69d 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -15,6 +15,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/StringExtras.h" #include <optional> using namespace clang; @@ -74,20 +75,9 @@ static std::string stringFromPath(ModuleIdPath Path) { Sema::DeclGroupPtrTy Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) { - if (!ModuleScopes.empty() && - ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) { - // Under -std=c++2a -fmodules-ts, we can find an explicit 'module;' after - // already implicitly entering the global module fragment. That's OK. - assert(getLangOpts().CPlusPlusModules && getLangOpts().ModulesTS && - "unexpectedly encountered multiple global module fragment decls"); - ModuleScopes.back().BeginLoc = ModuleLoc; - return nullptr; - } - - // We start in the global module; all those declarations are implicitly - // module-private (though they do not have module linkage). + // We start in the global module; Module *GlobalModule = - PushGlobalModuleFragment(ModuleLoc, /*IsImplicit=*/false); + PushGlobalModuleFragment(ModuleLoc); // All declarations created from now on are owned by the global module. auto *TU = Context.getTranslationUnitDecl(); @@ -135,7 +125,6 @@ void Sema::HandleStartOfHeaderUnit() { ModuleScopes.back().BeginLoc = StartOfTU; ModuleScopes.back().Module = Mod; ModuleScopes.back().ModuleInterface = true; - ModuleScopes.back().IsPartition = false; VisibleModules.setVisible(Mod, StartOfTU); // From now on, we have an owning module for all declarations we see. @@ -168,19 +157,24 @@ static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II, if (Reason == Reserved && S.getSourceManager().isInSystemHeader(Loc)) Reason = Valid; - if (Reason != Valid) { - S.Diag(Loc, diag::err_invalid_module_name) << II << (int)Reason; - return true; + switch (Reason) { + case Valid: + return false; + case Invalid: + return S.Diag(Loc, diag::err_invalid_module_name) << II; + case Reserved: + S.Diag(Loc, diag::warn_reserved_module_name) << II; + return false; } - return false; + llvm_unreachable("fell off a fully covered switch"); } Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, ModuleIdPath Partition, ModuleImportState &ImportState) { - assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) && - "should only have module decl in Modules TS or C++20"); + assert(getLangOpts().CPlusPlusModules && + "should only have module decl in standard C++ modules"); bool IsFirstDecl = ImportState == ModuleImportState::FirstDecl; bool SeenGMF = ImportState == ModuleImportState::GlobalFragment; @@ -244,8 +238,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, return nullptr; } - assert((!getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS || - SeenGMF == (bool)this->GlobalModuleFragment) && + assert((!getLangOpts().CPlusPlusModules || + SeenGMF == (bool)this->TheGlobalModuleFragment) && "mismatched global module state"); // In C++20, the module-declaration must be the first declaration if there @@ -262,7 +256,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, } } - // C++2b [module.unit]p1: ... The identifiers module and import shall not + // C++23 [module.unit]p1: ... The identifiers module and import shall not // appear as identifiers in a module-name or module-partition. All // module-names either beginning with an identifier consisting of std // followed by zero or more digits or containing a reserved identifier @@ -275,11 +269,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, if (!getSourceManager().isInSystemHeader(Path[0].second) && (FirstComponentName == "std" || (FirstComponentName.startswith("std") && - llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) { - Diag(Path[0].second, diag::err_invalid_module_name) - << Path[0].first << /*reserved*/ 1; - return nullptr; - } + llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) + Diag(Path[0].second, diag::warn_reserved_module_name) << Path[0].first; // Then test all of the components in the path to see if any of them are // using another kind of reserved or invalid identifier. @@ -310,8 +301,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - Module *Mod; - + Module *Mod; // The module we are creating. + Module *Interface = nullptr; // The interface for an implementation. switch (MDK) { case ModuleDeclKind::Interface: case ModuleDeclKind::PartitionInterface: { @@ -337,19 +328,29 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, } case ModuleDeclKind::Implementation: { - std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( - PP.getIdentifierInfo(ModuleName), Path[0].second); // C++20 A module-declaration that contains neither an export- // keyword nor a module-partition implicitly imports the primary // module interface unit of the module as if by a module-import- // declaration. - Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, - Module::AllVisible, - /*IsInclusionDirective=*/false); - if (!Mod) { + std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( + PP.getIdentifierInfo(ModuleName), Path[0].second); + + // The module loader will assume we're trying to import the module that + // we're building if `LangOpts.CurrentModule` equals to 'ModuleName'. + // Change the value for `LangOpts.CurrentModule` temporarily to make the + // module loader work properly. + const_cast<LangOptions &>(getLangOpts()).CurrentModule = ""; + Interface = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, + Module::AllVisible, + /*IsInclusionDirective=*/false); + const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; + + if (!Interface) { Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; // Create an empty module interface unit for error recovery. Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + } else { + Mod = Map.createModuleForImplementationUnit(ModuleLoc, ModuleName); } } break; @@ -361,7 +362,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, break; } - if (!this->GlobalModuleFragment) { + if (!this->TheGlobalModuleFragment) { ModuleScopes.push_back({}); if (getLangOpts().ModulesLocalVisibility) ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); @@ -374,7 +375,6 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleScopes.back().BeginLoc = StartLoc; ModuleScopes.back().Module = Mod; ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation; - ModuleScopes.back().IsPartition = IsPartition; VisibleModules.setVisible(Mod, ModuleLoc); // From now on, we have an owning module for all declarations we see. @@ -390,17 +390,32 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // statements, so imports are allowed. ImportState = ModuleImportState::ImportAllowed; - // For an implementation, We already made an implicit import (its interface). - // Make and return the import decl to be added to the current TU. - if (MDK == ModuleDeclKind::Implementation) { - // Make the import decl for the interface. - ImportDecl *Import = - ImportDecl::Create(Context, CurContext, ModuleLoc, Mod, Path[0].second); - // and return it to be added. + getASTContext().setCurrentNamedModule(Mod); + + // We already potentially made an implicit import (in the case of a module + // implementation unit importing its interface). Make this module visible + // and return the import decl to be added to the current TU. + if (Interface) { + + VisibleModules.setVisible(Interface, ModuleLoc); + VisibleModules.makeTransitiveImportsVisible(Interface, ModuleLoc); + + // Make the import decl for the interface in the impl module. + ImportDecl *Import = ImportDecl::Create(Context, CurContext, ModuleLoc, + Interface, Path[0].second); + CurContext->addDecl(Import); + + // Sequence initialization of the imported module before that of the current + // module, if any. + Context.addModuleInitializer(ModuleScopes.back().Module, Import); + Mod->Imports.insert(Interface); // As if we imported it. + // Also save this as a shortcut to checking for decls in the interface + ThePrimaryInterface = Interface; + // If we made an implicit import of the module interface, then return the + // imported module decl. return ConvertDeclToDeclGroup(Import); } - // FIXME: Create a ModuleDecl. return nullptr; } @@ -410,10 +425,11 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, // C++20 [basic.link]/2: // A private-module-fragment shall appear only in a primary module // interface unit. - switch (ModuleScopes.empty() ? Module::GlobalModuleFragment + switch (ModuleScopes.empty() ? Module::ExplicitGlobalModuleFragment : ModuleScopes.back().Module->Kind) { case Module::ModuleMapModule: - case Module::GlobalModuleFragment: + case Module::ExplicitGlobalModuleFragment: + case Module::ImplicitGlobalModuleFragment: case Module::ModulePartitionImplementation: case Module::ModulePartitionInterface: case Module::ModuleHeaderUnit: @@ -425,19 +441,17 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition); return nullptr; - case Module::ModuleInterfaceUnit: - break; - } - - if (!ModuleScopes.back().ModuleInterface) { + case Module::ModuleImplementationUnit: Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); Diag(ModuleScopes.back().BeginLoc, diag::note_not_module_interface_add_export) << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); return nullptr; + + case Module::ModuleInterfaceUnit: + break; } - // FIXME: Check this isn't a module interface partition. // FIXME: Check that this translation unit does not import any partitions; // such imports would violate [basic.link]/2's "shall be the only module unit" // restriction. @@ -473,9 +487,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, ModuleIdPath Path, bool IsPartition) { - - bool Cxx20Mode = getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS; - assert((!IsPartition || Cxx20Mode) && "partition seen in non-C++20 code?"); + assert((!IsPartition || getLangOpts().CPlusPlusModules) && + "partition seen in non-C++20 code?"); // For a C++20 module name, flatten into a single identifier with the source // location of the first component. @@ -493,7 +506,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, ModuleName += stringFromPath(Path); ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; Path = ModuleIdPath(ModuleNameLoc); - } else if (Cxx20Mode) { + } else if (getLangOpts().CPlusPlusModules) { ModuleName = stringFromPath(Path); ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second}; Path = ModuleIdPath(ModuleNameLoc); @@ -533,6 +546,9 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, Module *Mod, ModuleIdPath Path) { + if (Mod->isHeaderUnit()) + Diag(ImportLoc, diag::warn_experimental_header_unit); + VisibleModules.setVisible(Mod, ImportLoc); checkModuleImportContext(*this, Mod, ImportLoc, CurContext); @@ -541,8 +557,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. // FIXME: Should we warn on a redundant import of the current module? - if (Mod->isForBuilding(getLangOpts()) && - (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { + if (Mod->isForBuilding(getLangOpts())) { Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import : diag::err_module_import_in_implementation) @@ -602,16 +617,9 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // [module.interface]p1: // An export-declaration shall inhabit a namespace scope and appear in the // purview of a module interface unit. - Diag(ExportLoc, diag::err_export_not_in_module_interface) - << (!ModuleScopes.empty() && - !ModuleScopes.back().ImplicitGlobalModuleFragment); + Diag(ExportLoc, diag::err_export_not_in_module_interface); } - // In some cases we need to know if an entity was present in a directly- - // imported module (as opposed to a transitive import). This avoids - // searching both Imports and Exports. - DirectModuleImports.insert(Mod); - return Import; } @@ -630,11 +638,9 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { TUKind == TU_Module && getSourceManager().isWrittenInMainFile(DirectiveLoc); - bool ShouldAddImport = !IsInModuleIncludes; - - // If this module import was due to an inclusion directive, create an - // implicit import declaration to capture it in the AST. - if (ShouldAddImport) { + // If we are really importing a module (not just checking layering) due to an + // #include in the main file, synthesize an ImportDecl. + if (getLangOpts().Modules && !IsInModuleIncludes) { TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, DirectiveLoc, Mod, @@ -810,76 +816,22 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, return D; } -static bool checkExportedDeclContext(Sema &S, DeclContext *DC, - SourceLocation BlockStart); - -namespace { -enum class UnnamedDeclKind { - Empty, - StaticAssert, - Asm, - UsingDirective, - Namespace, - Context -}; -} - -static std::optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { - if (isa<EmptyDecl>(D)) - return UnnamedDeclKind::Empty; - if (isa<StaticAssertDecl>(D)) - return UnnamedDeclKind::StaticAssert; - if (isa<FileScopeAsmDecl>(D)) - return UnnamedDeclKind::Asm; - if (isa<UsingDirectiveDecl>(D)) - return UnnamedDeclKind::UsingDirective; - // Everything else either introduces one or more names or is ill-formed. - return std::nullopt; -} - -unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { - switch (UDK) { - case UnnamedDeclKind::Empty: - case UnnamedDeclKind::StaticAssert: - // Allow empty-declarations and static_asserts in an export block as an - // extension. - return InBlock ? diag::ext_export_no_name_block : diag::err_export_no_name; +static bool checkExportedDecl(Sema &, Decl *, SourceLocation); - case UnnamedDeclKind::UsingDirective: - // Allow exporting using-directives as an extension. - return diag::ext_export_using_directive; - - case UnnamedDeclKind::Namespace: - // Anonymous namespace with no content. - return diag::introduces_no_names; - - case UnnamedDeclKind::Context: - // Allow exporting DeclContexts that transitively contain no declarations - // as an extension. - return diag::ext_export_no_names; - - case UnnamedDeclKind::Asm: - return diag::err_export_no_name; - } - llvm_unreachable("unknown kind"); -} - -static void diagExportedUnnamedDecl(Sema &S, UnnamedDeclKind UDK, Decl *D, - SourceLocation BlockStart) { - S.Diag(D->getLocation(), getUnnamedDeclDiag(UDK, BlockStart.isValid())) - << (unsigned)UDK; - if (BlockStart.isValid()) - S.Diag(BlockStart, diag::note_export); +/// Check that it's valid to export all the declarations in \p DC. +static bool checkExportedDeclContext(Sema &S, DeclContext *DC, + SourceLocation BlockStart) { + bool AllUnnamed = true; + for (auto *D : DC->decls()) + AllUnnamed &= checkExportedDecl(S, D, BlockStart); + return AllUnnamed; } /// Check that it's valid to export \p D. static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { - // C++2a [module.interface]p3: - // An exported declaration shall declare at least one name - if (auto UDK = getUnnamedDeclKind(D)) - diagExportedUnnamedDecl(S, *UDK, D, BlockStart); - // [...] shall not declare a name with internal linkage. + // C++20 [module.interface]p3: + // [...] it shall not declare a name with internal linkage. bool HasName = false; if (auto *ND = dyn_cast<NamedDecl>(D)) { // Don't diagnose anonymous union objects; we'll diagnose their members @@ -889,6 +841,7 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { S.Diag(ND->getLocation(), diag::err_export_internal) << ND; if (BlockStart.isValid()) S.Diag(BlockStart, diag::note_export); + return false; } } @@ -904,31 +857,29 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) { S.Diag(Target->getLocation(), diag::note_using_decl_target); if (BlockStart.isValid()) S.Diag(BlockStart, diag::note_export); + return false; } } // Recurse into namespace-scope DeclContexts. (Only namespace-scope - // declarations are exported.). + // declarations are exported). if (auto *DC = dyn_cast<DeclContext>(D)) { - if (isa<NamespaceDecl>(D) && DC->decls().empty()) { - if (!HasName) - // We don't allow an empty anonymous namespace (we don't allow decls - // in them either, but that's handled in the recursion). - diagExportedUnnamedDecl(S, UnnamedDeclKind::Namespace, D, BlockStart); - // We allow an empty named namespace decl. - } else if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D)) - return checkExportedDeclContext(S, DC, BlockStart); - } - return false; -} - -/// Check that it's valid to export all the declarations in \p DC. -static bool checkExportedDeclContext(Sema &S, DeclContext *DC, - SourceLocation BlockStart) { - bool AllUnnamed = true; - for (auto *D : DC->decls()) - AllUnnamed &= checkExportedDecl(S, D, BlockStart); - return AllUnnamed; + if (!isa<NamespaceDecl>(D)) + return true; + + if (auto *ND = dyn_cast<NamedDecl>(D)) { + if (!ND->getDeclName()) { + S.Diag(ND->getLocation(), diag::err_export_anon_ns_internal); + if (BlockStart.isValid()) + S.Diag(BlockStart, diag::note_export); + return false; + } else if (!DC->decls().empty() && + DC->getRedeclContext()->isFileContext()) { + return checkExportedDeclContext(S, DC, BlockStart); + } + } + } + return true; } /// Complete the definition of an export declaration. @@ -943,12 +894,7 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { SourceLocation BlockStart = ED->hasBraces() ? ED->getBeginLoc() : SourceLocation(); for (auto *Child : ED->decls()) { - if (checkExportedDecl(*this, Child, BlockStart)) { - // If a top-level child is a linkage-spec declaration, it might contain - // no declarations (transitively), in which case it's ill-formed. - diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, - BlockStart); - } + checkExportedDecl(*this, Child, BlockStart); if (auto *FD = dyn_cast<FunctionDecl>(Child)) { // [dcl.inline]/7 // If an inline function or variable that is attached to a named module @@ -966,44 +912,55 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { return D; } -Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc, - bool IsImplicit) { +Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc) { // We shouldn't create new global module fragment if there is already // one. - if (!GlobalModuleFragment) { + if (!TheGlobalModuleFragment) { ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap(); - GlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit( + TheGlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit( BeginLoc, getCurrentModule()); } - assert(GlobalModuleFragment && "module creation should not fail"); + assert(TheGlobalModuleFragment && "module creation should not fail"); // Enter the scope of the global module. - ModuleScopes.push_back({BeginLoc, GlobalModuleFragment, + ModuleScopes.push_back({BeginLoc, TheGlobalModuleFragment, /*ModuleInterface=*/false, - /*IsPartition=*/false, - /*ImplicitGlobalModuleFragment=*/IsImplicit, /*OuterVisibleModules=*/{}}); - VisibleModules.setVisible(GlobalModuleFragment, BeginLoc); + VisibleModules.setVisible(TheGlobalModuleFragment, BeginLoc); - return GlobalModuleFragment; + return TheGlobalModuleFragment; } void Sema::PopGlobalModuleFragment() { - assert(!ModuleScopes.empty() && getCurrentModule()->isGlobalModule() && + assert(!ModuleScopes.empty() && + getCurrentModule()->isExplicitGlobalModule() && "left the wrong module scope, which is not global module fragment"); ModuleScopes.pop_back(); } -bool Sema::isModuleUnitOfCurrentTU(const Module *M) const { - assert(M); - - Module *CurrentModuleUnit = getCurrentModule(); +Module *Sema::PushImplicitGlobalModuleFragment(SourceLocation BeginLoc, + bool IsExported) { + Module **M = IsExported ? &TheExportedImplicitGlobalModuleFragment + : &TheImplicitGlobalModuleFragment; + if (!*M) { + ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap(); + *M = Map.createImplicitGlobalModuleFragmentForModuleUnit( + BeginLoc, IsExported, getCurrentModule()); + } + assert(*M && "module creation should not fail"); - // If we are not in a module currently, M must not be the module unit of - // current TU. - if (!CurrentModuleUnit) - return false; + // Enter the scope of the global module. + ModuleScopes.push_back({BeginLoc, *M, + /*ModuleInterface=*/false, + /*OuterVisibleModules=*/{}}); + VisibleModules.setVisible(*M, BeginLoc); + return *M; +} - return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule()); +void Sema::PopImplicitGlobalModuleFragment() { + assert(!ModuleScopes.empty() && + getCurrentModule()->isImplicitGlobalModule() && + "left the wrong module scope, which is not global module fragment"); + ModuleScopes.pop_back(); } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 584c4a31793c..7e5dc3a71cbb 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1363,10 +1363,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!Context.hasSameType(PropertyIvarType, IvarType)) { if (isa<ObjCObjectPointerType>(PropertyIvarType) && isa<ObjCObjectPointerType>(IvarType)) - compat = - Context.canAssignObjCInterfaces( - PropertyIvarType->getAs<ObjCObjectPointerType>(), - IvarType->getAs<ObjCObjectPointerType>()); + compat = Context.canAssignObjCInterfaces( + PropertyIvarType->castAs<ObjCObjectPointerType>(), + IvarType->castAs<ObjCObjectPointerType>()); else { compat = (CheckAssignmentConstraints(PropertyIvarLoc, PropertyIvarType, IvarType) @@ -2508,8 +2507,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { if (const SectionAttr *SA = property->getAttr<SectionAttr>()) GetterMethod->addAttr(SectionAttr::CreateImplicit( - Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU, - SectionAttr::GNU_section)); + Context, SA->getName(), Loc, SectionAttr::GNU_section)); if (getLangOpts().ObjCAutoRefCount) CheckARCMethodDecl(GetterMethod); @@ -2581,8 +2579,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { CD->addDecl(SetterMethod); if (const SectionAttr *SA = property->getAttr<SectionAttr>()) SetterMethod->addAttr(SectionAttr::CreateImplicit( - Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU, - SectionAttr::GNU_section)); + Context, SA->getName(), Loc, SectionAttr::GNU_section)); // It's possible for the user to have set a very odd custom // setter selector that causes it to have a method family. if (getLangOpts().ObjCAutoRefCount) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c767341d922b..cf805987b378 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -27,6 +27,7 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -87,8 +88,7 @@ public: }; using OperatorOffsetTy = llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>; - using DoacrossDependMapTy = - llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>; + using DoacrossClauseMapTy = llvm::DenseMap<OMPClause *, OperatorOffsetTy>; /// Kind of the declaration used in the uses_allocators clauses. enum class UsesAllocatorsDeclKind { /// Predefined allocator @@ -169,7 +169,7 @@ private: /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to /// get the data (loop counters etc.) about enclosing loop-based construct. /// This data is required during codegen. - DoacrossDependMapTy DoacrossDepends; + DoacrossClauseMapTy DoacrossDepends; /// First argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. @@ -1054,17 +1054,16 @@ public: assert(!isStackEmpty()); return getStackSize() - 1; } - void addDoacrossDependClause(OMPDependClause *C, - const OperatorOffsetTy &OpsOffs) { + void addDoacrossDependClause(OMPClause *C, const OperatorOffsetTy &OpsOffs) { SharingMapTy *Parent = getSecondOnStackOrNull(); assert(Parent && isOpenMPWorksharingDirective(Parent->Directive)); Parent->DoacrossDepends.try_emplace(C, OpsOffs); } - llvm::iterator_range<DoacrossDependMapTy::const_iterator> + llvm::iterator_range<DoacrossClauseMapTy::const_iterator> getDoacrossDependClauses() const { const SharingMapTy &StackElem = getTopOfStack(); if (isOpenMPWorksharingDirective(StackElem.Directive)) { - const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends; + const DoacrossClauseMapTy &Ref = StackElem.DoacrossDepends; return llvm::make_range(Ref.begin(), Ref.end()); } return llvm::make_range(StackElem.DoacrossDepends.end(), @@ -2011,7 +2010,7 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) { } static bool isOpenMPDeviceDelayedContext(Sema &S) { - assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice && + assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsTargetDevice && "Expected OpenMP device compilation."); return !S.isInOpenMPTargetExecutionDirective(); } @@ -2025,10 +2024,10 @@ enum class FunctionEmissionStatus { }; } // anonymous namespace -Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, - unsigned DiagID, - FunctionDecl *FD) { - assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && +Sema::SemaDiagnosticBuilder +Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID, + const FunctionDecl *FD) { + assert(LangOpts.OpenMP && LangOpts.OpenMPIsTargetDevice && "Expected OpenMP device compilation."); SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop; @@ -2065,8 +2064,8 @@ Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, unsigned DiagID, - FunctionDecl *FD) { - assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && + const FunctionDecl *FD) { + assert(LangOpts.OpenMP && !LangOpts.OpenMPIsTargetDevice && "Expected OpenMP host compilation."); SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop; @@ -2203,11 +2202,14 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, ++EI; if (EI == EE) return false; - - if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) || - isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) || + auto Last = std::prev(EE); + const auto *UO = + dyn_cast<UnaryOperator>(Last->getAssociatedExpression()); + if ((UO && UO->getOpcode() == UO_Deref) || + isa<ArraySubscriptExpr>(Last->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(Last->getAssociatedExpression()) || isa<MemberExpr>(EI->getAssociatedExpression()) || - isa<OMPArrayShapingExpr>(EI->getAssociatedExpression())) { + isa<OMPArrayShapingExpr>(Last->getAssociatedExpression())) { IsVariableAssociatedWithSection = true; // There is nothing more we need to know about this variable. return true; @@ -2270,10 +2272,10 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, // and alignment, because the runtime library only deals with uintptr types. // If it does not fit the uintptr size, we need to pass the data by reference // instead. - if (!IsByRef && - (Ctx.getTypeSizeInChars(Ty) > - Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) || - Ctx.getDeclAlign(D) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) { + if (!IsByRef && (Ctx.getTypeSizeInChars(Ty) > + Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) || + Ctx.getAlignOfGlobalVarInChars(Ty) > + Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) { IsByRef = true; } @@ -2547,7 +2549,8 @@ OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, } } } - if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { + if (isOpenMPLoopDirective(DSAStack->getCurrentDirective()) && + !isOpenMPLoopTransformationDirective(DSAStack->getCurrentDirective())) { if (DSAStack->getAssociatedLoops() > 0 && !DSAStack->isLoopStarted()) { DSAStack->resetPossibleLoopCounter(D); DSAStack->loopStart(); @@ -2699,16 +2702,16 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl()); // Ignore host functions during device analyzis. - if (LangOpts.OpenMPIsDevice && + if (LangOpts.OpenMPIsTargetDevice && (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host)) return; // Ignore nohost functions during host analyzis. - if (!LangOpts.OpenMPIsDevice && DevTy && + if (!LangOpts.OpenMPIsTargetDevice && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) return; const FunctionDecl *FD = Callee->getMostRecentDecl(); DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD); - if (LangOpts.OpenMPIsDevice && DevTy && + if (LangOpts.OpenMPIsTargetDevice && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { // Diagnose host function called during device codegen. StringRef HostDevTy = @@ -2719,8 +2722,8 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, << HostDevTy; return; } - if (!LangOpts.OpenMPIsDevice && !LangOpts.OpenMPOffloadMandatory && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { + if (!LangOpts.OpenMPIsTargetDevice && !LangOpts.OpenMPOffloadMandatory && + DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { // In OpenMP 5.2 or later, if the function has a host variant then allow // that to be called instead auto &&HasHostAttr = [](const FunctionDecl *Callee) { @@ -3383,7 +3386,7 @@ Sema::ActOnOpenMPAllocateDirective(SourceLocation Loc, ArrayRef<Expr *> VarList, // allocate directives that appear in a target region must specify an // allocator clause unless a requires directive with the dynamic_allocators // clause is present in the same compilation unit. - if (LangOpts.OpenMPIsDevice && + if (LangOpts.OpenMPIsTargetDevice && !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) targetDiag(Loc, diag::err_expected_allocator_clause); } else { @@ -4196,7 +4199,6 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_target_parallel: case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: - case OMPD_target_teams_loop: case OMPD_target_parallel_loop: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: { @@ -4224,8 +4226,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -4269,8 +4270,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, std::make_pair(StringRef(), QualType()), /*OpenMPCaptureLevel=*/1); @@ -4330,8 +4330,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_taskloop: @@ -4377,8 +4376,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_parallel_masked_taskloop: @@ -4430,8 +4428,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_distribute_parallel_for_simd: @@ -4450,6 +4447,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); @@ -4477,8 +4475,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); Sema::CapturedParamNameType ParamsTarget[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -4509,22 +4506,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } - case OMPD_teams_loop: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); - - Sema::CapturedParamNameType ParamsTeams[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - // Start a captured region for 'teams'. - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsTeams, /*OpenMPCaptureLevel=*/0); - break; - } - + case OMPD_teams_loop: case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst(); @@ -4580,8 +4562,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( AlwaysInlineAttr::CreateImplicit( - Context, {}, AttributeCommonInfo::AS_Keyword, - AlwaysInlineAttr::Keyword_forceinline)); + Context, {}, AlwaysInlineAttr::Keyword_forceinline)); break; } case OMPD_threadprivate: @@ -4668,11 +4649,12 @@ static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, CaptureExpr->getExprLoc()); } -static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) { +static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref, + StringRef Name) { CaptureExpr = S.DefaultLvalueConversion(CaptureExpr).get(); if (!Ref) { OMPCapturedExprDecl *CD = buildCaptureDecl( - S, &S.getASTContext().Idents.get(".capture_expr."), CaptureExpr, + S, &S.getASTContext().Idents.get(Name), CaptureExpr, /*WithInit=*/true, S.CurContext, /*AsExpression=*/true); Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), CaptureExpr->getExprLoc()); @@ -6118,6 +6100,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( BindKind, StartLoc)) return StmtError(); + // Report affected OpenMP target offloading behavior when in HIP lang-mode. + if (getLangOpts().HIP && (isOpenMPTargetExecutionDirective(Kind) || + isOpenMPTargetDataManagementDirective(Kind))) + Diag(StartLoc, diag::warn_hip_omp_target_directives); + llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; VarsWithInheritedDSAType VarsWithInheritedDSA; bool ErrorFound = false; @@ -7259,7 +7246,7 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, return Call; if (LangOpts.OpenMP >= 51 && CalleeFnDecl->getIdentifier() && - CalleeFnDecl->getName().startswith_insensitive("omp_")) { + CalleeFnDecl->getName().starts_with_insensitive("omp_")) { // checking for any calls inside an Order region if (Scope && Scope->isOpenMPOrderClauseScope()) Diag(LParenLoc, diag::err_omp_unexpected_call_to_omp_runtime_api); @@ -8441,7 +8428,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) { static ExprResult tryBuildCapture(Sema &SemaRef, Expr *Capture, - llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, + StringRef Name = ".capture_expr.") { if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors()) return Capture; if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) @@ -8450,9 +8438,9 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, /*AllowExplicit=*/true); auto I = Captures.find(Capture); if (I != Captures.end()) - return buildCapture(SemaRef, Capture, I->second); + return buildCapture(SemaRef, Capture, I->second, Name); DeclRefExpr *Ref = nullptr; - ExprResult Res = buildCapture(SemaRef, Capture, Ref); + ExprResult Res = buildCapture(SemaRef, Capture, Ref, Name); Captures[Capture] = Ref; return Res; } @@ -8464,7 +8452,7 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy, bool TestIsStrictOp, bool RoundToStep, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, ".new_step"); if (!NewStep.isUsable()) return nullptr; llvm::APSInt LRes, SRes; @@ -8640,8 +8628,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( return nullptr; Expr *LBVal = LB; Expr *UBVal = UB; - // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : - // max(LB(MinVal), LB(MaxVal)) + // OuterVar = (LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal))) if (InitDependOnLC) { const LoopIterationSpace &IS = ResultIterSpaces[*InitDependOnLC - 1]; if (!IS.MinValue || !IS.MaxValue) @@ -8686,8 +8674,10 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( if (!LBMaxVal.isUsable()) return nullptr; - Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); - Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + Expr *LBMin = + tryBuildCapture(SemaRef, LBMinVal.get(), Captures, ".lb_min").get(); + Expr *LBMax = + tryBuildCapture(SemaRef, LBMaxVal.get(), Captures, ".lb_max").get(); if (!LBMin || !LBMax) return nullptr; // LB(MinVal) < LB(MaxVal) @@ -8696,7 +8686,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( if (!MinLessMaxRes.isUsable()) return nullptr; Expr *MinLessMax = - tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures, ".min_less_max") + .get(); if (!MinLessMax) return nullptr; if (*TestIsLessOp) { @@ -8716,6 +8707,12 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( return nullptr; LBVal = MaxLB.get(); } + // OuterVar = LB + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, IS.CounterVar, LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + LBVal = LBMinVal.get(); } // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : // min(UB(MinVal), UB(MaxVal)) @@ -8763,8 +8760,10 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( if (!UBMaxVal.isUsable()) return nullptr; - Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); - Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + Expr *UBMin = + tryBuildCapture(SemaRef, UBMinVal.get(), Captures, ".ub_min").get(); + Expr *UBMax = + tryBuildCapture(SemaRef, UBMaxVal.get(), Captures, ".ub_max").get(); if (!UBMin || !UBMax) return nullptr; // UB(MinVal) > UB(MaxVal) @@ -8772,8 +8771,9 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); if (!MinGreaterMaxRes.isUsable()) return nullptr; - Expr *MinGreaterMax = - tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + Expr *MinGreaterMax = tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), + Captures, ".min_greater_max") + .get(); if (!MinGreaterMax) return nullptr; if (*TestIsLessOp) { @@ -8796,8 +8796,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( } Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal; Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal; - Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); - Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); + Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures, ".upper").get(); + Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures, ".lower").get(); if (!Upper || !Lower) return nullptr; @@ -8891,7 +8891,7 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, ".new_step"); if (!NewStep.isUsable()) return std::make_pair(nullptr, nullptr); Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); @@ -9165,6 +9165,22 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { } } +namespace { +// Utility for openmp doacross clause kind +class OMPDoacrossKind { +public: + bool isSource(const OMPDoacrossClause *C) { + return C->getDependenceType() == OMPC_DOACROSS_source || + C->getDependenceType() == OMPC_DOACROSS_source_omp_cur_iteration; + } + bool isSink(const OMPDoacrossClause *C) { + return C->getDependenceType() == OMPC_DOACROSS_sink; + } + bool isSinkIter(const OMPDoacrossClause *C) { + return C->getDependenceType() == OMPC_DOACROSS_sink_omp_cur_iteration; + } +}; +} // namespace /// Called on a for stmt to check and extract its iteration space /// for further processing (such as collapsing). static bool checkOpenMPIterationSpace( @@ -9318,30 +9334,61 @@ static bool checkOpenMPIterationSpace( } } for (auto &Pair : DSA.getDoacrossDependClauses()) { - if (CurrentNestedLoopCount >= Pair.first->getNumLoops()) { + auto *DependC = dyn_cast<OMPDependClause>(Pair.first); + auto *DoacrossC = dyn_cast<OMPDoacrossClause>(Pair.first); + unsigned NumLoops = + DependC ? DependC->getNumLoops() : DoacrossC->getNumLoops(); + if (CurrentNestedLoopCount >= NumLoops) { // Erroneous case - clause has some problems. continue; } - if (Pair.first->getDependencyKind() == OMPC_DEPEND_sink && + if (DependC && DependC->getDependencyKind() == OMPC_DEPEND_sink && Pair.second.size() <= CurrentNestedLoopCount) { // Erroneous case - clause has some problems. - Pair.first->setLoopData(CurrentNestedLoopCount, nullptr); + DependC->setLoopData(CurrentNestedLoopCount, nullptr); + continue; + } + OMPDoacrossKind ODK; + if (DoacrossC && ODK.isSink(DoacrossC) && + Pair.second.size() <= CurrentNestedLoopCount) { + // Erroneous case - clause has some problems. + DoacrossC->setLoopData(CurrentNestedLoopCount, nullptr); continue; } Expr *CntValue; - if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) + SourceLocation DepLoc = + DependC ? DependC->getDependencyLoc() : DoacrossC->getDependenceLoc(); + if ((DependC && DependC->getDependencyKind() == OMPC_DEPEND_source) || + (DoacrossC && ODK.isSource(DoacrossC))) CntValue = ISC.buildOrderedLoopData( DSA.getCurScope(), ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, - Pair.first->getDependencyLoc()); - else + DepLoc); + else if (DoacrossC && ODK.isSinkIter(DoacrossC)) { + Expr *Cnt = SemaRef + .DefaultLvalueConversion( + ResultIterSpaces[CurrentNestedLoopCount].CounterVar) + .get(); + if (!Cnt) + continue; + // build CounterVar - 1 + Expr *Inc = + SemaRef.ActOnIntegerConstant(DoacrossC->getColonLoc(), /*Val=*/1) + .get(); + CntValue = ISC.buildOrderedLoopData( + DSA.getCurScope(), + ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, + DepLoc, Inc, clang::OO_Minus); + } else CntValue = ISC.buildOrderedLoopData( DSA.getCurScope(), ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures, - Pair.first->getDependencyLoc(), - Pair.second[CurrentNestedLoopCount].first, + DepLoc, Pair.second[CurrentNestedLoopCount].first, Pair.second[CurrentNestedLoopCount].second); - Pair.first->setLoopData(CurrentNestedLoopCount, CntValue); + if (DependC) + DependC->setLoopData(CurrentNestedLoopCount, CntValue); + else + DoacrossC->setLoopData(CurrentNestedLoopCount, CntValue); } } @@ -10164,10 +10211,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.DependentInits[Cnt] = nullptr; Built.FinalsConditions[Cnt] = nullptr; if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) { - Built.DependentCounters[Cnt] = - Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx]; - Built.DependentInits[Cnt] = - Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx]; + Built.DependentCounters[Cnt] = Built.Counters[IS.LoopDependentIdx - 1]; + Built.DependentInits[Cnt] = Built.Inits[IS.LoopDependentIdx - 1]; Built.FinalsConditions[Cnt] = IS.FinalCondition; } } @@ -11259,33 +11304,48 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, const OMPClause *DependFound = nullptr; const OMPClause *DependSourceClause = nullptr; const OMPClause *DependSinkClause = nullptr; + const OMPClause *DoacrossFound = nullptr; + const OMPClause *DoacrossSourceClause = nullptr; + const OMPClause *DoacrossSinkClause = nullptr; bool ErrorFound = false; 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) { - if (DependSourceClause) { + auto DOC = dyn_cast<OMPDoacrossClause>(C); + auto DC = dyn_cast<OMPDependClause>(C); + if (DC || DOC) { + DependFound = DC ? C : nullptr; + DoacrossFound = DOC ? C : nullptr; + OMPDoacrossKind ODK; + if ((DC && DC->getDependencyKind() == OMPC_DEPEND_source) || + (DOC && (ODK.isSource(DOC)))) { + if ((DC && DependSourceClause) || (DOC && DoacrossSourceClause)) { Diag(C->getBeginLoc(), diag::err_omp_more_one_clause) << getOpenMPDirectiveName(OMPD_ordered) - << getOpenMPClauseName(OMPC_depend) << 2; + << getOpenMPClauseName(DC ? OMPC_depend : OMPC_doacross) << 2; ErrorFound = true; } else { - DependSourceClause = C; + if (DC) + DependSourceClause = C; + else + DoacrossSourceClause = C; } - if (DependSinkClause) { - Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed) - << 0; + if ((DC && DependSinkClause) || (DOC && DoacrossSinkClause)) { + Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed) + << (DC ? "depend" : "doacross") << 0; ErrorFound = true; } - } else if (DC->getDependencyKind() == OMPC_DEPEND_sink) { - if (DependSourceClause) { - Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed) - << 1; + } else if ((DC && DC->getDependencyKind() == OMPC_DEPEND_sink) || + (DOC && (ODK.isSink(DOC) || ODK.isSinkIter(DOC)))) { + if (DependSourceClause || DoacrossSourceClause) { + Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed) + << (DC ? "depend" : "doacross") << 1; ErrorFound = true; } - DependSinkClause = C; + if (DC) + DependSinkClause = C; + else + DoacrossSinkClause = C; } } else if (C->getClauseKind() == OMPC_threads) { TC = cast<OMPThreadsClause>(C); @@ -11301,13 +11361,19 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, Diag(StartLoc, diag::err_omp_prohibited_region_simd) << (LangOpts.OpenMP >= 50 ? 1 : 0); ErrorFound = true; - } else if (DependFound && (TC || SC)) { - Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd) + } else if ((DependFound || DoacrossFound) && (TC || SC)) { + SourceLocation Loc = + DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc(); + Diag(Loc, diag::err_omp_depend_clause_thread_simd) + << getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross) << getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind()); ErrorFound = true; - } else if (DependFound && !DSAStack->getParentOrderedRegionParam().first) { - Diag(DependFound->getBeginLoc(), - diag::err_omp_ordered_directive_without_param); + } else if ((DependFound || DoacrossFound) && + !DSAStack->getParentOrderedRegionParam().first) { + SourceLocation Loc = + DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc(); + Diag(Loc, diag::err_omp_ordered_directive_without_param) + << getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross); ErrorFound = true; } else if (TC || Clauses.empty()) { if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) { @@ -11318,7 +11384,7 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, ErrorFound = true; } } - if ((!AStmt && !DependFound) || ErrorFound) + if ((!AStmt && !DependFound && !DoacrossFound) || ErrorFound) return StmtError(); // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions. @@ -11326,7 +11392,7 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread // must not execute more than one ordered region corresponding to an ordered // construct without a depend clause. - if (!DependFound) { + if (!DependFound && !DoacrossFound) { if (DSAStack->doesParentHasOrderedDirective()) { Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered"; Diag(DSAStack->getParentOrderedDirectiveLoc(), @@ -13271,6 +13337,10 @@ StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); + // Report affected OpenMP target offloading behavior when in HIP lang-mode. + if (getLangOpts().HIP && (DSAStack->getParentDirective() == OMPD_target)) + Diag(StartLoc, diag::warn_hip_omp_target_directives); + auto *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -15329,6 +15399,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( break; } [[fallthrough]]; + case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: // If this clause applies to the nested 'parallel' region, capture within // the 'teams' region, otherwise do not capture. @@ -15421,7 +15492,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target: case OMPD_target_teams: case OMPD_target_teams_distribute: - case OMPD_target_teams_loop: case OMPD_distribute_parallel_for: case OMPD_task: case OMPD_taskloop: @@ -17662,6 +17732,13 @@ OMPClause *Sema::ActOnOpenMPDestroyClause(Expr *InteropVar, SourceLocation LParenLoc, SourceLocation VarLoc, SourceLocation EndLoc) { + if (!InteropVar && LangOpts.OpenMP >= 52 && + DSAStack->getCurrentDirective() == OMPD_depobj) { + Diag(StartLoc, diag::err_omp_expected_clause_argument) + << getOpenMPClauseName(OMPC_destroy) + << getOpenMPDirectiveName(OMPD_depobj); + return nullptr; + } if (InteropVar && !isValidInteropVariable(*this, InteropVar, VarLoc, OMPC_destroy)) return nullptr; @@ -17878,6 +17955,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, Data.DepModOrTailExpr, VarList); break; + case OMPC_doacross: + Res = ActOnOpenMPDoacrossClause( + static_cast<OpenMPDoacrossClauseModifier>(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_depobj: case OMPC_final: @@ -19087,9 +19169,17 @@ static bool actOnOMPReductionKindClause( // operators: +, -, *, &, |, ^, && and || switch (OOK) { case OO_Plus: - case OO_Minus: BOK = BO_Add; break; + case OO_Minus: + // Minus(-) operator is not supported in TR11 (OpenMP 6.0). Setting BOK to + // BO_Comma will automatically diagnose it for OpenMP > 52 as not allowed + // reduction identifier. + if (S.LangOpts.OpenMP > 52) + BOK = BO_Comma; + else + BOK = BO_Add; + break; case OO_Star: BOK = BO_Mul; break; @@ -19156,6 +19246,12 @@ static bool actOnOMPReductionKindClause( } break; } + + // OpenMP 5.2, 5.5.5 (see page 627, line 18) reduction Clause, Restrictions + // A reduction clause with the minus (-) operator was deprecated + if (OOK == OO_Minus && S.LangOpts.OpenMP == 52) + S.Diag(ReductionId.getLoc(), diag::warn_omp_minus_in_reduction_deprecated); + SourceRange ReductionIdRange; if (ReductionIdScopeSpec.isValid()) ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); @@ -19324,9 +19420,14 @@ static bool actOnOMPReductionKindClause( } if (BOK == BO_Comma && DeclareReductionRef.isUnset()) { // Not allowed reduction identifier is found. - S.Diag(ReductionId.getBeginLoc(), - diag::err_omp_unknown_reduction_identifier) - << Type << ReductionIdRange; + if (S.LangOpts.OpenMP > 52) + S.Diag(ReductionId.getBeginLoc(), + diag::err_omp_unknown_reduction_identifier_since_omp_6_0) + << Type << ReductionIdRange; + else + S.Diag(ReductionId.getBeginLoc(), + diag::err_omp_unknown_reduction_identifier_prior_omp_6_0) + << Type << ReductionIdRange; continue; } @@ -20487,71 +20588,35 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj); } -OMPClause * -Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, - Expr *DepModifier, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - OpenMPDependClauseKind DepKind = Data.DepKind; - SourceLocation DepLoc = Data.DepLoc; - if (DSAStack->getCurrentDirective() == OMPD_ordered && - DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { - Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); - return nullptr; - } - if (DSAStack->getCurrentDirective() == OMPD_taskwait && - DepKind == OMPC_DEPEND_mutexinoutset) { - Diag(DepLoc, diag::err_omp_taskwait_depend_mutexinoutset_not_allowed); - return nullptr; - } - if ((DSAStack->getCurrentDirective() != OMPD_ordered || - DSAStack->getCurrentDirective() == OMPD_depobj) && - (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || - DepKind == OMPC_DEPEND_sink || - ((LangOpts.OpenMP < 50 || - DSAStack->getCurrentDirective() == OMPD_depobj) && - DepKind == OMPC_DEPEND_depobj))) { - SmallVector<unsigned, 6> Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink, - OMPC_DEPEND_outallmemory, - OMPC_DEPEND_inoutallmemory}; - if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) - Except.push_back(OMPC_DEPEND_depobj); - if (LangOpts.OpenMP < 51) - Except.push_back(OMPC_DEPEND_inoutset); - std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) - ? "depend modifier(iterator) or " - : ""; - Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, - /*Last=*/OMPC_DEPEND_unknown, - Except) - << getOpenMPClauseName(OMPC_depend); - return nullptr; - } - if (DepModifier && - (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { - Diag(DepModifier->getExprLoc(), - diag::err_omp_depend_sink_source_with_modifier); - return nullptr; - } - if (DepModifier && - !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) - Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); +namespace { +// Utility struct that gathers the related info for doacross clause. +struct DoacrossDataInfoTy { + // The list of expressions. + SmallVector<Expr *, 8> Vars; + // The OperatorOffset for doacross loop. + DSAStackTy::OperatorOffsetTy OpsOffs; + // The depended loop count. + llvm::APSInt TotalDepCount; +}; +} // namespace +static DoacrossDataInfoTy +ProcessOpenMPDoacrossClauseCommon(Sema &SemaRef, bool IsSource, + ArrayRef<Expr *> VarList, DSAStackTy *Stack, + SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); - if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) { - if (const Expr *OrderedCountExpr = - DSAStack->getParentOrderedRegionParam().first) { - TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context); - TotalDepCount.setIsUnsigned(/*Val=*/true); - } + + if (const Expr *OrderedCountExpr = + Stack->getParentOrderedRegionParam().first) { + TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(SemaRef.Context); + TotalDepCount.setIsUnsigned(/*Val=*/true); } + for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP doacross clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -20560,10 +20625,10 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, SourceLocation ELoc = RefExpr->getExprLoc(); Expr *SimpleExpr = RefExpr->IgnoreParenCasts(); - if (DepKind == OMPC_DEPEND_sink) { - if (DSAStack->getParentOrderedRegionParam().first && + if (!IsSource) { + if (Stack->getParentOrderedRegionParam().first && DepCounter >= TotalDepCount) { - Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr); continue; } ++DepCounter; @@ -20575,7 +20640,7 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, // 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()) { + if (SemaRef.CurContext->isDependentContext()) { // It will be analyzed later. Vars.push_back(RefExpr); continue; @@ -20606,7 +20671,7 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, } SourceLocation ELoc; SourceRange ERange; - auto Res = getPrivateItem(*this, LHS, ELoc, ERange); + auto Res = getPrivateItem(SemaRef, LHS, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -20616,129 +20681,213 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, continue; if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { - Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + SemaRef.Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); continue; } if (RHS) { - ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( + ExprResult RHSRes = SemaRef.VerifyPositiveIntegerConstantInClause( RHS, OMPC_depend, /*StrictlyPositive=*/false); if (RHSRes.isInvalid()) continue; } - if (!CurContext->isDependentContext() && - DSAStack->getParentOrderedRegionParam().first && - DepCounter != DSAStack->isParentLoopControlVariable(D).first) { + if (!SemaRef.CurContext->isDependentContext() && + Stack->getParentOrderedRegionParam().first && + DepCounter != Stack->isParentLoopControlVariable(D).first) { const ValueDecl *VD = - DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue()); + Stack->getParentLoopControlVariable(DepCounter.getZExtValue()); if (VD) - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 1 << VD; else - Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0; + SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 0; continue; } OpsOffs.emplace_back(RHS, OOK); - } else { - bool OMPDependTFound = LangOpts.OpenMP >= 50; - if (OMPDependTFound) - OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack, - DepKind == OMPC_DEPEND_depobj); - if (DepKind == OMPC_DEPEND_depobj) { - // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ - // List items used in depend clauses with the depobj dependence type - // must be expressions of the omp_depend_t type. - if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && - !RefExpr->isInstantiationDependent() && - !RefExpr->containsUnexpandedParameterPack() && - (OMPDependTFound && - !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(), - RefExpr->getType()))) { - Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) - << 0 << RefExpr->getType() << RefExpr->getSourceRange(); - continue; - } - if (!RefExpr->isLValue()) { - Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) - << 1 << RefExpr->getType() << RefExpr->getSourceRange(); - continue; - } - } else { - // OpenMP 5.0 [2.17.11, Restrictions] - // List items used in depend clauses cannot be zero-length array - // sections. - QualType ExprTy = RefExpr->getType().getNonReferenceType(); - const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); - if (OASE) { - QualType BaseType = - OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); - if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) - ExprTy = ATy->getElementType(); - else - ExprTy = BaseType->getPointeeType(); - ExprTy = ExprTy.getNonReferenceType(); - const Expr *Length = OASE->getLength(); - Expr::EvalResult Result; - if (Length && !Length->isValueDependent() && - Length->EvaluateAsInt(Result, Context) && - Result.Val.getInt().isZero()) { - Diag(ELoc, - diag::err_omp_depend_zero_length_array_section_not_allowed) - << SimpleExpr->getSourceRange(); + } + Vars.push_back(RefExpr->IgnoreParenImpCasts()); + } + if (!SemaRef.CurContext->isDependentContext() && !IsSource && + TotalDepCount > VarList.size() && + Stack->getParentOrderedRegionParam().first && + Stack->getParentLoopControlVariable(VarList.size() + 1)) { + SemaRef.Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration) + << 1 << Stack->getParentLoopControlVariable(VarList.size() + 1); + } + return {Vars, OpsOffs, TotalDepCount}; +} + +OMPClause * +Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data, + Expr *DepModifier, ArrayRef<Expr *> VarList, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) { + OpenMPDependClauseKind DepKind = Data.DepKind; + SourceLocation DepLoc = Data.DepLoc; + if (DSAStack->getCurrentDirective() == OMPD_ordered && + DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) { + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); + return nullptr; + } + if (DSAStack->getCurrentDirective() == OMPD_taskwait && + DepKind == OMPC_DEPEND_mutexinoutset) { + Diag(DepLoc, diag::err_omp_taskwait_depend_mutexinoutset_not_allowed); + return nullptr; + } + if ((DSAStack->getCurrentDirective() != OMPD_ordered || + DSAStack->getCurrentDirective() == OMPD_depobj) && + (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || + DepKind == OMPC_DEPEND_sink || + ((LangOpts.OpenMP < 50 || + DSAStack->getCurrentDirective() == OMPD_depobj) && + DepKind == OMPC_DEPEND_depobj))) { + SmallVector<unsigned, 6> Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink, + OMPC_DEPEND_outallmemory, + OMPC_DEPEND_inoutallmemory}; + if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) + Except.push_back(OMPC_DEPEND_depobj); + if (LangOpts.OpenMP < 51) + Except.push_back(OMPC_DEPEND_inoutset); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, + Except) + << getOpenMPClauseName(OMPC_depend); + return nullptr; + } + if (DepModifier && + (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { + Diag(DepModifier->getExprLoc(), + diag::err_omp_depend_sink_source_with_modifier); + return nullptr; + } + if (DepModifier && + !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) + Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); + + SmallVector<Expr *, 8> Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; + llvm::APSInt TotalDepCount(/*BitWidth=*/32); + + if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) { + DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon( + *this, DepKind == OMPC_DEPEND_source, VarList, DSAStack, EndLoc); + Vars = VarOffset.Vars; + OpsOffs = VarOffset.OpsOffs; + TotalDepCount = VarOffset.TotalDepCount; + } else { + 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 && DepKind != OMPC_DEPEND_source) { + bool OMPDependTFound = LangOpts.OpenMP >= 50; + if (OMPDependTFound) + OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack, + DepKind == OMPC_DEPEND_depobj); + if (DepKind == OMPC_DEPEND_depobj) { + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the depobj dependence type + // must be expressions of the omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (OMPDependTFound && + !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(), + RefExpr->getType()))) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 0 << RefExpr->getType() << RefExpr->getSourceRange(); continue; } - } + if (!RefExpr->isLValue()) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 1 << RefExpr->getType() << RefExpr->getSourceRange(); + continue; + } + } else { + // OpenMP 5.0 [2.17.11, Restrictions] + // List items used in depend clauses cannot be zero-length array + // sections. + QualType ExprTy = RefExpr->getType().getNonReferenceType(); + const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + if (OASE) { + QualType BaseType = + OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) + ExprTy = ATy->getElementType(); + else + ExprTy = BaseType->getPointeeType(); + ExprTy = ExprTy.getNonReferenceType(); + const Expr *Length = OASE->getLength(); + Expr::EvalResult Result; + if (Length && !Length->isValueDependent() && + Length->EvaluateAsInt(Result, Context) && + Result.Val.getInt().isZero()) { + Diag(ELoc, + diag::err_omp_depend_zero_length_array_section_not_allowed) + << SimpleExpr->getSourceRange(); + continue; + } + } - // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ - // List items used in depend clauses with the in, out, inout, - // inoutset, or mutexinoutset dependence types cannot be - // expressions of the omp_depend_t type. - if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && - !RefExpr->isInstantiationDependent() && - !RefExpr->containsUnexpandedParameterPack() && - (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (OMPDependTFound && - DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr()))) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << (LangOpts.OpenMP >= 50 ? 1 : 0) - << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); - continue; - } + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the in, out, inout, + // inoutset, or mutexinoutset dependence types cannot be + // expressions of the omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (OMPDependTFound && DSAStack->getOMPDependT().getTypePtr() == + ExprTy.getTypePtr()))) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } - auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (ASE && !ASE->getBase()->isTypeDependent() && - !ASE->getBase()->getType().getNonReferenceType()->isPointerType() && - !ASE->getBase()->getType().getNonReferenceType()->isArrayType()) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << (LangOpts.OpenMP >= 50 ? 1 : 0) - << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); - continue; - } + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + if (ASE && !ASE->getBase()->isTypeDependent() && + !ASE->getBase() + ->getType() + .getNonReferenceType() + ->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType()) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } - ExprResult Res; - { - Sema::TentativeAnalysisScope Trap(*this); - Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, - RefExpr->IgnoreParenImpCasts()); - } - if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && - !isa<OMPArrayShapingExpr>(SimpleExpr)) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << (LangOpts.OpenMP >= 50 ? 1 : 0) - << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); - continue; + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + } + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && + !isa<OMPArrayShapingExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } } } + Vars.push_back(RefExpr->IgnoreParenImpCasts()); } - Vars.push_back(RefExpr->IgnoreParenImpCasts()); } - if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink && - TotalDepCount > VarList.size() && - DSAStack->getParentOrderedRegionParam().first && - 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 && DepKind != OMPC_DEPEND_outallmemory && DepKind != OMPC_DEPEND_inoutallmemory && Vars.empty()) @@ -22833,6 +22982,11 @@ bool Sema::ActOnStartOpenMPDeclareTargetContext( Diag(DTCI.Loc, diag::err_omp_region_not_file_context); return false; } + + // Report affected OpenMP target offloading behavior when in HIP lang-mode. + if (getLangOpts().HIP) + Diag(DTCI.Loc, diag::warn_hip_omp_target_directives); + DeclareTargetNesting.push_back(DTCI); return true; } @@ -22905,6 +23059,10 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced())) Diag(Loc, diag::warn_omp_declare_target_after_first_use); + // Report affected OpenMP target offloading behavior when in HIP lang-mode. + if (getLangOpts().HIP) + Diag(Loc, diag::warn_hip_omp_target_directives); + // Explicit declare target lists have precedence. const unsigned Level = -1; @@ -23054,6 +23212,55 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); } +/// This class visits every VarDecl that the initializer references and adds +/// OMPDeclareTargetDeclAttr to each of them. +class GlobalDeclRefChecker final + : public StmtVisitor<GlobalDeclRefChecker> { + SmallVector<VarDecl *> DeclVector; + Attr *A; + +public: + /// A StmtVisitor class function that visits all DeclRefExpr and adds + /// OMPDeclareTargetDeclAttr to them. + void VisitDeclRefExpr(DeclRefExpr *Node) { + if (auto *VD = dyn_cast<VarDecl>(Node->getDecl())) { + VD->addAttr(A); + DeclVector.push_back(VD); + } + } + /// A function that iterates across each of the Expr's children. + void VisitExpr(Expr *Ex) { + for (auto *Child : Ex->children()) { + Visit(Child); + } + } + /// A function that keeps a record of all the Decls that are variables, has + /// OMPDeclareTargetDeclAttr, and has global storage in the DeclVector. Pop + /// each Decl one at a time and use the inherited 'visit' functions to look + /// for DeclRefExpr. + void declareTargetInitializer(Decl *TD) { + A = TD->getAttr<OMPDeclareTargetDeclAttr>(); + DeclVector.push_back(cast<VarDecl>(TD)); + while (!DeclVector.empty()) { + VarDecl *TargetVarDecl = DeclVector.pop_back_val(); + if (TargetVarDecl->hasAttr<OMPDeclareTargetDeclAttr>() && + TargetVarDecl->hasInit() && TargetVarDecl->hasGlobalStorage()) { + if (Expr *Ex = TargetVarDecl->getInit()) + Visit(Ex); + } + } + } +}; + +/// Adding OMPDeclareTargetDeclAttr to variables with static storage +/// duration that are referenced in the initializer expression list of +/// variables with static storage duration in declare target directive. +void Sema::ActOnOpenMPDeclareTargetInitializer(Decl *TargetDecl) { + GlobalDeclRefChecker Checker; + if (isa<VarDecl>(TargetDecl)) + Checker.declareTargetInitializer(TargetDecl); +} + OMPClause *Sema::ActOnOpenMPToClause( ArrayRef<OpenMPMotionModifierKind> MotionModifiers, ArrayRef<SourceLocation> MotionModifiersLoc, @@ -23459,7 +23666,7 @@ OMPClause *Sema::ActOnOpenMPAllocateClause( // target region must specify an allocator expression unless a requires // directive with the dynamic_allocators clause is present in the same // compilation unit. - if (LangOpts.OpenMPIsDevice && + if (LangOpts.OpenMPIsTargetDevice && !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>()) targetDiag(StartLoc, diag::err_expected_allocator_expression); } @@ -23851,3 +24058,38 @@ OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size, return new (Context) OMPXDynCGroupMemClause( ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } + +OMPClause *Sema::ActOnOpenMPDoacrossClause( + OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc, + SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + + if (DSAStack->getCurrentDirective() == OMPD_ordered && + DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink && + DepType != OMPC_DOACROSS_sink_omp_cur_iteration && + DepType != OMPC_DOACROSS_source_omp_cur_iteration && + DepType != OMPC_DOACROSS_source) { + Diag(DepLoc, diag::err_omp_unexpected_clause_value) + << "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross); + return nullptr; + } + + SmallVector<Expr *, 8> Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; + llvm::APSInt TotalDepCount(/*BitWidth=*/32); + DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon( + *this, + DepType == OMPC_DOACROSS_source || + DepType == OMPC_DOACROSS_source_omp_cur_iteration || + DepType == OMPC_DOACROSS_sink_omp_cur_iteration, + VarList, DSAStack, EndLoc); + Vars = VarOffset.Vars; + OpsOffs = VarOffset.OpsOffs; + TotalDepCount = VarOffset.TotalDepCount; + auto *C = OMPDoacrossClause::Create(Context, StartLoc, LParenLoc, EndLoc, + DepType, DepLoc, ColonLoc, Vars, + TotalDepCount.getZExtValue()); + if (DSAStack->isParentOrderedRegion()) + DSAStack->addDoacrossDependClause(C, OpsOffs); + return C; +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d68337a26d97..a3d9abb15377 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -26,6 +27,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" @@ -120,7 +122,7 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc, /// corresponding to the given implicit conversion kind. ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { static const ImplicitConversionRank - Rank[(int)ICK_Num_Conversion_Kinds] = { + Rank[] = { ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match, @@ -141,6 +143,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, + ICR_Conversion, ICR_OCL_Scalar_Widening, ICR_Complex_Real_Conversion, ICR_Conversion, @@ -149,16 +152,20 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, // NOTE(gbiv): This may not be completely right -- // it was omitted by the patch that added // ICK_Zero_Event_Conversion + ICR_Exact_Match, // NOTE(ctopper): This may not be completely right -- + // it was omitted by the patch that added + // ICK_Zero_Queue_Conversion ICR_C_Conversion, ICR_C_Conversion_Extension }; + static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds); return Rank[(int)Kind]; } /// GetImplicitConversionName - Return the name of this kind of /// implicit conversion. static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { - static const char* const Name[(int)ICK_Num_Conversion_Kinds] = { + static const char* const Name[] = { "No conversion", "Lvalue-to-rvalue", "Array-to-pointer", @@ -179,15 +186,18 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Derived-to-base conversion", "Vector conversion", "SVE Vector conversion", + "RVV Vector conversion", "Vector splat", "Complex-real conversion", "Block Pointer conversion", "Transparent Union Conversion", "Writeback conversion", "OpenCL Zero Event Conversion", + "OpenCL Zero Queue Conversion", "C specific type conversion", "Incompatible pointer conversion" }; + static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds); return Name[Kind]; } @@ -1155,15 +1165,6 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, !shouldLinkPossiblyHiddenDecl(*I, New)) continue; - // C++20 [temp.friend] p9: A non-template friend declaration with a - // requires-clause shall be a definition. A friend function template - // with a constraint that depends on a template parameter from an - // enclosing template shall be a definition. Such a constrained friend - // function or function template declaration does not declare the same - // function or function template as a declaration in any other scope. - if (Context.FriendsDifferByConstraints(OldF, New)) - continue; - Match = *I; return Ovl_Match; } @@ -1280,6 +1281,12 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, !FunctionParamTypesAreEqual(OldType, NewType))) return true; + // For member-like friends, the enclosing class is part of the signature. + if ((New->isMemberLikeConstrainedFriend() || + Old->isMemberLikeConstrainedFriend()) && + !New->getLexicalDeclContext()->Equals(Old->getLexicalDeclContext())) + return true; + if (NewTemplate) { // C++ [temp.over.link]p4: // The signature of a function template consists of its function @@ -1291,7 +1298,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // We check the return type and template parameter lists for function // templates first; the remaining checks follow. bool SameTemplateParameterList = TemplateParameterListsAreEqual( - NewTemplate->getTemplateParameters(), + NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch); bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(), New->getDeclaredReturnType()); @@ -1750,13 +1757,22 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, } } - if (ToType->isSizelessBuiltinType() || FromType->isSizelessBuiltinType()) + if (ToType->isSVESizelessBuiltinType() || + FromType->isSVESizelessBuiltinType()) if (S.Context.areCompatibleSveTypes(FromType, ToType) || S.Context.areLaxCompatibleSveTypes(FromType, ToType)) { ICK = ICK_SVE_Vector_Conversion; return true; } + if (ToType->isRVVSizelessBuiltinType() || + FromType->isRVVSizelessBuiltinType()) + if (S.Context.areCompatibleRVVTypes(FromType, ToType) || + S.Context.areLaxCompatibleRVVTypes(FromType, ToType)) { + ICK = ICK_RVV_Vector_Conversion; + return true; + } + // We can perform the conversion between vector types in the following cases: // 1)vector types are equivalent AltiVec and GCC vector types // 2)lax vector conversions are permitted and the vector types are of the @@ -1768,9 +1784,10 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, if (S.Context.areCompatibleVectorTypes(FromType, ToType) || (S.isLaxVectorConversion(FromType, ToType) && !ToType->hasAttr(attr::ArmMveStrictPolymorphism))) { - if (S.isLaxVectorConversion(FromType, ToType) && + if (S.getASTContext().getTargetInfo().getTriple().isPPC() && + S.isLaxVectorConversion(FromType, ToType) && S.anyAltivecTypes(FromType, ToType) && - !S.areSameVectorElemTypes(FromType, ToType) && + !S.Context.areCompatibleVectorTypes(FromType, ToType) && !InOverloadResolution && !CStyle) { S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all) << FromType << ToType; @@ -1979,8 +1996,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // if their representation is different until there is back end support // We of course allow this conversion if long double is really double. - // Conversions between bfloat and other floats are not permitted. - if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty) + // Conversions between bfloat16 and float16 are currently not supported. + if ((FromType->isBFloat16Type() && + (ToType->isFloat16Type() || ToType->isHalfType())) || + (ToType->isBFloat16Type() && + (FromType->isFloat16Type() || FromType->isHalfType()))) return false; // Conversions between IEEE-quad and IBM-extended semantics are not @@ -2001,9 +2021,6 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, ToType->isIntegralType(S.Context)) || (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isRealFloatingType())) { - // Conversions between bfloat and int are not permitted. - if (FromType->isBFloat16Type() || ToType->isBFloat16Type()) - return false; // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; @@ -4322,6 +4339,20 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, : ImplicitConversionSequence::Worse; } + if (SCS1.Second == ICK_RVV_Vector_Conversion && + SCS2.Second == ICK_RVV_Vector_Conversion) { + bool SCS1IsCompatibleRVVVectorConversion = + S.Context.areCompatibleRVVTypes(SCS1.getFromType(), SCS1.getToType(2)); + bool SCS2IsCompatibleRVVVectorConversion = + S.Context.areCompatibleRVVTypes(SCS2.getFromType(), SCS2.getToType(2)); + + if (SCS1IsCompatibleRVVVectorConversion != + SCS2IsCompatibleRVVVectorConversion) + return SCS1IsCompatibleRVVVectorConversion + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + } + return ImplicitConversionSequence::Indistinguishable; } @@ -5125,6 +5156,18 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, if (!S.isCompleteType(From->getBeginLoc(), InitTy)) return Result; + // C++20 [over.ics.list]/2: + // If the initializer list is a designated-initializer-list, a conversion + // is only possible if the parameter has an aggregate type + // + // FIXME: The exception for reference initialization here is not part of the + // language rules, but follow other compilers in adding it as a tentative DR + // resolution. + bool IsDesignatedInit = From->hasDesignatedInit(); + if (!ToType->isAggregateType() && !ToType->isReferenceType() && + IsDesignatedInit) + return Result; + // Per DR1467: // If the parameter type is a class X and the initializer list has a single // element of type cv U, where U is X or a class derived from X, the @@ -5135,7 +5178,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // and the initializer list has a single element that is an // appropriately-typed string literal (8.5.2 [dcl.init.string]), the // implicit conversion sequence is the identity conversion. - if (From->getNumInits() == 1) { + if (From->getNumInits() == 1 && !IsDesignatedInit) { if (ToType->isRecordType()) { QualType InitType = From->getInit(0)->getType(); if (S.Context.hasSameUnqualifiedType(InitType, ToType) || @@ -5173,7 +5216,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // default-constructible, and if all the elements of the initializer list // can be implicitly converted to X, the implicit conversion sequence is // the worst conversion necessary to convert an element of the list to X. - if (AT || S.isStdInitializerList(ToType, &InitTy)) { + if ((AT || S.isStdInitializerList(ToType, &InitTy)) && !IsDesignatedInit) { unsigned e = From->getNumInits(); ImplicitConversionSequence DfltElt; DfltElt.setBad(BadConversionSequence::no_conversion, QualType(), @@ -5315,7 +5358,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // If the initializer list has a single element that is reference-related // to the parameter type, we initialize the reference from that. - if (From->getNumInits() == 1) { + if (From->getNumInits() == 1 && !IsDesignatedInit) { Expr *Init = From->getInit(0); QualType T2 = Init->getType(); @@ -5748,6 +5791,7 @@ static bool CheckConvertedConstantConversions(Sema &S, case ICK_Derived_To_Base: case ICK_Vector_Conversion: case ICK_SVE_Vector_Conversion: + case ICK_RVV_Vector_Conversion: case ICK_Vector_Splat: case ICK_Complex_Real: case ICK_Block_Pointer_Conversion: @@ -5774,14 +5818,14 @@ static bool CheckConvertedConstantConversions(Sema &S, llvm_unreachable("unknown conversion kind"); } -/// CheckConvertedConstantExpression - Check that the expression From is a -/// converted constant expression of type T, perform the conversion and produce -/// the converted expression, per C++11 [expr.const]p3. -static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, - QualType T, APValue &Value, +/// BuildConvertedConstantExpression - Check that the expression From is a +/// converted constant expression of type T, perform the conversion but +/// does not evaluate the expression +static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, + QualType T, Sema::CCEKind CCE, - bool RequireInt, - NamedDecl *Dest) { + NamedDecl *Dest, + APValue &PreNarrowingValue) { assert(S.getLangOpts().CPlusPlus11 && "converted constant expression outside C++11"); @@ -5865,7 +5909,6 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // Check for a narrowing implicit conversion. bool ReturnPreNarrowingValue = false; - APValue PreNarrowingValue; QualType PreNarrowingType; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, PreNarrowingType)) { @@ -5899,12 +5942,19 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, << CCE << /*Constant*/ 0 << From->getType() << T; break; } + if (!ReturnPreNarrowingValue) + PreNarrowingValue = {}; - if (Result.get()->isValueDependent()) { - Value = APValue(); - return Result; - } + return Result; +} +/// EvaluateConvertedConstantExpression - Evaluate an Expression +/// That is a converted constant expression +/// (which was built with BuildConvertedConstantExpression) +static ExprResult EvaluateConvertedConstantExpression( + Sema &S, Expr *E, QualType T, APValue &Value, Sema::CCEKind CCE, + bool RequireInt, const APValue &PreNarrowingValue) { + ExprResult Result = E; // Check the expression is a constant expression. SmallVector<PartialDiagnosticAt, 8> Notes; Expr::EvalResult Eval; @@ -5918,7 +5968,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, else Kind = ConstantExprKind::Normal; - if (!Result.get()->EvaluateAsConstantExpr(Eval, S.Context, Kind) || + if (!E->EvaluateAsConstantExpr(Eval, S.Context, Kind) || (RequireInt && !Eval.Val.isInt())) { // The expression can't be folded, so we can't keep it at this position in // the AST. @@ -5929,7 +5979,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, if (Notes.empty()) { // It's a constant expression. Expr *E = ConstantExpr::Create(S.Context, Result.get(), Value); - if (ReturnPreNarrowingValue) + if (!PreNarrowingValue.isAbsent()) Value = std::move(PreNarrowingValue); return E; } @@ -5945,14 +5995,42 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, for (unsigned I = 0; I < Notes.size(); ++I) S.Diag(Notes[I].first, Notes[I].second); } else { - S.Diag(From->getBeginLoc(), diag::err_expr_not_cce) - << CCE << From->getSourceRange(); + S.Diag(E->getBeginLoc(), diag::err_expr_not_cce) + << CCE << E->getSourceRange(); for (unsigned I = 0; I < Notes.size(); ++I) S.Diag(Notes[I].first, Notes[I].second); } return ExprError(); } +/// CheckConvertedConstantExpression - Check that the expression From is a +/// converted constant expression of type T, perform the conversion and produce +/// the converted expression, per C++11 [expr.const]p3. +static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, + QualType T, APValue &Value, + Sema::CCEKind CCE, + bool RequireInt, + NamedDecl *Dest) { + + APValue PreNarrowingValue; + ExprResult Result = BuildConvertedConstantExpression(S, From, T, CCE, Dest, + PreNarrowingValue); + if (Result.isInvalid() || Result.get()->isValueDependent()) { + Value = APValue(); + return Result; + } + return EvaluateConvertedConstantExpression(S, Result.get(), T, Value, CCE, + RequireInt, PreNarrowingValue); +} + +ExprResult Sema::BuildConvertedConstantExpression(Expr *From, QualType T, + CCEKind CCE, + NamedDecl *Dest) { + APValue PreNarrowingValue; + return ::BuildConvertedConstantExpression(*this, From, T, CCE, Dest, + PreNarrowingValue); +} + ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE, NamedDecl *Dest) { @@ -6425,7 +6503,7 @@ void Sema::AddOverloadCandidate( OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO) { + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6500,23 +6578,20 @@ void Sema::AddOverloadCandidate( } // Functions with internal linkage are only viable in the same module unit. - if (auto *MF = Function->getOwningModule()) { - if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() && - !isModuleUnitOfCurrentTU(MF)) { - /// FIXME: Currently, the semantics of linkage in clang is slightly - /// different from the semantics in C++ spec. In C++ spec, only names - /// have linkage. So that all entities of the same should share one - /// linkage. But in clang, different entities of the same could have - /// different linkage. - NamedDecl *ND = Function; - if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) - ND = SpecInfo->getTemplate(); - - if (ND->getFormalLinkage() == Linkage::InternalLinkage) { - Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_module_mismatched; - return; - } + if (getLangOpts().CPlusPlusModules && Function->isInAnotherModuleUnit()) { + /// FIXME: Currently, the semantics of linkage in clang is slightly + /// different from the semantics in C++ spec. In C++ spec, only names + /// have linkage. So that all entities of the same should share one + /// linkage. But in clang, different entities of the same could have + /// different linkage. + NamedDecl *ND = Function; + if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) + ND = SpecInfo->getTemplate(); + + if (ND->getFormalLinkage() == Linkage::InternalLinkage) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_module_mismatched; + return; } } @@ -6595,7 +6670,8 @@ void Sema::AddOverloadCandidate( // parameter list is truncated on the right, so that there are // exactly m parameters. unsigned MinRequiredArgs = Function->getMinRequiredArguments(); - if (Args.size() < MinRequiredArgs && !PartialOverloading) { + if (!AggregateCandidateDeduction && Args.size() < MinRequiredArgs && + !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; Candidate.FailureKind = ovl_fail_too_few_arguments; @@ -7221,7 +7297,8 @@ void Sema::AddMethodTemplateCandidate( ConversionSequenceList Conversions; if (TemplateDeductionResult Result = DeduceTemplateArguments( MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, - PartialOverloading, [&](ArrayRef<QualType> ParamTypes) { + PartialOverloading, /*AggregateDeductionCandidate=*/false, + [&](ArrayRef<QualType> ParamTypes) { return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, ActingContext, ObjectType, @@ -7274,7 +7351,7 @@ void Sema::AddTemplateOverloadCandidate( TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, - OverloadCandidateParamOrder PO) { + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) return; @@ -7304,7 +7381,8 @@ void Sema::AddTemplateOverloadCandidate( ConversionSequenceList Conversions; if (TemplateDeductionResult Result = DeduceTemplateArguments( FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, - PartialOverloading, [&](ArrayRef<QualType> ParamTypes) { + PartialOverloading, AggregateCandidateDeduction, + [&](ArrayRef<QualType> ParamTypes) { return CheckNonDependentConversions( FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, nullptr, QualType(), {}, PO); @@ -7340,7 +7418,8 @@ void Sema::AddTemplateOverloadCandidate( AddOverloadCandidate( Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, AllowExplicit, - /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO); + /*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO, + Info.AggregateDeductionCandidateHasMismatchedArity); } /// Check that implicit conversion sequences can be formed for each argument @@ -7807,6 +7886,17 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } + if (Conversion->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (CheckFunctionConstraints(Conversion, Satisfaction, /*Loc*/ {}, + /*ForOverloadResolution*/ true) || + !Satisfaction.IsSatisfied) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_constraints_not_satisfied; + return; + } + } + if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) { Candidate.Viable = false; @@ -7984,8 +8074,7 @@ namespace { /// enumeration types. class BuiltinCandidateTypeSet { /// TypeSet - A set of types. - typedef llvm::SetVector<QualType, SmallVector<QualType, 8>, - llvm::SmallPtrSet<QualType, 8>> TypeSet; + typedef llvm::SmallSetVector<QualType, 8> TypeSet; /// PointerTypes - The set of pointer types that will be used in the /// built-in candidates. @@ -9886,7 +9975,7 @@ bool clang::isBetterOverloadCandidate( } } - // C++ [over.match.best]p1: (Changed in C++2b) + // C++ [over.match.best]p1: (Changed in C++23) // // -- if F is a static member function, ICS1(F) is defined such // that ICS1(F) is neither better nor worse than ICS1(G) for @@ -10108,7 +10197,7 @@ bool clang::isBetterOverloadCandidate( return Guide2->isImplicit(); // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not - if (Guide1->isCopyDeductionCandidate()) + if (Guide1->getDeductionCandidateKind() == DeductionCandidate::Copy) return true; } } @@ -10368,7 +10457,8 @@ enum OverloadCandidateSelect { }; static std::pair<OverloadCandidateKind, OverloadCandidateSelect> -ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, +ClassifyOverloadCandidate(Sema &S, const NamedDecl *Found, + const FunctionDecl *Fn, OverloadCandidateRewriteKind CRK, std::string &Description) { @@ -10392,7 +10482,7 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, if (CRK & CRK_Reversed) return oc_reversed_binary_operator; - if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { if (!Ctor->isImplicit()) { if (isa<ConstructorUsingShadowDecl>(Found)) return oc_inherited_constructor; @@ -10411,7 +10501,7 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, return oc_implicit_copy_constructor; } - if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { + if (const auto *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()) @@ -10433,10 +10523,10 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, return std::make_pair(Kind, Select); } -void MaybeEmitInheritedConstructorNote(Sema &S, Decl *FoundDecl) { +void MaybeEmitInheritedConstructorNote(Sema &S, const Decl *FoundDecl) { // FIXME: It'd be nice to only emit a note once per using-decl per overload // set. - if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) + if (const auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) S.Diag(FoundDecl->getLocation(), diag::note_ovl_candidate_inherited_constructor) << Shadow->getNominatedBaseClass(); @@ -10543,7 +10633,7 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, // Don't print candidates other than the one that matches the calling // convention of the call operator, since that is guaranteed to exist. -static bool shouldSkipNotingLambdaConversionDecl(FunctionDecl *Fn) { +static bool shouldSkipNotingLambdaConversionDecl(const FunctionDecl *Fn) { const auto *ConvD = dyn_cast<CXXConversionDecl>(Fn); if (!ConvD) @@ -10563,7 +10653,7 @@ static bool shouldSkipNotingLambdaConversionDecl(FunctionDecl *Fn) { } // Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, +void Sema::NoteOverloadCandidate(const NamedDecl *Found, const FunctionDecl *Fn, OverloadCandidateRewriteKind RewriteKind, QualType DestType, bool TakingAddress) { if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn)) @@ -10709,6 +10799,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, Expr *FromExpr = Conv.Bad.FromExpr; QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); + SourceRange ToParamRange = + !isObjectArgument ? Fn->getParamDecl(I)->getSourceRange() : SourceRange(); if (FromTy == S.Context.OverloadTy) { assert(FromExpr && "overload set argument came from implicit argument?"); @@ -10719,8 +10811,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << ToTy - << Name << I + 1; + << ToParamRange << ToTy << Name << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10749,14 +10840,12 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (isObjectArgument) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second - << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromQs.getAddressSpace() << ToQs.getAddressSpace(); + << FnDesc << FromQs.getAddressSpace() << ToQs.getAddressSpace(); else S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second - << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromQs.getAddressSpace() << ToQs.getAddressSpace() - << ToTy->isReferenceType() << I + 1; + << FnDesc << ToParamRange << FromQs.getAddressSpace() + << ToQs.getAddressSpace() << ToTy->isReferenceType() << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10764,9 +10853,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << FromQs.getObjCLifetime() << ToQs.getObjCLifetime() - << (unsigned)isObjectArgument << I + 1; + << ToParamRange << FromTy << FromQs.getObjCLifetime() + << ToQs.getObjCLifetime() << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10774,18 +10862,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc) << (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)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << FromQs.hasUnaligned() << I + 1; + << ToParamRange << FromTy << FromQs.getObjCGCAttr() + << ToQs.getObjCGCAttr() << (unsigned)isObjectArgument << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10796,13 +10874,11 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (isObjectArgument) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << (CVR - 1); + << FromTy << (CVR - 1); } else { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << (CVR - 1) << I + 1; + << ToParamRange << FromTy << (CVR - 1) << I + 1; } MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; @@ -10814,7 +10890,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc << (unsigned)isObjectArgument << I + 1 << (Conv.Bad.Kind == BadConversionSequence::rvalue_ref_to_lvalue) - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()); + << ToParamRange; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10824,8 +10900,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (FromExpr && isa<InitListExpr>(FromExpr)) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << ToTy << (unsigned)isObjectArgument << I + 1 + << ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1 << (Conv.Bad.Kind == BadConversionSequence::too_few_initializers ? 1 : Conv.Bad.Kind == BadConversionSequence::too_many_initializers ? 2 @@ -10844,8 +10919,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, // Emit the generic diagnostic and, optionally, add the hints to it. S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << ToTy << (unsigned)isObjectArgument << I + 1 + << ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1 << (unsigned)(Cand->Fix.Kind); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); @@ -10886,24 +10960,24 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (BaseToDerivedConversion) { 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; + << ToParamRange << (BaseToDerivedConversion - 1) << FromTy << ToTy + << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } if (isa<ObjCObjectPointerType>(CFromTy) && isa<PointerType>(CToTy)) { - Qualifiers FromQs = CFromTy.getQualifiers(); - Qualifiers ToQs = CToTy.getQualifiers(); - if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv) - << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second - << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned)isObjectArgument << I + 1; - MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); - return; - } + Qualifiers FromQs = CFromTy.getQualifiers(); + Qualifiers ToQs = CToTy.getQualifiers(); + if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument + << I + 1; + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); + return; + } } if (TakingCandidateAddress && @@ -10913,8 +10987,7 @@ 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)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << ToTy << (unsigned)isObjectArgument << I + 1 + << ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1 << (unsigned)(Cand->Fix.Kind); // Check that location of Fn is not in system header. @@ -10997,11 +11070,13 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second - << Description << mode << Fn->getParamDecl(0) << NumFormalArgs; + << Description << mode << Fn->getParamDecl(0) << NumFormalArgs + << Fn->getParametersSourceRange(); else S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second - << Description << mode << modeCount << NumFormalArgs; + << Description << mode << modeCount << NumFormalArgs + << Fn->getParametersSourceRange(); MaybeEmitInheritedConstructorNote(S, Found); } @@ -11583,8 +11658,18 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType); if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType); - S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) - << FnType; + if (!Cand->Viable && + Cand->FailureKind == ovl_fail_constraints_not_satisfied) { + S.Diag(Cand->Surrogate->getLocation(), + diag::note_ovl_surrogate_constraints_not_satisfied) + << Cand->Surrogate; + ConstraintSatisfaction Satisfaction; + if (S.CheckFunctionConstraints(Cand->Surrogate, Satisfaction)) + S.DiagnoseUnsatisfiedConstraint(Satisfaction); + } else { + S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) + << FnType; + } } static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc, @@ -11979,7 +12064,16 @@ void OverloadCandidateSet::NoteCandidates( S.Diag(PD.first, PD.second, shouldDeferDiags(S, Args, OpLoc)); - NoteCandidates(S, Args, Cands, Opc, OpLoc); + // In WebAssembly we don't want to emit further diagnostics if a table is + // passed as an argument to a function. + bool NoteCands = true; + for (const Expr *Arg : Args) { + if (Arg->getType()->isWebAssemblyTableType()) + NoteCands = false; + } + + if (NoteCands) + NoteCandidates(S, Args, Cands, Opc, OpLoc); if (OCD == OCD_AmbiguousCandidates) MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()}); @@ -12756,10 +12850,9 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate( /// /// If no template-ids are found, no diagnostics are emitted and NULL is /// returned. -FunctionDecl * -Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, - bool Complain, - DeclAccessPair *FoundResult) { +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization( + OverloadExpr *ovl, bool Complain, DeclAccessPair *FoundResult, + TemplateSpecCandidateSet *FailedTSC) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -12773,7 +12866,6 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, TemplateArgumentListInfo ExplicitTemplateArgs; ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); - TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc()); // Look through all of the overloaded functions, searching for one // whose type matches exactly. @@ -12796,16 +12888,16 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = nullptr; - TemplateDeductionInfo Info(FailedCandidates.getLocation()); + TemplateDeductionInfo Info(ovl->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info, /*IsAddressOfFunction*/true)) { // Make a note of the failed deduction for diagnostics. - // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(I.getPair(), FunctionTemplate->getTemplatedDecl(), - MakeDeductionFailureInfo(Context, Result, Info)); + if (FailedTSC) + FailedTSC->addCandidate().set( + I.getPair(), FunctionTemplate->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, Result, Info)); continue; } @@ -13962,8 +14054,8 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(FnDecl->getLocation(), diag::note_ovl_ambiguous_oper_binary_reversed_self); // Mark member== const or provide matching != to disallow reversed - // args. Eg. - // struct S { bool operator==(const S&); }; + // args. Eg. + // struct S { bool operator==(const S&); }; // S()==S(); if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl)) if (Op == OverloadedOperatorKind::OO_EqualEqual && @@ -14900,6 +14992,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, /*SuppressUserConversion=*/false); } + // When calling a lambda, both the call operator, and + // the conversion operator to function pointer + // are considered. But when constraint checking + // on the call operator fails, it will also fail on the + // conversion operator as the constraints are always the same. + // As the user probably does not intend to perform a surrogate call, + // we filter them out to produce better error diagnostics, ie to avoid + // showing 2 failed overloads instead of one. + bool IgnoreSurrogateFunctions = false; + if (CandidateSet.size() == 1 && Record->getAsCXXRecordDecl()->isLambda()) { + const OverloadCandidate &Candidate = *CandidateSet.begin(); + if (!Candidate.Viable && + Candidate.FailureKind == ovl_fail_constraints_not_satisfied) + IgnoreSurrogateFunctions = true; + } + // C++ [over.call.object]p2: // In addition, for each (non-explicit in C++0x) conversion function // declared in T of the form @@ -14919,7 +15027,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // within T by another intervening declaration. const auto &Conversions = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions(); - for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + for (auto I = Conversions.begin(), E = Conversions.end(); + !IgnoreSurrogateFunctions && I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) @@ -15055,7 +15164,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, bool IsError = false; // Initialize the implicit object parameter if needed. - // Since C++2b, this could also be a call to a static call operator + // Since C++23, this could also be a call to a static call operator // which we emit as a regular CallExpr. if (Method->isInstance()) { ExprResult ObjRes = PerformObjectArgumentInitialization( @@ -15421,8 +15530,14 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, unsigned ResultIdx = GSE->getResultIndex(); AssocExprs[ResultIdx] = SubExpr; + if (GSE->isExprPredicate()) + return GenericSelectionExpr::Create( + Context, GSE->getGenericLoc(), GSE->getControllingExpr(), + GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(), + GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(), + ResultIdx); return GenericSelectionExpr::Create( - Context, GSE->getGenericLoc(), GSE->getControllingExpr(), + Context, GSE->getGenericLoc(), GSE->getControllingType(), GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(), GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(), ResultIdx); diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index abbdc12e7047..408f71044fa3 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -152,8 +152,13 @@ namespace { assocTypes.push_back(assoc.getTypeSourceInfo()); } + if (gse->isExprPredicate()) + return GenericSelectionExpr::Create( + S.Context, gse->getGenericLoc(), gse->getControllingExpr(), + assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(), + gse->containsUnexpandedParameterPack(), resultIndex); return GenericSelectionExpr::Create( - S.Context, gse->getGenericLoc(), gse->getControllingExpr(), + S.Context, gse->getGenericLoc(), gse->getControllingType(), assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(), gse->containsUnexpandedParameterPack(), resultIndex); } diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp index 7716dfb15458..db2059e68b3d 100644 --- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp +++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp @@ -28,6 +28,8 @@ using namespace llvm; using namespace clang; using namespace clang::RISCV; +using IntrinsicKind = sema::RISCVIntrinsicManager::IntrinsicKind; + namespace { // Function definition of a RVV intrinsic. @@ -58,16 +60,34 @@ static const PrototypeDescriptor RVVSignatureTable[] = { #undef DECL_SIGNATURE_TABLE }; +static const PrototypeDescriptor RVSiFiveVectorSignatureTable[] = { +#define DECL_SIGNATURE_TABLE +#include "clang/Basic/riscv_sifive_vector_builtin_sema.inc" +#undef DECL_SIGNATURE_TABLE +}; + static const RVVIntrinsicRecord RVVIntrinsicRecords[] = { #define DECL_INTRINSIC_RECORDS #include "clang/Basic/riscv_vector_builtin_sema.inc" #undef DECL_INTRINSIC_RECORDS }; +static const RVVIntrinsicRecord RVSiFiveVectorIntrinsicRecords[] = { +#define DECL_INTRINSIC_RECORDS +#include "clang/Basic/riscv_sifive_vector_builtin_sema.inc" +#undef DECL_INTRINSIC_RECORDS +}; + // Get subsequence of signature table. -static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index, - uint8_t Length) { - return ArrayRef(&RVVSignatureTable[Index], Length); +static ArrayRef<PrototypeDescriptor> +ProtoSeq2ArrayRef(IntrinsicKind K, uint16_t Index, uint8_t Length) { + switch (K) { + case IntrinsicKind::RVV: + return ArrayRef(&RVVSignatureTable[Index], Length); + case IntrinsicKind::SIFIVE_VECTOR: + return ArrayRef(&RVSiFiveVectorSignatureTable[Index], Length); + } + llvm_unreachable("Unhandled IntrinsicKind"); } static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { @@ -115,8 +135,12 @@ static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { case Invalid: llvm_unreachable("Unhandled type."); } - if (Type->isVector()) - QT = Context.getScalableVectorType(QT, *Type->getScale()); + if (Type->isVector()) { + if (Type->isTuple()) + QT = Context.getScalableVectorType(QT, *Type->getScale(), Type->getNF()); + else + QT = Context.getScalableVectorType(QT, *Type->getScale()); + } if (Type->isConstant()) QT = Context.getConstType(QT); @@ -134,6 +158,8 @@ private: Sema &S; ASTContext &Context; RVVTypeCache TypeCache; + bool ConstructedRISCVVBuiltins; + bool ConstructedRISCVSiFiveVectorBuiltins; // List of all RVV intrinsic. std::vector<RVVIntrinsicDef> IntrinsicList; @@ -142,8 +168,6 @@ private: // Mapping function name to RVVOverloadIntrinsicDef. StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics; - // Create IntrinsicList - void InitIntrinsicList(); // Create RVVIntrinsicDef. void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr, @@ -155,11 +179,18 @@ private: Preprocessor &PP, unsigned Index, bool IsOverload); + void ConstructRVVIntrinsics(ArrayRef<RVVIntrinsicRecord> Recs, + IntrinsicKind K); + public: RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) { - InitIntrinsicList(); + ConstructedRISCVVBuiltins = false; + ConstructedRISCVSiFiveVectorBuiltins = false; } + // Initialize IntrinsicList + void InitIntrinsicList() override; + // Create RISC-V vector intrinsic and insert into symbol table if found, and // return true, otherwise return false. bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II, @@ -167,49 +198,45 @@ public: }; } // namespace -void RISCVIntrinsicManagerImpl::InitIntrinsicList() { +void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics( + ArrayRef<RVVIntrinsicRecord> Recs, IntrinsicKind K) { const TargetInfo &TI = Context.getTargetInfo(); - bool HasVectorFloat32 = TI.hasFeature("zve32f"); - bool HasVectorFloat64 = TI.hasFeature("zve64d"); - bool HasZvfh = TI.hasFeature("experimental-zvfh"); bool HasRV64 = TI.hasFeature("64bit"); - bool HasFullMultiply = TI.hasFeature("v"); - // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics // in RISCVVEmitter.cpp. - for (auto &Record : RVVIntrinsicRecords) { + for (auto &Record : Recs) { // Create Intrinsics for each type and LMUL. BasicType BaseType = BasicType::Unknown; ArrayRef<PrototypeDescriptor> BasicProtoSeq = - ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength); + ProtoSeq2ArrayRef(K, Record.PrototypeIndex, Record.PrototypeLength); ArrayRef<PrototypeDescriptor> SuffixProto = - ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength); + ProtoSeq2ArrayRef(K, Record.SuffixIndex, Record.SuffixLength); ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef( - Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); + K, Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); PolicyScheme UnMaskedPolicyScheme = static_cast<PolicyScheme>(Record.UnMaskedPolicyScheme); PolicyScheme MaskedPolicyScheme = static_cast<PolicyScheme>(Record.MaskedPolicyScheme); - const Policy DefaultPolicy(Record.HasTailPolicy, Record.HasMaskPolicy); + const Policy DefaultPolicy; llvm::SmallVector<PrototypeDescriptor> ProtoSeq = - RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false, - /*HasMaskedOffOperand=*/false, - Record.HasVL, Record.NF, - UnMaskedPolicyScheme, DefaultPolicy); + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/false, + /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, + UnMaskedPolicyScheme, DefaultPolicy, Record.IsTuple); llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq = RVVIntrinsic::computeBuiltinTypes( BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, - Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy); + Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy, + Record.IsTuple); bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone; bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone; SmallVector<Policy> SupportedUnMaskedPolicies = - RVVIntrinsic::getSupportedUnMaskedPolicies(Record.HasTailPolicy, - Record.HasMaskPolicy); + RVVIntrinsic::getSupportedUnMaskedPolicies(); SmallVector<Policy> SupportedMaskedPolicies = RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy, Record.HasMaskPolicy); @@ -224,25 +251,10 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { continue; // Check requirement. - if (BaseType == BasicType::Float16 && !HasZvfh) - continue; - - if (BaseType == BasicType::Float32 && !HasVectorFloat32) - continue; - - if (BaseType == BasicType::Float64 && !HasVectorFloat64) - continue; - if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) && !HasRV64) continue; - if ((BaseType == BasicType::Int64) && - ((Record.RequiredExtensions & RVV_REQ_FullMultiply) == - RVV_REQ_FullMultiply) && - !HasFullMultiply) - continue; - // Expanded with different LMUL. for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) { if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3)))) @@ -271,7 +283,7 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { RVVIntrinsic::computeBuiltinTypes( BasicProtoSeq, /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, - UnMaskedPolicyScheme, P); + UnMaskedPolicyScheme, P, Record.IsTuple); std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes( BaseType, Log2LMUL, Record.NF, PolicyPrototype); InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, @@ -293,14 +305,30 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { llvm::SmallVector<PrototypeDescriptor> PolicyPrototype = RVVIntrinsic::computeBuiltinTypes( BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, - Record.HasVL, Record.NF, MaskedPolicyScheme, P); + Record.HasVL, Record.NF, MaskedPolicyScheme, P, + Record.IsTuple); std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes( BaseType, Log2LMUL, Record.NF, PolicyPrototype); InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P); } } // End for different LMUL - } // End for different TypeRange + } // End for different TypeRange + } +} + +void RISCVIntrinsicManagerImpl::InitIntrinsicList() { + + if (S.DeclareRISCVVBuiltins && !ConstructedRISCVVBuiltins) { + ConstructedRISCVVBuiltins = true; + ConstructRVVIntrinsics(RVVIntrinsicRecords, + IntrinsicKind::RVV); + } + if (S.DeclareRISCVSiFiveVectorBuiltins && + !ConstructedRISCVSiFiveVectorBuiltins) { + ConstructedRISCVSiFiveVectorBuiltins = true; + ConstructRVVIntrinsics(RVSiFiveVectorIntrinsicRecords, + IntrinsicKind::SIFIVE_VECTOR); } } @@ -327,7 +355,8 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name); RVVIntrinsic::updateNamesAndPolicy(IsMasked, HasPolicy, Name, BuiltinName, - OverloadedName, PolicyAttrs); + OverloadedName, PolicyAttrs, + Record.HasFRMRoundModeOp); // Put into IntrinsicList. size_t Index = IntrinsicList.size(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index f8c713c8545d..ca0254d29e7f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -33,22 +33,6 @@ Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); } -bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { - assert(getLangOpts().SYCLIsDevice && - "Should only be called during SYCL compilation"); - assert(Callee && "Callee may not be null."); - - // Errors in an unevaluated context don't need to be generated, - // so we can safely skip them. - if (isUnevaluatedContext() || isConstantEvaluated()) - return true; - - SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop; - - return DiagKind != SemaDiagnosticBuilder::K_Immediate && - DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; -} - static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) return CAT->getSize() == 0; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index f15603fd0bd4..70a549938d08 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace sema; @@ -932,11 +933,12 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, } if (ConstevalOrNegatedConsteval) { - bool Immediate = isImmediateFunctionContext(); + bool Immediate = ExprEvalContexts.back().Context == + ExpressionEvaluationContext::ImmediateFunctionContext; if (CurContext->isFunctionOrMethod()) { const auto *FD = dyn_cast<FunctionDecl>(Decl::castFromDeclContext(CurContext)); - if (FD && FD->isConsteval()) + if (FD && FD->isImmediateFunction()) Immediate = true; } if (isUnevaluatedContext() || Immediate) @@ -1728,9 +1730,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, namespace { // Use SetVector since the diagnostic cares about the ordering of the Decl's. - using DeclSetVector = - llvm::SetVector<VarDecl *, llvm::SmallVector<VarDecl *, 8>, - llvm::SmallPtrSet<VarDecl *, 8>>; + using DeclSetVector = llvm::SmallSetVector<VarDecl *, 8>; // This visitor will traverse a conditional statement and store all // the evaluated decls into a vector. Simple is set to true if none @@ -3364,7 +3364,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// might be modified by the implementation. /// /// \param Mode Overrides detection of current language mode -/// and uses the rules for C++2b. +/// and uses the rules for C++23. /// /// \returns An aggregate which contains the Candidate and isMoveEligible /// and isCopyElidable methods. If Candidate is non-null, it means @@ -3385,7 +3385,7 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, if (Res.Candidate && !E->isXValue() && (Mode == SimplerImplicitMoveMode::ForceOn || (Mode != SimplerImplicitMoveMode::ForceOff && - getLangOpts().CPlusPlus2b))) { + getLangOpts().CPlusPlus23))) { E = ImplicitCastExpr::Create(Context, VD->getType().getNonReferenceType(), CK_NoOp, E, nullptr, VK_XValue, FPOptionsOverride()); @@ -3529,7 +3529,7 @@ ExprResult Sema::PerformMoveOrCopyInitialization( const InitializedEntity &Entity, const NamedReturnInfo &NRInfo, Expr *Value, bool SupressSimplerImplicitMoves) { if (getLangOpts().CPlusPlus && - (!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) && + (!getLangOpts().CPlusPlus23 || SupressSimplerImplicitMoves) && NRInfo.isMoveEligible()) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_NoOp, Value, VK_XValue, FPOptionsOverride()); @@ -3730,6 +3730,11 @@ StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, if (FunctionScopes.back()->FirstReturnLoc.isInvalid()) FunctionScopes.back()->FirstReturnLoc = ReturnLoc; + if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap); + CurBlock && CurCap->HasImplicitReturnType && RetValExp && + RetValExp->containsErrors()) + CurBlock->TheDecl->setInvalidDecl(); + return Result; } @@ -3825,9 +3830,18 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, { // Otherwise, [...] deduce a value for U using the rules of template // argument deduction. - TemplateDeductionInfo Info(RetExpr->getExprLoc()); - TemplateDeductionResult Res = - DeduceAutoType(OrigResultType, RetExpr, Deduced, Info); + auto RetExprLoc = RetExpr->getExprLoc(); + TemplateDeductionInfo Info(RetExprLoc); + SourceLocation TemplateSpecLoc; + if (RetExpr->getType() == Context.OverloadTy) { + auto FindResult = OverloadExpr::find(RetExpr); + if (FindResult.Expression) + TemplateSpecLoc = FindResult.Expression->getNameLoc(); + } + TemplateSpecCandidateSet FailedTSC(TemplateSpecLoc); + TemplateDeductionResult Res = DeduceAutoType( + OrigResultType, RetExpr, Deduced, Info, /*DependentDeduction=*/false, + /*IgnoreConstraints=*/false, &FailedTSC); if (Res != TDK_Success && FD->isInvalidDecl()) return true; switch (Res) { @@ -3853,6 +3867,7 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, default: Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) << OrigResultType.getType() << RetExpr->getType(); + FailedTSC.NoteCandidates(*this, RetExprLoc); return true; } } @@ -3902,7 +3917,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, static bool CheckSimplerImplicitMovesMSVCWorkaround(const Sema &S, const Expr *E) { - if (!E || !S.getLangOpts().CPlusPlus2b || !S.getLangOpts().MSVCCompat) + if (!E || !S.getLangOpts().CPlusPlus23 || !S.getLangOpts().MSVCCompat) return false; const Decl *D = E->getReferencedDeclOfCallee(); if (!D || !S.SourceMgr.isInSystemHeader(D->getLocation())) @@ -3969,6 +3984,14 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, } else // If we don't have a function/method context, bail. return StmtError(); + if (RetValExp) { + const auto *ATy = dyn_cast<ArrayType>(RetValExp->getType()); + if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) { + Diag(ReturnLoc, diag::err_wasm_table_art) << 1; + return StmtError(); + } + } + // C++1z: discarded return statements are not considered when deducing a // return type. if (ExprEvalContexts.back().isDiscardedStatementContext() && @@ -4351,9 +4374,9 @@ public: if (QT->isPointerType()) IsPointer = true; + QT = QT.getUnqualifiedType(); if (IsPointer || QT->isReferenceType()) QT = QT->getPointeeType(); - QT = QT.getUnqualifiedType(); } /// Used when creating a CatchHandlerType from a base class type; pretends the @@ -4401,32 +4424,42 @@ template <> struct DenseMapInfo<CatchHandlerType> { namespace { class CatchTypePublicBases { - ASTContext &Ctx; - const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &TypesToCheck; - const bool CheckAgainstPointer; + const llvm::DenseMap<QualType, CXXCatchStmt *> &TypesToCheck; CXXCatchStmt *FoundHandler; - CanQualType FoundHandlerType; + QualType FoundHandlerType; + QualType TestAgainstType; public: - CatchTypePublicBases( - ASTContext &Ctx, - const llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> &T, bool C) - : Ctx(Ctx), TypesToCheck(T), CheckAgainstPointer(C), - FoundHandler(nullptr) {} + CatchTypePublicBases(const llvm::DenseMap<QualType, CXXCatchStmt *> &T, + QualType QT) + : TypesToCheck(T), FoundHandler(nullptr), TestAgainstType(QT) {} CXXCatchStmt *getFoundHandler() const { return FoundHandler; } - CanQualType getFoundHandlerType() const { return FoundHandlerType; } + QualType getFoundHandlerType() const { return FoundHandlerType; } bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) { if (S->getAccessSpecifier() == AccessSpecifier::AS_public) { - CatchHandlerType Check(S->getType(), CheckAgainstPointer); + QualType Check = S->getType().getCanonicalType(); const auto &M = TypesToCheck; auto I = M.find(Check); if (I != M.end()) { - FoundHandler = I->second; - FoundHandlerType = Ctx.getCanonicalType(S->getType()); - return true; + // We're pretty sure we found what we need to find. However, we still + // need to make sure that we properly compare for pointers and + // references, to handle cases like: + // + // } catch (Base *b) { + // } catch (Derived &d) { + // } + // + // where there is a qualification mismatch that disqualifies this + // handler as a potential problem. + if (I->second->getCaughtType()->isPointerType() == + TestAgainstType->isPointerType()) { + FoundHandler = I->second; + FoundHandlerType = Check; + return true; + } } } return false; @@ -4465,6 +4498,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, assert(!Handlers.empty() && "The parser shouldn't call this if there are no handlers."); + llvm::DenseMap<QualType, CXXCatchStmt *> HandledBaseTypes; llvm::DenseMap<CatchHandlerType, CXXCatchStmt *> HandledTypes; for (unsigned i = 0; i < NumHandlers; ++i) { CXXCatchStmt *H = cast<CXXCatchStmt>(Handlers[i]); @@ -4482,8 +4516,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // Walk the type hierarchy to diagnose when this type has already been // handled (duplication), or cannot be handled (derivation inversion). We // ignore top-level cv-qualifiers, per [except.handle]p3 - CatchHandlerType HandlerCHT = - (QualType)Context.getCanonicalType(H->getCaughtType()); + CatchHandlerType HandlerCHT = H->getCaughtType().getCanonicalType(); // We can ignore whether the type is a reference or a pointer; we need the // underlying declaration type in order to get at the underlying record @@ -4499,10 +4532,12 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // as the original type. CXXBasePaths Paths; Paths.setOrigin(RD); - CatchTypePublicBases CTPB(Context, HandledTypes, HandlerCHT.isPointer()); + CatchTypePublicBases CTPB(HandledBaseTypes, + H->getCaughtType().getCanonicalType()); if (RD->lookupInBases(CTPB, Paths)) { const CXXCatchStmt *Problem = CTPB.getFoundHandler(); - if (!Paths.isAmbiguous(CTPB.getFoundHandlerType())) { + if (!Paths.isAmbiguous( + CanQualType::CreateUnsafe(CTPB.getFoundHandlerType()))) { Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), diag::warn_exception_caught_by_earlier_handler) << H->getCaughtType(); @@ -4511,11 +4546,16 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, << Problem->getCaughtType(); } } + // Strip the qualifiers here because we're going to be comparing this + // type to the base type specifiers of a class, which are ignored in a + // base specifier per [class.derived.general]p2. + HandledBaseTypes[Underlying.getUnqualifiedType()] = H; } // Add the type the list of ones we have handled; diagnose if we've already // handled it. - auto R = HandledTypes.insert(std::make_pair(H->getCaughtType(), H)); + auto R = HandledTypes.insert( + std::make_pair(H->getCaughtType().getCanonicalType(), H)); if (!R.second) { const CXXCatchStmt *Problem = R.first->second; Diag(H->getExceptionDecl()->getTypeSpecStartLoc(), @@ -4529,7 +4569,8 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, FSI->setHasCXXTry(TryLoc); - return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers); + return CXXTryStmt::Create(Context, TryLoc, cast<CompoundStmt>(TryBlock), + Handlers); } StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, @@ -4725,6 +4766,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); + ExprEvalContexts.back().InImmediateEscalatingFunctionContext = false; } void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 97400483c63a..2acb269f0423 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include <optional> diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 6d443837a4c5..ad20bc8871f1 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -215,6 +215,59 @@ static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A, return ::new (S.Context) NoMergeAttr(S.Context, A); } +template <typename OtherAttr, int DiagIdx> +static bool CheckStmtInlineAttr(Sema &SemaRef, const Stmt *OrigSt, + const Stmt *CurSt, + const AttributeCommonInfo &A) { + CallExprFinder OrigCEF(SemaRef, OrigSt); + CallExprFinder CEF(SemaRef, CurSt); + + // If the call expressions lists are equal in size, we can skip + // previously emitted diagnostics. However, if the statement has a pack + // expansion, we have no way of telling which CallExpr is the instantiated + // version of the other. In this case, we will end up re-diagnosing in the + // instantiation. + // ie: [[clang::always_inline]] non_dependent(), (other_call<Pack>()...) + // will diagnose nondependent again. + bool CanSuppressDiag = + OrigSt && CEF.getCallExprs().size() == OrigCEF.getCallExprs().size(); + + if (!CEF.foundCallExpr()) { + return SemaRef.Diag(CurSt->getBeginLoc(), + diag::warn_attribute_ignored_no_calls_in_stmt) + << A; + } + + for (const auto &Tup : + llvm::zip_longest(OrigCEF.getCallExprs(), CEF.getCallExprs())) { + // If the original call expression already had a callee, we already + // diagnosed this, so skip it here. We can't skip if there isn't a 1:1 + // relationship between the two lists of call expressions. + if (!CanSuppressDiag || !(*std::get<0>(Tup))->getCalleeDecl()) { + const Decl *Callee = (*std::get<1>(Tup))->getCalleeDecl(); + if (Callee && + (Callee->hasAttr<OtherAttr>() || Callee->hasAttr<FlattenAttr>())) { + SemaRef.Diag(CurSt->getBeginLoc(), + diag::warn_function_stmt_attribute_precedence) + << A << (Callee->hasAttr<OtherAttr>() ? DiagIdx : 1); + SemaRef.Diag(Callee->getBeginLoc(), diag::note_conflicting_attribute); + } + } + } + + return false; +} + +bool Sema::CheckNoInlineAttr(const Stmt *OrigSt, const Stmt *CurSt, + const AttributeCommonInfo &A) { + return CheckStmtInlineAttr<AlwaysInlineAttr, 0>(*this, OrigSt, CurSt, A); +} + +bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt, + const AttributeCommonInfo &A) { + return CheckStmtInlineAttr<NoInlineAttr, 2>(*this, OrigSt, CurSt, A); +} + static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { NoInlineAttr NIA(S.Context, A); @@ -224,19 +277,8 @@ static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } - CallExprFinder CEF(S, St); - if (!CEF.foundCallExpr()) { - S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt) - << A; + if (S.CheckNoInlineAttr(/*OrigSt=*/nullptr, St, A)) return nullptr; - } - - for (const auto *CallExpr : CEF.getCallExprs()) { - const Decl *Decl = CallExpr->getCalleeDecl(); - if (Decl->hasAttr<AlwaysInlineAttr>() || Decl->hasAttr<FlattenAttr>()) - S.Diag(St->getBeginLoc(), diag::warn_function_stmt_attribute_precedence) - << A << (Decl->hasAttr<AlwaysInlineAttr>() ? 0 : 1); - } return ::new (S.Context) NoInlineAttr(S.Context, A); } @@ -250,19 +292,8 @@ static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } - CallExprFinder CEF(S, St); - if (!CEF.foundCallExpr()) { - S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt) - << A; + if (S.CheckAlwaysInlineAttr(/*OrigSt=*/nullptr, St, A)) return nullptr; - } - - for (const auto *CallExpr : CEF.getCallExprs()) { - const Decl *Decl = CallExpr->getCalleeDecl(); - if (Decl->hasAttr<NoInlineAttr>() || Decl->hasAttr<FlattenAttr>()) - S.Diag(St->getBeginLoc(), diag::warn_function_stmt_attribute_precedence) - << A << (Decl->hasAttr<NoInlineAttr>() ? 2 : 1); - } return ::new (S.Context) AlwaysInlineAttr(S.Context, A); } @@ -459,7 +490,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { - S.Diag(A.getLoc(), A.isDeclspecAttribute() + S.Diag(A.getLoc(), A.isRegularKeywordAttribute() + ? (unsigned)diag::err_keyword_not_supported_on_target + : A.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) << A << A.getRange(); @@ -495,7 +528,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, // declaration attribute is not written on a statement, but this code is // needed for attributes in Attr.td that do not list any subjects. S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt) - << A << St->getBeginLoc(); + << A << A.isRegularKeywordAttribute() << St->getBeginLoc(); return nullptr; } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4b144c239fa4..a1f0f5732b2b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" @@ -315,9 +316,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, } bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, - SourceLocation NameLoc, - ParsedTemplateTy *Template) { - CXXScopeSpec SS; + SourceLocation NameLoc, CXXScopeSpec &SS, + ParsedTemplateTy *Template /*=nullptr*/) { bool MemberOfUnknownSpecialization = false; // We could use redeclaration lookup here, but we don't need to: the @@ -1107,19 +1107,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } -bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, - TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, - SourceLocation EllipsisLoc) { - return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, - false); -} +bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) { -bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, - TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, - SourceLocation EllipsisLoc, - bool AllowUnexpandedPack) { TemplateName TN = TypeConstr->Template.get(); ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl()); @@ -1137,9 +1126,32 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, if (!WereArgsSpecified && CD->getTemplateParameters()->getMinRequiredArguments() > 1) { Diag(TypeConstr->TemplateNameLoc, - diag::err_type_constraint_missing_arguments) << CD; + diag::err_type_constraint_missing_arguments) + << CD; return true; } + return false; +} + +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, + false); +} + +bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc, + bool AllowUnexpandedPack) { + + if (CheckTypeConstraint(TypeConstr)) + return true; + + TemplateName TN = TypeConstr->Template.get(); + ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl()); DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc); @@ -1251,35 +1263,41 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, return false; } -bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, + NonTypeTemplateParmDecl *NewConstrainedParm, + NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc) { - if (NTTP->getType() != TL.getType() || + if (NewConstrainedParm->getType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { - Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) - << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + << NewConstrainedParm->getTypeSourceInfo() + ->getTypeLoc() + .getSourceRange(); return true; } // FIXME: Concepts: This should be the type of the placeholder, but this is // unclear in the wording right now. DeclRefExpr *Ref = - BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); + BuildDeclRefExpr(OrigConstrainedParm, OrigConstrainedParm->getType(), + VK_PRValue, OrigConstrainedParm->getLocation()); if (!Ref) return true; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref), NTTP->getLocation(), + BuildDecltypeType(Ref), OrigConstrainedParm->getLocation(), [&](TemplateArgumentListInfo &ConstraintArgs) { for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) ConstraintArgs.addArgument(TL.getArgLoc(I)); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || - !ImmediatelyDeclaredConstraint.isUsable()) + !ImmediatelyDeclaredConstraint.isUsable()) return true; - NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + NewConstrainedParm->setPlaceholderTypeConstraint( + ImmediatelyDeclaredConstraint.get()); return false; } @@ -1559,7 +1577,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) + if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; if (Invalid) @@ -1592,16 +1610,6 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; - TemplateArgument SugaredConverted, CanonicalConverted; - ExprResult DefaultRes = CheckTemplateArgument( - Param, Param->getType(), Default, SugaredConverted, CanonicalConverted, - CTAK_Specified); - if (DefaultRes.isInvalid()) { - Param->setInvalidDecl(); - return Param; - } - Default = DefaultRes.get(); - Param->setDefaultArgument(Default); } @@ -2540,8 +2548,6 @@ private: TInfo->getType(), TInfo, LocEnd, Ctor); Guide->setImplicit(); Guide->setParams(Params); - if (Ctor && Ctor->getTrailingRequiresClause()) - Guide->setTrailingRequiresClause(Ctor->getTrailingRequiresClause()); for (auto *Param : Params) Param->setDeclContext(Guide); @@ -2564,12 +2570,47 @@ private: }; } +FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList( + TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes, + SourceLocation Loc) { + if (CXXRecordDecl *DefRecord = + cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) { + if (TemplateDecl *DescribedTemplate = + DefRecord->getDescribedClassTemplate()) + Template = DescribedTemplate; + } + + DeclContext *DC = Template->getDeclContext(); + if (DC->isDependentContext()) + return nullptr; + + ConvertConstructorToDeductionGuideTransform Transform( + *this, cast<ClassTemplateDecl>(Template)); + if (!isCompleteType(Loc, Transform.DeducedType)) + return nullptr; + + // In case we were expanding a pack when we attempted to declare deduction + // guides, turn off pack expansion for everything we're about to do. + ArgumentPackSubstitutionIndexRAII SubstIndex(*this, + /*NewSubstitutionIndex=*/-1); + // Create a template instantiation record to track the "instantiation" of + // constructors into deduction guides. + InstantiatingTemplate BuildingDeductionGuides( + *this, Loc, Template, + Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); + if (BuildingDeductionGuides.isInvalid()) + return nullptr; + + return cast<FunctionTemplateDecl>( + Transform.buildSimpleDeductionGuide(ParamTypes)); +} + void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc) { if (CXXRecordDecl *DefRecord = cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) { - TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate(); - Template = DescribedTemplate ? DescribedTemplate : Template; + if (TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate()) + Template = DescribedTemplate; } DeclContext *DC = Template->getDeclContext(); @@ -2593,9 +2634,9 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); // Create a template instantiation record to track the "instantiation" of // constructors into deduction guides. - // FIXME: Add a kind for this to give more meaningful diagnostics. But can - // this substitution process actually fail? - InstantiatingTemplate BuildingDeductionGuides(*this, Loc, Template); + InstantiatingTemplate BuildingDeductionGuides( + *this, Loc, Template, + Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); if (BuildingDeductionGuides.isInvalid()) return; @@ -2603,13 +2644,21 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // FIXME: Skip constructors for which deduction must necessarily fail (those // for which some class template parameter without a default argument never // appears in a deduced context). + llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors; bool AddedAny = false; for (NamedDecl *D : LookupConstructors(Transform.Primary)) { D = D->getUnderlyingDecl(); if (D->isInvalidDecl() || D->isImplicit()) continue; + D = cast<NamedDecl>(D->getCanonicalDecl()); + // Within C++20 modules, we may have multiple same constructors in + // multiple same RecordDecls. And it doesn't make sense to create + // duplicated deduction guides for the duplicated constructors. + if (ProcessedCtors.count(D)) + continue; + auto *FTD = dyn_cast<FunctionTemplateDecl>(D); auto *CD = dyn_cast_or_null<CXXConstructorDecl>(FTD ? FTD->getTemplatedDecl() : D); @@ -2624,6 +2673,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, })) continue; + ProcessedCtors.insert(D); Transform.transformConstructor(FTD, CD); AddedAny = true; } @@ -2641,7 +2691,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, cast<FunctionTemplateDecl>( Transform.buildSimpleDeductionGuide(Transform.DeducedType)) ->getTemplatedDecl()) - ->setIsCopyDeductionCandidate(); + ->setDeductionCandidateKind(DeductionCandidate::Copy); } /// Diagnose the presence of a default template argument on a @@ -2836,8 +2886,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule())) + if (!OldTypeParm->getOwningModule()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm, NewTypeParm)) { @@ -2889,8 +2938,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldNonTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule())) + if (!OldNonTypeParm->getOwningModule()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldNonTypeParm, NewNonTypeParm)) { @@ -2941,8 +2989,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; - if (!OldTemplateParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule())) + if (!OldTemplateParm->getOwningModule()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldTemplateParm, NewTemplateParm)) { @@ -4989,13 +5036,20 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, return ExprError(); } - if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) { - Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_class_template) - << SS.getScopeRep() - << NameInfo.getName().getAsString() << SS.getRange(); - Diag(Temp->getLocation(), diag::note_referenced_class_template); + auto DiagnoseTypeTemplateDecl = [&](TemplateDecl *Temp, + bool isTypeAliasTemplateDecl) { + Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template) + << SS.getScopeRep() << NameInfo.getName().getAsString() << SS.getRange() + << isTypeAliasTemplateDecl; + Diag(Temp->getLocation(), diag::note_referenced_type_template) << 0; return ExprError(); - } + }; + + if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) + return DiagnoseTypeTemplateDecl(Temp, false); + + if (TypeAliasTemplateDecl *Temp = R.getAsSingle<TypeAliasTemplateDecl>()) + return DiagnoseTypeTemplateDecl(Temp, true); return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs); } @@ -5897,6 +5951,11 @@ bool Sema::CheckTemplateArgumentList( CTAK_Specified)) return true; + CanonicalConverted.back().setIsDefaulted( + clang::isSubstitutedDefaultArgument( + Context, NewArgs[ArgIdx].getArgument(), *Param, + CanonicalConverted, Params->getDepth())); + bool PackExpansionIntoNonPack = NewArgs[ArgIdx].getArgument().isPackExpansion() && (!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param)); @@ -6072,6 +6131,8 @@ bool Sema::CheckTemplateArgumentList( CTAK_Specified)) return true; + CanonicalConverted.back().setIsDefaulted(true); + // Core issue 150 (assumed resolution): if this is a template template // parameter, keep track of the default template arguments from the // template definition. @@ -7514,7 +7575,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, else if (OldValue.isUnsigned()) RequiredBits = OldValue.getActiveBits() + 1; else - RequiredBits = OldValue.getMinSignedBits(); + RequiredBits = OldValue.getSignificantBits(); if (RequiredBits > AllowedBits) { Diag(Arg->getBeginLoc(), diag::warn_template_arg_too_large) << toString(OldValue, 10) << toString(Value, 10) << Param->getType() @@ -7947,8 +8008,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, static bool MatchTemplateParameterKind( Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old, const NamedDecl *OldInstFrom, bool Complain, - Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc, - bool PartialOrdering) { + Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { // Check the actual kind (type, non-type, template). if (Old->getKind() != New->getKind()) { if (Complain) { @@ -8004,8 +8064,14 @@ static bool MatchTemplateParameterKind( // to actually compare the arguments. if (Kind != Sema::TPL_TemplateTemplateArgumentMatch || (!OldNTTP->getType()->isDependentType() && - !NewNTTP->getType()->isDependentType())) - if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + !NewNTTP->getType()->isDependentType())) { + // C++20 [temp.over.link]p6: + // Two [non-type] template-parameters are equivalent [if] they have + // equivalent types ignoring the use of type-constraints for + // placeholder types + QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType()); + QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType()); + if (!S.Context.hasSameType(OldType, NewType)) { if (Complain) { unsigned NextDiag = diag::err_template_nontype_parm_different_type; if (TemplateArgLoc.isValid()) { @@ -8023,6 +8089,7 @@ static bool MatchTemplateParameterKind( return false; } + } } // For template template parameters, check the template parameter types. // The template parameter lists of template template @@ -8036,11 +8103,12 @@ static bool MatchTemplateParameterKind( (Kind == Sema::TPL_TemplateMatch ? Sema::TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc, PartialOrdering)) + TemplateArgLoc)) return false; } - if (!PartialOrdering && Kind != Sema::TPL_TemplateTemplateArgumentMatch && + if (Kind != Sema::TPL_TemplateParamsEquivalent && + Kind != Sema::TPL_TemplateTemplateArgumentMatch && !isa<TemplateTemplateParmDecl>(Old)) { const Expr *NewC = nullptr, *OldC = nullptr; @@ -8133,8 +8201,7 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S, bool Sema::TemplateParameterListsAreEqual( const NamedDecl *NewInstFrom, TemplateParameterList *New, const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain, - TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc, - bool PartialOrdering) { + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) { if (Complain) DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, @@ -8166,7 +8233,7 @@ bool Sema::TemplateParameterListsAreEqual( if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm, OldInstFrom, Complain, Kind, - TemplateArgLoc, PartialOrdering)) + TemplateArgLoc)) return false; ++NewParm; @@ -8183,7 +8250,7 @@ bool Sema::TemplateParameterListsAreEqual( for (; NewParm != NewParmEnd; ++NewParm) { if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm, OldInstFrom, Complain, Kind, - TemplateArgLoc, PartialOrdering)) + TemplateArgLoc)) return false; } } @@ -8197,7 +8264,8 @@ bool Sema::TemplateParameterListsAreEqual( return false; } - if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) { + if (Kind != TPL_TemplateTemplateArgumentMatch && + Kind != TPL_TemplateParamsEquivalent) { const Expr *NewRC = New->getRequiresClause(); const Expr *OldRC = Old->getRequiresClause(); @@ -10181,14 +10249,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, bool Owned = false; bool IsDependent = false; - UsingShadowDecl* FoundUsing = nullptr; - Decl *TagD = - ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, - AS_none, /*ModulePrivateLoc=*/SourceLocation(), + Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, + NameLoc, Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(), false, TypeResult(), /*IsTypeSpecifier*/ false, - /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside, FoundUsing) - .get(); + /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside).get(); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -11312,6 +11377,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, // Take tokens to avoid allocations LPT->Toks.swap(Toks); LPT->D = FnD; + LPT->FPO = getCurFPFeatures(); LateParsedTemplateMap.insert(std::make_pair(FD, std::move(LPT))); FD->setLateTemplateParsed(true); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9e48a2a35a34..31ea7be2975e 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/TemplateDeduction.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" @@ -37,9 +36,11 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" @@ -211,7 +212,8 @@ static bool isSameDeclaration(Decl *X, Decl *Y) { static DeducedTemplateArgument checkDeducedTemplateArguments(ASTContext &Context, const DeducedTemplateArgument &X, - const DeducedTemplateArgument &Y) { + const DeducedTemplateArgument &Y, + bool AggregateCandidateDeduction = false) { // We have no deduction for one or both of the arguments; they're compatible. if (X.isNull()) return Y; @@ -349,20 +351,24 @@ checkDeducedTemplateArguments(ASTContext &Context, case TemplateArgument::Pack: { if (Y.getKind() != TemplateArgument::Pack || - X.pack_size() != Y.pack_size()) + (!AggregateCandidateDeduction && X.pack_size() != Y.pack_size())) return DeducedTemplateArgument(); llvm::SmallVector<TemplateArgument, 8> NewPack; - for (TemplateArgument::pack_iterator XA = X.pack_begin(), - XAEnd = X.pack_end(), - YA = Y.pack_begin(); + for (TemplateArgument::pack_iterator + XA = X.pack_begin(), + XAEnd = X.pack_end(), YA = Y.pack_begin(), YAEnd = Y.pack_end(); XA != XAEnd; ++XA, ++YA) { - TemplateArgument Merged = checkDeducedTemplateArguments( - Context, DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), - DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound())); - if (Merged.isNull() && !(XA->isNull() && YA->isNull())) - return DeducedTemplateArgument(); - NewPack.push_back(Merged); + if (YA != YAEnd) { + TemplateArgument Merged = checkDeducedTemplateArguments( + Context, DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), + DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound())); + if (Merged.isNull() && !(XA->isNull() && YA->isNull())) + return DeducedTemplateArgument(); + NewPack.push_back(Merged); + } else { + NewPack.push_back(*XA); + } } return DeducedTemplateArgument( @@ -693,8 +699,10 @@ 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) { + TemplateDeductionInfo &Info, TemplateArgument Pattern, + bool DeducePackIfNotAlreadyDeduced = false) + : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info), + DeducePackIfNotAlreadyDeduced(DeducePackIfNotAlreadyDeduced){ unsigned NumNamedPacks = addPacks(Pattern); finishConstruction(NumNamedPacks); } @@ -756,11 +764,8 @@ private: SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - UnexpandedParameterPack U = Unexpanded[I]; - if (U.first.is<const SubstTemplateTypeParmPackType *>() || - U.first.is<const SubstNonTypeTemplateParmPackExpr *>()) - continue; - auto [Depth, Index] = getDepthAndIndex(U); + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); if (Depth == Info.getDeducedDepth()) AddPack(Index); } @@ -941,8 +946,13 @@ public: // Check the new pack matches any previous value. DeducedTemplateArgument OldPack = *Loc; - DeducedTemplateArgument Result = - checkDeducedTemplateArguments(S.Context, OldPack, NewPack); + DeducedTemplateArgument Result = checkDeducedTemplateArguments( + S.Context, OldPack, NewPack, DeducePackIfNotAlreadyDeduced); + + Info.AggregateDeductionCandidateHasMismatchedArity = + OldPack.getKind() == TemplateArgument::Pack && + NewPack.getKind() == TemplateArgument::Pack && + OldPack.pack_size() != NewPack.pack_size() && !Result.isNull(); // If we deferred a deduction of this pack, check that one now too. if (!Result.isNull() && !Pack.DeferredDeduction.isNull()) { @@ -982,6 +992,7 @@ private: TemplateDeductionInfo &Info; unsigned PackElements = 0; bool IsPartiallyExpanded = false; + bool DeducePackIfNotAlreadyDeduced = false; /// The number of expansions, if we have a fully-expanded pack in this scope. std::optional<unsigned> FixedNumExpansions; @@ -1616,7 +1627,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( llvm_unreachable("Type nodes handled above"); case Type::Auto: - // FIXME: Implement deduction in dependent case. + // C++23 [temp.deduct.funcaddr]/3: + // A placeholder type in the return type of a function template is a + // non-deduced context. + // There's no corresponding wording for [temp.deduct.decl], but we treat + // it the same to match other compilers. if (P->isDependentType()) return Sema::TDK_Success; [[fallthrough]]; @@ -1703,10 +1718,12 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!IAA) return Sema::TDK_NonDeducedMismatch; + const auto *IAP = S.Context.getAsIncompleteArrayType(P); + assert(IAP && "Template parameter not of incomplete array type"); + return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, - S.Context.getAsIncompleteArrayType(P)->getElementType(), - IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers); + S, TemplateParams, IAP->getElementType(), IAA->getElementType(), Info, + Deduced, TDF & TDF_IgnoreQualifiers); } // T [integer-constant] @@ -2882,7 +2899,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, // not class-scope explicit specialization, so replace with Deduced Args // instead of adding to inner-most. if (NeedsReplacement) - MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs); + MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs); if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, Info.getLocation(), @@ -3592,11 +3609,28 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); + FunctionDecl *FD = FunctionTemplate->getTemplatedDecl(); + // additional check for inline friend, + // ``` + // template <class F1> int foo(F1 X); + // template <int A1> struct A { + // template <class F1> friend int foo(F1 X) { return A1; } + // }; + // template struct A<1>; + // int a = foo(1.0); + // ``` + const FunctionDecl *FDFriend; + if (FD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None && + FD->isDefined(FDFriend, /*CheckForPendingFriendDefinition*/ true) && + FDFriend->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None) { + FD = const_cast<FunctionDecl *>(FDFriend); + Owner = FD->getLexicalDeclContext(); + } MultiLevelTemplateArgumentList SubstArgs( FunctionTemplate, CanonicalDeducedArgumentList->asArray(), /*Final=*/false); Specialization = cast_or_null<FunctionDecl>( - SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); + SubstDecl(FD, Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) return TDK_SubstitutionFailure; @@ -3732,7 +3766,8 @@ static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, static QualType ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, Expr *Arg, QualType ParamType, - bool ParamWasReference) { + bool ParamWasReference, + TemplateSpecCandidateSet *FailedTSC = nullptr) { OverloadExpr::FindResult R = OverloadExpr::find(Arg); @@ -3754,8 +3789,10 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, !ParamType->isMemberFunctionPointerType()) { if (Ovl->hasExplicitTemplateArgs()) { // But we can still look for an explicit specialization. - if (FunctionDecl *ExplicitSpec - = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) + if (FunctionDecl *ExplicitSpec = + S.ResolveSingleFunctionTemplateSpecialization( + Ovl, /*Complain=*/false, + /*FoundDeclAccessPair=*/nullptr, FailedTSC)) return GetTypeOfFunction(S, R, ExplicitSpec); } @@ -3837,7 +3874,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, /// overloaded function set that could not be resolved. static bool AdjustFunctionParmAndArgTypesForDeduction( Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex, - QualType &ParamType, QualType &ArgType, Expr *Arg, unsigned &TDF) { + QualType &ParamType, QualType &ArgType, Expr *Arg, unsigned &TDF, + TemplateSpecCandidateSet *FailedTSC = nullptr) { // C++0x [temp.deduct.call]p3: // If P is a cv-qualified type, the top level cv-qualifiers of P's type // are ignored for type deduction. @@ -3854,9 +3892,8 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( // but there are sometimes special circumstances. Typically // involving a template-id-expr. if (ArgType == S.Context.OverloadTy) { - ArgType = ResolveOverloadForDeduction(S, TemplateParams, - Arg, ParamType, - ParamRefType != nullptr); + ArgType = ResolveOverloadForDeduction(S, TemplateParams, Arg, ParamType, + ParamRefType != nullptr, FailedTSC); if (ArgType.isNull()) return true; } @@ -3934,7 +3971,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, - bool DecomposedParam, unsigned ArgIdx, unsigned TDF); + bool DecomposedParam, unsigned ArgIdx, unsigned TDF, + TemplateSpecCandidateSet *FailedTSC = nullptr); /// Attempt template argument deduction from an initializer list /// deemed to be an argument in a function call. @@ -4010,14 +4048,16 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, - bool DecomposedParam, unsigned ArgIdx, unsigned TDF) { + bool DecomposedParam, unsigned ArgIdx, unsigned TDF, + TemplateSpecCandidateSet *FailedTSC) { QualType ArgType = Arg->getType(); QualType OrigParamType = ParamType; // If P is a reference type [...] // If P is a cv-qualified type [...] - if (AdjustFunctionParmAndArgTypesForDeduction( - S, TemplateParams, FirstInnerIndex, ParamType, ArgType, Arg, TDF)) + if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, + FirstInnerIndex, ParamType, + ArgType, Arg, TDF, FailedTSC)) return Sema::TDK_Success; // If [...] the argument is a non-empty initializer list [...] @@ -4065,7 +4105,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, - bool PartialOverloading, + bool PartialOverloading, bool AggregateDeductionCandidate, llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -4152,9 +4192,12 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( continue; } + bool IsTrailingPack = ParamIdx + 1 == NumParamTypes; + QualType ParamPattern = ParamExpansion->getPattern(); PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info, - ParamPattern); + ParamPattern, + AggregateDeductionCandidate && IsTrailingPack); // C++0x [temp.deduct.call]p1: // For a function parameter pack that occurs at the end of the @@ -4172,7 +4215,7 @@ 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 || PackScope.hasFixedArity()) { + if (IsTrailingPack || PackScope.hasFixedArity()) { for (; ArgIdx < Args.size() && PackScope.hasNextElement(); PackScope.nextPackElement(), ++ArgIdx) { ParamTypesForArgChecking.push_back(ParamPattern); @@ -4328,11 +4371,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( Deduced.resize(TemplateParams->size()); // If the function has a deduced return type, substitute it for a dependent - // type so that we treat it as a non-deduced context in what follows. If we - // are looking up by signature, the signature type should also have a deduced - // return type, which we instead expect to exactly match. + // type so that we treat it as a non-deduced context in what follows. bool HasDeducedReturnType = false; - if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && + if (getLangOpts().CPlusPlus14 && Function->getReturnType()->getContainedAutoType()) { FunctionType = SubstAutoTypeDependent(FunctionType); HasDeducedReturnType = true; @@ -4360,11 +4401,17 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // If the function has a deduced return type, deduce it now, so we can check // that the deduced function type matches the requested type. - if (HasDeducedReturnType && + if (HasDeducedReturnType && IsAddressOfFunction && Specialization->getReturnType()->isUndeducedType() && DeduceReturnType(Specialization, Info.getLocation(), false)) return TDK_MiscellaneousDeductionFailure; + if (IsAddressOfFunction && getLangOpts().CPlusPlus20 && + Specialization->isImmediateEscalating() && + CheckIfFunctionSpecializationIsImmediate(Specialization, + Info.getLocation())) + return TDK_MiscellaneousDeductionFailure; + // If the function has a dependent exception specification, resolve it now, // so we can check that the exception specification matches. auto *SpecializationFPT = @@ -4379,23 +4426,31 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // noreturn can't be dependent, so we don't actually need this for them // right now.) QualType SpecializationType = Specialization->getType(); - if (!IsAddressOfFunction) + if (!IsAddressOfFunction) { ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType, /*AdjustExceptionSpec*/true); + // Revert placeholder types in the return type back to undeduced types so + // that the comparison below compares the declared return types. + if (HasDeducedReturnType) { + SpecializationType = SubstAutoType(SpecializationType, QualType()); + ArgFunctionType = SubstAutoType(ArgFunctionType, QualType()); + } + } + // If the requested function type does not match the actual type of the // specialization with respect to arguments of compatible pointer to function // types, template argument deduction fails. if (!ArgFunctionType.isNull()) { - if (IsAddressOfFunction && - !isSameOrCompatibleFunctionType( - Context.getCanonicalType(SpecializationType), - Context.getCanonicalType(ArgFunctionType))) - return TDK_MiscellaneousDeductionFailure; - - if (!IsAddressOfFunction && - !Context.hasSameType(SpecializationType, ArgFunctionType)) - return TDK_MiscellaneousDeductionFailure; + if (IsAddressOfFunction + ? !isSameOrCompatibleFunctionType( + Context.getCanonicalType(SpecializationType), + Context.getCanonicalType(ArgFunctionType)) + : !Context.hasSameType(SpecializationType, ArgFunctionType)) { + Info.FirstArg = TemplateArgument(SpecializationType); + Info.SecondArg = TemplateArgument(ArgFunctionType); + return TDK_NonDeducedMismatch; + } } return TDK_Success; @@ -4700,11 +4755,11 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, /// should be specified in the 'Info' parameter. /// \param IgnoreConstraints Set if we should not fail if the deduced type does /// not satisfy the type-constraint in the auto type. -Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, - QualType &Result, - TemplateDeductionInfo &Info, - bool DependentDeduction, - bool IgnoreConstraints) { +Sema::TemplateDeductionResult +Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, + TemplateDeductionInfo &Info, bool DependentDeduction, + bool IgnoreConstraints, + TemplateSpecCandidateSet *FailedTSC) { assert(DependentDeduction || Info.getDeducedDepth() == 0); if (Init->containsErrors()) return TDK_AlreadyDiagnosed; @@ -4818,7 +4873,8 @@ Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, "substituting template parameter for 'auto' failed"); if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0)) + OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, + FailedTSC)) return DeductionFailed(TDK); } @@ -4985,6 +5041,33 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, return StillUndeduced; } +bool Sema::CheckIfFunctionSpecializationIsImmediate(FunctionDecl *FD, + SourceLocation Loc) { + assert(FD->isImmediateEscalating()); + + if (isLambdaConversionOperator(FD)) { + CXXRecordDecl *Lambda = cast<CXXMethodDecl>(FD)->getParent(); + FunctionDecl *CallOp = Lambda->getLambdaCallOperator(); + + // For a generic lambda, instantiate the call operator if needed. + if (auto *Args = FD->getTemplateSpecializationArgs()) { + CallOp = InstantiateFunctionDeclaration( + CallOp->getDescribedFunctionTemplate(), Args, Loc); + if (!CallOp || CallOp->isInvalidDecl()) + return true; + runWithSufficientStackSpace( + Loc, [&] { InstantiateFunctionDefinition(Loc, CallOp); }); + } + return CallOp->isInvalidDecl(); + } + + if (FD->getTemplateInstantiationPattern()) { + runWithSufficientStackSpace( + Loc, [&] { InstantiateFunctionDefinition(Loc, FD); }); + } + return false; +} + /// If this is a non-static member function, static void AddImplicitObjectParameterType(ASTContext &Context, @@ -5282,8 +5365,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // function parameters that positionally correspond between the two // templates are not of the same type, neither template is more specialized // than the other. - if (!TemplateParameterListsAreEqual( - TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + if (!TemplateParameterListsAreEqual(TPL1, TPL2, false, + Sema::TPL_TemplateParamsEquivalent)) return nullptr; for (unsigned i = 0; i < NumParams1; ++i) @@ -5640,8 +5723,8 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1, // function parameters that positionally correspond between the two // templates are not of the same type, neither template is more specialized // than the other. - if (!S.TemplateParameterListsAreEqual( - TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + if (!S.TemplateParameterListsAreEqual(TPL1, TPL2, false, + Sema::TPL_TemplateParamsEquivalent)) return nullptr; if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 2790e78aa53a..8702e2ca3a1b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" @@ -34,6 +35,8 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" #include <optional> @@ -131,6 +134,14 @@ HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, return Response::Done(); } +Response HandlePartialClassTemplateSpec( + const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, + MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { + if (!SkipForSpecialization) + Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); + return Response::Done(); +} + // Add template arguments from a class template instantiation. Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, @@ -153,6 +164,14 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) return Response::Done(); + + // If this was instantiated from a partial template specialization, we need + // to get the next level of declaration context from the partial + // specialization, as the ClassTemplateSpecializationDecl's + // DeclContext/LexicalDeclContext will be for the primary template. + if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial() + .dyn_cast<ClassTemplatePartialSpecializationDecl *>()) + return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext()); } return Response::UseNextDecl(ClassTemplSpec); } @@ -208,6 +227,21 @@ Response HandleFunction(const FunctionDecl *Function, return Response::UseNextDecl(Function); } +Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, + MultiLevelTemplateArgumentList &Result) { + if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) { + NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); + const Type *Ty; + const TemplateSpecializationType *TSTy; + if (NNS && (Ty = NNS->getAsType()) && + (TSTy = Ty->getAs<TemplateSpecializationType>())) + Result.addOuterTemplateArguments(const_cast<FunctionTemplateDecl *>(FTD), + TSTy->template_arguments(), + /*Final=*/false); + } + return Response::ChangeDecl(FTD->getLexicalDeclContext()); +} + Response HandleRecordDecl(const CXXRecordDecl *Rec, MultiLevelTemplateArgumentList &Result, ASTContext &Context, @@ -218,17 +252,17 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec, "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) return Response::Done(); - if (ForConstraintInstantiation) { - QualType RecordType = Context.getTypeDeclType(Rec); - QualType Injected = cast<InjectedClassNameType>(RecordType) - ->getInjectedSpecializationType(); - const auto *InjectedType = cast<TemplateSpecializationType>(Injected); + if (ForConstraintInstantiation) Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec), - InjectedType->template_arguments(), + ClassTemplate->getInjectedTemplateArgs(), /*Final=*/false); - } } + if (const MemberSpecializationInfo *MSInfo = + Rec->getMemberSpecializationInfo()) + if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return Response::Done(); + bool IsFriend = Rec->getFriendObjectKind() || (Rec->getDescribedClassTemplate() && Rec->getDescribedClassTemplate()->getFriendObjectKind()); @@ -294,18 +328,23 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; - if (Innermost) + using namespace TemplateInstArgsHelpers; + const Decl *CurDecl = ND; + if (Innermost) { Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), Innermost->asArray(), Final); - - const Decl *CurDecl = ND; + CurDecl = Response::UseNextDecl(ND).NextDecl; + } while (!CurDecl->isFileContextDecl()) { - using namespace TemplateInstArgsHelpers; Response R; if (const auto *VarTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) { R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); + } else if (const auto *PartialClassTemplSpec = + dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) { + R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result, + SkipForSpecialization); } else if (const auto *ClassTemplSpec = dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { R = HandleClassTemplateSpec(ClassTemplSpec, Result, @@ -318,6 +357,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( } else if (const auto *CSD = dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) { R = HandleImplicitConceptSpecializationDecl(CSD, Result); + } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) { + R = HandleFunctionTemplateDecl(FTD, Result); } else if (!isa<DeclContext>(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); if (CurDecl->getDeclContext()->isTranslationUnit()) { @@ -367,6 +408,8 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case InitializingStructuredBinding: case MarkingClassDllexported: case BuildingBuiltinDumpStructCall: + case LambdaExpressionSubstitution: + case BuildingDeductionGuides: return false; // This function should never be called when Kind's value is Memoization. @@ -583,6 +626,13 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( SemaRef, CodeSynthesisContext::ParameterMappingSubstitution, PointOfInstantiation, InstantiationRange, Template) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Entity, + BuildingDeductionGuidesTag, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::BuildingDeductionGuides, + PointOfInstantiation, InstantiationRange, Entity) {} + void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; @@ -925,11 +975,13 @@ void Sema::PrintInstantiationStack() { << MD->isExplicitlyDefaulted() << DFK.asSpecialMember() << Context.getTagDeclType(MD->getParent()); } else if (DFK.isComparison()) { + QualType RecordType = FD->getParamDecl(0) + ->getType() + .getNonReferenceType() + .getUnqualifiedType(); Diags.Report(Active->PointOfInstantiation, diag::note_comparison_synthesized_at) - << (int)DFK.asComparison() - << Context.getTagDeclType( - cast<CXXRecordDecl>(FD->getLexicalDeclContext())); + << (int)DFK.asComparison() << RecordType; } break; } @@ -961,6 +1013,10 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::Memoization: break; + case CodeSynthesisContext::LambdaExpressionSubstitution: + Diags.Report(Active->PointOfInstantiation, + diag::note_lambda_substitution_here); + break; case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; if (!Active->Entity) { @@ -1008,6 +1064,8 @@ void Sema::PrintInstantiationStack() { diag::note_parameter_mapping_substitution_here) << Active->InstantiationRange; break; + case CodeSynthesisContext::BuildingDeductionGuides: + llvm_unreachable("unexpected deduction guide in instantiation stack"); } } } @@ -1016,6 +1074,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { if (InNonInstantiationSFINAEContext) return std::optional<TemplateDeductionInfo *>(nullptr); + bool SawLambdaSubstitution = false; for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), ActiveEnd = CodeSynthesisContexts.rend(); @@ -1037,6 +1096,15 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return std::nullopt; + case CodeSynthesisContext::LambdaExpressionSubstitution: + // [temp.deduct]p9 + // A lambda-expression appearing in a function type or a template + // parameter is not considered part of the immediate context for the + // purposes of template argument deduction. + + // We need to check parents. + SawLambdaSubstitution = true; + break; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -1049,12 +1117,17 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: + // We're either substituting explicitly-specified template arguments, + // deduced template arguments. SFINAE applies unless we are in a lambda + // expression, see [temp.deduct]p9. + if (SawLambdaSubstitution) + return std::nullopt; + [[fallthrough]]; case CodeSynthesisContext::ConstraintSubstitution: case CodeSynthesisContext::RequirementInstantiation: case CodeSynthesisContext::RequirementParameterInstantiation: - // We're either substituting explicitly-specified template arguments, - // deduced template arguments, a constraint expression or a requirement - // in a requires expression, so SFINAE applies. + // SFINAE always applies in a constraint expression or a requirement + // in a requires expression. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; @@ -1064,6 +1137,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::InitializingStructuredBinding: case CodeSynthesisContext::MarkingClassDllexported: case CodeSynthesisContext::BuildingBuiltinDumpStructCall: + case CodeSynthesisContext::BuildingDeductionGuides: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return std::nullopt; @@ -1231,7 +1305,8 @@ namespace { // We recreated a local declaration, but not by instantiating it. There // may be pending dependent diagnostics to produce. - if (auto *DC = dyn_cast<DeclContext>(Old); DC && DC->isDependentContext()) + if (auto *DC = dyn_cast<DeclContext>(Old); + DC && DC->isDependentContext() && DC->isFunctionOrMethod()) SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } @@ -1271,6 +1346,12 @@ namespace { bool AllowInjectedClassName = false); const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); + const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS, + const Stmt *InstS, + const NoInlineAttr *A); + const AlwaysInlineAttr * + TransformStmtAlwaysInlineAttr(const Stmt *OrigS, const Stmt *InstS, + const AlwaysInlineAttr *A); ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); @@ -1336,12 +1417,21 @@ namespace { ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this); + + Sema::CodeSynthesisContext C; + C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; + C.PointOfInstantiation = E->getBeginLoc(); + SemaRef.pushCodeSynthesisContext(C); + auto PopCtx = + llvm::make_scope_exit([this] { SemaRef.popCodeSynthesisContext(); }); + ExprResult Result = inherited::TransformLambdaExpr(E); if (Result.isInvalid()) return Result; CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator(); for (ParmVarDecl *PVD : MD->parameters()) { + assert(PVD && "null in a parameter list"); if (!PVD->hasDefaultArg()) continue; Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); @@ -1766,6 +1856,20 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(), LH->getState(), TransformedExpr, *LH); } +const NoInlineAttr *TemplateInstantiator::TransformStmtNoInlineAttr( + const Stmt *OrigS, const Stmt *InstS, const NoInlineAttr *A) { + if (!A || getSema().CheckNoInlineAttr(OrigS, InstS, *A)) + return nullptr; + + return A; +} +const AlwaysInlineAttr *TemplateInstantiator::TransformStmtAlwaysInlineAttr( + const Stmt *OrigS, const Stmt *InstS, const AlwaysInlineAttr *A) { + if (!A || getSema().CheckAlwaysInlineAttr(OrigS, InstS, *A)) + return nullptr; + + return A; +} ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7a0da8d08333..f78d46f59503 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -22,6 +22,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" @@ -94,11 +95,14 @@ static void instantiateDependentAlignedAttr( if (!Result.isInvalid()) S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion); } else { - TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(), - TemplateArgs, Aligned->getLocation(), - DeclarationName()); - if (Result) - S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion); + if (TypeSourceInfo *Result = + S.SubstType(Aligned->getAlignmentType(), TemplateArgs, + Aligned->getLocation(), DeclarationName())) { + if (!S.CheckAlignasTypeArgument(Aligned->getSpelling(), Result, + Aligned->getLocation(), + Result->getTypeLoc().getSourceRange())) + S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion); + } } } @@ -834,6 +838,22 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } +/// Update instantiation attributes after template was late parsed. +/// +/// Some attributes are evaluated based on the body of template. If it is +/// late parsed, such attributes cannot be evaluated when declaration is +/// instantiated. This function is used to update instantiation attributes when +/// template definition is ready. +void Sema::updateAttrsForLateParsedTemplate(const Decl *Pattern, Decl *Inst) { + for (const auto *Attr : Pattern->attrs()) { + if (auto *A = dyn_cast<StrictFPAttr>(Attr)) { + if (!Inst->hasAttr<StrictFPAttr>()) + Inst->addAttr(A->clone(getASTContext())); + continue; + } + } +} + /// In the MS ABI, we need to instantiate default arguments of dllexported /// default constructors along with the constructor definition. This allows IR /// gen to emit a constructor closure which calls the default constructor with @@ -1409,11 +1429,14 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { if (InstantiatedAssertExpr.isInvalid()) return nullptr; - return SemaRef.BuildStaticAssertDeclaration(D->getLocation(), - InstantiatedAssertExpr.get(), - D->getMessage(), - D->getRParenLoc(), - D->isFailed()); + ExprResult InstantiatedMessageExpr = + SemaRef.SubstExpr(D->getMessage(), TemplateArgs); + if (InstantiatedMessageExpr.isInvalid()) + return nullptr; + + return SemaRef.BuildStaticAssertDeclaration( + D->getLocation(), InstantiatedAssertExpr.get(), + InstantiatedMessageExpr.get(), D->getRParenLoc(), D->isFailed()); } Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { @@ -1637,33 +1660,12 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { << QualifierLoc.getSourceRange(); return nullptr; } - - if (PrevClassTemplate) { - const ClassTemplateDecl *MostRecentPrevCT = - PrevClassTemplate->getMostRecentDecl(); - TemplateParameterList *PrevParams = - MostRecentPrevCT->getTemplateParameters(); - - // Make sure the parameter lists match. - if (!SemaRef.TemplateParameterListsAreEqual( - D->getTemplatedDecl(), InstParams, - MostRecentPrevCT->getTemplatedDecl(), PrevParams, true, - Sema::TPL_TemplateMatch)) - return nullptr; - - // Do some additional validation, then merge default arguments - // from the existing declarations. - if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, - Sema::TPC_ClassTemplate)) - return nullptr; - } } CXXRecordDecl *RecordInst = CXXRecordDecl::Create( SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getBeginLoc(), Pattern->getLocation(), Pattern->getIdentifier(), PrevDecl, /*DelayTypeCreation=*/true); - if (QualifierLoc) RecordInst->setQualifierInfo(QualifierLoc); @@ -1673,16 +1675,38 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { ClassTemplateDecl *Inst = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, RecordInst); - assert(!(isFriend && Owner->isDependentContext())); - Inst->setPreviousDecl(PrevClassTemplate); - RecordInst->setDescribedClassTemplate(Inst); if (isFriend) { - if (PrevClassTemplate) + assert(!Owner->isDependentContext()); + Inst->setLexicalDeclContext(Owner); + RecordInst->setLexicalDeclContext(Owner); + + if (PrevClassTemplate) { + Inst->setCommonPtr(PrevClassTemplate->getCommonPtr()); + RecordInst->setTypeForDecl( + PrevClassTemplate->getTemplatedDecl()->getTypeForDecl()); + const ClassTemplateDecl *MostRecentPrevCT = + PrevClassTemplate->getMostRecentDecl(); + TemplateParameterList *PrevParams = + MostRecentPrevCT->getTemplateParameters(); + + // Make sure the parameter lists match. + if (!SemaRef.TemplateParameterListsAreEqual( + RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(), + PrevParams, true, Sema::TPL_TemplateMatch)) + return nullptr; + + // Do some additional validation, then merge default arguments + // from the existing declarations. + if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + Sema::TPC_ClassTemplate)) + return nullptr; + Inst->setAccess(PrevClassTemplate->getAccess()); - else + } else { Inst->setAccess(D->getAccess()); + } Inst->setObjectOfFriendDecl(); // TODO: do we want to track the instantiation progeny of this @@ -1693,15 +1717,15 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Inst->setInstantiatedFromMemberTemplate(D); } + Inst->setPreviousDecl(PrevClassTemplate); + // Trigger creation of the type for the instantiation. - SemaRef.Context.getInjectedClassNameType(RecordInst, - Inst->getInjectedClassNameSpecialization()); + SemaRef.Context.getInjectedClassNameType( + RecordInst, Inst->getInjectedClassNameSpecialization()); // Finish handling of friends. if (isFriend) { DC->makeDeclVisibleInContext(Inst); - Inst->setLexicalDeclContext(Owner); - RecordInst->setLexicalDeclContext(Owner); return Inst; } @@ -2108,9 +2132,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Function = CXXDeductionGuideDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), InstantiatedExplicitSpecifier, NameInfo, T, TInfo, - D->getSourceRange().getEnd()); - if (DGuide->isCopyDeductionCandidate()) - cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate(); + D->getSourceRange().getEnd(), /*Ctor=*/nullptr, + DGuide->getDeductionCandidateKind()); Function->setAccess(D->getAccess()); } else { Function = FunctionDecl::Create( @@ -2277,7 +2300,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Filter out previous declarations that don't match the scope. The only // effect this has is to remove declarations found in inline namespaces // for friend declarations with unqualified names. - if (isFriend && !QualifierLoc && !FunctionTemplate) { + if (isFriend && !QualifierLoc) { SemaRef.FilterLookupForScope(Previous, DC, /*Scope=*/ nullptr, /*ConsiderLinkage=*/ true, QualifierLoc.hasQualifier()); @@ -2506,9 +2529,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Constructor->getConstexprKind(), InheritedConstructor(), TrailingRequiresClause); Method->setRangeEnd(Constructor->getEndLoc()); - if (Constructor->isDefaultConstructor() || - Constructor->isCopyOrMoveConstructor()) - Method->setIneligibleOrNotSelected(true); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -2531,8 +2551,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(), D->getEndLoc(), TrailingRequiresClause); - if (D->isMoveAssignmentOperator() || D->isCopyAssignmentOperator()) - Method->setIneligibleOrNotSelected(true); } if (D->isInlined()) @@ -2735,6 +2753,22 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (IsExplicitSpecialization && !isFriend) SemaRef.CompleteMemberSpecialization(Method, Previous); + // If the method is a special member function, we need to mark it as + // ineligible so that Owner->addDecl() won't mark the class as non trivial. + // At the end of the class instantiation, we calculate eligibility again and + // then we adjust trivility if needed. + // We need this check to happen only after the method parameters are set, + // because being e.g. a copy constructor depends on the instantiated + // arguments. + if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Method)) { + if (Constructor->isDefaultConstructor() || + Constructor->isCopyOrMoveConstructor()) + Method->setIneligibleOrNotSelected(true); + } else if (Method->isCopyAssignmentOperator() || + Method->isMoveAssignmentOperator()) { + Method->setIneligibleOrNotSelected(true); + } + // If there's a function template, let our caller handle it. if (FunctionTemplate) { // do nothing @@ -2992,8 +3026,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) if (AutoLoc.isConstrained()) + // Note: We attach the uninstantiated constriant here, so that it can be + // instantiated relative to the top level, like all our other constraints. if (SemaRef.AttachTypeConstraint( - AutoLoc, Param, + AutoLoc, Param, D, IsExpandedParameterPack ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>() .getEllipsisLoc() @@ -4644,11 +4680,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back(); if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { - if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(ActiveInst.Entity)) { - assert(FunTmpl->getTemplatedDecl() == Tmpl && - "Deduction from the wrong function template?"); - (void) FunTmpl; + if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) { SemaRef.InstantiatingSpecializations.erase( {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind}); atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); @@ -4916,6 +4948,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, "missing LateParsedTemplate"); LateTemplateParser(OpaqueParser, *LPTIter->second); Pattern = PatternDecl->getBody(PatternDecl); + updateAttrsForLateParsedTemplate(PatternDecl, Function); } // Note, we should never try to instantiate a deleted function template. @@ -5057,6 +5090,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Function); + FPFeaturesStateRAII SavedFPFeatures(*this); + CurFPFeatures = FPOptions(getLangOpts()); + FpPragmaStack.CurrentValue = FPOptionsOverride(); + if (addInstantiatedParametersToScope(Function, PatternDecl, Scope, TemplateArgs)) return; diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 01a435668d88..dfcc78dafdc4 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -89,23 +89,6 @@ namespace { return true; } - bool - VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc TL) { - Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()}); - return true; - } - - bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *T) { - Unexpanded.push_back({T, SourceLocation()}); - return true; - } - - bool - VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E) { - Unexpanded.push_back({E, E->getParameterPackLocation()}); - return true; - } - /// Record occurrences of function and non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { @@ -324,8 +307,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack); return TTPD && TTPD->getTypeForDecl() == TTPT; } - return declaresSameEntity(Pack.first.get<const NamedDecl *>(), - LocalPack); + return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack); }; if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack)) LambdaParamPackReferences.push_back(Pack); @@ -377,7 +359,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) Name = TTP->getIdentifier(); else - Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier(); + Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -440,7 +422,7 @@ bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) { llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end()); SmallVector<UnexpandedParameterPack, 2> UnexpandedParms; for (auto Parm : Unexpanded) - if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>())) + if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl *>())) UnexpandedParms.push_back(Parm); if (UnexpandedParms.empty()) return false; @@ -692,95 +674,109 @@ bool Sema::CheckParameterPacksForExpansion( bool &RetainExpansion, std::optional<unsigned> &NumExpansions) { ShouldExpand = true; RetainExpansion = false; - std::pair<const IdentifierInfo *, SourceLocation> FirstPack; - std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion; - std::optional<unsigned> CurNumExpansions; + std::pair<IdentifierInfo *, SourceLocation> FirstPack; + bool HaveFirstPack = false; + std::optional<unsigned> NumPartialExpansions; + SourceLocation PartiallySubstitutedPackLoc; - for (auto [P, Loc] : Unexpanded) { + for (UnexpandedParameterPack ParmPack : Unexpanded) { // Compute the depth and index for this parameter pack. - std::optional<std::pair<unsigned, unsigned>> Pos; + unsigned Depth = 0, Index = 0; + IdentifierInfo *Name; + bool IsVarDeclPack = false; + + if (const TemplateTypeParmType *TTP = + ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + Name = TTP->getIdentifier(); + } else { + NamedDecl *ND = ParmPack.first.get<NamedDecl *>(); + if (isa<VarDecl>(ND)) + IsVarDeclPack = true; + else + std::tie(Depth, Index) = getDepthAndIndex(ND); + + Name = ND->getIdentifier(); + } + + // Determine the size of this argument pack. unsigned NewPackSize; - const auto *ND = P.dyn_cast<const NamedDecl *>(); - if (ND && isa<VarDecl>(ND)) { - const auto *DAP = - CurrentInstantiationScope->findInstantiationOf(ND) - ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); - if (!DAP) { + if (IsVarDeclPack) { + // Figure out whether we're instantiating to an argument pack or not. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = + CurrentInstantiationScope->findInstantiationOf( + ParmPack.first.get<NamedDecl *>()); + if (Instantiation->is<DeclArgumentPack *>()) { + // We could expand this function parameter pack. + NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); + } else { // We can't expand this function parameter pack, so we can't expand // the pack expansion. ShouldExpand = false; continue; } - NewPackSize = DAP->size(); - } else if (ND) { - Pos = getDepthAndIndex(ND); - } else if (const auto *TTP = P.dyn_cast<const TemplateTypeParmType *>()) { - Pos = {TTP->getDepth(), TTP->getIndex()}; - ND = TTP->getDecl(); - // FIXME: We either should have some fallback for canonical TTP, or - // never have canonical TTP here. - } else if (const auto *STP = - P.dyn_cast<const SubstTemplateTypeParmPackType *>()) { - NewPackSize = STP->getNumArgs(); - ND = STP->getReplacedParameter(); } else { - const auto *SEP = P.get<const SubstNonTypeTemplateParmPackExpr *>(); - NewPackSize = SEP->getArgumentPack().pack_size(); - ND = SEP->getParameterPack(); - } - - if (Pos) { // If we don't have a template argument at this depth/index, then we // cannot expand the pack expansion. Make a note of this, but we still // want to check any parameter packs we *do* have arguments for. - if (Pos->first >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) { + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) { ShouldExpand = false; continue; } + // Determine the size of the argument pack. - NewPackSize = TemplateArgs(Pos->first, Pos->second).pack_size(); - // C++0x [temp.arg.explicit]p9: - // Template argument deduction can extend the sequence of template - // arguments corresponding to a template parameter pack, even when the - // sequence contains explicitly specified template arguments. - if (CurrentInstantiationScope) - if (const NamedDecl *PartialPack = - CurrentInstantiationScope->getPartiallySubstitutedPack(); - PartialPack && getDepthAndIndex(PartialPack) == *Pos) { + NewPackSize = TemplateArgs(Depth, Index).pack_size(); + } + + // C++0x [temp.arg.explicit]p9: + // Template argument deduction can extend the sequence of template + // arguments corresponding to a template parameter pack, even when the + // sequence contains explicitly specified template arguments. + if (!IsVarDeclPack && CurrentInstantiationScope) { + if (NamedDecl *PartialPack = + CurrentInstantiationScope->getPartiallySubstitutedPack()) { + unsigned PartialDepth, PartialIndex; + std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); + if (PartialDepth == Depth && PartialIndex == Index) { RetainExpansion = true; // We don't actually know the new pack size yet. - PartialExpansion = {NewPackSize, Loc}; + NumPartialExpansions = NewPackSize; + PartiallySubstitutedPackLoc = ParmPack.second; continue; } + } } - // FIXME: Workaround for Canonical TTP. - const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr; - if (!CurNumExpansions) { + if (!NumExpansions) { // The is the first pack we've seen for which we have an argument. // Record it. - CurNumExpansions = NewPackSize; - FirstPack = {Name, Loc}; - } else if (NewPackSize != *CurNumExpansions) { + NumExpansions = NewPackSize; + FirstPack.first = Name; + FirstPack.second = ParmPack.second; + HaveFirstPack = true; + continue; + } + + if (NewPackSize != *NumExpansions) { // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *CurNumExpansions << NewPackSize - << SourceRange(FirstPack.second) << SourceRange(Loc); + if (HaveFirstPack) + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << *NumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); + else + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) + << Name << *NumExpansions << NewPackSize + << SourceRange(ParmPack.second); return true; } } - if (NumExpansions && CurNumExpansions && - *NumExpansions != *CurNumExpansions) { - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << FirstPack.first << *CurNumExpansions << *NumExpansions - << SourceRange(FirstPack.second); - return true; - } - // If we're performing a partial expansion but we also have a full expansion, // expand to the number of common arguments. For example, given: // @@ -790,18 +786,17 @@ bool Sema::CheckParameterPacksForExpansion( // // ... a call to 'A<int, int>().f<int>' should expand the pack once and // retain an expansion. - if (PartialExpansion) { - if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) { + if (NumPartialExpansions) { + if (NumExpansions && *NumExpansions < *NumPartialExpansions) { NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack(); Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) - << PartialPack << PartialExpansion->first << *CurNumExpansions - << SourceRange(PartialExpansion->second); + << PartialPack << *NumPartialExpansions << *NumExpansions + << SourceRange(PartiallySubstitutedPackLoc); return true; } - NumExpansions = PartialExpansion->first; - } else { - NumExpansions = CurNumExpansions; + + NumExpansions = NumPartialExpansions; } return false; @@ -814,48 +809,47 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansion( CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); std::optional<unsigned> Result; - auto setResultSz = [&Result](unsigned Size) { - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; - }; - auto setResultPos = [&](const std::pair<unsigned, unsigned> &Pos) -> bool { - unsigned Depth = Pos.first, Index = Pos.second; - if (Depth >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Depth, Index)) - // The pattern refers to an unknown template argument. We're not ready to - // expand this pack yet. - return true; - // Determine the size of the argument pack. - setResultSz(TemplateArgs(Depth, Index).pack_size()); - return false; - }; + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + // Compute the depth and index for this parameter pack. + unsigned Depth; + unsigned Index; - for (auto [I, _] : Unexpanded) { - if (const auto *TTP = I.dyn_cast<const TemplateTypeParmType *>()) { - if (setResultPos({TTP->getDepth(), TTP->getIndex()})) - return std::nullopt; - } else if (const auto *STP = - I.dyn_cast<const SubstTemplateTypeParmPackType *>()) { - setResultSz(STP->getNumArgs()); - } else if (const auto *SEP = - I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) { - setResultSz(SEP->getArgumentPack().pack_size()); + if (const TemplateTypeParmType *TTP = + Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); } else { - const auto *ND = I.get<const NamedDecl *>(); - // Function parameter pack or init-capture pack. + NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); if (isa<VarDecl>(ND)) { - const auto *DAP = - CurrentInstantiationScope->findInstantiationOf(ND) - ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); - if (!DAP) + // Function parameter pack or init-capture pack. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = + CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get<NamedDecl *>()); + if (Instantiation->is<Decl *>()) // The pattern refers to an unexpanded pack. We're not ready to expand // this pack yet. return std::nullopt; - setResultSz(DAP->size()); - } else if (setResultPos(getDepthAndIndex(ND))) { - return std::nullopt; + + unsigned Size = Instantiation->get<DeclArgumentPack *>()->size(); + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + continue; } + + std::tie(Depth, Index) = getDepthAndIndex(ND); } + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) + // The pattern refers to an unknown template argument. We're not ready to + // expand this pack yet. + return std::nullopt; + + // Determine the size of the argument pack. + unsigned Size = TemplateArgs(Depth, Index).pack_size(); + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; } return Result; @@ -1226,10 +1220,11 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, if (!LHS || !RHS) { Expr *Pack = LHS ? LHS : RHS; assert(Pack && "fold expression with neither LHS nor RHS"); - DiscardOperands(); - if (!Pack->containsUnexpandedParameterPack()) + if (!Pack->containsUnexpandedParameterPack()) { + DiscardOperands(); return Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << Pack->getSourceRange(); + } } BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Operator); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 89d819a77dcb..0aa691d24171 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -38,6 +38,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/ErrorHandling.h" #include <bitset> @@ -102,8 +103,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, } } - S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType - << type; + S.Diag(loc, attr.isRegularKeywordAttribute() + ? diag::err_type_attribute_wrong_type + : diag::warn_type_attribute_wrong_type) + << name << WhichType << type; } // objc_gc applies to Objective-C pointers or, otherwise, to the @@ -125,6 +128,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_VectorCall: \ case ParsedAttr::AT_AArch64VectorPcs: \ case ParsedAttr::AT_AArch64SVEPcs: \ + case ParsedAttr::AT_ArmStreaming: \ case ParsedAttr::AT_AMDGPUKernelCall: \ case ParsedAttr::AT_MSABI: \ case ParsedAttr::AT_SysVABI: \ @@ -683,7 +687,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, for (ParsedAttr &attr : AttrsCopy) { // Do not distribute [[]] attributes. They have strict rules for what // they appertain to. - if (attr.isStandardAttributeSyntax()) + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) continue; switch (attr.getKind()) { @@ -946,7 +950,7 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, // Retrieve the bound. QualType bound = typeParam->getUnderlyingType(); - const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + const auto *boundObjC = bound->castAs<ObjCObjectPointerType>(); // Determine whether the type argument is substitutable for the bound. if (typeArgObjC->isObjCIdType()) { @@ -1498,7 +1502,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type() && !(S.getLangOpts().SYCLIsDevice || S.getLangOpts().CUDAIsDevice || - (S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))) + (S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice))) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__int128"; if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) @@ -1511,16 +1515,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // do not diagnose _Float16 usage to avoid false alarm. // ToDo: more precise diagnostics for CUDA. if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "_Float16"; Result = Context.Float16Ty; break; case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_BFloat16: - if (!S.Context.getTargetInfo().hasBFloat16Type()) - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__bf16"; + if (!S.Context.getTargetInfo().hasBFloat16Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice) && + !S.getLangOpts().SYCLIsDevice) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__bf16"; Result = Context.BFloat16Ty; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; @@ -1543,7 +1548,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type() && !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; Result = Context.Float128Ty; @@ -1551,7 +1556,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_ibm128: if (!S.Context.getTargetInfo().hasIbm128Type() && !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__ibm128"; Result = Context.Ibm128Ty; break; @@ -1588,9 +1593,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); - if (const auto *Using = - dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsFoundDecl())) - Result = Context.getUsingType(Using, Result); // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword @@ -2200,6 +2202,21 @@ QualType Sema::BuildPointerType(QualType T, if (getLangOpts().OpenCL) T = deduceOpenCLPointeeAddrSpace(*this, T); + // In WebAssembly, pointers to reference types and pointers to tables are + // illegal. + if (getASTContext().getTargetInfo().getTriple().isWasm()) { + if (T.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reference_pr) << 0; + return QualType(); + } + + // We need to desugar the type here in case T is a ParenType. + if (T->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_pr) << 0; + return QualType(); + } + } + // Build the pointer type. return Context.getPointerType(T); } @@ -2275,6 +2292,17 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, if (getLangOpts().OpenCL) T = deduceOpenCLPointeeAddrSpace(*this, T); + // In WebAssembly, references to reference types and tables are illegal. + if (getASTContext().getTargetInfo().getTriple().isWasm() && + T.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reference_pr) << 1; + return QualType(); + } + if (T->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_pr) << 1; + return QualType(); + } + // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); @@ -2478,12 +2506,22 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteSizedType(Loc, T, + if (!T.isWebAssemblyReferenceType() && + RequireCompleteSizedType(Loc, T, diag::err_array_incomplete_or_sizeless_type)) return QualType(); } - if (T->isSizelessType()) { + // Multi-dimensional arrays of WebAssembly references are not allowed. + if (Context.getTargetInfo().getTriple().isWasm() && T->isArrayType()) { + const auto *ATy = dyn_cast<ArrayType>(T); + if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reftype_multidimensional_array); + return QualType(); + } + } + + if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) { Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T; return QualType(); } @@ -2602,7 +2640,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, << ArraySize->getSourceRange(); return QualType(); } - if (ConstVal == 0) { + if (ConstVal == 0 && !T.isWebAssemblyReferenceType()) { // GCC accepts zero sized static arrays. We allow them when // we're not in a SFINAE context. Diag(ArraySize->getBeginLoc(), @@ -2671,8 +2709,8 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, return QualType(); } // Only support _BitInt elements with byte-sized power of 2 NumBits. - if (CurType->isBitIntType()) { - unsigned NumBits = CurType->getAs<BitIntType>()->getNumBits(); + if (const auto *BIT = CurType->getAs<BitIntType>()) { + unsigned NumBits = BIT->getNumBits(); if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) << (NumBits < 8); @@ -2753,7 +2791,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, // Only support _BitInt elements with byte-sized power of 2 NumBits. if (T->isBitIntType()) { - unsigned NumBits = T->getAs<BitIntType>()->getNumBits(); + unsigned NumBits = T->castAs<BitIntType>()->getNumBits(); if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) << (NumBits < 8); @@ -2991,6 +3029,9 @@ QualType Sema::BuildFunctionType(QualType T, Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Loc, "*"); Invalid = true; + } else if (ParamType->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_as_function_parameter); + Invalid = true; } // C++2a [dcl.fct]p4: @@ -3632,7 +3673,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::FunctionalCast: if (isa<DeducedTemplateSpecializationType>(Deduced)) break; - if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType && + if (SemaRef.getLangOpts().CPlusPlus23 && IsCXXAutoType && !Auto->isDecltypeAuto()) break; // auto(x) [[fallthrough]]; @@ -4541,7 +4582,7 @@ static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) { return false; } -static bool IsNoDerefableChunk(DeclaratorChunk Chunk) { +static bool IsNoDerefableChunk(const DeclaratorChunk &Chunk) { return (Chunk.Kind == DeclaratorChunk::Pointer || Chunk.Kind == DeclaratorChunk::Array); } @@ -4881,12 +4922,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If we're supposed to infer nullability, do so now. if (inferNullability && !inferNullabilityInnerOnlyComplete) { - ParsedAttr::Syntax syntax = inferNullabilityCS - ? ParsedAttr::AS_ContextSensitiveKeyword - : ParsedAttr::AS_Keyword; + ParsedAttr::Form form = + inferNullabilityCS + ? ParsedAttr::Form::ContextSensitiveKeyword() + : ParsedAttr::Form::Keyword(false /*IsAlignAs*/, + false /*IsRegularKeywordAttribute*/); ParsedAttr *nullabilityAttr = Pool.create( S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), - nullptr, SourceLocation(), nullptr, 0, syntax); + nullptr, SourceLocation(), nullptr, 0, form); attrs.addAtEnd(nullabilityAttr); @@ -4967,6 +5010,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). + + // Track if the produced type matches the structure of the declarator. + // This is used later to decide if we can fill `TypeLoc` from + // `DeclaratorChunk`s. E.g. it must be false if Clang recovers from + // an error by replacing the type with `int`. + bool AreDeclaratorChunksValid = true; for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -5058,6 +5107,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast<Expr*>(ATI.NumElts); ArrayType::ArraySizeModifier ASM; + + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Skip all of these except one to avoid creating + // bad incomplete array types. + if (chunkIndex != 0 && !ArraySize && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) { + // This is a sizeless chunk. If the next is also, skip this one. + DeclaratorChunk &NextDeclType = D.getTypeObject(chunkIndex - 1); + if (NextDeclType.Kind == DeclaratorChunk::Array && + !NextDeclType.Arr.NumElts) + break; + } + if (ATI.isStar) ASM = ArrayType::Star; else if (ATI.hasStatic) @@ -5099,17 +5161,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); } } - const AutoType *AT = T->getContainedAutoType(); - // Allow arrays of auto if we are a generic lambda parameter. - // i.e. [](auto (&array)[5]) { return array[0]; }; OK - if (AT && D.getContext() != DeclaratorContext::LambdaExprParameter) { - // We've already diagnosed this for decltype(auto). - if (!AT->isDecltypeAuto()) - S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Name) << T; - T = QualType(); - break; - } // Array parameters can be marked nullable as well, although it's not // necessary if they're marked 'static'. @@ -5147,6 +5198,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, : diag::err_deduced_return_type); T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } else { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::warn_cxx11_compat_deduced_return_type); @@ -5157,6 +5209,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(D.getBeginLoc(), diag::err_trailing_return_in_parens) << T << D.getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } else if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName) { if (T != Context.DependentTy) { @@ -5164,6 +5218,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, diag::err_deduction_guide_with_complex_decl) << D.getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } } else if (D.getContext() != DeclaratorContext::LambdaExpr && (T.hasQualifiers() || !isa<AutoType>(T) || @@ -5174,6 +5230,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo); if (T.isNull()) { @@ -5214,6 +5272,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } // Do not allow returning half FP value. @@ -5280,6 +5339,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ObjCObjectPointerTypeLoc TLoc = TLB.push<ObjCObjectPointerTypeLoc>(T); TLoc.setStarLoc(FixitLoc); TInfo = TLB.getTypeSourceInfo(Context, T); + } else { + AreDeclaratorChunksValid = false; } D.setInvalidType(true); @@ -5400,6 +5461,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T = (!LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL) ? Context.getFunctionNoProtoType(T, EI) : Context.IntTy; + AreDeclaratorChunksValid = false; break; } @@ -5634,9 +5696,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (!ClsType.isNull()) T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); + else + AreDeclaratorChunksValid = false; + if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } else if (DeclType.Mem.TypeQuals) { T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); } @@ -5654,6 +5720,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; + AreDeclaratorChunksValid = false; } // See if there are any attributes on this declarator chunk. @@ -5912,9 +5979,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } assert(!T.isNull() && "T must not be null at the end of this function"); - if (D.isInvalidType()) + if (!AreDeclaratorChunksValid) return Context.getTrivialTypeSourceInfo(T); - return GetTypeSourceInfoForDeclarator(state, T, TInfo); } @@ -5979,7 +6045,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, ParsedAttr *attr = D.getAttributePool().create( &S.Context.Idents.get("objc_ownership"), SourceLocation(), /*scope*/ nullptr, SourceLocation(), - /*args*/ &Args, 1, ParsedAttr::AS_GNU); + /*args*/ &Args, 1, ParsedAttr::Form::GNU()); chunk.getAttrs().addAtEnd(attr); // TODO: mark whether we did this inference? } @@ -6256,9 +6322,6 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } - void VisitUsingTypeLoc(UsingTypeLoc TL) { - TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); - } void VisitAtomicTypeLoc(AtomicTypeLoc TL) { // An AtomicTypeLoc can come from either an _Atomic(...) type specifier // or an _Atomic qualifier. @@ -6514,6 +6577,12 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Don't create more than one level of incomplete array. + if (CurrTL.getTypeLocClass() == TypeLoc::IncompleteArray && e != 1 && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) + continue; + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) { @@ -7292,12 +7361,12 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" - << "'__ptr64'"; + << "'__ptr64'" << /*isRegularKeyword=*/0; return true; } else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" - << "'__uptr'"; + << "'__uptr'" << /*isRegularKeyword=*/0; return true; } @@ -7337,6 +7406,37 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return false; } +static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State, + QualType &QT, ParsedAttr &PAttr) { + assert(PAttr.getKind() == ParsedAttr::AT_WebAssemblyFuncref); + + Sema &S = State.getSema(); + Attr *A = createSimpleAttr<WebAssemblyFuncrefAttr>(S.Context, PAttr); + + std::bitset<attr::LastAttr> Attrs; + attr::Kind NewAttrKind = A->getKind(); + const auto *AT = dyn_cast<AttributedType>(QT); + while (AT) { + Attrs[AT->getAttrKind()] = true; + AT = dyn_cast<AttributedType>(AT->getModifiedType()); + } + + // You cannot specify duplicate type attributes, so if the attribute has + // already been applied, flag it. + if (Attrs[NewAttrKind]) { + S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; + return true; + } + + // Add address space to type based on its attributes. + LangAS ASIdx = LangAS::wasm_funcref; + QualType Pointee = QT->getPointeeType(); + Pointee = S.Context.getAddrSpaceQualType( + S.Context.removeAddrSpaceQualType(Pointee), ASIdx); + QT = State.getAttributedType(A, QT, S.Context.getPointerType(Pointee)); + return false; +} + /// Map a nullability attribute kind to a nullability kind. static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { switch (kind) { @@ -7640,6 +7740,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr<AArch64VectorPcsAttr>(Ctx, Attr); case ParsedAttr::AT_AArch64SVEPcs: return createSimpleAttr<AArch64SVEPcsAttr>(Ctx, Attr); + case ParsedAttr::AT_ArmStreaming: + return createSimpleAttr<ArmStreamingAttr>(Ctx, Attr); case ParsedAttr::AT_AMDGPUKernelCall: return createSimpleAttr<AMDGPUKernelCallAttr>(Ctx, Attr); case ParsedAttr::AT_Pcs: { @@ -7787,8 +7889,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, CallingConv CC = fn->getCallConv(); if (CC == CC_X86FastCall) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << "regparm"; + << FunctionType::getNameForCallConv(CC) << "regparm" + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7867,8 +7969,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // and the CCs don't match. if (S.getCallingConvAttributedType(type)) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << FunctionType::getNameForCallConv(CCOld); + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7900,7 +8003,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Also diagnose fastcall with regparm. if (CC == CC_X86FastCall && fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall); + << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -8091,10 +8195,18 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, /// match one of the standard Neon vector types. static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S, VectorType::VectorKind VecKind) { + bool IsTargetCUDAAndHostARM = false; + if (S.getLangOpts().CUDAIsDevice) { + const TargetInfo *AuxTI = S.getASTContext().getAuxTargetInfo(); + IsTargetCUDAAndHostARM = + AuxTI && (AuxTI->getTriple().isAArch64() || AuxTI->getTriple().isARM()); + } + // Target must have NEON (or MVE, whose vectors are similar enough // not to need a separate attribute) - if (!S.Context.getTargetInfo().hasFeature("neon") && - !S.Context.getTargetInfo().hasFeature("mve")) { + if (!(S.Context.getTargetInfo().hasFeature("neon") || + S.Context.getTargetInfo().hasFeature("mve") || + IsTargetCUDAAndHostARM)) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr << "'neon' or 'mve'"; Attr.setInvalid(); @@ -8102,8 +8214,8 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr - << 1; + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; Attr.setInvalid(); return; } @@ -8113,7 +8225,8 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, return; // Only certain element types are supported for Neon vectors. - if (!isPermittedNeonBaseType(CurType, VecKind, S)) { + if (!isPermittedNeonBaseType(CurType, VecKind, S) && + !IsTargetCUDAAndHostARM) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; Attr.setInvalid(); return; @@ -8216,6 +8329,69 @@ static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State, CurType, CurType); } +/// HandleRISCVRVVVectorBitsTypeAttr - The "riscv_rvv_vector_bits" attribute is +/// used to create fixed-length versions of sizeless RVV types such as +/// vint8m1_t_t. +static void HandleRISCVRVVVectorBitsTypeAttr(QualType &CurType, + ParsedAttr &Attr, Sema &S) { + // Target must have vector extension. + if (!S.Context.getTargetInfo().hasFeature("zve32x")) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) + << Attr << "'zve32x'"; + Attr.setInvalid(); + return; + } + + auto VScale = S.Context.getTargetInfo().getVScaleRange(S.getLangOpts()); + if (!VScale || !VScale->first || VScale->first != VScale->second) { + S.Diag(Attr.getLoc(), diag::err_attribute_riscv_rvv_bits_unsupported) + << Attr; + Attr.setInvalid(); + return; + } + + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return; + } + + // The vector size must be an integer constant expression. + llvm::APSInt RVVVectorSizeInBits(32); + if (!verifyValidIntegerConstantExpr(S, Attr, RVVVectorSizeInBits)) + return; + + // Attribute can only be attached to a single RVV vector type. + if (!CurType->isRVVVLSBuiltinType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_rvv_type) + << Attr << CurType; + Attr.setInvalid(); + return; + } + + unsigned VecSize = static_cast<unsigned>(RVVVectorSizeInBits.getZExtValue()); + + ASTContext::BuiltinVectorTypeInfo Info = + S.Context.getBuiltinVectorTypeInfo(CurType->castAs<BuiltinType>()); + unsigned EltSize = S.Context.getTypeSize(Info.ElementType); + unsigned MinElts = Info.EC.getKnownMinValue(); + + // The attribute vector size must match -mrvv-vector-bits. + unsigned ExpectedSize = VScale->first * MinElts * EltSize; + if (VecSize != ExpectedSize) { + S.Diag(Attr.getLoc(), diag::err_attribute_bad_rvv_vector_size) + << VecSize << ExpectedSize; + Attr.setInvalid(); + return; + } + + VectorType::VectorKind VecKind = VectorType::RVVFixedLengthDataVector; + VecSize /= EltSize; + CurType = S.Context.getVectorType(Info.ElementType, VecSize, VecKind); +} + /// Handle OpenCL Access Qualifier Attribute. static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { @@ -8354,12 +8530,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (attr.isInvalid()) continue; - if (attr.isStandardAttributeSyntax()) { + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) { // [[gnu::...]] attributes are treated as declaration attributes, so may // not appertain to a DeclaratorChunk. If we handle them as type // attributes, accept them in that position and diagnose the GCC // incompatibility. if (attr.isGNUScope()) { + assert(attr.isStandardAttributeSyntax()); bool IsTypeAttr = attr.isTypeAttr(); if (TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), @@ -8387,9 +8564,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, switch (attr.getKind()) { default: // A [[]] attribute on a declarator chunk must appertain to a type. - if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) { + if ((attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) && + TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr) - << attr; + << attr << attr.isRegularKeywordAttribute(); attr.setUsedAsTypeAttr(); } break; @@ -8462,6 +8641,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; } + case ParsedAttr::AT_RISCVRVVVectorBits: + HandleRISCVRVVVectorBitsTypeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); + break; case ParsedAttr::AT_OpenCLAccess: HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); @@ -8494,6 +8677,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; + case ParsedAttr::AT_WebAssemblyFuncref: { + if (!HandleWebAssemblyFuncrefAttr(state, type, attr)) + attr.setUsedAsTypeAttr(); + break; + } + MS_TYPE_ATTRS_CASELIST: if (!handleMSPointerTypeQualifierAttr(state, attr, type)) attr.setUsedAsTypeAttr(); @@ -8560,7 +8749,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // Attributes with standard syntax have strict rules for what they // appertain to and hence should not use the "distribution" logic below. - if (attr.isStandardAttributeSyntax()) { + if (attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) { if (!handleFunctionTypeAttr(state, attr, type)) { diagnoseBadTypeAttribute(state.getSema(), attr, type); attr.setInvalid(); @@ -8895,8 +9085,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { ? S.ImplicitMSInheritanceAttrLoc : RD->getSourceRange(); RD->addAttr(MSInheritanceAttr::CreateImplicit( - S.getASTContext(), BestCase, Loc, AttributeCommonInfo::AS_Microsoft, - MSInheritanceAttr::Spelling(IM))); + S.getASTContext(), BestCase, Loc, MSInheritanceAttr::Spelling(IM))); S.Consumer.AssignInheritanceModel(RD); } } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6a05ecc5370f..10b3587885e3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -19,8 +19,8 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" -#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/OpenMPClause.h" @@ -31,6 +31,7 @@ #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedTemplate.h" @@ -377,22 +378,43 @@ public: /// By default, this routine transforms a statement by delegating to the /// appropriate TransformXXXAttr function to transform a specific kind /// of attribute. Subclasses may override this function to transform - /// attributed statements using some other mechanism. + /// attributed statements/types using some other mechanism. /// /// \returns the transformed attribute const Attr *TransformAttr(const Attr *S); -/// Transform the specified attribute. -/// -/// Subclasses should override the transformation of attributes with a pragma -/// spelling to transform expressions stored within the attribute. -/// -/// \returns the transformed attribute. -#define ATTR(X) -#define PRAGMA_SPELLING_ATTR(X) \ + // Transform the given statement attribute. + // + // Delegates to the appropriate TransformXXXAttr function to transform a + // specific kind of statement attribute. Unlike the non-statement taking + // version of this, this implements all attributes, not just pragmas. + const Attr *TransformStmtAttr(const Stmt *OrigS, const Stmt *InstS, + const Attr *A); + + // Transform the specified attribute. + // + // Subclasses should override the transformation of attributes with a pragma + // spelling to transform expressions stored within the attribute. + // + // \returns the transformed attribute. +#define ATTR(X) \ const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; } #include "clang/Basic/AttrList.inc" + // Transform the specified attribute. + // + // Subclasses should override the transformation of attributes to do + // transformation and checking of statement attributes. By default, this + // delegates to the non-statement taking version. + // + // \returns the transformed attribute. +#define ATTR(X) \ + const X##Attr *TransformStmt##X##Attr(const Stmt *, const Stmt *, \ + const X##Attr *A) { \ + return getDerived().Transform##X##Attr(A); \ + } +#include "clang/Basic/AttrList.inc" + /// Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the @@ -2400,6 +2422,19 @@ public: return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'doacross' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPDoacrossClause(OpenMPDoacrossClauseModifier DepType, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDoacrossClause( + DepType, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -2803,6 +2838,21 @@ public: R.addDecl(FoundDecl); R.resolveKind(); + if (getSema().isUnevaluatedContext() && Base->isImplicitCXXThis() && + isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(Member)) { + if (auto *ThisClass = cast<CXXThisExpr>(Base) + ->getType() + ->getPointeeType() + ->getAsCXXRecordDecl()) { + auto *Class = cast<CXXRecordDecl>(Member->getDeclContext()); + // In unevaluated contexts, an expression supposed to be a member access + // might reference a member in an unrelated class. + if (!ThisClass->Equals(Class) && !ThisClass->isDerivedFrom(Class)) + return getSema().BuildDeclRefExpr(Member, Member->getType(), + VK_LValue, Member->getLocation()); + } + } + return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow, SS, TemplateKWLoc, FirstQualifierInScope, @@ -2977,7 +3027,7 @@ public: RParenLoc); } - /// Build a new generic selection expression. + /// Build a new generic selection expression with an expression predicate. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -2988,9 +3038,25 @@ public: ArrayRef<TypeSourceInfo *> Types, ArrayRef<Expr *> Exprs) { return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + /*PredicateIsExpr=*/true, ControllingExpr, Types, Exprs); } + /// Build a new generic selection expression with a type predicate. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + TypeSourceInfo *ControllingType, + ArrayRef<TypeSourceInfo *> Types, + ArrayRef<Expr *> Exprs) { + return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + /*PredicateIsExpr=*/false, + ControllingType, Types, Exprs); + } + /// Build a new overloaded operator call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3000,10 +3066,11 @@ public: /// argument-dependent lookup, etc. Subclasses may override this routine to /// provide different behavior. ExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr *Callee, - Expr *First, - Expr *Second); + SourceLocation OpLoc, + SourceLocation CalleeLoc, + bool RequiresADL, + const UnresolvedSetImpl &Functions, + Expr *First, Expr *Second); /// Build a new C++ "named" cast expression, such as static_cast or /// reinterpret_cast. @@ -3137,6 +3204,13 @@ public: Expr *Sub, SourceLocation RParenLoc, bool ListInitialization) { + // If Sub is a ParenListExpr, then Sub is the syntatic form of a + // CXXParenListInitExpr. Pass its expanded arguments so that the + // CXXParenListInitExpr can be rebuilt. + if (auto *PLE = dyn_cast<ParenListExpr>(Sub)) + return getSema().BuildCXXTypeConstructExpr( + TInfo, LParenLoc, MultiExprArg(PLE->getExprs(), PLE->getNumExprs()), + RParenLoc, ListInitialization); return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc, MultiExprArg(&Sub, 1), RParenLoc, ListInitialization); @@ -3866,16 +3940,6 @@ public: return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } - ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T, - unsigned NumUserSpecifiedExprs, - SourceLocation InitLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - return CXXParenListInitExpr::Create(getSema().Context, Args, T, - NumUserSpecifiedExprs, InitLoc, - LParenLoc, RParenLoc); - } - /// Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. @@ -4569,7 +4633,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( getSema(), Uneval ? Sema::ExpressionEvaluationContext::Unevaluated : Sema::ExpressionEvaluationContext::ConstantEvaluated, - /*LambdaContextDecl=*/nullptr, /*ExprContext=*/ + Sema::ReuseLambdaContextDecl, /*ExprContext=*/ Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); Expr *InputExpr = Input.getSourceExpression(); @@ -5897,7 +5961,6 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); - NumExpansions = Expansion->getNumExpansions(); SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); @@ -6992,7 +7055,8 @@ QualType TreeTransform<Derived>::TransformAttributedType( // type sugar, and therefore cannot be diagnosed in any other way. if (auto nullability = oldType->getImmediateNullability()) { if (!modifiedType->canHaveNullability()) { - SemaRef.Diag(TL.getAttr()->getLocation(), + SemaRef.Diag((TL.getAttr() ? TL.getAttr()->getLocation() + : TL.getModifiedLoc().getBeginLoc()), diag::err_nullability_nonpointer) << DiagNullabilityKind(*nullability, false) << modifiedType; return QualType(); @@ -7536,36 +7600,52 @@ const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) { return R; switch (R->getKind()) { -// Transform attributes with a pragma spelling by calling TransformXXXAttr. -#define ATTR(X) -#define PRAGMA_SPELLING_ATTR(X) \ +// Transform attributes by calling TransformXXXAttr. +#define ATTR(X) \ case attr::X: \ return getDerived().Transform##X##Attr(cast<X##Attr>(R)); #include "clang/Basic/AttrList.inc" - default: + } + return R; +} + +template <typename Derived> +const Attr *TreeTransform<Derived>::TransformStmtAttr(const Stmt *OrigS, + const Stmt *InstS, + const Attr *R) { + if (!R) return R; + + switch (R->getKind()) { +// Transform attributes by calling TransformStmtXXXAttr. +#define ATTR(X) \ + case attr::X: \ + return getDerived().TransformStmt##X##Attr(OrigS, InstS, cast<X##Attr>(R)); +#include "clang/Basic/AttrList.inc" } + return TransformAttr(R); } template <typename Derived> StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S, StmtDiscardKind SDK) { + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); + if (SubStmt.isInvalid()) + return StmtError(); + bool AttrsChanged = false; SmallVector<const Attr *, 1> Attrs; // Visit attributes and keep track if any are transformed. for (const auto *I : S->getAttrs()) { - const Attr *R = getDerived().TransformAttr(I); + const Attr *R = + getDerived().TransformStmtAttr(S->getSubStmt(), SubStmt.get(), I); AttrsChanged |= (I != R); if (R) Attrs.push_back(R); } - StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); - if (SubStmt.isInvalid()) - return StmtError(); - if (SubStmt.get() == S->getSubStmt() && !AttrsChanged) return S; @@ -7943,8 +8023,7 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { TransformedExprs, S->getEndLoc()); } -// C++ Coroutines TS - +// C++ Coroutines template<typename Derived> StmtResult TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { @@ -8052,6 +8131,13 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { return StmtError(); Builder.Deallocate = DeallocRes.get(); + if (auto *ResultDecl = S->getResultDecl()) { + StmtResult Res = getDerived().TransformStmt(ResultDecl); + if (Res.isInvalid()) + return StmtError(); + Builder.ResultDecl = Res.get(); + } + if (auto *ReturnStmt = S->getReturnStmt()) { StmtResult Res = getDerived().TransformStmt(ReturnStmt); if (Res.isInvalid()) @@ -10654,6 +10740,22 @@ OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause( Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPDoacrossClause(OMPDoacrossClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPDoacrossClause( + C->getDependenceType(), C->getDependenceLoc(), C->getColonLoc(), Vars, + C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -10797,9 +10899,14 @@ TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { - ExprResult ControllingExpr = - getDerived().TransformExpr(E->getControllingExpr()); - if (ControllingExpr.isInvalid()) + ExprResult ControllingExpr; + TypeSourceInfo *ControllingType = nullptr; + if (E->isExprPredicate()) + ControllingExpr = getDerived().TransformExpr(E->getControllingExpr()); + else + ControllingType = getDerived().TransformType(E->getControllingType()); + + if (ControllingExpr.isInvalid() && !ControllingType) return ExprError(); SmallVector<Expr *, 4> AssocExprs; @@ -10822,12 +10929,16 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { AssocExprs.push_back(AssocExpr.get()); } + if (!ControllingType) return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(), E->getDefaultLoc(), E->getRParenLoc(), ControllingExpr.get(), AssocTypes, AssocExprs); + return getDerived().RebuildGenericSelectionExpr( + E->getGenericLoc(), E->getDefaultLoc(), E->getRParenLoc(), + ControllingType, AssocTypes, AssocExprs); } template<typename Derived> @@ -11346,7 +11457,8 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { if (LHS.isInvalid()) return ExprError(); - ExprResult RHS = getDerived().TransformExpr(E->getRHS()); + ExprResult RHS = + getDerived().TransformInitializer(E->getRHS(), /*NotCopyInit=*/false); if (RHS.isInvalid()) return ExprError(); @@ -11606,13 +11718,12 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { bool ExprChanged = false; for (const DesignatedInitExpr::Designator &D : E->designators()) { if (D.isFieldDesignator()) { - Desig.AddDesignator(Designator::getField(D.getFieldName(), - D.getDotLoc(), - D.getFieldLoc())); - if (D.getField()) { + Desig.AddDesignator(Designator::CreateFieldDesignator( + D.getFieldName(), D.getDotLoc(), D.getFieldLoc())); + if (D.getFieldDecl()) { FieldDecl *Field = cast_or_null<FieldDecl>( - getDerived().TransformDecl(D.getFieldLoc(), D.getField())); - if (Field != D.getField()) + getDerived().TransformDecl(D.getFieldLoc(), D.getFieldDecl())); + if (Field != D.getFieldDecl()) // Rebuild the expression when the transformed FieldDecl is // different to the already assigned FieldDecl. ExprChanged = true; @@ -11631,7 +11742,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { return ExprError(); Desig.AddDesignator( - Designator::getArray(Index.get(), D.getLBracketLoc())); + Designator::CreateArrayDesignator(Index.get(), D.getLBracketLoc())); ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(D); ArrayExprs.push_back(Index.get()); @@ -11648,10 +11759,8 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { if (End.isInvalid()) return ExprError(); - Desig.AddDesignator(Designator::getArrayRange(Start.get(), - End.get(), - D.getLBracketLoc(), - D.getEllipsisLoc())); + Desig.AddDesignator(Designator::CreateArrayRangeDesignator( + Start.get(), End.get(), D.getLBracketLoc(), D.getEllipsisLoc())); ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(D) || End.get() != E->getArrayRangeEnd(D); @@ -11883,10 +11992,6 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { llvm_unreachable("not an overloaded operator?"); } - ExprResult Callee = getDerived().TransformExpr(E->getCallee()); - if (Callee.isInvalid()) - return ExprError(); - ExprResult First; if (E->getOperator() == OO_Amp) First = getDerived().TransformAddressOfOperand(E->getArg(0)); @@ -11897,28 +12002,45 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { ExprResult Second; if (E->getNumArgs() == 2) { - Second = getDerived().TransformExpr(E->getArg(1)); + Second = + getDerived().TransformInitializer(E->getArg(1), /*NotCopyInit=*/false); if (Second.isInvalid()) return ExprError(); } - if (!getDerived().AlwaysRebuild() && - Callee.get() == E->getCallee() && - First.get() == E->getArg(0) && - (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) - return SemaRef.MaybeBindToTemporary(E); - Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); FPOptionsOverride NewOverrides(E->getFPFeatures()); getSema().CurFPFeatures = NewOverrides.applyOverrides(getSema().getLangOpts()); getSema().FpPragmaStack.CurrentValue = NewOverrides; - return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), - E->getOperatorLoc(), - Callee.get(), - First.get(), - Second.get()); + Expr *Callee = E->getCallee(); + if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) { + LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), + Sema::LookupOrdinaryName); + if (getDerived().TransformOverloadExprDecls(ULE, ULE->requiresADL(), R)) + return ExprError(); + + return getDerived().RebuildCXXOperatorCallExpr( + E->getOperator(), E->getOperatorLoc(), Callee->getBeginLoc(), + ULE->requiresADL(), R.asUnresolvedSet(), First.get(), Second.get()); + } + + UnresolvedSet<1> Functions; + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) + Callee = ICE->getSubExprAsWritten(); + NamedDecl *DR = cast<DeclRefExpr>(Callee)->getDecl(); + ValueDecl *VD = cast_or_null<ValueDecl>( + getDerived().TransformDecl(DR->getLocation(), DR)); + if (!VD) + return ExprError(); + + if (!isa<CXXMethodDecl>(VD)) + Functions.addDecl(VD); + + return getDerived().RebuildCXXOperatorCallExpr( + E->getOperator(), E->getOperatorLoc(), Callee->getBeginLoc(), + /*RequiresADL=*/false, Functions, First.get(), Second.get()); } template<typename Derived> @@ -13237,37 +13359,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { LambdaScopeInfo *LSI = getSema().PushLambdaScope(); Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); - // Transform the template parameters, and add them to the current - // instantiation scope. The null case is handled correctly. - auto TPL = getDerived().TransformTemplateParameterList( - E->getTemplateParameterList()); - LSI->GLTemplateParameterList = TPL; - - // Transform the type of the original lambda's call operator. - // The transformation MUST be done in the CurrentInstantiationScope since - // it introduces a mapping of the original to the newly created - // transformed parameters. - TypeSourceInfo *NewCallOpTSI = nullptr; - { - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - FunctionProtoTypeLoc OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); - - TypeLocBuilder NewCallOpTLBuilder; - SmallVector<QualType, 4> ExceptionStorage; - TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. - QualType NewCallOpType = TransformFunctionProtoType( - NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, - ExceptionStorage, Changed); - }); - if (NewCallOpType.isNull()) - return ExprError(); - NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, - NewCallOpType); - } - // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated @@ -13284,49 +13375,24 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { DependencyKind = CXXRecordDecl::LDK_NeverDependent; CXXRecordDecl *OldClass = E->getLambdaClass(); - CXXRecordDecl *Class = - getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI, - DependencyKind, E->getCaptureDefault()); - + CXXRecordDecl *Class = getSema().createLambdaClosureType( + E->getIntroducerRange(), /*Info=*/nullptr, DependencyKind, + E->getCaptureDefault()); getDerived().transformedLocalDecl(OldClass, {Class}); - std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling; - if (getDerived().ReplacingOriginal()) - Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(), - OldClass->getLambdaManglingNumber(), - OldClass->getDeviceLambdaManglingNumber(), - OldClass->getLambdaContextDecl()); - - // Build the call operator. - CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( - Class, E->getIntroducerRange(), NewCallOpTSI, - E->getCallOperator()->getEndLoc(), - NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), - E->getCallOperator()->getConstexprKind(), - E->getCallOperator()->getStorageClass(), - E->getCallOperator()->getTrailingRequiresClause()); - - LSI->CallOperator = NewCallOperator; - - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); + CXXMethodDecl *NewCallOperator = + getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class); + NewCallOperator->setLexicalDeclContext(getSema().CurContext); - // Number the lambda for linkage purposes if necessary. - getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); + // Enter the scope of the lambda. + getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(), + E->getCaptureDefault(), E->getCaptureDefaultLoc(), + E->hasExplicitParameters(), E->isMutable()); // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); - // Enter the scope of the lambda. - getSema().buildLambdaScope(LSI, NewCallOperator, - E->getIntroducerRange(), - E->getCaptureDefault(), - E->getCaptureDefaultLoc(), - E->hasExplicitParameters(), - E->hasExplicitResultType(), - E->isMutable()); - bool Invalid = false; // Transform captures. @@ -13366,7 +13432,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl( OldVD->getLocation(), InitQualType, NewC.EllipsisLoc, - OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get()); + OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get(), + getSema().CurContext); if (!NewVD) { Invalid = true; break; @@ -13446,6 +13513,61 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } getSema().finishLambdaExplicitCaptures(LSI); + // Transform the template parameters, and add them to the current + // instantiation scope. The null case is handled correctly. + auto TPL = getDerived().TransformTemplateParameterList( + E->getTemplateParameterList()); + LSI->GLTemplateParameterList = TPL; + + // Transform the type of the original lambda's call operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. + TypeSourceInfo *NewCallOpTSI = nullptr; + { + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + auto OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + + TypeLocBuilder NewCallOpTLBuilder; + SmallVector<QualType, 4> ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + if (NewCallOpType.isNull()) + return ExprError(); + NewCallOpTSI = + NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); + } + + getSema().CompleteLambdaCallOperator( + NewCallOperator, E->getCallOperator()->getLocation(), + E->getCallOperator()->getInnerLocStart(), + E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI, + E->getCallOperator()->getConstexprKind(), + E->getCallOperator()->getStorageClass(), + NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), + E->hasExplicitResultType()); + + getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); + getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); + + { + // Number the lambda for linkage purposes if necessary. + Sema::ContextRAII ManglingContext(getSema(), Class->getDeclContext()); + + std::optional<CXXRecordDecl::LambdaNumbering> Numbering; + if (getDerived().ReplacingOriginal()) { + Numbering = OldClass->getLambdaNumbering(); + } + + getSema().handleLambdaNumbering(Class, NewCallOperator, Numbering); + } + // FIXME: Sema's lambda-building mechanism expects us to push an expression // evaluation context even if we're not transforming the function body. getSema().PushExpressionEvaluationContext( @@ -14028,13 +14150,17 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { // We've got down to a single element; build a binary operator. Expr *LHS = LeftFold ? Result.get() : Out.get(); Expr *RHS = LeftFold ? Out.get() : Result.get(); - if (Callee) + if (Callee) { + UnresolvedSet<16> Functions; + Functions.append(Callee->decls_begin(), Callee->decls_end()); Result = getDerived().RebuildCXXOperatorCallExpr( BinaryOperator::getOverloadedOperator(E->getOperator()), - E->getEllipsisLoc(), Callee, LHS, RHS); - else + E->getEllipsisLoc(), Callee->getBeginLoc(), Callee->requiresADL(), + Functions, LHS, RHS); + } else { Result = getDerived().RebuildBinaryOperator(E->getEllipsisLoc(), E->getOperator(), LHS, RHS); + } } else Result = Out; @@ -14076,9 +14202,8 @@ TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) { TransformedInits)) return ExprError(); - return getDerived().RebuildCXXParenListInitExpr( - TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(), - E->getInitLoc(), E->getBeginLoc(), E->getEndLoc()); + return getDerived().RebuildParenListExpr(E->getBeginLoc(), TransformedInits, + E->getEndLoc()); } template<typename Derived> @@ -14600,7 +14725,12 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { oldCapture)); assert(blockScope->CaptureMap.count(newCapture)); } - assert(oldBlock->capturesCXXThis() == blockScope->isCXXThisCaptured()); + + // The this pointer may not be captured by the instantiated block, even when + // it's captured by the original block, if the expression causing the + // capture is in the discarded branch of a constexpr if statement. + assert((!blockScope->isCXXThisCaptured() || oldBlock->capturesCXXThis()) && + "this pointer isn't captured in the old block"); } #endif @@ -15034,14 +15164,11 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, return Template.get(); } -template<typename Derived> -ExprResult -TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr *OrigCallee, - Expr *First, - Expr *Second) { - Expr *Callee = OrigCallee->IgnoreParenCasts(); +template <typename Derived> +ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr( + OverloadedOperatorKind Op, SourceLocation OpLoc, SourceLocation CalleeLoc, + bool RequiresADL, const UnresolvedSetImpl &Functions, Expr *First, + Expr *Second) { bool isPostIncDec = Second && (Op == OO_PlusPlus || Op == OO_MinusMinus); if (First->getObjectKind() == OK_ObjCProperty) { @@ -15066,8 +15193,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (Op == OO_Subscript) { if (!First->getType()->isOverloadableType() && !Second->getType()->isOverloadableType()) - return getSema().CreateBuiltinArraySubscriptExpr( - First, Callee->getBeginLoc(), Second, OpLoc); + return getSema().CreateBuiltinArraySubscriptExpr(First, CalleeLoc, Second, + OpLoc); } else if (Op == OO_Arrow) { // It is possible that the type refers to a RecoveryExpr created earlier // in the tree transformation. @@ -15101,27 +15228,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, } } - // Compute the transformed set of functions (and function templates) to be - // used during overload resolution. - UnresolvedSet<16> Functions; - bool RequiresADL; - - if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) { - Functions.append(ULE->decls_begin(), ULE->decls_end()); - // If the overload could not be resolved in the template definition - // (because we had a dependent argument), ADL is performed as part of - // template instantiation. - RequiresADL = ULE->requiresADL(); - } else { - // If we've resolved this to a particular non-member function, just call - // that function. If we resolved it to a member function, - // CreateOverloaded* will find that function for us. - NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl(); - if (!isa<CXXMethodDecl>(ND)) - Functions.addDecl(ND); - RequiresADL = false; - } - // Add any functions found via argument-dependent lookup. Expr *Args[2] = { First, Second }; unsigned NumArgs = 1 + (Second != nullptr); @@ -15134,23 +15240,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, RequiresADL); } - if (Op == OO_Subscript) { - SourceLocation LBrace; - SourceLocation RBrace; - - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) { - DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo(); - LBrace = NameLoc.getCXXOperatorNameBeginLoc(); - RBrace = NameLoc.getCXXOperatorNameEndLoc(); - } else { - LBrace = Callee->getBeginLoc(); - RBrace = OpLoc; - } - - return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace, - First, Second); - } - // Create the overloaded operator invocation for binary operators. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); ExprResult Result = SemaRef.CreateOverloadedBinOp( |