aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-07-26 19:03:47 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-07-26 19:04:23 +0000
commit7fa27ce4a07f19b07799a767fc29416f3b625afb (patch)
tree27825c83636c4de341eb09a74f49f5d38a15d165 /clang/lib/Sema
parente3b557809604d036af6e00c60f012c2025b59a5e (diff)
downloadsrc-7fa27ce4a07f19b07799a767fc29416f3b625afb.tar.gz
src-7fa27ce4a07f19b07799a767fc29416f3b625afb.zip
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp233
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp3
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp4
-rw-r--r--clang/lib/Sema/IdentifierResolver.cpp9
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp147
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp6
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp23
-rw-r--r--clang/lib/Sema/Scope.cpp6
-rw-r--r--clang/lib/Sema/ScopeInfo.cpp1
-rw-r--r--clang/lib/Sema/Sema.cpp158
-rw-r--r--clang/lib/Sema/SemaAccess.cpp13
-rw-r--r--clang/lib/Sema/SemaAttr.cpp23
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp112
-rw-r--r--clang/lib/Sema/SemaCast.cpp70
-rw-r--r--clang/lib/Sema/SemaChecking.cpp1544
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp56
-rw-r--r--clang/lib/Sema/SemaConcept.cpp250
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp172
-rw-r--r--clang/lib/Sema/SemaDecl.cpp456
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp410
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp576
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp6
-rw-r--r--clang/lib/Sema/SemaExpr.cpp1264
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp177
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp9
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp4
-rw-r--r--clang/lib/Sema/SemaInit.cpp980
-rw-r--r--clang/lib/Sema/SemaLambda.cpp796
-rw-r--r--clang/lib/Sema/SemaLookup.cpp251
-rw-r--r--clang/lib/Sema/SemaModule.cpp323
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp13
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp804
-rw-r--r--clang/lib/Sema/SemaOverload.cpp391
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp7
-rw-r--r--clang/lib/Sema/SemaRISCVVectorLookup.cpp119
-rw-r--r--clang/lib/Sema/SemaSYCL.cpp16
-rw-r--r--clang/lib/Sema/SemaStmt.cpp108
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp1
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp85
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp212
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp215
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp140
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp147
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp239
-rw-r--r--clang/lib/Sema/SemaType.cpp311
-rw-r--r--clang/lib/Sema/TreeTransform.h473
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(