aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp108
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp2
-rw-r--r--clang/lib/Sema/DeclSpec.cpp25
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp425
-rw-r--r--clang/lib/Sema/IdentifierResolver.cpp8
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp2
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp24
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td1
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp4
-rw-r--r--clang/lib/Sema/Scope.cpp9
-rw-r--r--clang/lib/Sema/ScopeInfo.cpp9
-rw-r--r--clang/lib/Sema/Sema.cpp135
-rw-r--r--clang/lib/Sema/SemaAccess.cpp2
-rw-r--r--clang/lib/Sema/SemaAttr.cpp24
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp31
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp18
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp7
-rw-r--r--clang/lib/Sema/SemaCast.cpp86
-rw-r--r--clang/lib/Sema/SemaChecking.cpp938
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp161
-rw-r--r--clang/lib/Sema/SemaConcept.cpp692
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp244
-rw-r--r--clang/lib/Sema/SemaDecl.cpp1221
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp454
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp804
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp108
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp5
-rw-r--r--clang/lib/Sema/SemaExpr.cpp1133
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp401
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp29
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp114
-rw-r--r--clang/lib/Sema/SemaFixItUtils.cpp6
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp34
-rw-r--r--clang/lib/Sema/SemaInit.cpp402
-rw-r--r--clang/lib/Sema/SemaLambda.cpp222
-rw-r--r--clang/lib/Sema/SemaLookup.cpp119
-rw-r--r--clang/lib/Sema/SemaModule.cpp115
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp19
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp919
-rw-r--r--clang/lib/Sema/SemaOverload.cpp606
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp10
-rw-r--r--clang/lib/Sema/SemaRISCVVectorLookup.cpp106
-rw-r--r--clang/lib/Sema/SemaStmt.cpp166
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp31
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp51
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp1261
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp1170
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp1000
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp406
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp286
-rw-r--r--clang/lib/Sema/SemaType.cpp701
-rw-r--r--clang/lib/Sema/TreeTransform.h729
-rw-r--r--clang/lib/Sema/TypeLocBuilder.cpp29
-rw-r--r--clang/lib/Sema/TypeLocBuilder.h12
-rw-r--r--clang/lib/Sema/UsedDeclVisitor.h17
55 files changed, 10603 insertions, 5038 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 9780a0aba749..4530154ac944 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -16,8 +16,10 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
@@ -29,6 +31,7 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -47,6 +50,7 @@
#include <algorithm>
#include <deque>
#include <iterator>
+#include <optional>
using namespace clang;
@@ -326,7 +330,7 @@ static void visitReachableThrows(
if (!Reachable[B->getBlockID()])
continue;
for (CFGElement &E : *B) {
- Optional<CFGStmt> S = E.getAs<CFGStmt>();
+ std::optional<CFGStmt> S = E.getAs<CFGStmt>();
if (!S)
continue;
if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
@@ -1113,19 +1117,19 @@ namespace {
if (!ReachableBlocks.count(P)) {
for (const CFGElement &Elem : llvm::reverse(*P)) {
- if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
- if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
- // Don't issue a warning for an unreachable fallthrough
- // attribute in template instantiations as it may not be
- // unreachable in all instantiations of the template.
- if (!IsTemplateInstantiation)
- S.Diag(AS->getBeginLoc(),
- diag::warn_unreachable_fallthrough_attr);
- markFallthroughVisited(AS);
- ++AnnotatedCnt;
- break;
- }
- // Don't care about other unreachable statements.
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
+ if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
+ // Don't issue a warning for an unreachable fallthrough
+ // attribute in template instantiations as it may not be
+ // unreachable in all instantiations of the template.
+ if (!IsTemplateInstantiation)
+ S.Diag(AS->getBeginLoc(),
+ diag::warn_unreachable_fallthrough_attr);
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ break;
+ }
+ // Don't care about other unreachable statements.
}
}
// If there are no unreachable statements, this may be a special
@@ -1198,7 +1202,7 @@ namespace {
if (const Stmt *Term = B.getTerminatorStmt())
return Term;
for (const CFGElement &Elem : llvm::reverse(B))
- if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
return CS->getStmt();
// Workaround to detect a statement thrown out by CFGBuilder:
// case X: {} case Y:
@@ -2139,6 +2143,71 @@ public:
} // namespace clang
//===----------------------------------------------------------------------===//
+// Unsafe buffer usage analysis.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
+ Sema &S;
+
+public:
+ UnsafeBufferUsageReporter(Sema &S) : S(S) {}
+
+ void handleUnsafeOperation(const Stmt *Operation,
+ bool IsRelatedToDecl) override {
+ SourceLocation Loc;
+ SourceRange Range;
+ unsigned MsgParam = 0;
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
+ Loc = ASE->getBase()->getExprLoc();
+ Range = ASE->getBase()->getSourceRange();
+ MsgParam = 2;
+ } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
+ BinaryOperator::Opcode Op = BO->getOpcode();
+ if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
+ Op == BO_SubAssign) {
+ if (BO->getRHS()->getType()->isIntegerType()) {
+ Loc = BO->getLHS()->getExprLoc();
+ Range = BO->getLHS()->getSourceRange();
+ } else {
+ Loc = BO->getRHS()->getExprLoc();
+ Range = BO->getRHS()->getSourceRange();
+ }
+ MsgParam = 1;
+ }
+ } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
+ UnaryOperator::Opcode Op = UO->getOpcode();
+ if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
+ Op == UO_PostDec) {
+ Loc = UO->getSubExpr()->getExprLoc();
+ Range = UO->getSubExpr()->getSourceRange();
+ MsgParam = 1;
+ }
+ } else {
+ Loc = Operation->getBeginLoc();
+ Range = Operation->getSourceRange();
+ }
+ if (IsRelatedToDecl)
+ S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
+ else
+ S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
+ }
+
+ // FIXME: rename to handleUnsafeVariable
+ void handleFixableVariable(const VarDecl *Variable,
+ 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;
+ }
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
@@ -2269,7 +2338,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
}
// Install the logical handler.
- llvm::Optional<LogicalErrorHandler> LEH;
+ std::optional<LogicalErrorHandler> LEH;
if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
LEH.emplace(S);
AC.getCFGBuildOptions().Observer = &*LEH;
@@ -2430,6 +2499,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (S.getLangOpts().CPlusPlus && 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 e93be3e04dfe..b91291cfea0b 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -776,7 +776,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
// Do nothing: Patterns can come with cursor kinds!
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case RK_Declaration: {
// Set the availability based on attributes.
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index d4dc790c008a..d59778b5b614 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
@@ -238,7 +239,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
// is already used (consider a function returning a function pointer) or too
// small (function with too many parameters), go to the heap.
if (!TheDeclarator.InlineStorageUsed &&
- NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
+ NumParams <= std::size(TheDeclarator.InlineParams)) {
I.Fun.Params = TheDeclarator.InlineParams;
new (I.Fun.Params) ParamInfo[NumParams];
I.Fun.DeleteParams = false;
@@ -307,8 +308,7 @@ void Declarator::setDecompositionBindings(
// Allocate storage for bindings and stash them away.
if (Bindings.size()) {
- if (!InlineStorageUsed &&
- Bindings.size() <= llvm::array_lengthof(InlineBindings)) {
+ if (!InlineStorageUsed && Bindings.size() <= std::size(InlineBindings)) {
BindingGroup.Bindings = InlineBindings;
BindingGroup.DeleteBindings = false;
InlineStorageUsed = true;
@@ -384,13 +384,16 @@ bool Declarator::isDeclarationOfFunction() const {
return false;
case TST_decltype:
+ case TST_typeof_unqualExpr:
case TST_typeofExpr:
if (Expr *E = DS.getRepAsExpr())
return E->getType()->isFunctionType();
return false;
- case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case TST_typename:
+ case TST_typeof_unqualType:
case TST_typeofType: {
QualType QT = DS.getRepAsType().get();
if (QT.isNull())
@@ -412,7 +415,7 @@ bool Declarator::isDeclarationOfFunction() const {
bool Declarator::isStaticMember() {
assert(getContext() == DeclaratorContext::Member);
return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
- (getName().Kind == UnqualifiedIdKind::IK_OperatorFunctionId &&
+ (getName().getKind() == UnqualifiedIdKind::IK_OperatorFunctionId &&
CXXMethodDecl::isStaticOverloadedOperator(
getName().OperatorFunctionId.Operator));
}
@@ -572,11 +575,16 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
+ case DeclSpec::TST_typeof_unqualType:
+ case DeclSpec::TST_typeof_unqualExpr: return "typeof_unqual";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_auto_type: return "__auto_type";
case DeclSpec::TST_decltype: return "(decltype)";
case DeclSpec::TST_decltype_auto: return "decltype(auto)";
- case DeclSpec::TST_underlyingType: return "__underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
+ case DeclSpec::TST_##Trait: \
+ return "__" #Trait;
+#include "clang/Basic/TransformTypeTraits.def"
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
case DeclSpec::TST_BFloat16: return "__bf16";
@@ -1109,9 +1117,8 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
}
/// Finish - This does final analysis of the declspec, rejecting things like
-/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
-/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
-/// DeclSpec is guaranteed self-consistent, even if an error occurred.
+/// "_Imaginary" (lacking an FP type). After calling this method, DeclSpec is
+/// guaranteed to be self-consistent, even if an error occurred.
void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 56c2dd40bd9a..3ff4e75b5694 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -11,24 +11,391 @@
#include "clang/Sema/HLSLExternalSemaSource.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
+
+#include <functional>
using namespace clang;
+using namespace llvm::hlsl;
+
+namespace {
+
+struct TemplateParameterListBuilder;
+
+struct BuiltinTypeDeclBuilder {
+ CXXRecordDecl *Record = nullptr;
+ ClassTemplateDecl *Template = nullptr;
+ ClassTemplateDecl *PrevTemplate = nullptr;
+ NamespaceDecl *HLSLNamespace = nullptr;
+ llvm::StringMap<FieldDecl *> Fields;
+
+ BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
+ Record->startDefinition();
+ Template = Record->getDescribedClassTemplate();
+ }
+
+ BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
+ : HLSLNamespace(Namespace) {
+ ASTContext &AST = S.getASTContext();
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+
+ LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
+ CXXRecordDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, HLSLNamespace)) {
+ NamedDecl *Found = Result.getFoundDecl();
+ if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
+ PrevDecl = TD->getTemplatedDecl();
+ PrevTemplate = TD;
+ } else
+ PrevDecl = dyn_cast<CXXRecordDecl>(Found);
+ assert(PrevDecl && "Unexpected lookup result type.");
+ }
+
+ if (PrevDecl && PrevDecl->isCompleteDefinition()) {
+ Record = PrevDecl;
+ return;
+ }
+
+ Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::TTK_Class,
+ HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II, PrevDecl, true);
+ Record->setImplicit(true);
+ Record->setLexicalDeclContext(HLSLNamespace);
+ Record->setHasExternalLexicalStorage();
+
+ // Don't let anyone derive from built-in types.
+ Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
+ AttributeCommonInfo::AS_Keyword,
+ FinalAttr::Keyword_final));
+ }
+
+ ~BuiltinTypeDeclBuilder() {
+ if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
+ HLSLNamespace->addDecl(Record);
+ }
+
+ BuiltinTypeDeclBuilder &
+ addMemberVariable(StringRef Name, QualType Type,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before adding members!");
+ ASTContext &AST = Record->getASTContext();
+
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ TypeSourceInfo *MemTySource =
+ AST.getTrivialTypeSourceInfo(Type, SourceLocation());
+ auto *Field = FieldDecl::Create(
+ AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
+ nullptr, false, InClassInitStyle::ICIS_NoInit);
+ Field->setAccess(Access);
+ Field->setImplicit(true);
+ Record->addDecl(Field);
+ Fields[Name] = Field;
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &
+ addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ QualType Ty = Record->getASTContext().VoidPtrTy;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0)))
+ Ty = Record->getASTContext().getPointerType(
+ QualType(TTD->getTypeForDecl(), 0));
+ }
+ return addMemberVariable("h", Ty, Access);
+ }
+
+ BuiltinTypeDeclBuilder &
+ annotateResourceClass(HLSLResourceAttr::ResourceClass RC,
+ HLSLResourceAttr::ResourceKind RK) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->addAttr(
+ HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK));
+ return *this;
+ }
+
+ static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
+ StringRef Name) {
+ CXXScopeSpec SS;
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ DeclarationNameInfo NameInfo =
+ DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+ LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+ S.LookupParsedName(R, S.getCurScope(), &SS, false);
+ assert(R.isSingleResult() &&
+ "Since this is a builtin it should always resolve!");
+ auto *VD = cast<ValueDecl>(R.getFoundDecl());
+ QualType Ty = VD->getType();
+ return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
+ VD, false, NameInfo, Ty, VK_PRValue);
+ }
+
+ static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
+ return IntegerLiteral::Create(
+ AST,
+ llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
+ static_cast<uint8_t>(RC)),
+ AST.UnsignedCharTy, SourceLocation());
+ }
+
+ BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
+ ResourceClass RC) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ ASTContext &AST = Record->getASTContext();
+
+ QualType ConstructorType =
+ AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
+
+ CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
+ DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
+ CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
+ AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
+ ExplicitSpecifier(), false, true, false,
+ ConstexprSpecKind::Unspecified);
+
+ DeclRefExpr *Fn =
+ lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
+
+ Expr *RCExpr = emitResourceClassExpr(AST, RC);
+ Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
+ SourceLocation(), FPOptionsOverride());
+
+ CXXThisExpr *This = new (AST) CXXThisExpr(
+ SourceLocation(),
+ Constructor->getThisType().getTypePtr()->getPointeeType(), true);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
+ Fields["h"]->getType(), VK_LValue,
+ OK_Ordinary);
+
+ // If the handle isn't a void pointer, cast the builtin result to the
+ // correct type.
+ if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
+ Call = CXXStaticCastExpr::Create(
+ AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
+ AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
+ FPOptionsOverride(), SourceLocation(), SourceLocation(),
+ SourceRange());
+ }
+
+ BinaryOperator *Assign = BinaryOperator::Create(
+ AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
+ SourceLocation(), FPOptionsOverride());
+
+ Constructor->setBody(
+ CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
+ SourceLocation(), SourceLocation()));
+ Constructor->setAccess(AccessSpecifier::AS_public);
+ Record->addDecl(Constructor);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ addArraySubscriptOperator(true);
+ addArraySubscriptOperator(false);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Fields.count("h") > 0 &&
+ "Subscript operator must be added after the handle.");
+
+ FieldDecl *Handle = Fields["h"];
+ ASTContext &AST = Record->getASTContext();
+
+ assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
+ "Not yet supported for void pointer handles.");
+
+ QualType ElemTy =
+ QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
+ QualType ReturnTy = ElemTy;
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+
+ // Subscript operators return references to elements, const makes the
+ // reference and method const so that the underlying data is not mutable.
+ ReturnTy = AST.getLValueReferenceType(ReturnTy);
+ if (IsConst) {
+ ExtInfo.TypeQuals.addConst();
+ ReturnTy.addConst();
+ }
+
+ QualType MethodTy =
+ AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
+ auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+ auto *MethodDecl = CXXMethodDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(
+ AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
+ SourceLocation()),
+ MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
+ SourceLocation());
+
+ IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
+ auto *IdxParam = ParmVarDecl::Create(
+ AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
+ &II, AST.UnsignedIntTy,
+ AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
+ SC_None, nullptr);
+ MethodDecl->setParams({IdxParam});
+
+ // Also add the parameter to the function prototype.
+ auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ FnProtoLoc.setParam(0, IdxParam);
+
+ auto *This = new (AST) CXXThisExpr(
+ SourceLocation(),
+ MethodDecl->getThisType().getTypePtr()->getPointeeType(), true);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ auto *HandleAccess = MemberExpr::CreateImplicit(
+ AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
+
+ auto *IndexExpr = DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
+ DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
+ AST.UnsignedIntTy, VK_PRValue);
+
+ auto *Array =
+ new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
+ OK_Ordinary, SourceLocation());
+
+ auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
+
+ MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
+ SourceLocation(),
+ SourceLocation()));
+ MethodDecl->setLexicalDeclContext(Record);
+ MethodDecl->setAccess(AccessSpecifier::AS_public);
+ MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
+ AST, SourceRange(), AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::CXX11_clang_always_inline));
+ Record->addDecl(MethodDecl);
+
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &startDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->startDefinition();
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &completeDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before completing it.");
+
+ Record->completeDefinition();
+ return *this;
+ }
+
+ TemplateParameterListBuilder addTemplateArgumentList();
+};
+
+struct TemplateParameterListBuilder {
+ BuiltinTypeDeclBuilder &Builder;
+ ASTContext &AST;
+ llvm::SmallVector<NamedDecl *> Params;
+
+ TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
+ : Builder(RB), AST(RB.Record->getASTContext()) {}
+
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
+
+ TemplateParameterListBuilder &
+ addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
+ if (Builder.Record->isCompleteDefinition())
+ return *this;
+ unsigned Position = static_cast<unsigned>(Params.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ AST, Builder.Record->getDeclContext(), SourceLocation(),
+ SourceLocation(), /* TemplateDepth */ 0, Position,
+ &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
+ /* ParameterPack */ false);
+ if (!DefaultValue.isNull())
+ Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
+
+ Params.emplace_back(Decl);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
+ if (Params.empty())
+ return Builder;
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ Params, SourceLocation(), nullptr);
+ Builder.Template = ClassTemplateDecl::Create(
+ AST, Builder.Record->getDeclContext(), SourceLocation(),
+ DeclarationName(Builder.Record->getIdentifier()), ParamList,
+ Builder.Record);
+ Builder.Record->setDescribedClassTemplate(Builder.Template);
+ Builder.Template->setImplicit(true);
+ Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
+ // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
+ // make visible.
+ Builder.Template->setPreviousDecl(Builder.PrevTemplate);
+ Builder.Record->getDeclContext()->addDecl(Builder.Template);
+ Params.clear();
+
+ QualType T = Builder.Template->getInjectedClassNameSpecialization();
+ T = AST.getInjectedClassNameType(Builder.Record, T);
+
+ return Builder;
+ }
+};
+
+TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
+ return TemplateParameterListBuilder(*this);
+}
+} // namespace
HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
void HLSLExternalSemaSource::InitializeSema(Sema &S) {
SemaPtr = &S;
ASTContext &AST = SemaPtr->getASTContext();
+ // If the translation unit has external storage force external decls to load.
+ if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
+ (void)AST.getTranslationUnitDecl()->decls_begin();
+
IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
- HLSLNamespace =
- NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false,
- SourceLocation(), SourceLocation(), &HLSL, nullptr);
+ LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
+ NamespaceDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
+ PrevDecl = Result.getAsSingle<NamespaceDecl>();
+ HLSLNamespace = NamespaceDecl::Create(
+ AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
+ SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
HLSLNamespace->setImplicit(true);
+ HLSLNamespace->setHasExternalLexicalStorage();
AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
- defineHLSLVectorAlias();
+
+ // Force external decls in the HLSL namespace to load from the PCH.
+ (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
+ defineTrivialHLSLTypes();
+ forwardDeclareHLSLTypes();
// This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
// built in types inside a namespace, but we are planning to change that in
@@ -94,3 +461,53 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() {
Template->setLexicalDeclContext(Record->getDeclContext());
HLSLNamespace->addDecl(Template);
}
+
+void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
+ defineHLSLVectorAlias();
+
+ ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
+ .startDefinition()
+ .addHandleMember(AccessSpecifier::AS_public)
+ .completeDefinition()
+ .Record;
+}
+
+void HLSLExternalSemaSource::forwardDeclareHLSLTypes() {
+ CXXRecordDecl *Decl;
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+ .addTemplateArgumentList()
+ .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy)
+ .finalizeTemplateArgs()
+ .Record;
+ if (!Decl->isCompleteDefinition())
+ Completions.insert(
+ std::make_pair(Decl->getCanonicalDecl(),
+ std::bind(&HLSLExternalSemaSource::completeBufferType,
+ this, std::placeholders::_1)));
+}
+
+void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
+ if (!isa<CXXRecordDecl>(Tag))
+ return;
+ auto Record = cast<CXXRecordDecl>(Tag);
+
+ // If this is a specialization, we need to get the underlying templated
+ // declaration and complete that.
+ if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+ Record = Record->getCanonicalDecl();
+ auto It = Completions.find(Record);
+ if (It == Completions.end())
+ return;
+ It->second(Record);
+}
+
+void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) {
+ BuiltinTypeDeclBuilder(Record)
+ .addHandleMember()
+ .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV)
+ .addArraySubscriptOperators()
+ .annotateResourceClass(HLSLResourceAttr::UAV,
+ HLSLResourceAttr::TypedBuffer)
+ .completeDefinition();
+}
diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp
index 9081714c893f..607dc3111e9d 100644
--- a/clang/lib/Sema/IdentifierResolver.cpp
+++ b/clang/lib/Sema/IdentifierResolver.cpp
@@ -99,7 +99,11 @@ IdentifierResolver::~IdentifierResolver() {
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
-
+ // The names for HLSL cbuffer/tbuffers only used by the CPU-side
+ // reflection API which supports querying bindings. It will not have name
+ // conflict with other Decls.
+ if (LangOpt.HLSL && isa<HLSLBufferDecl>(D))
+ return false;
if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() && S->getEntity()->isTransparentContext())
@@ -287,7 +291,7 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
// If the existing declaration is somewhere in the previous declaration
// chain of the new declaration, then prefer the new declaration.
- for (auto RD : New->redecls()) {
+ for (auto *RD : New->redecls()) {
if (RD == Existing)
return DMK_Replace;
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index 94f39e1eea6e..bd2ce9a93e7e 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -354,7 +354,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
BuildScopeInformation(Var, ParentScope);
++StmtsToSkip;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Stmt::GotoStmtClass:
// Remember both what scope a goto is in as well as the fact that we have
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 072775642d75..55e015487f3b 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -16,24 +16,30 @@ using namespace clang;
char MultiplexExternalSemaSource::ID;
-///Constructs a new multiplexing external sema source and appends the
+/// Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
-MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
- ExternalSemaSource &s2){
- Sources.push_back(&s1);
- Sources.push_back(&s2);
+MultiplexExternalSemaSource::MultiplexExternalSemaSource(
+ ExternalSemaSource *S1, ExternalSemaSource *S2) {
+ S1->Retain();
+ S2->Retain();
+ Sources.push_back(S1);
+ Sources.push_back(S2);
}
// pin the vtable here.
-MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {}
+MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {
+ for (auto *S : Sources)
+ S->Release();
+}
-///Appends new source to the source list.
+/// Appends new source to the source list.
///
///\param[in] source - An ExternalSemaSource.
///
-void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) {
- Sources.push_back(&source);
+void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) {
+ Source->Retain();
+ Sources.push_back(Source);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index dc158454556a..0cceba090bd8 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -246,6 +246,7 @@ class ImageType<Type _Ty, string _AccessQualifier> :
let Extension = !cond(
!and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "WO")) : TypeExtension<"cl_khr_3d_image_writes">,
!and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "RW")) : TypeExtension<"cl_khr_3d_image_writes __opencl_c_read_write_images">,
+ !or(!eq(_Ty.Name, "image2d_depth_t"), !eq(_Ty.Name, "image2d_array_depth_t")) : TypeExtension<"cl_khr_depth_images">,
!eq(_AccessQualifier, "RW") : TypeExtension<"__opencl_c_read_write_images">,
true : _Ty.Extension);
}
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 4b9a694270c5..c1e39acb14ec 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -111,7 +111,7 @@ namespace {
const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
// If we have a ParsedAttrInfo for this ParsedAttr then return that.
- if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap))
+ if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
return *AttrInfoMap[A.getParsedKind()];
// If this is an ignored attribute then return an appropriate ParsedAttrInfo.
@@ -146,7 +146,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
}
ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
- return llvm::makeArrayRef(AttrInfoMap);
+ return llvm::ArrayRef(AttrInfoMap);
}
unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 98260226dfd3..c995c7e65f4b 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -43,6 +43,9 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
0)
Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
+ // transmit the parent's 'order' flag, if exists
+ if (parent->getFlags() & OpenMPOrderClauseScope)
+ Flags |= OpenMPOrderClauseScope;
} else {
Depth = 0;
PrototypeDepth = 0;
@@ -91,7 +94,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
- NRVO = None;
+ NRVO = std::nullopt;
}
bool Scope::containedInPrototypeScope() const {
@@ -156,11 +159,11 @@ void Scope::updateNRVOCandidate(VarDecl *VD) {
void Scope::applyNRVO() {
// There is no NRVO candidate in the current scope.
- if (!NRVO.hasValue())
+ if (!NRVO.has_value())
return;
if (*NRVO && isDeclScope(*NRVO))
- NRVO.getValue()->setNRVOVariable(true);
+ (*NRVO)->setNRVOVariable(true);
// It's necessary to propagate NRVO candidate to the parent scope for cases
// when the parent scope doesn't contain a return statement.
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index cc7de16de2fd..e313052b3ab3 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() {
ModifiedNonNullParams.clear();
Blocks.clear();
ByrefBlockVars.clear();
+ AddrLabels.clear();
}
static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
@@ -231,14 +232,14 @@ bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
}
void LambdaScopeInfo::visitPotentialCaptures(
- llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
+ llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const {
for (Expr *E : PotentiallyCapturingExprs) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
- Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
+ Callback(cast<ValueDecl>(DRE->getFoundDecl()), E);
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
- Callback(cast<VarDecl>(ME->getMemberDecl()), E);
+ Callback(cast<ValueDecl>(ME->getMemberDecl()), E);
} else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
- for (VarDecl *VD : *FP)
+ for (ValueDecl *VD : *FP)
Callback(VD, E);
} else {
llvm_unreachable("unexpected expression in potential captures list");
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 08957ce9fada..0f0305422454 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -46,8 +46,10 @@
#include "clang/Sema/TemplateInstCallback.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -185,20 +187,19 @@ const uint64_t Sema::MaximumAlignment;
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
- : ExternalSource(nullptr), isMultiplexExternalSource(false),
- CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
- Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
- SourceMgr(PP.getSourceManager()), CollectStats(false),
- CodeCompleter(CodeCompleter), CurContext(nullptr),
+ : ExternalSource(nullptr), CurFPFeatures(pp.getLangOpts()),
+ LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
+ Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
+ CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr),
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()),
AlignPackStack(AlignPackInfo(getLangOpts().XLPragmaPack)),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()),
- CurInitSeg(nullptr), VisContext(nullptr),
- PragmaAttributeCurrentTargetDecl(nullptr),
+ CodeSegStack(nullptr), StrictGuardStackCheckStack(false),
+ FpPragmaStack(FPOptionsOverride()), CurInitSeg(nullptr),
+ VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
@@ -473,10 +474,6 @@ Sema::~Sema() {
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->ForgetSema();
- // If Sema's ExternalSource is the multiplexer - we own it.
- if (isMultiplexExternalSource)
- delete ExternalSource;
-
// Delete cached satisfactions.
std::vector<ConstraintSatisfaction *> Satisfactions;
Satisfactions.reserve(Satisfactions.size());
@@ -550,12 +547,10 @@ void Sema::addExternalSource(ExternalSemaSource *E) {
return;
}
- if (isMultiplexExternalSource)
- static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E);
- else {
- ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E);
- isMultiplexExternalSource = true;
- }
+ if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource))
+ Ex->AddSource(E);
+ else
+ ExternalSource = new MultiplexExternalSemaSource(ExternalSource.get(), E);
}
/// Print out statistics about the semantic analysis.
@@ -570,22 +565,19 @@ void Sema::PrintStats() const {
void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
QualType SrcType,
SourceLocation Loc) {
- Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context);
+ std::optional<NullabilityKind> ExprNullability = SrcType->getNullability();
if (!ExprNullability || (*ExprNullability != NullabilityKind::Nullable &&
*ExprNullability != NullabilityKind::NullableResult))
return;
- Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context);
+ std::optional<NullabilityKind> TypeNullability = DstType->getNullability();
if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull)
return;
Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
}
-void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
- if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
- E->getBeginLoc()))
- return;
+void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E) {
// nullptr only exists from C++11 on, so don't warn on its absence earlier.
if (!getLangOpts().CPlusPlus11)
return;
@@ -595,6 +587,10 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
return;
+ if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
+ E->getBeginLoc()))
+ return;
+
// Don't diagnose the conversion from a 0 literal to a null pointer argument
// in a synthesized call to operator<=>.
if (!CodeSynthesisContexts.empty() &&
@@ -602,6 +598,12 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
CodeSynthesisContext::RewritingOperatorAsSpaceship)
return;
+ // Ignore null pointers in defaulted comparison operators.
+ FunctionDecl *FD = getCurFunctionDecl();
+ if (FD && FD->isDefaulted()) {
+ return;
+ }
+
// If it is a macro from system header, and if the macro name is not "NULL",
// do not warn.
SourceLocation MaybeMacroLoc = E->getBeginLoc();
@@ -1216,9 +1218,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// module declaration by now.
if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface &&
- (ModuleScopes.empty() ||
- !ModuleScopes.back().Module->isModulePurview()) &&
- !DiagnosedMissingModuleDeclaration) {
+ !isCurrentModulePurview() && !DiagnosedMissingModuleDeclaration) {
// FIXME: Make a better guess as to where to put the module declaration.
Diag(getSourceManager().getLocForStartOfFile(
getSourceManager().getMainFileID()),
@@ -1253,6 +1253,33 @@ void Sema::ActOnEndOfTranslationUnit() {
emitAndClearUnusedLocalTypedefWarnings();
}
+ // C++ standard modules. Diagnose cases where a function is declared inline
+ // in the module purview but has no definition before the end of the TU or
+ // the start of a Private Module Fragment (if one is present).
+ if (!PendingInlineFuncDecls.empty()) {
+ for (auto *D : PendingInlineFuncDecls) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ bool DefInPMF = false;
+ if (auto *FDD = FD->getDefinition()) {
+ assert(FDD->getOwningModule() &&
+ FDD->getOwningModule()->isModulePurview());
+ DefInPMF = FDD->getOwningModule()->isPrivateModule();
+ if (!DefInPMF)
+ continue;
+ }
+ Diag(FD->getLocation(), diag::err_export_inline_not_defined)
+ << DefInPMF;
+ // If we have a PMF it should be at the end of the ModuleScopes.
+ if (DefInPMF &&
+ ModuleScopes.back().Module->Kind == Module::PrivateModuleFragment) {
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::note_private_module_fragment);
+ }
+ }
+ }
+ PendingInlineFuncDecls.clear();
+ }
+
// C99 6.9.2p2:
// A declaration of an identifier for an object that has file
// scope without an initializer, and without a storage-class
@@ -1266,8 +1293,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit, with an initializer equal to 0.
llvm::SmallSet<VarDecl *, 32> Seen;
for (TentativeDefinitionsType::iterator
- T = TentativeDefinitions.begin(ExternalSource),
- TEnd = TentativeDefinitions.end();
+ T = TentativeDefinitions.begin(ExternalSource.get()),
+ TEnd = TentativeDefinitions.end();
T != TEnd; ++T) {
VarDecl *VD = (*T)->getActingDefinition();
@@ -1297,7 +1324,7 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
- for (auto D : ExternalDeclarations) {
+ for (auto *D : ExternalDeclarations) {
if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed())
continue;
@@ -1311,8 +1338,9 @@ void Sema::ActOnEndOfTranslationUnit() {
if (!Diags.hasErrorOccurred() && TUKind != TU_Module) {
// Output warning for unused file scoped decls.
for (UnusedFileScopedDeclsType::iterator
- I = UnusedFileScopedDecls.begin(ExternalSource),
- E = UnusedFileScopedDecls.end(); I != E; ++I) {
+ I = UnusedFileScopedDecls.begin(ExternalSource.get()),
+ E = UnusedFileScopedDecls.end();
+ I != E; ++I) {
if (ShouldRemoveFromUnused(this, *I))
continue;
@@ -1470,7 +1498,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// eliminated. If it truly cannot be (for example, there is some reentrancy
// issue I am not seeing yet), then there should at least be a clarifying
// comment somewhere.
- if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
+ if (std::optional<TemplateDeductionInfo *> Info = isSFINAEContext()) {
switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
Diags.getCurrentDiagID())) {
case DiagnosticIDs::SFINAE_Report:
@@ -1765,7 +1793,7 @@ void Sema::emitDeferredDiags() {
return;
DeferredDiagnosticsEmitter DDE(*this);
- for (auto D : DeclsToCheckForDeferredDiags)
+ for (auto *D : DeclsToCheckForDeferredDiags)
DDE.checkRecordedDecl(D);
}
@@ -2008,6 +2036,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
if (D)
targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
}
+
+ // Don't allow SVE types in functions without a SVE target.
+ if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) {
+ llvm::StringMap<bool> CallerFeatureMap;
+ Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+ if (!Builtin::evaluateRequiredTargetFeatures(
+ "sve", CallerFeatureMap))
+ Diag(D->getLocation(), diag::err_sve_vector_in_non_sve_target) << Ty;
+ }
};
CheckType(Ty);
@@ -2448,7 +2485,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
if (IsMemExpr && !E.isTypeDependent()) {
Sema::TentativeAnalysisScope Trap(*this);
ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(),
- None, SourceLocation());
+ std::nullopt, SourceLocation());
if (R.isUsable()) {
ZeroArgCallReturnTy = R.get()->getType();
return true;
@@ -2512,6 +2549,9 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
if (FD->isMultiVersion() && FD->hasAttr<TargetAttr>() &&
!FD->getAttr<TargetAttr>()->isDefaultVersion())
continue;
+ if (FD->isMultiVersion() && FD->hasAttr<TargetVersionAttr>() &&
+ !FD->getAttr<TargetVersionAttr>()->isDefaultVersion())
+ continue;
}
S.Diag(Fn->getLocation(), diag::note_possible_target_of_call);
++ShownOverloads;
@@ -2598,7 +2638,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
- E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), None,
+ E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), std::nullopt,
Range.getEnd().getLocWithOffset(1));
return true;
}
@@ -2659,3 +2699,26 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() {
S.FpPragmaStack.CurrentValue = OldOverrides;
S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod);
}
+
+bool Sema::isDeclaratorFunctionLike(Declarator &D) {
+ assert(D.getCXXScopeSpec().isSet() &&
+ "can only be called for qualified names");
+
+ auto LR = LookupResult(*this, D.getIdentifier(), D.getBeginLoc(),
+ LookupOrdinaryName, forRedeclarationInCurContext());
+ DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(),
+ !D.getDeclSpec().isFriendSpecified());
+ if (!DC)
+ return false;
+
+ LookupQualifiedName(LR, DC);
+ bool Result = std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Dcl)) {
+ ND = ND->getUnderlyingDecl();
+ return isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+ isa<UsingDecl>(ND);
+ }
+ return false;
+ });
+ return Result;
+}
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 00d3efd19d7a..cbda62497e6a 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1493,6 +1493,8 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
if (isa<DeclContext>(TD->getTemplatedDecl()))
DC = cast<DeclContext>(TD->getTemplatedDecl());
+ } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(D)) {
+ DC = RD;
}
EffectiveContext EC(DC);
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index c997d018a406..42f582724564 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -18,6 +18,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
+#include <optional>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -34,6 +35,7 @@ Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S,
S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel);
S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel);
S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel);
+ S.StrictGuardStackCheckStack.SentinelAction(PSK_Push, SlotLabel);
}
}
@@ -44,6 +46,7 @@ Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() {
S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel);
S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel);
S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.StrictGuardStackCheckStack.SentinelAction(PSK_Pop, SlotLabel);
}
}
@@ -335,7 +338,7 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
AlignPackInfo::Mode ModeVal = CurVal.getAlignMode();
if (Alignment) {
- Optional<llvm::APSInt> Val;
+ std::optional<llvm::APSInt> Val;
Val = Alignment->getIntegerConstantExpr(Context);
// pack(0) is like pack(), which just works out since that is what
@@ -774,6 +777,17 @@ void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
}
+/// Called on well formed \#pragma strict_gs_check().
+void Sema::ActOnPragmaMSStrictGuardStackCheck(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ bool Value) {
+ if (Action & PSK_Pop && StrictGuardStackCheckStack.Stack.empty())
+ Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "strict_gs_check"
+ << "stack empty";
+
+ StrictGuardStackCheckStack.Act(PragmaLocation, Action, StringRef(), Value);
+}
+
/// Called on well formed \#pragma bss_seg().
void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
int SectionFlags, StringLiteral *SegmentName) {
@@ -872,12 +886,12 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
namespace {
-Optional<attr::SubjectMatchRule>
+std::optional<attr::SubjectMatchRule>
getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
using namespace attr;
switch (Rule) {
default:
- return None;
+ return std::nullopt;
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
case Value: \
@@ -947,7 +961,7 @@ void Sema::ActOnPragmaAttributeAttribute(
RulesToFirstSpecifiedNegatedSubRule;
for (const auto &Rule : Rules) {
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
- Optional<attr::SubjectMatchRule> ParentRule =
+ std::optional<attr::SubjectMatchRule> ParentRule =
getParentAttrMatcherRule(MatchRule);
if (!ParentRule)
continue;
@@ -971,7 +985,7 @@ void Sema::ActOnPragmaAttributeAttribute(
bool IgnoreNegatedSubRules = false;
for (const auto &Rule : Rules) {
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
- Optional<attr::SubjectMatchRule> ParentRule =
+ std::optional<attr::SubjectMatchRule> ParentRule =
getParentAttrMatcherRule(MatchRule);
if (!ParentRule)
continue;
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index bf4a226668f7..05ad42780e50 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -192,6 +193,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
case llvm::Triple::MacOSX:
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
break;
+ case llvm::Triple::ShaderModel:
+ // Always enable availability diagnostics for shader models.
+ return true;
default:
// New targets should always warn about availability.
return Triple.getVendor() == llvm::Triple::Apple;
@@ -241,16 +245,16 @@ struct AttributeInsertion {
/// attribute argument.
/// \param SlotNames The vector that will be populated with slot names. In case
/// of unsuccessful parsing can contain invalid data.
-/// \returns A number of method parameters if parsing was successful, None
-/// otherwise.
-static Optional<unsigned>
+/// \returns A number of method parameters if parsing was successful,
+/// std::nullopt otherwise.
+static std::optional<unsigned>
tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
const LangOptions &LangOpts) {
// Accept replacements starting with - or + as valid ObjC method names.
if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
Name = Name.drop_front(1);
if (Name.empty())
- return None;
+ return std::nullopt;
Name.split(SlotNames, ':');
unsigned NumParams;
if (Name.back() == ':') {
@@ -260,7 +264,7 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
} else {
if (SlotNames.size() != 1)
// Not a valid method name, just a colon-separated string.
- return None;
+ return std::nullopt;
NumParams = 0;
}
// Verify all slot names are valid.
@@ -269,28 +273,28 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
if (S.empty())
continue;
if (!isValidAsciiIdentifier(S, AllowDollar))
- return None;
+ return std::nullopt;
}
return NumParams;
}
/// Returns a source location in which it's appropriate to insert a new
/// attribute for the given declaration \D.
-static Optional<AttributeInsertion>
+static std::optional<AttributeInsertion>
createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
const LangOptions &LangOpts) {
if (isa<ObjCPropertyDecl>(D))
return AttributeInsertion::createInsertionAfter(D);
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->hasBody())
- return None;
+ return std::nullopt;
return AttributeInsertion::createInsertionAfter(D);
}
if (const auto *TD = dyn_cast<TagDecl>(D)) {
SourceLocation Loc =
Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
if (Loc.isInvalid())
- return None;
+ return std::nullopt;
// Insert after the 'struct'/whatever keyword.
return AttributeInsertion::createInsertionAfter(Loc);
}
@@ -397,7 +401,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
return;
if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
return;
- Optional<AttributeInsertion> Insertion = createAttributeInsertion(
+ std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
Enclosing, S.getSourceManager(), S.getLangOpts());
if (!Insertion)
return;
@@ -499,7 +503,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
Selector Sel = MethodDecl->getSelector();
SmallVector<StringRef, 12> SelectorSlotNames;
- Optional<unsigned> NumParams = tryParseObjCMethodName(
+ std::optional<unsigned> NumParams = tryParseObjCMethodName(
Replacement, SelectorSlotNames, S.getLangOpts());
if (NumParams && *NumParams == Sel.getNumArgs()) {
assert(SelectorSlotNames.size() == Locs.size());
@@ -895,6 +899,11 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
return;
Body = FD->getBody();
+
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+ for (const CXXCtorInitializer *CI : CD->inits())
+ DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
+
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
Body = MD->getBody();
else if (auto *BD = dyn_cast<BlockDecl>(D))
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 0a49d72ba963..cfea6493ced7 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -22,8 +22,8 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
template <typename AttrT> static bool hasExplicitAttr(const VarDecl *D) {
@@ -338,7 +338,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
if (!InClass || HasExplicitAttr)
return false;
- llvm::Optional<CUDAFunctionTarget> InferredTarget;
+ std::optional<CUDAFunctionTarget> InferredTarget;
// We're going to invoke special member lookup; mark that these special
// members are called from this one, and not from its caller.
@@ -381,13 +381,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = BaseMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.value(), BaseMethodTarget,
- InferredTarget.getPointer());
+ *InferredTarget, BaseMethodTarget, &*InferredTarget);
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.value() << BaseMethodTarget;
+ << (unsigned)CSM << *InferredTarget << BaseMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -425,13 +424,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = FieldMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.value(), FieldMethodTarget,
- InferredTarget.getPointer());
+ *InferredTarget, FieldMethodTarget, &*InferredTarget);
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.value() << FieldMethodTarget;
+ << (unsigned)CSM << *InferredTarget << FieldMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -444,9 +442,9 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
// it's the least restrictive option that can be invoked from any target.
bool NeedsH = true, NeedsD = true;
if (InferredTarget) {
- if (InferredTarget.value() == CFT_Device)
+ if (*InferredTarget == CFT_Device)
NeedsH = false;
- else if (InferredTarget.value() == CFT_Host)
+ else if (*InferredTarget == CFT_Host)
NeedsD = false;
}
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 3f8fedda7174..daa61ba45e8e 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -931,10 +931,9 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// Handle a dependent template specialization for which we cannot resolve
// the template name.
assert(DTN->getQualifier() == SS.getScopeRep());
- QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 7b5bc7ca80b1..9fd9369c9641 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -451,6 +451,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case InitializationSequence::FK_ConstructorOverloadFailed:
case InitializationSequence::FK_UserConversionOverloadFailed:
+ case InitializationSequence::FK_ParenthesizedListInitFailed:
break;
}
@@ -1059,11 +1060,19 @@ static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType,
return Context.hasSameUnqualifiedType(SrcType, DestType);
}
-static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
- QualType DestType) {
- if (Self.Diags.isIgnored(diag::warn_cast_function_type,
- SrcExpr.get()->getExprLoc()))
- return true;
+static unsigned int checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ unsigned int DiagID = 0;
+ const unsigned int DiagList[] = {diag::warn_cast_function_type_strict,
+ diag::warn_cast_function_type};
+ for (auto ID : DiagList) {
+ if (!Self.Diags.isIgnored(ID, SrcExpr.get()->getExprLoc())) {
+ DiagID = ID;
+ break;
+ }
+ }
+ if (!DiagID)
+ return 0;
QualType SrcType = SrcExpr.get()->getType();
const FunctionType *SrcFTy = nullptr;
@@ -1078,10 +1087,17 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
SrcFTy = SrcType->castAs<FunctionType>();
DstFTy = DestType.getNonReferenceType()->castAs<FunctionType>();
} else {
- return true;
+ return 0;
}
assert(SrcFTy && DstFTy);
+ if (Self.Context.hasSameType(SrcFTy, DstFTy))
+ return 0;
+
+ // For strict checks, ensure we have an exact match.
+ if (DiagID == diag::warn_cast_function_type_strict)
+ return DiagID;
+
auto IsVoidVoid = [](const FunctionType *T) {
if (!T->getReturnType()->isVoidType())
return false;
@@ -1092,16 +1108,16 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
// Skip if either function type is void(*)(void)
if (IsVoidVoid(SrcFTy) || IsVoidVoid(DstFTy))
- return true;
+ return 0;
// Check return type.
if (!argTypeIsABIEquivalent(SrcFTy->getReturnType(), DstFTy->getReturnType(),
Self.Context))
- return false;
+ return DiagID;
// Check if either has unspecified number of parameters
if (SrcFTy->isFunctionNoProtoType() || DstFTy->isFunctionNoProtoType())
- return true;
+ return 0;
// Check parameter types.
@@ -1114,19 +1130,19 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
unsigned DstNumParams = DstFPTy->getNumParams();
if (NumParams > DstNumParams) {
if (!DstFPTy->isVariadic())
- return false;
+ return DiagID;
NumParams = DstNumParams;
} else if (NumParams < DstNumParams) {
if (!SrcFPTy->isVariadic())
- return false;
+ return DiagID;
}
for (unsigned i = 0; i < NumParams; ++i)
if (!argTypeIsABIEquivalent(SrcFPTy->getParamType(i),
DstFPTy->getParamType(i), Self.Context))
- return false;
+ return DiagID;
- return true;
+ return 0;
}
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
@@ -1167,8 +1183,8 @@ void CastOperation::CheckReinterpretCast() {
checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID)
<< SrcExpr.get()->getType() << DestType << OpRange;
} else {
SrcExpr = ExprError();
@@ -2797,8 +2813,8 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
if (Kind == CK_BitCast)
checkCastAlign();
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID)
<< SrcExpr.get()->getType() << DestType << OpRange;
} else {
@@ -2985,6 +3001,37 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // C2x 6.5.4p4:
+ // The type nullptr_t shall not be converted to any type other than void,
+ // bool, or a pointer type. No type other than nullptr_t shall be converted
+ // to nullptr_t.
+ if (SrcType->isNullPtrType()) {
+ // FIXME: 6.3.2.4p2 says that nullptr_t can be converted to itself, but
+ // 6.5.4p4 is a constraint check and nullptr_t is not void, bool, or a
+ // pointer type. We're not going to diagnose that as a constraint violation.
+ if (!DestType->isVoidType() && !DestType->isBooleanType() &&
+ !DestType->isPointerType() && !DestType->isNullPtrType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
+ << /*nullptr to type*/ 0 << DestType;
+ SrcExpr = ExprError();
+ return;
+ }
+ if (!DestType->isNullPtrType()) {
+ // Implicitly cast from the null pointer type to the type of the
+ // destination.
+ CastKind CK = DestType->isPointerType() ? CK_NullToPointer : CK_BitCast;
+ SrcExpr = ImplicitCastExpr::Create(Self.Context, DestType, CK,
+ SrcExpr.get(), nullptr, VK_PRValue,
+ Self.CurFPFeatureOverrides());
+ }
+ }
+ if (DestType->isNullPtrType() && !SrcType->isNullPtrType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
+ << /*type to nullptr*/ 1 << SrcType;
+ SrcExpr = ExprError();
+ return;
+ }
+
if (DestType->isExtVectorType()) {
SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.get(), Kind);
return;
@@ -3125,9 +3172,8 @@ void CastOperation::CheckCStyleCast() {
}
}
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
- << SrcType << DestType << OpRange;
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << OpRange;
if (isa<PointerType>(SrcType) && isa<PointerType>(DestType)) {
QualType SrcTy = cast<PointerType>(SrcType)->getPointeeType();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dae51d0690e6..ea21171aaac6 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -67,8 +67,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -96,6 +94,7 @@
#include <cstdint>
#include <functional>
#include <limits>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -128,6 +127,28 @@ static bool checkArgCountAtLeast(Sema &S, CallExpr *Call,
<< Call->getSourceRange();
}
+/// Checks that a call expression's argument count is at most the desired
+/// number. This is useful when doing custom type-checking on a variadic
+/// function. Returns true on error.
+static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) {
+ unsigned ArgCount = Call->getNumArgs();
+ if (ArgCount <= MaxArgCount)
+ return false;
+ return S.Diag(Call->getEndLoc(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << MaxArgCount << ArgCount
+ << Call->getSourceRange();
+}
+
+/// Checks that a call expression's argument count is in the desired range. This
+/// is useful when doing custom type-checking on a variadic function. Returns
+/// true on error.
+static bool checkArgCountRange(Sema &S, CallExpr *Call, unsigned MinArgCount,
+ unsigned MaxArgCount) {
+ return checkArgCountAtLeast(S, Call, MinArgCount) ||
+ checkArgCountAtMost(S, Call, MaxArgCount);
+}
+
/// Checks that a call expression's argument count is the desired number.
/// This is useful when doing custom type-checking. Returns true on error.
static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {
@@ -148,6 +169,20 @@ static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {
<< Call->getArg(1)->getSourceRange();
}
+static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
+ if (Value->isTypeDependent())
+ return false;
+
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(S.Context, Ty, false);
+ ExprResult Result =
+ S.PerformCopyInitialization(Entity, SourceLocation(), Value);
+ if (Result.isInvalid())
+ return true;
+ Value = Result.get();
+ return false;
+}
+
/// Check that the first argument to __builtin_annotation is an integer
/// and the second argument is a non-wide string literal.
static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
@@ -760,7 +795,7 @@ class ScanfDiagnosticFormatHandler
// Accepts the argument index (relative to the first destination index) of the
// argument whose size we want.
using ComputeSizeFunction =
- llvm::function_ref<Optional<llvm::APSInt>(unsigned)>;
+ llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>;
// Accepts the argument index (relative to the first destination index), the
// destination size, and the source size).
@@ -800,7 +835,8 @@ public:
unsigned SourceSize = FW.getConstantAmount() + NulByte;
- Optional<llvm::APSInt> DestSizeAPS = ComputeSizeArgument(FS.getArgIndex());
+ std::optional<llvm::APSInt> DestSizeAPS =
+ ComputeSizeArgument(FS.getArgIndex());
if (!DestSizeAPS)
return true;
@@ -1018,7 +1054,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
const TargetInfo &TI = getASTContext().getTargetInfo();
unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
- auto TranslateIndex = [&](unsigned Index) -> Optional<unsigned> {
+ auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> {
// If we refer to a diagnose_as_builtin attribute, we need to change the
// argument index to refer to the arguments of the called function. Unless
// the index is out of bounds, which presumably means it's a variadic
@@ -1030,26 +1066,27 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
? DABAttr->argIndices_begin()[Index]
: Index - DABIndices + FD->getNumParams();
if (NewIndex >= TheCall->getNumArgs())
- return llvm::None;
+ return std::nullopt;
return NewIndex;
};
auto ComputeExplicitObjectSizeArgument =
- [&](unsigned Index) -> Optional<llvm::APSInt> {
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
Expr::EvalResult Result;
Expr *SizeArg = TheCall->getArg(NewIndex);
if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
- return llvm::None;
+ return std::nullopt;
llvm::APSInt Integer = Result.Val.getInt();
Integer.setIsUnsigned(true);
return Integer;
};
- auto ComputeSizeArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
+ auto ComputeSizeArgument =
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
// If the parameter has a pass_object_size attribute, then we should use its
// (potentially) more strict checking mode. Otherwise, conservatively assume
// type 0.
@@ -1061,36 +1098,40 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
BOSType = POS->getType();
}
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
+ if (NewIndex >= TheCall->getNumArgs())
+ return std::nullopt;
+
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
- return llvm::None;
+ return std::nullopt;
// Get the object size in the target's size_t width.
return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
};
- auto ComputeStrLenArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ auto ComputeStrLenArgument =
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
if (!ObjArg->tryEvaluateStrLen(Result, getASTContext()))
- return llvm::None;
+ return std::nullopt;
// Add 1 for null byte.
return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth);
};
- Optional<llvm::APSInt> SourceSize;
- Optional<llvm::APSInt> DestinationSize;
+ std::optional<llvm::APSInt> SourceSize;
+ std::optional<llvm::APSInt> DestinationSize;
unsigned DiagID = 0;
bool IsChkVariant = false;
@@ -1869,18 +1910,18 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
TheCall->setType(ParamTy);
- auto DiagSelect = [&]() -> llvm::Optional<unsigned> {
+ auto DiagSelect = [&]() -> std::optional<unsigned> {
if (!ParamTy->isPointerType())
return 0;
if (ParamTy->isFunctionPointerType())
return 1;
if (ParamTy->isVoidPointerType())
return 2;
- return llvm::Optional<unsigned>{};
+ return std::optional<unsigned>{};
}();
if (DiagSelect) {
S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
- << DiagSelect.value() << TheCall->getSourceRange();
+ << *DiagSelect << TheCall->getSourceRange();
return ExprError();
}
@@ -1981,7 +2022,37 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ }
+}
+
+// Check if \p Ty is a valid type for the elementwise math builtins. If it is
+// not a valid type, emit an error message and return true. Otherwise return
+// false.
+static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
+ QualType Ty) {
+ if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
+ return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+ << 1 << /* vector, integer or float ty*/ 0 << Ty;
+ }
+
+ return false;
+}
+
+static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
+ QualType ArgTy, int ArgIndex) {
+ QualType EltTy = ArgTy;
+ if (auto *VecTy = EltTy->getAs<VectorType>())
+ EltTy = VecTy->getElementType();
+
+ if (!EltTy->isRealFloatingType()) {
+ return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+ << ArgIndex << /* vector or float ty*/ 5 << ArgTy;
}
+
+ return false;
}
ExprResult
@@ -2108,7 +2179,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_alloca_with_align_uninitialized:
if (SemaBuiltinAllocaWithAlign(TheCall))
return ExprError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_alloca:
case Builtin::BI__builtin_alloca_uninitialized:
Diag(TheCall->getBeginLoc(), diag::warn_alloca)
@@ -2485,7 +2556,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
case Builtin::BI__builtin_os_log_format:
Cleanup.setExprNeedsCleanups(true);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_os_log_format_buffer_size:
if (SemaBuiltinOSLogFormat(TheCall))
return ExprError();
@@ -2532,9 +2603,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// These builtins restrict the element type to floating point
// types only.
case Builtin::BI__builtin_elementwise_ceil:
+ case Builtin::BI__builtin_elementwise_cos:
case Builtin::BI__builtin_elementwise_floor:
case Builtin::BI__builtin_elementwise_roundeven:
- case Builtin::BI__builtin_elementwise_trunc: {
+ case Builtin::BI__builtin_elementwise_sin:
+ case Builtin::BI__builtin_elementwise_trunc:
+ case Builtin::BI__builtin_elementwise_canonicalize: {
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return ExprError();
@@ -2580,6 +2654,35 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinElementwiseMath(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_elementwise_copysign: {
+ if (checkArgCount(*this, TheCall, 2))
+ return ExprError();
+
+ ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0));
+ ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1));
+ if (Magnitude.isInvalid() || Sign.isInvalid())
+ return ExprError();
+
+ QualType MagnitudeTy = Magnitude.get()->getType();
+ QualType SignTy = Sign.get()->getType();
+ if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
+ MagnitudeTy, 1) ||
+ checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
+ SignTy, 2)) {
+ return ExprError();
+ }
+
+ if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) {
+ return Diag(Sign.get()->getBeginLoc(),
+ diag::err_typecheck_call_different_arg_types)
+ << MagnitudeTy << SignTy;
+ }
+
+ TheCall->setArg(0, Magnitude.get());
+ TheCall->setArg(1, Sign.get());
+ TheCall->setType(Magnitude.get()->getType());
+ break;
+ }
case Builtin::BI__builtin_reduce_max:
case Builtin::BI__builtin_reduce_min: {
if (PrepareBuiltinReduceMathOneArgCall(TheCall))
@@ -3183,13 +3286,15 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
- SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) ||
- SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) ||
- SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 3) ||
+ SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
}
if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_wsr64)
+ BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
// Memory Tagging Extensions (MTE) Intrinsics
@@ -3338,7 +3443,7 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
// The second argument needs to be a constant int
Expr *Arg = TheCall->getArg(1);
- Optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
diag::kind kind;
if (!Value) {
if (BuiltinID == BPF::BI__builtin_preserve_field_info)
@@ -3585,6 +3690,31 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
{ Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} },
{ Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B,
{{ 3, false, 1, 0 }} },
+
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B,
+ {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B,
+ {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B,
+ {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B,
+ {{ 3, false, 3, 0 }} },
};
// Use a dynamically initialized static to sort the table exactly once on
@@ -3629,6 +3759,91 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
return CheckHexagonBuiltinArgument(BuiltinID, TheCall);
}
+bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
+ unsigned BuiltinID,
+ CallExpr *TheCall) {
+ switch (BuiltinID) {
+ default:
+ break;
+ case LoongArch::BI__builtin_loongarch_cacop_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ LLVM_FALLTHROUGH;
+ case LoongArch::BI__builtin_loongarch_cacop_w: {
+ if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w &&
+ !TI.hasFeature("32bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la32)
+ << TheCall->getSourceRange();
+ SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5));
+ SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12),
+ llvm::maxIntN(12));
+ break;
+ }
+ case LoongArch::BI__builtin_loongarch_crc_w_b_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_h_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_w_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_d_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_b_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_h_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_w_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_d_w:
+ case LoongArch::BI__builtin_loongarch_iocsrrd_d:
+ case LoongArch::BI__builtin_loongarch_iocsrwr_d:
+ case LoongArch::BI__builtin_loongarch_asrtle_d:
+ case LoongArch::BI__builtin_loongarch_asrtgt_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ break;
+ case LoongArch::BI__builtin_loongarch_break:
+ case LoongArch::BI__builtin_loongarch_dbar:
+ case LoongArch::BI__builtin_loongarch_ibar:
+ case LoongArch::BI__builtin_loongarch_syscall:
+ // Check if immediate is in [0, 32767].
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767);
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_lddir_d:
+ case LoongArch::BI__builtin_loongarch_ldpte_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31);
+ case LoongArch::BI__builtin_loongarch_movfcsr2gr:
+ case LoongArch::BI__builtin_loongarch_movgr2fcsr:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2));
+ }
+
+ return false;
+}
+
bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID, CallExpr *TheCall) {
return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) ||
@@ -4039,7 +4254,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case PPC::BI__builtin_unpack_longdouble:
if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1))
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case PPC::BI__builtin_pack_longdouble:
if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble())
return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi)
@@ -4172,10 +4387,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
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 either a 'float' or a 'double'.
+ // valid. The argument must be 'float' or 'double' or '__float128'.
QualType ArgType = TheCall->getArg(0)->getType();
if (ArgType != QualType(Context.FloatTy) &&
- ArgType != QualType(Context.DoubleTy))
+ ArgType != QualType(Context.DoubleTy) &&
+ ArgType != QualType(Context.Float128Ty))
return Diag(TheCall->getBeginLoc(),
diag::err_ppc_invalid_test_data_class_type);
return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions",
@@ -4321,27 +4537,6 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) {
<< Arg->getSourceRange();
}
-static bool isRISCV32Builtin(unsigned BuiltinID) {
- // These builtins only work on riscv32 targets.
- switch (BuiltinID) {
- case RISCV::BI__builtin_riscv_zip_32:
- case RISCV::BI__builtin_riscv_unzip_32:
- 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_sha512sig0h_32:
- case RISCV::BI__builtin_riscv_sha512sig0l_32:
- case RISCV::BI__builtin_riscv_sha512sig1h_32:
- case RISCV::BI__builtin_riscv_sha512sig1l_32:
- case RISCV::BI__builtin_riscv_sha512sum0r_32:
- case RISCV::BI__builtin_riscv_sha512sum1r_32:
- return true;
- }
-
- return false;
-}
-
bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall) {
@@ -4352,31 +4547,28 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID);
Features.split(ReqFeatures, ',');
- // Check for 32-bit only builtins on a 64-bit target.
- const llvm::Triple &TT = TI.getTriple();
- if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID))
- return Diag(TheCall->getCallee()->getBeginLoc(),
- diag::err_32_bit_builtin_64_bit_tgt);
-
// Check if each required feature is included
for (StringRef F : ReqFeatures) {
SmallVector<StringRef> ReqOpFeatures;
F.split(ReqOpFeatures, '|');
- bool HasFeature = false;
- for (StringRef OF : ReqOpFeatures) {
- if (TI.hasFeature(OF)) {
- HasFeature = true;
- continue;
- }
- }
- if (!HasFeature) {
+ if (llvm::none_of(ReqOpFeatures,
+ [&TI](StringRef OF) { return TI.hasFeature(OF); })) {
std::string FeatureStrs;
+ bool IsExtension = true;
for (StringRef OF : ReqOpFeatures) {
// If the feature is 64bit, alter the string so it will print better in
// the diagnostic.
- if (OF == "64bit")
+ if (OF == "64bit") {
+ assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone");
OF = "RV64";
+ IsExtension = false;
+ }
+ if (OF == "32bit") {
+ assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone");
+ OF = "RV32";
+ IsExtension = false;
+ }
// Convert features like "zbr" and "experimental-zbr" to "Zbr".
OF.consume_front("experimental-");
@@ -4391,6 +4583,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
// Error message
FeatureMissing = true;
Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
+ << IsExtension
<< TheCall->getSourceRange() << StringRef(FeatureStrs);
}
}
@@ -4449,7 +4642,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
if (BuiltinID == SystemZ::BI__builtin_tabort) {
Expr *Arg = TheCall->getArg(0);
- if (Optional<llvm::APSInt> AbortCode = Arg->getIntegerConstantExpr(Context))
+ if (std::optional<llvm::APSInt> AbortCode =
+ Arg->getIntegerConstantExpr(Context))
if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256)
return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code)
<< Arg->getSourceRange();
@@ -5010,6 +5204,7 @@ bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_tdpbusd:
case X86::BI__builtin_ia32_tdpbuud:
case X86::BI__builtin_ia32_tdpbf16ps:
+ case X86::BI__builtin_ia32_tdpfp16ps:
return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2});
}
}
@@ -5394,6 +5589,10 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case X86::BI__builtin_ia32_reducesh_mask:
i = 4; l = 0; u = 255;
break;
+ case X86::BI__builtin_ia32_cmpccxadd32:
+ case X86::BI__builtin_ia32_cmpccxadd64:
+ i = 3; l = 0; u = 15;
+ break;
}
// Note that we don't force a hard error on the range check here, allowing
@@ -5437,8 +5636,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
/// Returns true if the value evaluates to null.
static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
// If the expression has non-null type, it doesn't evaluate to null.
- if (auto nullability
- = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) {
+ if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
if (*nullability == NullabilityKind::NonNull)
return false;
}
@@ -5522,8 +5720,8 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S,
}
/// Determine whether the given type has a non-null nullability annotation.
-static bool isNonNullType(ASTContext &ctx, QualType type) {
- if (auto nullability = type->getNullability(ctx))
+static bool isNonNullType(QualType type) {
+ if (auto nullability = type->getNullability())
return *nullability == NullabilityKind::NonNull;
return false;
@@ -5536,7 +5734,7 @@ static void CheckNonNullArguments(Sema &S,
SourceLocation CallSiteLoc) {
assert((FDecl || Proto) && "Need a function declaration or prototype");
- // Already checked by by constant evaluator.
+ // Already checked by constant evaluator.
if (S.isConstantEvaluated())
return;
// Check the attributes attached to the method/function itself.
@@ -5576,8 +5774,7 @@ static void CheckNonNullArguments(Sema &S,
for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
I != E; ++I, ++ParamIndex) {
const ParmVarDecl *PVD = *I;
- if (PVD->hasAttr<NonNullAttr>() ||
- isNonNullType(S.Context, PVD->getType())) {
+ if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) {
if (NonNullArgs.empty())
NonNullArgs.resize(Args.size());
@@ -5606,7 +5803,7 @@ static void CheckNonNullArguments(Sema &S,
if (Proto) {
unsigned Index = 0;
for (auto paramType : Proto->getParamTypes()) {
- if (isNonNullType(S.Context, paramType)) {
+ if (isNonNullType(paramType)) {
if (NonNullArgs.empty())
NonNullArgs.resize(Args.size());
@@ -5622,7 +5819,7 @@ static void CheckNonNullArguments(Sema &S,
for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size();
ArgIndex != ArgIndexEnd; ++ArgIndex) {
if (NonNullArgs[ArgIndex])
- CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc);
+ CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc());
}
}
@@ -5683,9 +5880,9 @@ void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
// Find expected alignment, and the actual alignment of the passed object.
// getTypeAlignInChars requires complete types
- if (ArgTy.isNull() || ParamTy->isIncompleteType() ||
- ArgTy->isIncompleteType() || ParamTy->isUndeducedType() ||
- ArgTy->isUndeducedType())
+ if (ArgTy.isNull() || ParamTy->isDependentType() ||
+ ParamTy->isIncompleteType() || ArgTy->isIncompleteType() ||
+ ParamTy->isUndeducedType() || ArgTy->isUndeducedType())
return;
CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy);
@@ -5837,14 +6034,14 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
unsigned NumArgs = TheCall->getNumArgs();
Expr *ImplicitThis = nullptr;
- if (IsMemberOperatorCall) {
- // If this is a call to a member operator, hide the first argument
- // from checkCall.
+ if (IsMemberOperatorCall && !FDecl->isStatic()) {
+ // If this is a call to a non-static member operator, hide the first
+ // argument from checkCall.
// FIXME: Our choice of AST representation here is less than ideal.
ImplicitThis = Args[0];
++Args;
--NumArgs;
- } else if (IsMemberFunction)
+ } else if (IsMemberFunction && !FDecl->isStatic())
ImplicitThis =
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
@@ -5864,7 +6061,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
ThisTypeFromDecl);
}
- checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs),
+ checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs),
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -5945,7 +6142,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
}
checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
- llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+ llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -5958,7 +6155,7 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
TheCall->getCallee());
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
- llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+ llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -6463,7 +6660,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
}
if (SubExprs.size() >= 2 && Form != Init) {
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
SubExprs[1]->getIntegerConstantExpr(Context))
if (!isValidOrderingForOp(Result->getSExtValue(), Op))
Diag(SubExprs[1]->getBeginLoc(),
@@ -6473,7 +6670,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
auto *Scope = Args[Args.size() - 1];
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
Scope->getIntegerConstantExpr(Context)) {
if (!ScopeModel->isValid(Result->getZExtValue()))
Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_synch_scope)
@@ -6840,7 +7037,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Get the decl for the concrete builtin from this, we can tell what the
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
- const char *NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
+ StringRef NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
FunctionDecl *NewBuiltinDecl;
if (NewBuiltinID == BuiltinID)
NewBuiltinDecl = FDecl;
@@ -7122,6 +7319,9 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
if (checkVAStartABI(*this, BuiltinID, Fn))
return true;
+ // In C2x mode, va_start only needs one argument. However, the builtin still
+ // requires two arguments (which matches the behavior of the GCC builtin),
+ // <stdarg.h> passes `0` as the second argument in C2x mode.
if (checkArgCount(*this, TheCall, 2))
return true;
@@ -7135,9 +7335,15 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return true;
// Verify that the second argument to the builtin is the last argument of the
- // current function or method.
+ // current function or method. In C2x mode, if the second argument is an
+ // integer constant expression with value 0, then we don't bother with this
+ // check.
bool SecondArgIsLastNamedArgument = false;
const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
+ if (std::optional<llvm::APSInt> Val =
+ TheCall->getArg(1)->getIntegerConstantExpr(Context);
+ Val && LangOpts.C2x && *Val == 0)
+ return false;
// These are valid if SecondArgIsLastNamedArgument is false after the next
// block.
@@ -7163,7 +7369,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Type->isSpecificBuiltinType(BuiltinType::Float) || [=] {
// Promotable integers are UB, but enumerations need a bit of
// extra checking to see what their promotable type actually is.
- if (!Type->isPromotableIntegerType())
+ if (!Context.isPromotableIntegerType(Type))
return false;
if (!Type->isEnumeralType())
return true;
@@ -7178,7 +7384,6 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Diag(ParamLoc, diag::note_parameter_type) << Type;
}
- TheCall->setType(Context.VoidTy);
return false;
}
@@ -7490,7 +7695,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getArg(i)->isValueDependent())
continue;
- Optional<llvm::APSInt> Result;
+ std::optional<llvm::APSInt> Result;
if (!(Result = TheCall->getArg(i)->getIntegerConstantExpr(Context)))
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_shufflevector_nonconstant_argument)
@@ -7644,38 +7849,43 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) {
/// Handle __builtin_assume_aligned. This is declared
/// as (const void*, size_t, ...) and can take one optional constant int arg.
bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
+ if (checkArgCountRange(*this, TheCall, 2, 3))
+ return true;
+
unsigned NumArgs = TheCall->getNumArgs();
+ Expr *FirstArg = TheCall->getArg(0);
- if (NumArgs > 3)
- return Diag(TheCall->getEndLoc(),
- diag::err_typecheck_call_too_many_args_at_most)
- << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange();
+ {
+ ExprResult FirstArgResult =
+ DefaultFunctionArrayLvalueConversion(FirstArg);
+ if (FirstArgResult.isInvalid())
+ return true;
+ TheCall->setArg(0, FirstArgResult.get());
+ }
// The alignment must be a constant integer.
- Expr *Arg = TheCall->getArg(1);
+ Expr *SecondArg = TheCall->getArg(1);
// We can't check the value of a dependent argument.
- if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+ if (!SecondArg->isValueDependent()) {
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
if (!Result.isPowerOf2())
return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
- << Arg->getSourceRange();
+ << SecondArg->getSourceRange();
if (Result > Sema::MaximumAlignment)
Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
- << Arg->getSourceRange() << Sema::MaximumAlignment;
+ << SecondArg->getSourceRange() << Sema::MaximumAlignment;
}
if (NumArgs > 2) {
- ExprResult Arg(TheCall->getArg(2));
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- Context.getSizeType(), false);
- Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
- if (Arg.isInvalid()) return true;
- TheCall->setArg(2, Arg.get());
+ Expr *ThirdArg = TheCall->getArg(2);
+ if (convertArgumentToType(*this, ThirdArg, Context.getSizeType()))
+ return true;
+ TheCall->setArg(2, ThirdArg);
}
return false;
@@ -7771,7 +7981,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
if (Arg->isTypeDependent() || Arg->isValueDependent()) return false;
- Optional<llvm::APSInt> R;
+ std::optional<llvm::APSInt> R;
if (!(R = Arg->getIntegerConstantExpr(Context)))
return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type)
<< FDecl->getDeclName() << Arg->getSourceRange();
@@ -8106,6 +8316,8 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
BuiltinID == ARM::BI__builtin_arm_wsrp;
bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
BuiltinID == AArch64::BI__builtin_arm_rsr ||
BuiltinID == AArch64::BI__builtin_arm_rsrp ||
BuiltinID == AArch64::BI__builtin_arm_wsr ||
@@ -8173,21 +8385,51 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
<< Arg->getSourceRange();
} else if (IsAArch64Builtin && Fields.size() == 1) {
- // If the register name is one of those that appear in the condition below
- // and the special register builtin being used is one of the write builtins,
- // then we require that the argument provided for writing to the register
- // is an integer constant expression. This is because it will be lowered to
- // an MSR (immediate) instruction, so we need to know the immediate at
- // compile time.
+ // This code validates writes to PSTATE registers.
+
+ // Not a write.
if (TheCall->getNumArgs() != 2)
return false;
- std::string RegLower = Reg.lower();
- if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" &&
- RegLower != "pan" && RegLower != "uao")
+ // The 128-bit system register accesses do not touch PSTATE.
+ if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return false;
- return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+ // These are the named PSTATE accesses using "MSR (immediate)" instructions,
+ // along with the upper limit on the immediates allowed.
+ auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
+ .CaseLower("spsel", 15)
+ .CaseLower("daifclr", 15)
+ .CaseLower("daifset", 15)
+ .CaseLower("pan", 15)
+ .CaseLower("uao", 15)
+ .CaseLower("dit", 15)
+ .CaseLower("ssbs", 15)
+ .CaseLower("tco", 15)
+ .CaseLower("allint", 1)
+ .CaseLower("pm", 1)
+ .Default(std::nullopt);
+
+ // If this is not a named PSTATE, just continue without validating, as this
+ // will be lowered to an "MSR (register)" instruction directly
+ if (!MaxLimit)
+ return false;
+
+ // Here we only allow constants in the range for that pstate, as required by
+ // the ACLE.
+ //
+ // While clang also accepts the names of system registers in its ACLE
+ // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
+ // as the value written via a register is different to the value used as an
+ // immediate to have the same effect. e.g., for the instruction `msr tco,
+ // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
+ // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
+ //
+ // If a programmer wants to codegen the MSR (register) form of `msr tco,
+ // xN`, they can still do so by specifying the register using five
+ // colon-separated numbers in a string.
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
}
return false;
@@ -8473,6 +8715,9 @@ static void CheckFormatString(
llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
bool IgnoreStringsWithoutSpecifiers);
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E);
+
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
// format string, we will usually need to emit a warning.
@@ -8503,6 +8748,15 @@ tryAgain:
return SLCT_UncheckedLiteral;
switch (E->getStmtClass()) {
+ case Stmt::InitListExprClass:
+ // Handle expressions like {"foobar"}.
+ if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) {
+ return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
+ Type, CallType, /*InFunctionCall*/ false,
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
+ }
+ return SLCT_NotALiteral;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
// The expression is a literal if both sub-expressions were, and it was
@@ -8713,7 +8967,11 @@ tryAgain:
}
}
}
-
+ if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
+ return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
+ Type, CallType, /*InFunctionCall*/ false,
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
return SLCT_NotALiteral;
}
case Stmt::ObjCMessageExprClass: {
@@ -8823,6 +9081,20 @@ tryAgain:
}
}
+// If this expression can be evaluated at compile-time,
+// check if the result is a StringLiteral and return it
+// otherwise return nullptr
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
+ const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
+ if (isa_and_nonnull<StringLiteral>(LVE))
+ return LVE;
+ }
+ return nullptr;
+}
+
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)
@@ -9013,7 +9285,7 @@ public:
EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
const PartialDiagnostic &PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- ArrayRef<FixItHint> Fixit = None);
+ ArrayRef<FixItHint> Fixit = std::nullopt);
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
@@ -9040,7 +9312,7 @@ protected:
template <typename Range>
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- ArrayRef<FixItHint> Fixit = None);
+ ArrayRef<FixItHint> Fixit = std::nullopt);
};
} // namespace
@@ -9083,7 +9355,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
@@ -9116,7 +9388,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< LM.toString() << 0,
@@ -9143,7 +9415,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier(
using namespace analyze_format_string;
// See if we know how to fix this conversion specifier.
- Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
if (FixedCS) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< CS.toString() << /*conversion specifier*/1,
@@ -10005,7 +10277,7 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) {
// It's an integer promotion if the destination type is the promoted
// source type.
if (ICE->getCastKind() == CK_IntegralCast &&
- From->isPromotableIntegerType() &&
+ S.Context.isPromotableIntegerType(From) &&
S.Context.getPromotedIntegerType(From) == To)
return true;
// Look through vector types, since we do default argument promotion for
@@ -10060,10 +10332,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
return true;
}
- analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
- if (Match == analyze_printf::ArgType::Match)
+ ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
+ ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
+ if (Match == ArgType::Match)
return true;
+ // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr
+ assert(Match != ArgType::NoMatchPromotionTypeConfusion);
+
// Look through argument promotions for our error message's reported type.
// This includes the integral and floating promotions, but excludes array
// and function pointer decay (seeing that an argument intended to be a
@@ -10080,13 +10356,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
// All further checking is done on the subexpression
- const analyze_printf::ArgType::MatchKind ImplicitMatch =
- AT.matchesType(S.Context, ExprTy);
- if (ImplicitMatch == analyze_printf::ArgType::Match)
+ ImplicitMatch = AT.matchesType(S.Context, ExprTy);
+ if (ImplicitMatch == ArgType::Match)
return true;
- if (ImplicitMatch == ArgType::NoMatchPedantic ||
- ImplicitMatch == ArgType::NoMatchTypeConfusion)
- Match = ImplicitMatch;
}
}
} else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
@@ -10097,10 +10369,29 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// modifier is provided.
if (ExprTy == S.Context.IntTy &&
FS.getLengthModifier().getKind() != LengthModifier::AsChar)
- if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) {
ExprTy = S.Context.CharTy;
+ // To improve check results, we consider a character literal in C
+ // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is
+ // more likely a type confusion situation, so we will suggest to
+ // use '%hhd' instead by discarding the MatchPromotion.
+ if (Match == ArgType::MatchPromotion)
+ Match = ArgType::NoMatch;
+ }
}
-
+ if (Match == ArgType::MatchPromotion) {
+ // WG14 N2562 only clarified promotions in *printf
+ // For NSLog in ObjC, just preserve -Wformat behavior
+ if (!S.getLangOpts().ObjC &&
+ ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion &&
+ ImplicitMatch != ArgType::NoMatchTypeConfusion)
+ return true;
+ Match = ArgType::NoMatch;
+ }
+ if (ImplicitMatch == ArgType::NoMatchPedantic ||
+ ImplicitMatch == ArgType::NoMatchTypeConfusion)
+ Match = ImplicitMatch;
+ assert(Match != ArgType::MatchPromotion);
// Look through enums to their underlying type.
bool IsEnum = false;
if (auto EnumTy = ExprTy->getAs<EnumType>()) {
@@ -10173,7 +10464,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
unsigned Diag;
switch (Match) {
- case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::Match:
+ case ArgType::MatchPromotion:
+ case ArgType::NoMatchPromotionTypeConfusion:
+ llvm_unreachable("expected non-matching");
case ArgType::NoMatchPedantic:
Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
break;
@@ -10236,7 +10530,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// We extract the name from the typedef because we don't want to show
// the underlying type in the diagnostic.
StringRef Name;
- if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(ExprTy))
+ if (const auto *TypedefTy = ExprTy->getAs<TypedefType>())
Name = TypedefTy->getDecl()->getName();
else
Name = CastTyName;
@@ -10270,7 +10564,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
case Sema::VAK_ValidInCXX11: {
unsigned Diag;
switch (Match) {
- case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::Match:
+ case ArgType::MatchPromotion:
+ case ArgType::NoMatchPromotionTypeConfusion:
+ llvm_unreachable("expected non-matching");
case ArgType::NoMatchPedantic:
Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
break;
@@ -10824,7 +11121,7 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
unsigned AbsKind, QualType ArgType) {
bool EmitHeaderHint = true;
const char *HeaderName = nullptr;
- const char *FunctionName = nullptr;
+ StringRef FunctionName;
if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
FunctionName = "std::abs";
if (ArgType->isIntegralOrEnumerationType()) {
@@ -10932,7 +11229,7 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
// Unsigned types cannot be negative. Suggest removing the absolute value
// function call.
if (ArgType->isUnsignedIntegerType()) {
- const char *FunctionName =
+ StringRef FunctionName =
IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind);
Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
Diag(Call->getExprLoc(), diag::note_remove_abs)
@@ -11851,7 +12148,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
const FunctionDecl *FD) {
// Check if the return value is null but should not be.
if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
- (!isObjCMethod && isNonNullType(Context, lhsType))) &&
+ (!isObjCMethod && isNonNullType(lhsType))) &&
CheckNonNullExpr(*this, RetValExp))
Diag(ReturnLoc, diag::warn_null_ret)
<< (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
@@ -12301,7 +12598,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
return IntRange(R.Width, /*NonNegative*/ true);
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_ShlAssign:
return IntRange::forValueOfType(C, GetExprType(E));
@@ -12314,7 +12611,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// If the shift amount is a positive constant, drop the width by
// that much.
- if (Optional<llvm::APSInt> shift =
+ if (std::optional<llvm::APSInt> shift =
BO->getRHS()->getIntegerConstantExpr(C)) {
if (shift->isNonNegative()) {
unsigned zext = shift->getZExtValue();
@@ -12359,7 +12656,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
Approximate);
// If the divisor is constant, use that.
- if (Optional<llvm::APSInt> divisor =
+ if (std::optional<llvm::APSInt> divisor =
BO->getRHS()->getIntegerConstantExpr(C)) {
unsigned log2 = divisor->logBase2(); // floor(log_2(divisor))
if (log2 >= L.Width)
@@ -12589,7 +12886,7 @@ struct PromotedRange {
llvm_unreachable("impossible compare result");
}
- static llvm::Optional<StringRef>
+ static std::optional<StringRef>
constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
if (Op == BO_Cmp) {
ComparisonResult LTFlag = LT, GTFlag = GT;
@@ -12598,7 +12895,7 @@ struct PromotedRange {
if (R & EQ) return StringRef("'std::strong_ordering::equal'");
if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
- return llvm::None;
+ return std::nullopt;
}
ComparisonResult TrueFlag, FalseFlag;
@@ -12623,7 +12920,7 @@ struct PromotedRange {
return StringRef("true");
if (R & FalseFlag)
return StringRef("false");
- return llvm::None;
+ return std::nullopt;
}
};
}
@@ -12833,8 +13130,10 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
Expr *RHS = E->getRHS();
if (T->isIntegralType(S.Context)) {
- Optional<llvm::APSInt> RHSValue = RHS->getIntegerConstantExpr(S.Context);
- Optional<llvm::APSInt> LHSValue = LHS->getIntegerConstantExpr(S.Context);
+ std::optional<llvm::APSInt> RHSValue =
+ RHS->getIntegerConstantExpr(S.Context);
+ std::optional<llvm::APSInt> LHSValue =
+ LHS->getIntegerConstantExpr(S.Context);
// We don't care about expressions whose result is a constant.
if (RHSValue && LHSValue)
@@ -12955,9 +13254,6 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
}
}
- if (Bitfield->getType()->isBooleanType())
- return false;
-
// Ignore value- or type-dependent expressions.
if (Bitfield->getBitWidth()->isValueDependent() ||
Bitfield->getBitWidth()->isTypeDependent() ||
@@ -13029,6 +13325,18 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
unsigned OriginalWidth = Value.getBitWidth();
+ // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce
+ // false positives where the user is demonstrating they intend to use the
+ // bit-field as a Boolean, check to see if the value is 1 and we're assigning
+ // to a one-bit bit-field to see if the value came from a macro named 'true'.
+ bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1;
+ if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) {
+ SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc();
+ if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
+ S.findMacroSpelling(MaybeMacroLoc, "true"))
+ return false;
+ }
+
if (!Value.isSigned() || Value.isNegative())
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not)
@@ -13046,17 +13354,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
if (llvm::APSInt::isSameValue(Value, TruncatedValue))
return false;
- // Special-case bitfields of width 1: booleans are naturally 0/1, and
- // therefore don't strictly fit into a signed bitfield of width 1.
- if (FieldWidth == 1 && Value == 1)
- return false;
-
std::string PrettyValue = toString(Value, 10);
std::string PrettyTrunc = toString(TruncatedValue, 10);
- S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant)
- << PrettyValue << PrettyTrunc << OriginalInit->getType()
- << Init->getSourceRange();
+ S.Diag(InitLoc, OneAssignedToOneBitBitfield
+ ? diag::warn_impcast_single_bit_bitield_precision_constant
+ : diag::warn_impcast_bitfield_precision_constant)
+ << PrettyValue << PrettyTrunc << OriginalInit->getType()
+ << Init->getSourceRange();
return true;
}
@@ -13342,9 +13647,10 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
return;
// Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
- const Expr::NullPointerConstantKind NullKind =
- E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull);
- if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr)
+ const Expr *NewE = E->IgnoreParenImpCasts();
+ bool IsGNUNullExpr = isa<GNUNullExpr>(NewE);
+ bool HasNullPtrType = NewE->getType()->isNullPtrType();
+ if (!IsGNUNullExpr && !HasNullPtrType)
return;
// Return if target type is a safe conversion.
@@ -13361,7 +13667,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
CC = S.SourceMgr.getTopMacroCallerLoc(CC);
// __null is usually wrapped in a macro. Go up a macro if that is the case.
- if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) {
+ if (IsGNUNullExpr && Loc.isMacroID()) {
StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
Loc, S.SourceMgr, S.getLangOpts());
if (MacroName == "NULL")
@@ -13373,7 +13679,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
return;
S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC)
+ << HasNullPtrType << T << SourceRange(CC)
<< FixItHint::CreateReplacement(Loc,
S.getFixItZeroLiteralForType(T, Loc));
}
@@ -13836,7 +14142,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (SourcePrecision > 0 && TargetPrecision > 0 &&
SourcePrecision > TargetPrecision) {
- if (Optional<llvm::APSInt> SourceInt =
+ if (std::optional<llvm::APSInt> SourceInt =
E->getIntegerConstantExpr(S.Context)) {
// If the source integer is a constant, convert it to the target
// floating point type. Issue a warning if the value changes
@@ -14559,6 +14865,17 @@ void Sema::CheckForIntOverflow (Expr *E) {
Exprs.append(Call->arg_begin(), Call->arg_end());
else if (auto Message = dyn_cast<ObjCMessageExpr>(E))
Exprs.append(Message->arg_begin(), Message->arg_end());
+ else if (auto Construct = dyn_cast<CXXConstructExpr>(E))
+ Exprs.append(Construct->arg_begin(), Construct->arg_end());
+ else if (auto Array = dyn_cast<ArraySubscriptExpr>(E))
+ Exprs.push_back(Array->getIdx());
+ else if (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);
+ }
} while (!Exprs.empty());
}
@@ -15425,8 +15742,8 @@ void Sema::CheckUnsequencedOperations(const Expr *E) {
void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
bool IsConstexpr) {
- llvm::SaveAndRestore<bool> ConstantContext(
- isConstantEvaluatedOverride, IsConstexpr || isa<ConstantExpr>(E));
+ llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride,
+ IsConstexpr || isa<ConstantExpr>(E));
CheckImplicitConversions(E, CheckLoc);
if (!E->isInstantiationDependent())
CheckUnsequencedOperations(E);
@@ -15551,8 +15868,11 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
return HasInvalidParm;
}
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx);
+std::optional<std::pair<
+ CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+ *E,
+ ASTContext
+ &Ctx);
/// Compute the alignment and offset of the base class object given the
/// derived-to-base cast expression and the alignment and offset of the derived
@@ -15586,21 +15906,21 @@ getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType,
}
/// Compute the alignment and offset of a binary additive operator.
-static Optional<std::pair<CharUnits, CharUnits>>
+static std::optional<std::pair<CharUnits, CharUnits>>
getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
bool IsSub, ASTContext &Ctx) {
QualType PointeeType = PtrE->getType()->getPointeeType();
if (!PointeeType->isConstantSizeType())
- return llvm::None;
+ return std::nullopt;
auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx);
if (!P)
- return llvm::None;
+ return std::nullopt;
CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType);
- if (Optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
+ if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
CharUnits Offset = EltSize * IdxRes->getExtValue();
if (IsSub)
Offset = -Offset;
@@ -15617,8 +15937,10 @@ getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
/// This helper function takes an lvalue expression and returns the alignment of
/// a VarDecl and a constant offset from the VarDecl.
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
+std::optional<std::pair<
+ CharUnits,
+ CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E,
+ ASTContext &Ctx) {
E = E->IgnoreParens();
switch (E->getStmtClass()) {
default:
@@ -15666,7 +15988,7 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
if (!FD || FD->getType()->isReferenceType() ||
FD->getParent()->isInvalidDecl())
break;
- Optional<std::pair<CharUnits, CharUnits>> P;
+ std::optional<std::pair<CharUnits, CharUnits>> P;
if (ME->isArrow())
P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx);
else
@@ -15700,13 +16022,16 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
break;
}
}
- return llvm::None;
+ return std::nullopt;
}
/// This helper function takes a pointer expression and returns the alignment of
/// a VarDecl and a constant offset from the VarDecl.
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) {
+std::optional<std::pair<
+ CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+ *E,
+ ASTContext
+ &Ctx) {
E = E->IgnoreParens();
switch (E->getStmtClass()) {
default:
@@ -15765,12 +16090,12 @@ static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) {
break;
}
}
- return llvm::None;
+ return std::nullopt;
}
static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {
// See if we can compute the alignment of a VarDecl and an offset from it.
- Optional<std::pair<CharUnits, CharUnits>> P =
+ std::optional<std::pair<CharUnits, CharUnits>> P =
getBaseAlignmentAndOffsetFromPtr(E, S.Context);
if (P)
@@ -15824,71 +16149,6 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
<< TRange << Op->getSourceRange();
}
-/// Check whether this array fits the idiom of a size-one tail padded
-/// array member of a struct.
-///
-/// We avoid emitting out-of-bounds access warnings for such arrays as they are
-/// commonly used to emulate flexible arrays in C89 code.
-static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size,
- const NamedDecl *ND,
- unsigned StrictFlexArraysLevel) {
- if (!ND)
- return false;
-
- if (StrictFlexArraysLevel >= 2 && Size != 0)
- return false;
-
- if (StrictFlexArraysLevel == 1 && Size.ule(1))
- return false;
-
- // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing
- // arrays to be treated as flexible-array-members, we still emit diagnostics
- // as if they are not. Pending further discussion...
- if (StrictFlexArraysLevel == 0 && Size != 1)
- return false;
-
- const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
- if (!FD)
- return false;
-
- // Don't consider sizes resulting from macro expansions or template argument
- // substitution to form C89 tail-padded arrays.
-
- TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
- while (TInfo) {
- TypeLoc TL = TInfo->getTypeLoc();
- // Look through typedefs.
- if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
- const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
- TInfo = TDL->getTypeSourceInfo();
- continue;
- }
- if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
- }
- break;
- }
-
- const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
- if (!RD)
- return false;
- if (RD->isUnion())
- return false;
- if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CRD->isStandardLayout())
- return false;
- }
-
- // See if this is the last field decl in the record.
- const Decl *D = FD;
- while ((D = D->getNextDeclInContext()))
- if (isa<FieldDecl>(D))
- return false;
- return true;
-}
-
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE,
bool AllowOnePastEnd, bool IndexNegated) {
@@ -15906,9 +16166,15 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
+ LangOptions::StrictFlexArraysLevelKind
+ StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
+
const Type *BaseType =
ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
- bool IsUnboundedArray = (BaseType == nullptr);
+ bool IsUnboundedArray =
+ BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike(
+ Context, StrictFlexArraysLevel,
+ /*IgnoreTemplateOrMacroSubstitution=*/true);
if (EffectiveType->isDependentType() ||
(!IsUnboundedArray && BaseType->isDependentType()))
return;
@@ -15923,23 +16189,16 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
index = -index;
}
- const NamedDecl *ND = nullptr;
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
-
if (IsUnboundedArray) {
if (EffectiveType->isFunctionType())
return;
if (index.isUnsigned() || !index.isNegative()) {
const auto &ASTC = getASTContext();
- unsigned AddrBits =
- ASTC.getTargetInfo().getPointerWidth(ASTC.getTargetAddressSpace(
- EffectiveType->getCanonicalTypeInternal()));
+ unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth(
+ EffectiveType->getCanonicalTypeInternal().getAddressSpace());
if (index.getBitWidth() < AddrBits)
index = index.zext(AddrBits);
- Optional<CharUnits> ElemCharUnits =
+ std::optional<CharUnits> ElemCharUnits =
ASTC.getTypeSizeInCharsIfKnown(EffectiveType);
// PR50741 - If EffectiveType has unknown size (e.g., if it's a void
// pointer) bounds-checking isn't meaningful.
@@ -15982,15 +16241,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< (unsigned)MaxElems.getLimitedValue(~0U)
<< IndexExpr->getSourceRange());
- if (!ND) {
- // Try harder to find a NamedDecl to point at in the note.
- while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
- BaseExpr = ASE->getBase()->IgnoreParenCasts();
- if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
- }
+ const NamedDecl *ND = nullptr;
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = ME->getMemberDecl();
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
@@ -16006,29 +16264,28 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
// example). In this case we have no information about whether the array
// access exceeds the array bounds. However we can still diagnose an array
// access which precedes the array bounds.
- //
- // FIXME: this check should be redundant with the IsUnboundedArray check
- // above.
if (BaseType->isIncompleteType())
return;
- // FIXME: this check should belong to the IsTailPaddedMemberArray call
- // below.
llvm::APInt size = ArrayTy->getSize();
- if (!size.isStrictlyPositive())
- return;
if (BaseType != EffectiveType) {
- // Make sure we're comparing apples to apples when comparing index to size
+ // Make sure we're comparing apples to apples when comparing index to
+ // size.
uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
uint64_t array_typesize = Context.getTypeSize(BaseType);
- // Handle ptrarith_typesize being zero, such as when casting to void*
- if (!ptrarith_typesize) ptrarith_typesize = 1;
+
+ // Handle ptrarith_typesize being zero, such as when casting to void*.
+ // Use the size in bits (what "getTypeSize()" returns) rather than bytes.
+ if (!ptrarith_typesize)
+ ptrarith_typesize = Context.getCharWidth();
+
if (ptrarith_typesize != array_typesize) {
- // There's a cast to a different size type involved
+ // There's a cast to a different size type involved.
uint64_t ratio = array_typesize / ptrarith_typesize;
+
// TODO: Be smarter about handling cases where array_typesize is not a
- // multiple of ptrarith_typesize
+ // multiple of ptrarith_typesize.
if (ptrarith_typesize * ratio == array_typesize)
size *= llvm::APInt(size.getBitWidth(), ratio);
}
@@ -16046,11 +16303,6 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
return;
- // Also don't warn for Flexible Array Member emulation.
- const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays;
- if (IsTailPaddedMemberArray(*this, size, ND, StrictFlexArraysLevel))
- return;
-
// Suppress the warning if the subscript expression (as identified by the
// ']' location) and the index expression are both from macro expansions
// within a system header.
@@ -16067,12 +16319,13 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds
: diag::warn_ptr_arith_exceeds_bounds;
+ unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1;
+ QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType();
- DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
- PDiag(DiagID) << toString(index, 10, true)
- << toString(size, 10, true)
- << (unsigned)size.getLimitedValue(~0U)
- << IndexExpr->getSourceRange());
+ DiagRuntimeBehavior(
+ BaseExpr->getBeginLoc(), BaseExpr,
+ PDiag(DiagID) << toString(index, 10, true) << ArrayTy->desugar()
+ << CastMsg << CastMsgTy << IndexExpr->getSourceRange());
} else {
unsigned DiagID = diag::warn_array_index_precedes_bounds;
if (!ASE) {
@@ -16085,15 +16338,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< IndexExpr->getSourceRange());
}
- if (!ND) {
- // Try harder to find a NamedDecl to point at in the note.
- while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
- BaseExpr = ASE->getBase()->IgnoreParenCasts();
- if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
- }
+ const NamedDecl *ND = nullptr;
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = ME->getMemberDecl();
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
@@ -16318,7 +16570,7 @@ namespace {
return;
if (Expr *RHS = BinOp->getRHS()) {
RHS = RHS->IgnoreParenCasts();
- Optional<llvm::APSInt> Value;
+ std::optional<llvm::APSInt> Value;
VarWillBeReased =
(RHS && (Value = RHS->getIntegerConstantExpr(Context)) &&
*Value == 0);
@@ -16399,21 +16651,21 @@ static bool isSetterLikeSelector(Selector sel) {
return !isLowercase(str.front());
}
-static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
- ObjCMessageExpr *Message) {
+static std::optional<int>
+GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableArray);
if (!IsMutableArray) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSArrayMethodKind> MKOpt =
- S.NSAPIObj->getNSArrayMethodKind(Sel);
+ std::optional<NSAPI::NSArrayMethodKind> MKOpt =
+ S.NSAPIObj->getNSArrayMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSArrayMethodKind MK = *MKOpt;
@@ -16427,28 +16679,27 @@ static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
return 1;
default:
- return None;
+ return std::nullopt;
}
- return None;
+ return std::nullopt;
}
-static
-Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
- ObjCMessageExpr *Message) {
+static std::optional<int>
+GetNSMutableDictionaryArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableDictionary);
if (!IsMutableDictionary) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSDictionaryMethodKind> MKOpt =
- S.NSAPIObj->getNSDictionaryMethodKind(Sel);
+ std::optional<NSAPI::NSDictionaryMethodKind> MKOpt =
+ S.NSAPIObj->getNSDictionaryMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSDictionaryMethodKind MK = *MKOpt;
@@ -16460,13 +16711,14 @@ Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
return 0;
default:
- return None;
+ return std::nullopt;
}
- return None;
+ return std::nullopt;
}
-static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
+static std::optional<int> GetNSSetArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableSet);
@@ -16475,14 +16727,15 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableOrderedSet);
if (!IsMutableSet && !IsMutableOrderedSet) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel);
+ std::optional<NSAPI::NSSetMethodKind> MKOpt =
+ S.NSAPIObj->getNSSetMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSSetMethodKind MK = *MKOpt;
@@ -16497,7 +16750,7 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
return 1;
}
- return None;
+ return std::nullopt;
}
void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
@@ -16505,7 +16758,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
return;
}
- Optional<int> ArgOpt;
+ std::optional<int> ArgOpt;
if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) &&
!(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) &&
@@ -17386,15 +17639,15 @@ void Sema::DiagnoseMisalignedMembers() {
void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
E = E->IgnoreParens();
- if (!T->isPointerType() && !T->isIntegerType())
+ if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType())
return;
if (isa<UnaryOperator>(E) &&
cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
if (isa<MemberExpr>(Op)) {
- auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
+ auto *MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
if (MA != MisalignedMembers.end() &&
- (T->isIntegerType() ||
+ (T->isDependentType() || T->isIntegerType() ||
(T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
Context.getTypeAlignInChars(
T->getPointeeType()) <= MA->Alignment))))
@@ -17520,19 +17773,6 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
_2, _3, _4));
}
-// Check if \p Ty is a valid type for the elementwise math builtins. If it is
-// not a valid type, emit an error message and return true. Otherwise return
-// false.
-static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
- QualType Ty) {
- if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
- S.Diag(Loc, diag::err_builtin_invalid_arg_type)
- << 1 << /* vector, integer or float ty*/ 0 << Ty;
- return true;
- }
- return false;
-}
-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 1))
return true;
@@ -17624,10 +17864,10 @@ ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall,
}
// Get and verify the matrix dimensions.
-static llvm::Optional<unsigned>
+static std::optional<unsigned>
getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) {
SourceLocation ErrorPos;
- Optional<llvm::APSInt> Value =
+ std::optional<llvm::APSInt> Value =
Expr->getIntegerConstantExpr(S.Context, &ErrorPos);
if (!Value) {
S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg)
@@ -17715,7 +17955,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
} else
ColumnsExpr = nullptr;
- // If any any part of the result matrix type is still pending, just use
+ // If any part of the result matrix type is still pending, just use
// Context.DependentTy, until all parts are resolved.
if ((RowsExpr && RowsExpr->isTypeDependent()) ||
(ColumnsExpr && ColumnsExpr->isTypeDependent())) {
@@ -17724,11 +17964,11 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
}
// Check row and column dimensions.
- llvm::Optional<unsigned> MaybeRows;
+ std::optional<unsigned> MaybeRows;
if (RowsExpr)
MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this);
- llvm::Optional<unsigned> MaybeColumns;
+ std::optional<unsigned> MaybeColumns;
if (ColumnsExpr)
MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this);
@@ -17740,7 +17980,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
TheCall->setArg(3, StrideExpr);
if (MaybeRows) {
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
StrideExpr->getIntegerConstantExpr(Context)) {
uint64_t Stride = Value->getZExtValue();
if (Stride < *MaybeRows) {
@@ -17840,7 +18080,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
// Check stride argument.
if (MatrixTy) {
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
StrideExpr->getIntegerConstantExpr(Context)) {
uint64_t Stride = Value->getZExtValue();
if (Stride < MatrixTy->getNumRows()) {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8ede7c015315..144bbe150abb 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -56,6 +56,7 @@
#include <list>
#include <map>
+#include <optional>
#include <string>
#include <vector>
@@ -1098,7 +1099,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
MaybeAddResult(Result, CurContext);
return;
@@ -1212,7 +1214,7 @@ static void setInBaseClass(ResultBuilder::Result &R) {
enum class OverloadCompare { BothViable, Dominates, Dominated };
// Will Candidate ever be called on the object, when overloaded with Incumbent?
// Returns Dominates if Candidate is always called, Dominated if Incumbent is
-// always called, BothViable if either may be called dependending on arguments.
+// always called, BothViable if either may be called depending on arguments.
// Precondition: must actually be overloads!
static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
@@ -1230,8 +1232,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
if (Candidate.parameters()[I]->getType().getCanonicalType() !=
Incumbent.parameters()[I]->getType().getCanonicalType())
return OverloadCompare::BothViable;
- if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) ||
- !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>()))
+ if (!Candidate.specific_attrs<EnableIfAttr>().empty() ||
+ !Incumbent.specific_attrs<EnableIfAttr>().empty())
return OverloadCompare::BothViable;
// At this point, we know calls can't pick one or the other based on
// arguments, so one of the two must win. (Or both fail, handled elsewhere).
@@ -1273,7 +1275,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
AddResult(Result, CurContext, Hiding);
return;
@@ -1377,6 +1380,33 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
OverloadSet.Add(Method, Results.size());
}
+ // When completing a non-static member function (and not via
+ // dot/arrow member access) and we're not inside that class' scope,
+ // it can't be a call.
+ if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
+ const auto *Method = dyn_cast<CXXMethodDecl>(R.getDeclaration());
+ if (Method && !Method->isStatic()) {
+ // Find the class scope that we're currently in.
+ // We could e.g. be inside a lambda, so walk up the DeclContext until we
+ // find a CXXMethodDecl.
+ const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * {
+ for (DeclContext *Ctx = SemaRef.CurContext; Ctx;
+ Ctx = Ctx->getParent()) {
+ const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx);
+ if (CtxMethod && !CtxMethod->getParent()->isLambda()) {
+ return CtxMethod->getParent();
+ }
+ }
+ return nullptr;
+ }();
+
+ R.FunctionCanBeCall =
+ CurrentClassScope &&
+ (CurrentClassScope == Method->getParent() ||
+ CurrentClassScope->isDerivedFrom(Method->getParent()));
+ }
+ }
+
// Insert this result into the set of results.
Results.push_back(R);
@@ -1807,7 +1837,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC,
Results.AddResult(Result("mutable"));
Results.AddResult(Result("virtual"));
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ObjCInterface:
case Sema::PCC_ObjCImplementation:
@@ -2095,7 +2125,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddObjCTopLevelResults(Results, true);
AddTypedefResult(Results);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Class:
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2153,7 +2183,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder);
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Template:
case Sema::PCC_MemberTemplate:
@@ -2423,14 +2453,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ParenthesizedExpression:
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
@@ -2460,7 +2490,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Expression: {
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2643,6 +2673,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
+ if (SemaRef.getLangOpts().C2x) {
+ // nullptr
+ Builder.AddResultTypeChunk("nullptr_t");
+ Builder.AddTypedTextChunk("nullptr");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+
// sizeof expression
Builder.AddResultTypeChunk("size_t");
Builder.AddTypedTextChunk("sizeof");
@@ -2783,7 +2820,7 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
while (true) {
// Look through typedefs.
if (!SuppressBlock) {
- if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) {
+ if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
if (TypeSourceInfo *InnerTSInfo =
TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
@@ -2814,18 +2851,16 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
}
}
-static std::string
-formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
- FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
- bool SuppressBlockName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None);
+static std::string formatBlockPlaceholder(
+ const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
+ FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
+ bool SuppressBlockName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt);
-static std::string
-FormatFunctionParameter(const PrintingPolicy &Policy,
- const DeclaratorDecl *Param, bool SuppressName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None) {
+static std::string FormatFunctionParameter(
+ const PrintingPolicy &Policy, const DeclaratorDecl *Param,
+ bool SuppressName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) {
// Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
// It would be better to pass in the param Type, which is usually available.
// But this case is rare, so just pretend we fell back to int as elsewhere.
@@ -2920,7 +2955,7 @@ static std::string
formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
bool SuppressBlockName, bool SuppressBlock,
- Optional<ArrayRef<QualType>> ObjCSubsts) {
+ std::optional<ArrayRef<QualType>> ObjCSubsts) {
std::string Result;
QualType ResultType = Block.getTypePtr()->getReturnType();
if (ObjCSubsts)
@@ -3589,7 +3624,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
std::string Arg;
QualType ParamType = (*P)->getType();
- Optional<ArrayRef<QualType>> ObjCSubsts;
+ std::optional<ArrayRef<QualType>> ObjCSubsts;
if (!CCContext.getBaseType().isNull())
ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method);
@@ -4199,7 +4234,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
// We need to have names for all of the parameters, if we're going to
// generate a forwarding call.
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
if (!P->getDeclName())
return;
@@ -4227,7 +4262,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Results.getAllocator().CopyString(Overridden->getNameAsString()));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
bool FirstParam = true;
- for (auto P : Method->parameters()) {
+ for (auto *P : Method->parameters()) {
if (FirstParam)
FirstParam = false;
else
@@ -4444,7 +4479,8 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
0) {
ParsedType T = DS.getRepAsType();
if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType())
- AddClassMessageCompletions(*this, S, T, None, false, false, Results);
+ AddClassMessageCompletions(*this, S, T, std::nullopt, false, false,
+ Results);
}
// Note that we intentionally suppress macro results here, since we do not
@@ -4657,9 +4693,9 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
// Note we only handle the sugared types, they closely match what users wrote.
// We explicitly choose to not handle ClassTemplateSpecializationDecl.
if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
- if (Specialization->getNumArgs() != 1)
+ if (Specialization->template_arguments().size() != 1)
return nullptr;
- const TemplateArgument &Argument = Specialization->getArg(0);
+ const TemplateArgument &Argument = Specialization->template_arguments()[0];
if (Argument.getKind() != TemplateArgument::Type)
return nullptr;
return Argument.getAsType()->getAs<FunctionProtoType>();
@@ -4801,7 +4837,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E,
if (E.isInvalid())
CodeCompleteExpression(S, PreferredType);
else if (getLangOpts().ObjC)
- CodeCompleteObjCInstanceMessage(S, E.get(), None, false);
+ CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false);
}
/// The set of properties that have already been added, referenced by
@@ -5045,9 +5081,11 @@ AddObjCProperties(const CodeCompletionContext &CCContext,
}
}
-static void AddRecordMembersCompletionResults(
- Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType,
- ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) {
+static void
+AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
+ Scope *S, QualType BaseType,
+ ExprValueKind BaseKind, RecordDecl *RD,
+ std::optional<FixItHint> AccessOpFixIt) {
// Indicate that we are performing a member access, and the cv-qualifiers
// for the base object type.
Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind);
@@ -5086,7 +5124,8 @@ static void AddRecordMembersCompletionResults(
// Returns the RecordDecl inside the BaseType, falling back to primary template
// in case of specializations. Since we might not have a decl for the
// instantiation/specialization yet, e.g. dependent code.
-static RecordDecl *getAsRecordDecl(const QualType BaseType) {
+static RecordDecl *getAsRecordDecl(QualType BaseType) {
+ BaseType = BaseType.getNonReferenceType();
if (auto *RD = BaseType->getAsRecordDecl()) {
if (const auto *CTSD =
llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
@@ -5145,7 +5184,7 @@ public:
// We don't have the declared parameter types, only the actual types of
// arguments we've seen. These are still valuable, as it's hard to render
// a useful function completion with neither parameter types nor names!
- llvm::Optional<SmallVector<QualType, 1>> ArgTypes;
+ std::optional<SmallVector<QualType, 1>> ArgTypes;
// Whether this is accessed as T.member, T->member, or T::member.
enum AccessOperator {
Colons,
@@ -5475,11 +5514,16 @@ private:
// We accept some lossiness (like dropping parameters).
// We only try to handle common expressions on the LHS of MemberExpr.
QualType getApproximateType(const Expr *E) {
+ if (E->getType().isNull())
+ return QualType();
+ E = E->IgnoreParenImpCasts();
QualType Unresolved = E->getType();
- if (Unresolved.isNull() ||
- !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent))
- return Unresolved;
- E = E->IgnoreParens();
+ // We only resolve DependentTy, or undeduced autos (including auto* etc).
+ if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
+ AutoType *Auto = Unresolved->getContainedAutoType();
+ if (!Auto || !Auto->isUndeducedAutoType())
+ return Unresolved;
+ }
// A call: approximate-resolve callee to a function type, get its return type
if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
QualType Callee = getApproximateType(CE->getCallee());
@@ -5542,6 +5586,13 @@ QualType getApproximateType(const Expr *E) {
}
}
}
+ // A reference to an `auto` variable: approximate-resolve its initializer.
+ if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (VD->hasInit())
+ return getApproximateType(VD->getInit());
+ }
+ }
return Unresolved;
}
@@ -5600,7 +5651,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
&ResultBuilder::IsMember);
auto DoCompletion = [&](Expr *Base, bool IsArrow,
- Optional<FixItHint> AccessOpFixIt) -> bool {
+ std::optional<FixItHint> AccessOpFixIt) -> bool {
if (!Base)
return false;
@@ -5698,7 +5749,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Results.EnterNewScope();
- bool CompletionSucceded = DoCompletion(Base, IsArrow, None);
+ bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt);
if (CodeCompleter->includeFixIts()) {
const CharSourceRange OpRange =
CharSourceRange::getTokenRange(OpLoc, OpLoc);
@@ -6157,8 +6208,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
// Only aggregate initialization is possible, but we can't assist with it.
// Returns an out-of-range index.
// - we saw no designators, just positional arguments.
-// Returns None.
-static llvm::Optional<unsigned>
+// Returns std::nullopt.
+static std::optional<unsigned>
getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
ArrayRef<Expr *> Args) {
static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max();
@@ -6183,7 +6234,7 @@ getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
}
}
if (!DesignatedFieldName)
- return llvm::None;
+ return std::nullopt;
// Find the index within the class's fields.
// (Probing getParamDecl() directly would be quadratic in number of fields).
@@ -7537,7 +7588,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
@@ -7563,7 +7615,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
@@ -7859,7 +7912,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
if (Iface->getSuperClass()) {
Results.AddResult(Result("super"));
- AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results);
+ AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, std::nullopt,
+ Results);
}
if (getLangOpts().CPlusPlus11)
@@ -8505,7 +8559,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCCategoryName);
- // Add all of the categories that have have corresponding interface
+ // Add all of the categories that have corresponding interface
// declarations in this class and any of its superclasses, except for
// already-implemented categories in the class itself.
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
@@ -8669,7 +8723,7 @@ typedef llvm::DenseMap<Selector,
/// indexed by selector so they can be easily found.
static void FindImplementableMethods(ASTContext &Context,
ObjCContainerDecl *Container,
- Optional<bool> WantInstanceMethods,
+ std::optional<bool> WantInstanceMethods,
QualType ReturnType,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
@@ -9393,7 +9447,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
}
}
-void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
+void Sema::CodeCompleteObjCMethodDecl(Scope *S,
+ std::optional<bool> IsInstanceMethod,
ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
@@ -9978,10 +10033,10 @@ 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).
- // Header extensions from Types.def, which we can't depend on here.
const bool IsHeader = Filename.endswith_insensitive(".h") ||
Filename.endswith_insensitive(".hh") ||
Filename.endswith_insensitive(".hpp") ||
+ Filename.endswith_insensitive(".hxx") ||
Filename.endswith_insensitive(".inc") ||
(ExtensionlessHeaders && !Filename.contains('.'));
if (!IsHeader)
@@ -10048,7 +10103,7 @@ void Sema::CodeCompleteAvailabilityPlatformName() {
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};
- for (const char *Platform : llvm::makeArrayRef(Platforms)) {
+ for (const char *Platform : llvm::ArrayRef(Platforms)) {
Results.AddResult(CodeCompletionResult(Platform));
Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(
Twine(Platform) + "ApplicationExtension")));
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 239e5dc4394c..4d4b2482d046 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TreeTransform.h"
#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
@@ -18,18 +19,21 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Initialization.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
namespace {
class LogicalBinOp {
+ SourceLocation Loc;
OverloadedOperatorKind Op = OO_None;
const Expr *LHS = nullptr;
const Expr *RHS = nullptr;
@@ -40,12 +44,14 @@ public:
Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
LHS = BO->getLHS();
RHS = BO->getRHS();
+ Loc = BO->getExprLoc();
} else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
// If OO is not || or && it might not have exactly 2 arguments.
if (OO->getNumArgs() == 2) {
Op = OO->getOperator();
LHS = OO->getArg(0);
RHS = OO->getArg(1);
+ Loc = OO->getOperatorLoc();
}
}
}
@@ -56,6 +62,26 @@ public:
const Expr *getLHS() const { return LHS; }
const Expr *getRHS() const { return RHS; }
+
+ ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
+ return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
+ }
+
+ ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
+ ExprResult RHS) const {
+ assert((isAnd() || isOr()) && "Not the right kind of op?");
+ assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
+
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprEmpty();
+
+ // We should just be able to 'normalize' these to the builtin Binary
+ // Operator, since that is how they are evaluated in constriant checks.
+ return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
+ BinaryOperator::getOverloadedOpcode(Op),
+ SemaRef.Context.BoolTy, VK_PRValue,
+ OK_Ordinary, Loc, FPOptionsOverride{});
+ }
};
}
@@ -121,17 +147,30 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
return true;
}
+namespace {
+struct SatisfactionStackRAII {
+ Sema &SemaRef;
+ SatisfactionStackRAII(Sema &SemaRef, llvm::FoldingSetNodeID FSNID)
+ : SemaRef(SemaRef) {
+ SemaRef.PushSatisfactionStackEntry(FSNID);
+ }
+ ~SatisfactionStackRAII() { SemaRef.PopSatisfactionStackEntry(); }
+};
+} // namespace
+
template <typename AtomicEvaluator>
-static bool
+static ExprResult
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction,
AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (LogicalBinOp BO = ConstraintExpr) {
- if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
- Evaluator))
- return true;
+ ExprResult LHSRes = calculateConstraintSatisfaction(
+ S, BO.getLHS(), Satisfaction, Evaluator);
+
+ if (LHSRes.isInvalid())
+ return ExprError();
bool IsLHSSatisfied = Satisfaction.IsSatisfied;
@@ -142,7 +181,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is satisfied, the disjunction is satisfied.
// Otherwise, the disjunction is satisfied if and only if the second
// operand is satisfied.
- return false;
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
if (BO.isAnd() && !IsLHSSatisfied)
// [temp.constr.op] p2
@@ -151,12 +191,22 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is not satisfied, the conjunction is not
// satisfied. Otherwise, the conjunction is satisfied if and only if
// the second operand is satisfied.
- return false;
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
- return calculateConstraintSatisfaction(
+ ExprResult RHSRes = calculateConstraintSatisfaction(
S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
- } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
- return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+ if (RHSRes.isInvalid())
+ return ExprError();
+
+ return BO.recreateBinOp(S, LHSRes, RHSRes);
+ }
+
+ if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
+ // These aren't evaluated, so we don't care about cleanups, so we can just
+ // evaluate these as if the cleanups didn't exist.
+ return calculateConstraintSatisfaction(
+ S, C->getSubExpr(), Satisfaction,
std::forward<AtomicEvaluator>(Evaluator));
}
@@ -164,11 +214,35 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
if (SubstitutedAtomicExpr.isInvalid())
- return true;
+ return ExprError();
if (!SubstitutedAtomicExpr.isUsable())
// Evaluator has decided satisfaction without yielding an expression.
- return false;
+ return ExprEmpty();
+
+ // We don't have the ability to evaluate this, since it contains a
+ // RecoveryExpr, so we want to fail overload resolution. Otherwise,
+ // we'd potentially pick up a different overload, and cause confusing
+ // diagnostics. SO, add a failure detail that will cause us to make this
+ // overload set not viable.
+ if (SubstitutedAtomicExpr.get()->containsErrors()) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+
+ PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ Msg.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
+ Satisfaction.Details.emplace_back(
+ ConstraintExpr,
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstitutedAtomicExpr.get()->getBeginLoc(),
+ StringRef(Mem, MessageSize)});
+ return SubstitutedAtomicExpr;
+ }
EnterExpressionEvaluationContext ConstantEvaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -185,7 +259,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
<< SubstitutedAtomicExpr.get()->getSourceRange();
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
S.Diag(PDiag.first, PDiag.second);
- return true;
+ return ExprError();
}
assert(EvalResult.Val.isInt() &&
@@ -195,17 +269,41 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
Satisfaction.Details.emplace_back(ConstraintExpr,
SubstitutedAtomicExpr.get());
+ return SubstitutedAtomicExpr;
+}
+
+static bool
+DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const Expr *E,
+ const MultiLevelTemplateArgumentList &MLTAL) {
+ E->Profile(ID, S.Context, /*Canonical=*/true);
+ for (const auto &List : MLTAL)
+ for (const auto &TemplateArg : List.Args)
+ TemplateArg.Profile(ID, S.Context);
+
+ // Note that we have to do this with our own collection, because there are
+ // times where a constraint-expression check can cause us to need to evaluate
+ // other constriants that are unrelated, such as when evaluating a recovery
+ // 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)) {
+ S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
+ << const_cast<Expr *>(E) << E->getSourceRange();
+ return true;
+ }
+
return false;
}
-static bool calculateConstraintSatisfaction(
- Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
- SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
- const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
+ const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ Sema::ReuseLambdaContextDecl);
// Atomic constraint - substitute arguments and check satisfaction.
ExprResult SubstitutedExpression;
@@ -217,17 +315,21 @@ static bool calculateConstraintSatisfaction(
AtomicExpr->getSourceRange());
if (Inst.isInvalid())
return ExprError();
+
+ llvm::FoldingSetNodeID ID;
+ if (DiagRecursiveConstraintEval(S, ID, AtomicExpr, MLTAL)) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+ return ExprEmpty();
+ }
+
+ SatisfactionStackRAII StackRAII(S, ID);
+
// We do not want error diagnostics escaping here.
Sema::SFINAETrap Trap(S);
- SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
- MLTAL);
- // Substitution might have stripped off a contextual conversion to
- // bool if this is the operand of an '&&' or '||'. For example, we
- // might lose an lvalue-to-rvalue conversion here. If so, put it back
- // before we try to evaluate.
- if (!SubstitutedExpression.isInvalid())
- SubstitutedExpression =
- S.PerformContextuallyConvertToBool(SubstitutedExpression.get());
+ SubstitutedExpression =
+ S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
+
if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
// C++2a [temp.constr.atomic]p1
// ...If substitution results in an invalid type or expression, the
@@ -264,78 +366,129 @@ static bool calculateConstraintSatisfaction(
if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
return ExprError();
+ // [temp.constr.atomic]p3: To determine if an atomic constraint is
+ // satisfied, the parameter mapping and template arguments are first
+ // substituted into its expression. If substitution results in an
+ // invalid type or expression, the constraint is not satisfied.
+ // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
+ // and E shall be a constant expression of type bool.
+ //
+ // Perform the L to R Value conversion if necessary. We do so for all
+ // non-PRValue categories, else we fail to extend the lifetime of
+ // temporaries, and that fails the constant expression check.
+ if (!SubstitutedExpression.get()->isPRValue())
+ SubstitutedExpression = ImplicitCastExpr::Create(
+ S.Context, SubstitutedExpression.get()->getType(),
+ CK_LValueToRValue, SubstitutedExpression.get(),
+ /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
+
return SubstitutedExpression;
});
}
-static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
+static bool CheckConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ llvm::SmallVectorImpl<Expr *> &Converted,
+ const MultiLevelTemplateArgumentList &TemplateArgsLists,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
if (ConstraintExprs.empty()) {
Satisfaction.IsSatisfied = true;
return false;
}
- for (auto& Arg : TemplateArgs)
- if (Arg.isInstantiationDependent()) {
- // No need to check satisfaction for dependent constraint expressions.
- Satisfaction.IsSatisfied = true;
- return false;
- }
+ if (TemplateArgsLists.isAnyArgInstantiationDependent()) {
+ // No need to check satisfaction for dependent constraint expressions.
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+ ArrayRef<TemplateArgument> TemplateArgs =
+ TemplateArgsLists.getNumSubstitutedLevels() > 0
+ ? TemplateArgsLists.getOutermost()
+ : ArrayRef<TemplateArgument> {};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
if (Inst.isInvalid())
return true;
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(TemplateArgs);
-
for (const Expr *ConstraintExpr : ConstraintExprs) {
- if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
- TemplateIDRange.getBegin(), MLTAL,
- ConstraintExpr, Satisfaction))
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
+ ConstraintExpr, Satisfaction);
+ if (Res.isInvalid())
return true;
- if (!Satisfaction.IsSatisfied)
+
+ Converted.push_back(Res.get());
+ if (!Satisfaction.IsSatisfied) {
+ // Backfill the 'converted' list with nulls so we can keep the Converted
+ // and unconverted lists in sync.
+ Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
// [temp.constr.op] p2
- // [...] To determine if a conjunction is satisfied, the satisfaction
- // of the first operand is checked. If that is not satisfied, the
- // conjunction is not satisfied. [...]
+ // [...] To determine if a conjunction is satisfied, the satisfaction
+ // of the first operand is checked. If that is not satisfied, the
+ // conjunction is not satisfied. [...]
return false;
+ }
}
return false;
}
bool Sema::CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
- ConstraintSatisfaction &OutSatisfaction) {
+ llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
+ const MultiLevelTemplateArgumentList &TemplateArgsLists,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
if (ConstraintExprs.empty()) {
OutSatisfaction.IsSatisfied = true;
return false;
}
if (!Template) {
- return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- OutSatisfaction);
+ return ::CheckConstraintSatisfaction(
+ *this, nullptr, ConstraintExprs, ConvertedConstraints,
+ TemplateArgsLists, TemplateIDRange, OutSatisfaction);
}
+
+ // A list of the template argument list flattened in a predictible manner for
+ // the purposes of caching. The ConstraintSatisfaction type is in AST so it
+ // has no access to the MultiLevelTemplateArgumentList, so this has to happen
+ // here.
+ llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
+ for (auto List : TemplateArgsLists)
+ FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(),
+ List.Args.end());
+
llvm::FoldingSetNodeID ID;
- ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
+ ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
void *InsertPos;
if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
OutSatisfaction = *Cached;
return false;
}
+
auto Satisfaction =
- std::make_unique<ConstraintSatisfaction>(Template, TemplateArgs);
+ std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- *Satisfaction)) {
+ ConvertedConstraints, TemplateArgsLists,
+ TemplateIDRange, *Satisfaction)) {
+ OutSatisfaction = *Satisfaction;
return true;
}
+
+ if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
+ // The evaluation of this constraint resulted in us trying to re-evaluate it
+ // recursively. This isn't really possible, except we try to form a
+ // RecoveryExpr as a part of the evaluation. If this is the case, just
+ // return the 'cached' version (which will have the same result), and save
+ // ourselves the extra-insert. If it ever becomes possible to legitimately
+ // recursively check a constraint, we should skip checking the 'inner' one
+ // above, and replace the cached version with this one, as it would be more
+ // specific.
+ OutSatisfaction = *Cached;
+ return false;
+ }
+
+ // Else we can simply add this satisfaction to the list.
OutSatisfaction = *Satisfaction;
// We cannot use InsertPos here because CheckConstraintSatisfaction might have
// invalidated it.
@@ -347,21 +500,133 @@ bool Sema::CheckConstraintSatisfaction(
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
- *this, ConstraintExpr, Satisfaction,
- [this](const Expr *AtomicExpr) -> ExprResult {
- // We only do this to immitate lvalue-to-rvalue conversion.
- return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
- });
+ *this, ConstraintExpr, Satisfaction,
+ [this](const Expr *AtomicExpr) -> ExprResult {
+ // We only do this to immitate lvalue-to-rvalue conversion.
+ return PerformContextuallyConvertToBool(
+ const_cast<Expr *>(AtomicExpr));
+ })
+ .isInvalid();
+}
+
+bool Sema::SetupConstraintScope(
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
+ if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
+ FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
+ InstantiatingTemplate Inst(
+ *this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
+ if (Inst.isInvalid())
+ return true;
+
+ // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
+ // 'instantiated' parameters and adds it to the context. For the case where
+ // this function is a template being instantiated NOW, we also need to add
+ // the list of current template arguments to the list so that they also can
+ // be picked out of the map.
+ if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
+ MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(),
+ /*Final=*/false);
+ if (addInstantiatedParametersToScope(
+ FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
+ return true;
+ }
+
+ // If this is a member function, make sure we get the parameters that
+ // reference the original primary template.
+ if (const auto *FromMemTempl =
+ PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
+ if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
+ Scope, MLTAL))
+ return true;
+ }
+
+ return false;
+ }
+
+ if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
+ FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
+ FunctionDecl *InstantiatedFrom =
+ FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
+ ? FD->getInstantiatedFromMemberFunction()
+ : FD->getInstantiatedFromDecl();
+
+ InstantiatingTemplate Inst(
+ *this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
+ if (Inst.isInvalid())
+ return true;
+
+ // Case where this was not a template, but instantiated as a
+ // child-function.
+ if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
+ return true;
+ }
+
+ return false;
+}
+
+// This function collects all of the template arguments for the purposes of
+// constraint-instantiation and checking.
+std::optional<MultiLevelTemplateArgumentList>
+Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ LocalInstantiationScope &Scope) {
+ MultiLevelTemplateArgumentList MLTAL;
+
+ // Collect the list of template arguments relative to the 'primary' template.
+ // We need the entire list, since the constraint is completely uninstantiated
+ // at this point.
+ MLTAL =
+ getTemplateInstantiationArgs(FD, /*Final=*/false, /*Innermost=*/nullptr,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+ if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
+ return std::nullopt;
+
+ return MLTAL;
}
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
- SourceLocation UsageLoc) {
- const Expr *RC = FD->getTrailingRequiresClause();
- if (RC->isInstantiationDependent()) {
+ SourceLocation UsageLoc,
+ bool ForOverloadResolution) {
+ // Don't check constraints if the function is dependent. Also don't check if
+ // this is a function template specialization, as the call to
+ // CheckinstantiatedFunctionTemplateConstraints after this will check it
+ // better.
+ if (FD->isDependentContext() ||
+ FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
Satisfaction.IsSatisfied = true;
return false;
}
+
+ DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);
+
+ while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) {
+ if (isLambdaCallOperator(CtxToSave))
+ CtxToSave = CtxToSave->getParent()->getParent();
+ else
+ CtxToSave = CtxToSave->getNonTransparentContext();
+ }
+
+ ContextRAII SavedContext{*this, CtxToSave};
+ LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
+ isLambdaCallOperator(FD));
+ std::optional<MultiLevelTemplateArgumentList> MLTAL =
+ SetupConstraintCheckingTemplateArgumentsAndScope(
+ const_cast<FunctionDecl *>(FD), {}, Scope);
+
+ if (!MLTAL)
+ return true;
+
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -372,19 +637,124 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// We substitute with empty arguments in order to rebuild the atomic
// constraint in a constant-evaluated context.
// FIXME: Should this be a dedicated TreeTransform?
- return CheckConstraintSatisfaction(
- FD, {RC}, /*TemplateArgs=*/{},
- SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
- Satisfaction);
+ 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;
+}
+
+
+// Figure out the to-translation-unit depth for this function declaration for
+// the purpose of seeing if they differ by constraints. This isn't the same as
+// getTemplateDepth, because it includes already instantiated parents.
+static unsigned
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
+ bool SkipForSpecialization = false) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+ return MLTAL.getNumSubstitutedLevels();
+}
+
+namespace {
+ class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
+ unsigned TemplateDepth = 0;
+ public:
+ using inherited = TreeTransform<AdjustConstraintDepth>;
+ AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
+ : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ const TemplateTypeParmType *T = TL.getTypePtr();
+
+ TemplateTypeParmDecl *NewTTPDecl = nullptr;
+ if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+ NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
+ NewTTPDecl);
+ TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+ }
+ };
+} // namespace
+
+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();
+ }
+ }
+
+ llvm::FoldingSetNodeID ID1, ID2;
+ OldConstr->Profile(ID1, Context, /*Canonical=*/true);
+ NewConstr->Profile(ID2, Context, /*Canonical=*/true);
+ return ID1 == ID2;
+}
+
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
+ assert(FD->getFriendObjectKind() && "Must be a friend!");
+
+ // The logic for non-templates is handled in ASTContext::isSameEntity, so we
+ // don't have to bother checking 'DependsOnEnclosingTemplate' for a
+ // non-function-template.
+ assert(FD->getDescribedFunctionTemplate() &&
+ "Non-function templates don't need to be checked");
+
+ SmallVector<const Expr *, 3> ACs;
+ FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+
+ unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+ for (const Expr *Constraint : ACs)
+ if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
+ Constraint))
+ return true;
+
+ return false;
}
bool Sema::EnsureTemplateArgumentListConstraints(
- TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
+ TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange) {
ConstraintSatisfaction Satisfaction;
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
TD->getAssociatedConstraints(AssociatedConstraints);
- if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs,
+ if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists,
TemplateIDRange, Satisfaction))
return true;
@@ -392,7 +762,8 @@ bool Sema::EnsureTemplateArgumentListConstraints(
SmallString<128> TemplateArgString;
TemplateArgString = " ";
TemplateArgString += getTemplateArgumentBindingsText(
- TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+ TD->getTemplateParameters(), TemplateArgsLists.getInnermost().data(),
+ TemplateArgsLists.getInnermost().size());
Diag(TemplateIDRange.getBegin(),
diag::err_template_arg_list_constraints_not_satisfied)
@@ -424,21 +795,13 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- // If this is not an explicit specialization - we need to get the instantiated
- // version of the template arguments and add them to scope for the
- // substitution.
- if (Decl->isTemplateInstantiation()) {
- InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
- InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
- TemplateArgs, SourceRange());
- if (Inst.isInvalid())
- return true;
- MultiLevelTemplateArgumentList MLTAL(
- *Decl->getTemplateSpecializationArgs());
- if (addInstantiatedParametersToScope(
- Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
- return true;
- }
+ std::optional<MultiLevelTemplateArgumentList> MLTAL =
+ SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
+ Scope);
+
+ if (!MLTAL)
+ return true;
+
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
@@ -446,7 +809,14 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Record = Method->getParent();
}
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
- return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
+ FunctionScopeRAII FuncScope(*this);
+ if (isLambdaCallOperator(Decl))
+ PushLambdaScope();
+ else
+ FuncScope.disable();
+
+ llvm::SmallVector<Expr *, 1> Converted;
+ return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
PointOfInstantiation, Satisfaction);
}
@@ -541,31 +911,28 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
return;
}
}
+static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
+ Expr *SubstExpr,
+ bool First = true);
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::NestedRequirement *Req,
bool First) {
- if (Req->isSubstitutionFailure()) {
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag =
- Req->getSubstitutionDiagnostic();
- if (!SubstDiag->DiagMessage.empty())
- S.Diag(SubstDiag->DiagLoc,
- diag::note_nested_requirement_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity
- << SubstDiag->DiagMessage;
+ using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
+ for (auto &Pair : Req->getConstraintSatisfaction()) {
+ if (auto *SubstDiag = Pair.second.dyn_cast<SubstitutionDiagnostic *>())
+ S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error)
+ << (int)First << Req->getInvalidConstraintEntity() << SubstDiag->second;
else
- S.Diag(SubstDiag->DiagLoc,
- diag::note_nested_requirement_unknown_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity;
- return;
+ diagnoseWellFormedUnsatisfiedConstraintExpr(
+ S, Pair.second.dyn_cast<Expr *>(), First);
+ First = false;
}
- S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First);
}
-
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
Expr *SubstExpr,
- bool First = true) {
+ bool First) {
SubstExpr = SubstExpr->IgnoreParenImpCasts();
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
switch (BO->getOpcode()) {
@@ -645,6 +1012,7 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
return;
} else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
+ // FIXME: RequiresExpr should store dependent diagnostics.
for (concepts::Requirement *Req : RE->getRequirements())
if (!Req->isDependent() && !Req->isSatisfied()) {
if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
@@ -721,34 +1089,33 @@ Sema::getNormalizedAssociatedConstraints(
return CacheEntry->second;
}
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
- ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
- const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+static bool
+substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
if (!N.isAtomic()) {
- if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
+ if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
ArgsAsWritten))
return true;
- return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
+ return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
ArgsAsWritten);
}
TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
AtomicConstraint &Atomic = *N.getAtomicConstraint();
TemplateArgumentListInfo SubstArgs;
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(TemplateArgs);
if (!Atomic.ParameterMapping) {
llvm::SmallBitVector OccurringIndices(TemplateParams->size());
S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
/*Depth=*/0, OccurringIndices);
- Atomic.ParameterMapping.emplace(
- MutableArrayRef<TemplateArgumentLoc>(
- new (S.Context) TemplateArgumentLoc[OccurringIndices.count()],
- OccurringIndices.count()));
+ TemplateArgumentLoc *TempArgs =
+ new (S.Context) TemplateArgumentLoc[OccurringIndices.count()];
for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
if (OccurringIndices[I])
- new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc(
- S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I],
+ new (&(TempArgs)[J++])
+ TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc(
+ TemplateParams->begin()[I],
// Here we assume we do not support things like
// template<typename A, typename B>
// concept C = ...;
@@ -757,9 +1124,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
// struct S { };
// The above currently yields a diagnostic.
// We still might have default arguments for concept parameters.
- ArgsAsWritten->NumTemplateArgs > I ?
- ArgsAsWritten->arguments()[I].getLocation() :
- SourceLocation()));
+ ArgsAsWritten->NumTemplateArgs > I
+ ? ArgsAsWritten->arguments()[I].getLocation()
+ : SourceLocation()));
+ Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count());
}
Sema::InstantiatingTemplate Inst(
S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
@@ -768,33 +1136,47 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
return true;
- Atomic.ParameterMapping.emplace(
- MutableArrayRef<TemplateArgumentLoc>(
- new (S.Context) TemplateArgumentLoc[SubstArgs.size()],
- SubstArgs.size()));
+
+ TemplateArgumentLoc *TempArgs =
+ new (S.Context) TemplateArgumentLoc[SubstArgs.size()];
std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
- N.getAtomicConstraint()->ParameterMapping->begin());
+ TempArgs);
+ Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size());
return false;
}
-Optional<NormalizedConstraint>
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ const ConceptSpecializationExpr *CSE) {
+ TemplateArgumentList TAL{TemplateArgumentList::OnStack,
+ CSE->getTemplateArguments()};
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ CSE->getNamedConcept(), /*Final=*/false, &TAL,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+
+ return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
+ CSE->getTemplateArgsAsWritten());
+}
+
+std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
ArrayRef<const Expr *> E) {
assert(E.size() != 0);
auto Conjunction = fromConstraintExpr(S, D, E[0]);
if (!Conjunction)
- return None;
+ return std::nullopt;
for (unsigned I = 1; I < E.size(); ++I) {
auto Next = fromConstraintExpr(S, D, E[I]);
if (!Next)
- return None;
+ return std::nullopt;
*Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
std::move(*Next), CCK_Conjunction);
}
return Conjunction;
}
-llvm::Optional<NormalizedConstraint>
+std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
assert(E != nullptr);
@@ -803,13 +1185,19 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
// - The normal form of an expression (E) is the normal form of E.
// [...]
E = E->IgnoreParenImpCasts();
+
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ // Fold expression is considered atomic constraints per current wording.
+ // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
+
if (LogicalBinOp BO = E) {
auto LHS = fromConstraintExpr(S, D, BO.getLHS());
if (!LHS)
- return None;
+ return std::nullopt;
auto RHS = fromConstraintExpr(S, D, BO.getRHS());
if (!RHS)
- return None;
+ return std::nullopt;
return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
@@ -833,16 +1221,14 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
SubNF = S.getNormalizedAssociatedConstraints(CD,
{CD->getConstraintExpr()});
if (!SubNF)
- return None;
+ return std::nullopt;
}
- Optional<NormalizedConstraint> New;
+ std::optional<NormalizedConstraint> New;
New.emplace(S.Context, *SubNF);
- if (substituteParameterMappings(
- S, *New, CSE->getNamedConcept(),
- CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
- return None;
+ if (substituteParameterMappings(S, *New, CSE))
+ return std::nullopt;
return New;
}
@@ -965,9 +1351,26 @@ static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
return false;
}
-bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
- NamedDecl *D2, ArrayRef<const Expr *> AC2,
+bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
+ MutableArrayRef<const Expr *> AC1,
+ NamedDecl *D2,
+ MutableArrayRef<const Expr *> AC2,
bool &Result) {
+ if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
+ auto IsExpectedEntity = [](const FunctionDecl *FD) {
+ FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
+ return Kind == FunctionDecl::TK_NonTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplate;
+ };
+ const auto *FD2 = dyn_cast<FunctionDecl>(D2);
+ (void)IsExpectedEntity;
+ (void)FD1;
+ (void)FD2;
+ assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) &&
+ "use non-instantiated function declaration for constraints partial "
+ "ordering");
+ }
+
if (AC1.empty()) {
Result = AC2.empty();
return false;
@@ -985,6 +1388,21 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
return false;
}
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+
+ for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
+ if (Depth2 > Depth1) {
+ AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1)
+ .TransformExpr(const_cast<Expr *>(AC1[I]))
+ .get();
+ } else if (Depth1 > Depth2) {
+ AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2)
+ .TransformExpr(const_cast<Expr *>(AC2[I]))
+ .get();
+ }
+ }
+
if (subsumes(*this, D1, AC1, D2, AC2, Result,
[this] (const AtomicConstraint &A, const AtomicConstraint &B) {
return A.subsumes(Context, B);
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index a738befdd6ce..79c08adb8fab 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -339,7 +339,7 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
// EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment
// a private function in SemaExprCXX.cpp
- ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None);
+ ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", std::nullopt);
if (AddressExpr.isInvalid())
return nullptr;
@@ -395,8 +395,8 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
return Result.get();
};
- CallExpr *AwaitReady =
- cast_or_null<CallExpr>(BuildSubExpr(ACT::ACT_Ready, "await_ready", None));
+ CallExpr *AwaitReady = cast_or_null<CallExpr>(
+ BuildSubExpr(ACT::ACT_Ready, "await_ready", std::nullopt));
if (!AwaitReady)
return Calls;
if (!AwaitReady->getType()->isDependentType()) {
@@ -457,7 +457,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
}
}
- BuildSubExpr(ACT::ACT_Resume, "await_resume", None);
+ BuildSubExpr(ACT::ACT_Resume, "await_resume", std::nullopt);
// Make sure the awaiter object gets a chance to be cleaned up.
S.Cleanup.setExprNeedsCleanups(true);
@@ -705,8 +705,8 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
SourceLocation Loc = Fn->getLocation();
// Build the initial suspend point
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
- ExprResult Operand =
- buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
+ ExprResult Operand = buildPromiseCall(*this, ScopeInfo->CoroutinePromise,
+ Loc, Name, std::nullopt);
if (Operand.isInvalid())
return StmtError();
ExprResult Suspend =
@@ -768,27 +768,34 @@ static bool isWithinCatchScope(Scope *S) {
// function-body *outside of a handler* [...] A context within a function
// where an await-expression can appear is called a suspension context of the
// function."
-static void checkSuspensionContext(Sema &S, SourceLocation Loc,
+static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
StringRef Keyword) {
// First emphasis of [expr.await]p2: must be a potentially evaluated context.
// That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
// \c sizeof.
- if (S.isUnevaluatedContext())
+ if (S.isUnevaluatedContext()) {
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
+ return false;
+ }
// Second emphasis of [expr.await]p2: must be outside of an exception handler.
- if (isWithinCatchScope(S.getCurScope()))
+ if (isWithinCatchScope(S.getCurScope())) {
S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword;
+ return false;
+ }
+
+ return true;
}
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ if (!checkSuspensionContext(*this, Loc, "co_await"))
+ return ExprError();
+
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
- checkSuspensionContext(*this, Loc, "co_await");
-
if (E->hasPlaceholderType()) {
ExprResult R = CheckPlaceholderExpr(E);
if (R.isInvalid()) return ExprError();
@@ -905,13 +912,14 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
}
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ if (!checkSuspensionContext(*this, Loc, "co_yield"))
+ return ExprError();
+
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
- checkSuspensionContext(*this, Loc, "co_yield");
-
// Build yield_value call.
ExprResult Awaitable = buildPromiseCall(
*this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
@@ -989,7 +997,7 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
} else {
E = MakeFullDiscardedValueExpr(E).get();
- PC = buildPromiseCall(*this, Promise, Loc, "return_void", None);
+ PC = buildPromiseCall(*this, Promise, Loc, "return_void", std::nullopt);
}
if (PC.isInvalid())
return StmtError();
@@ -1030,41 +1038,55 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
return DR.get();
}
-// Find an appropriate delete for the promise.
-static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
- QualType PromiseType) {
- FunctionDecl *OperatorDelete = nullptr;
+static TypeSourceInfo *getTypeSourceInfoForStdAlignValT(Sema &S,
+ SourceLocation Loc) {
+ EnumDecl *StdAlignValT = S.getStdAlignValT();
+ QualType StdAlignValDecl = S.Context.getTypeDeclType(StdAlignValT);
+ return S.Context.getTrivialTypeSourceInfo(StdAlignValDecl);
+}
+// Find an appropriate delete for the promise.
+static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType,
+ FunctionDecl *&OperatorDelete) {
DeclarationName DeleteName =
S.Context.DeclarationNames.getCXXOperatorName(OO_Delete);
auto *PointeeRD = PromiseType->getAsCXXRecordDecl();
assert(PointeeRD && "PromiseType must be a CxxRecordDecl type");
+ const bool Overaligned = S.getLangOpts().CoroAlignedAllocation;
+
// [dcl.fct.def.coroutine]p12
// The deallocation function's name is looked up by searching for it in the
// scope of the promise type. If nothing is found, a search is performed in
// the global scope.
- if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete))
- return nullptr;
+ if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete,
+ /*Diagnose*/ true, /*WantSize*/ true,
+ /*WantAligned*/ Overaligned))
+ return false;
- // FIXME: We didn't implement following selection:
// [dcl.fct.def.coroutine]p12
// If both a usual deallocation function with only a pointer parameter and a
// usual deallocation function with both a pointer parameter and a size
// parameter are found, then the selected deallocation function shall be the
// one with two parameters. Otherwise, the selected deallocation function
// shall be the function with one parameter.
-
if (!OperatorDelete) {
// Look for a global declaration.
- const bool CanProvideSize = S.isCompleteType(Loc, PromiseType);
- const bool Overaligned = false;
+ // Coroutines can always provide their required size.
+ const bool CanProvideSize = true;
+ // Sema::FindUsualDeallocationFunction will try to find the one with two
+ // parameters first. It will return the deallocation function with one
+ // parameter if failed.
OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize,
Overaligned, DeleteName);
+
+ if (!OperatorDelete)
+ return false;
}
+
S.MarkFunctionReferenced(Loc, OperatorDelete);
- return OperatorDelete;
+ return true;
}
@@ -1103,6 +1125,12 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
<< Fn->getFirstCoroutineStmtKeyword();
}
+
+ // Coroutines will get splitted into pieces. The GNU address of label
+ // extension wouldn't be meaningful in coroutines.
+ for (AddrLabelExpr *ALE : Fn->AddrLabels)
+ Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label);
+
CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body);
if (Builder.isInvalid() || !Builder.buildStatements())
return FD->setInvalidDecl();
@@ -1319,12 +1347,9 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// lvalue that denotes the parameter copy corresponding to p_i.
FunctionDecl *OperatorNew = nullptr;
- FunctionDecl *OperatorDelete = nullptr;
- FunctionDecl *UnusedResult = nullptr;
- bool PassAlignment = false;
SmallVector<Expr *, 1> PlacementArgs;
- bool PromiseContainsNew = [this, &PromiseType]() -> bool {
+ const bool PromiseContainsNew = [this, &PromiseType]() -> bool {
DeclarationName NewName =
S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New);
LookupResult R(S, NewName, Loc, Sema::LookupOrdinaryName);
@@ -1335,19 +1360,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return !R.empty() && !R.isAmbiguous();
}();
- auto LookupAllocationFunction = [&]() {
+ // Helper function to indicate whether the last lookup found the aligned
+ // allocation function.
+ bool PassAlignment = S.getLangOpts().CoroAlignedAllocation;
+ auto LookupAllocationFunction = [&](Sema::AllocationFunctionScope NewScope =
+ Sema::AFS_Both,
+ bool WithoutPlacementArgs = false,
+ bool ForceNonAligned = false) {
// [dcl.fct.def.coroutine]p9
// The allocation function's name is looked up by searching for it in the
// scope of the promise type.
// - If any declarations are found, ...
// - If no declarations are found in the scope of the promise type, a search
// is performed in the global scope.
- Sema::AllocationFunctionScope NewScope =
- PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
- S.FindAllocationFunctions(Loc, SourceRange(),
- NewScope,
+ if (NewScope == Sema::AFS_Both)
+ NewScope = PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
+
+ PassAlignment = !ForceNonAligned && S.getLangOpts().CoroAlignedAllocation;
+ FunctionDecl *UnusedResult = nullptr;
+ S.FindAllocationFunctions(Loc, SourceRange(), NewScope,
/*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
+ /*isArray*/ false, PassAlignment,
+ WithoutPlacementArgs ? MultiExprArg{}
+ : PlacementArgs,
OperatorNew, UnusedResult, /*Diagnose*/ false);
};
@@ -1359,15 +1394,58 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
LookupAllocationFunction();
- // [dcl.fct.def.coroutine]p9
- // If no viable function is found ([over.match.viable]), overload resolution
- // is performed again on a function call created by passing just the amount of
- // space required as an argument of type std::size_t.
- if (!OperatorNew && !PlacementArgs.empty() && PromiseContainsNew) {
- PlacementArgs.clear();
- LookupAllocationFunction();
+ if (PromiseContainsNew && !PlacementArgs.empty()) {
+ // [dcl.fct.def.coroutine]p9
+ // If no viable function is found ([over.match.viable]), overload
+ // resolution
+ // is performed again on a function call created by passing just the amount
+ // of space required as an argument of type std::size_t.
+ //
+ // Proposed Change of [dcl.fct.def.coroutine]p9 in P2014R0:
+ // Otherwise, overload resolution is performed again on a function call
+ // created
+ // by passing the amount of space requested as an argument of type
+ // std::size_t as the first argument, and the requested alignment as
+ // an argument of type std:align_val_t as the second argument.
+ if (!OperatorNew ||
+ (S.getLangOpts().CoroAlignedAllocation && !PassAlignment))
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ true);
}
+ // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
+ // Otherwise, overload resolution is performed again on a function call
+ // created
+ // by passing the amount of space requested as an argument of type
+ // std::size_t as the first argument, and the lvalues p1 ... pn as the
+ // succeeding arguments. Otherwise, overload resolution is performed again
+ // on a function call created by passing just the amount of space required as
+ // an argument of type std::size_t.
+ //
+ // So within the proposed change in P2014RO, the priority order of aligned
+ // allocation functions wiht promise_type is:
+ //
+ // void* operator new( std::size_t, std::align_val_t, placement_args... );
+ // void* operator new( std::size_t, std::align_val_t);
+ // void* operator new( std::size_t, placement_args... );
+ // void* operator new( std::size_t);
+
+ // Helper variable to emit warnings.
+ bool FoundNonAlignedInPromise = false;
+ if (PromiseContainsNew && S.getLangOpts().CoroAlignedAllocation)
+ if (!OperatorNew || !PassAlignment) {
+ FoundNonAlignedInPromise = OperatorNew;
+
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ false,
+ /*ForceNonAligned*/ true);
+
+ if (!OperatorNew && !PlacementArgs.empty())
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ true,
+ /*ForceNonAligned*/ true);
+ }
+
bool IsGlobalOverload =
OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
// If we didn't find a class-local new declaration and non-throwing new
@@ -1379,15 +1457,24 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
PlacementArgs = {StdNoThrow};
OperatorNew = nullptr;
- S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Both,
- /*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
- OperatorNew, UnusedResult);
+ LookupAllocationFunction(Sema::AFS_Global);
+ }
+
+ // If we found a non-aligned allocation function in the promise_type,
+ // it indicates the user forgot to update the allocation function. Let's emit
+ // a warning here.
+ if (FoundNonAlignedInPromise) {
+ S.Diag(OperatorNew->getLocation(),
+ diag::warn_non_aligned_allocation_function)
+ << &FD;
}
if (!OperatorNew) {
if (PromiseContainsNew)
S.Diag(Loc, diag::err_coroutine_unusable_new) << PromiseType << &FD;
+ else if (RequiresNoThrowAlloc)
+ S.Diag(Loc, diag::err_coroutine_unfound_nothrow_new)
+ << &FD << S.getLangOpts().CoroAlignedAllocation;
return false;
}
@@ -1404,7 +1491,8 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
}
}
- if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr) {
+ FunctionDecl *OperatorDelete = nullptr;
+ if (!findDeleteForPromise(S, Loc, PromiseType, OperatorDelete)) {
// FIXME: We should add an error here. According to:
// [dcl.fct.def.coroutine]p12
// If no usual deallocation function is found, the program is ill-formed.
@@ -1417,15 +1505,34 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
Expr *FrameSize =
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {});
- // Make new call.
+ Expr *FrameAlignment = nullptr;
+
+ if (S.getLangOpts().CoroAlignedAllocation) {
+ FrameAlignment =
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_align, {});
+
+ TypeSourceInfo *AlignValTy = getTypeSourceInfoForStdAlignValT(S, Loc);
+ if (!AlignValTy)
+ return false;
+
+ FrameAlignment = S.BuildCXXNamedCast(Loc, tok::kw_static_cast, AlignValTy,
+ FrameAlignment, SourceRange(Loc, Loc),
+ SourceRange(Loc, Loc))
+ .get();
+ }
+ // Make new call.
ExprResult NewRef =
S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc);
if (NewRef.isInvalid())
return false;
SmallVector<Expr *, 2> NewArgs(1, FrameSize);
- llvm::append_range(NewArgs, PlacementArgs);
+ if (S.getLangOpts().CoroAlignedAllocation && PassAlignment)
+ NewArgs.push_back(FrameAlignment);
+
+ if (OperatorNew->getNumParams() > NewArgs.size())
+ llvm::append_range(NewArgs, PlacementArgs);
ExprResult NewExpr =
S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
@@ -1454,9 +1561,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// used, the size of the block is passed as the corresponding argument.
const auto *OpDeleteType =
OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>();
- if (OpDeleteType->getNumParams() > 1)
+ if (OpDeleteType->getNumParams() > DeleteArgs.size() &&
+ S.getASTContext().hasSameType(
+ OpDeleteType->getParamType(DeleteArgs.size()), FrameSize->getType()))
DeleteArgs.push_back(FrameSize);
+ // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
+ // If deallocation function lookup finds a usual deallocation function with
+ // a pointer parameter, size parameter and alignment parameter then this
+ // will be the selected deallocation function, otherwise if lookup finds a
+ // usual deallocation function with both a pointer parameter and a size
+ // parameter, then this will be the selected deallocation function.
+ // Otherwise, if lookup finds a usual deallocation function with only a
+ // pointer parameter, then this will be the selected deallocation
+ // function.
+ //
+ // So we are not forced to pass alignment to the deallocation function.
+ if (S.getLangOpts().CoroAlignedAllocation &&
+ OpDeleteType->getNumParams() > DeleteArgs.size() &&
+ S.getASTContext().hasSameType(
+ OpDeleteType->getParamType(DeleteArgs.size()),
+ FrameAlignment->getType()))
+ DeleteArgs.push_back(FrameAlignment);
+
ExprResult DeleteExpr =
S.BuildCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
DeleteExpr =
@@ -1549,8 +1676,8 @@ bool CoroutineStmtBuilder::makeOnException() {
if (!S.getLangOpts().CXXExceptions)
return true;
- ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
- "unhandled_exception", None);
+ ExprResult UnhandledException = buildPromiseCall(
+ S, Fn.CoroutinePromise, Loc, "unhandled_exception", std::nullopt);
UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc,
/*DiscardedValue*/ false);
if (UnhandledException.isInvalid())
@@ -1573,8 +1700,8 @@ bool CoroutineStmtBuilder::makeReturnObject() {
// [dcl.fct.def.coroutine]p7
// The expression promise.get_return_object() is used to initialize the
// returned reference or prvalue result object of a call to a coroutine.
- ExprResult ReturnObject =
- buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
+ ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
+ "get_return_object", std::nullopt);
if (ReturnObject.isInvalid())
return false;
@@ -1694,7 +1821,7 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
// [dcl.fct.def.coroutine]p13
// The initialization and destruction of each parameter copy occurs in the
// context of the called coroutine.
- auto D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier());
+ auto *D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier());
AddInitializerToDecl(D, CExpr, /*DirectInit=*/true);
// Convert decl to a statement.
@@ -1724,7 +1851,8 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
// discovered.
// TODO: Become stricter when <experimental/coroutine> is removed.
- auto const &TraitIdent = PP.getIdentifierTable().get("coroutine_traits");
+ IdentifierInfo const &TraitIdent =
+ PP.getIdentifierTable().get("coroutine_traits");
NamespaceDecl *StdSpace = getStdNamespace();
LookupResult ResStd(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
@@ -1742,7 +1870,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
}
// Prefer ::std to std::experimental.
- auto &Result = InStd ? ResStd : ResExp;
+ LookupResult &Result = InStd ? ResStd : ResExp;
CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace;
// coroutine_traits is required to be a class template.
@@ -1759,7 +1887,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
<< "coroutine_traits";
ResExp.suppressDiagnostics();
- auto *Found = *ResExp.begin();
+ NamedDecl *Found = *ResExp.begin();
Diag(Found->getLocation(), diag::note_entity_declared_at) << Found;
if (InStd &&
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 985005d0b79b..e2b921bfe78f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/Randstruct.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -49,6 +50,7 @@
#include <algorithm>
#include <cstring>
#include <functional>
+#include <optional>
#include <unordered_map>
using namespace clang;
@@ -145,7 +147,8 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case tok::kw___auto_type:
return true;
@@ -275,6 +278,45 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
+/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier.
+static ParsedType buildNamedType(Sema &S, const CXXScopeSpec *SS, QualType T,
+ SourceLocation NameLoc,
+ bool WantNontrivialTypeSourceInfo = true) {
+ switch (T->getTypeClass()) {
+ case Type::DeducedTemplateSpecialization:
+ case Type::Enum:
+ case Type::InjectedClassName:
+ case Type::Record:
+ case Type::Typedef:
+ case Type::UnresolvedUsing:
+ case Type::Using:
+ break;
+ // These can never be qualified so an ElaboratedType node
+ // would carry no additional meaning.
+ case Type::ObjCInterface:
+ case Type::ObjCTypeParam:
+ case Type::TemplateTypeParm:
+ return ParsedType::make(T);
+ default:
+ llvm_unreachable("Unexpected Type Class");
+ }
+
+ if (!SS || SS->isEmpty())
+ return ParsedType::make(
+ S.Context.getElaboratedType(ETK_None, nullptr, T, nullptr));
+
+ QualType ElTy = S.getElaboratedType(ETK_None, *SS, T);
+ if (!WantNontrivialTypeSourceInfo)
+ return ParsedType::make(ElTy);
+
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(ElTy);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS->getWithLocInContext(S.Context));
+ return S.CreateParsedType(ElTy, Builder.getTypeSourceInfo(S.Context, ElTy));
+}
+
/// If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -284,12 +326,12 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
/// opaque pointer (actually a QualType) corresponding to that
/// type. Otherwise, returns NULL.
ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, CXXScopeSpec *SS,
- bool isClassName, bool HasTrailingDot,
- ParsedType ObjectTypePtr,
+ Scope *S, CXXScopeSpec *SS, bool isClassName,
+ bool HasTrailingDot, ParsedType ObjectTypePtr,
bool IsCtorOrDtorName,
bool WantNontrivialTypeSourceInfo,
bool IsClassTemplateDeductionContext,
+ ImplicitTypenameContext AllowImplicitTypename,
IdentifierInfo **CorrectedII) {
// FIXME: Consider allowing this outside C++1z mode as an extension.
bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
@@ -316,17 +358,33 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
//
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
- if (!isClassName && !IsCtorOrDtorName)
+ // In C++2a, in several contexts a 'typename' is not required. Also
+ // allow this as an extension.
+ if (AllowImplicitTypename == ImplicitTypenameContext::No &&
+ !isClassName && !IsCtorOrDtorName)
return nullptr;
+ bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
+ if (IsImplicitTypename) {
+ SourceLocation QualifiedLoc = SS->getRange().getBegin();
+ if (getLangOpts().CPlusPlus20)
+ Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
+ else
+ Diag(QualifiedLoc, diag::ext_implicit_typename)
+ << SS->getScopeRep() << II.getName()
+ << FixItHint::CreateInsertion(QualifiedLoc, "typename ");
+ }
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
if (WantNontrivialTypeSourceInfo)
- return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
+ return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc,
+ (ImplicitTypenameContext)IsImplicitTypename)
+ .get();
NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
- QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
- II, NameLoc);
+ QualType T =
+ CheckTypenameType(IsImplicitTypename ? ETK_Typename : ETK_None,
+ SourceLocation(), QualifierLoc, II, NameLoc);
return ParsedType::make(T);
}
@@ -417,7 +475,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
}
}
// If typo correction failed or was not performed, fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
@@ -500,8 +558,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
} else if (auto *UD = dyn_cast<UnresolvedUsingIfExistsDecl>(IIDecl)) {
(void)DiagnoseUseOfDecl(UD, NameLoc);
// Recover with 'int'
- T = Context.IntTy;
- FoundUsingShadow = nullptr;
+ return ParsedType::make(Context.IntTy);
} else if (AllowDeducedTemplate) {
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
@@ -523,27 +580,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (FoundUsingShadow)
T = Context.getUsingType(FoundUsingShadow, T);
- // NOTE: avoid constructing an ElaboratedType(Loc) if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Expr or Decl node).
- if (SS && SS->isNotEmpty() && !IsCtorOrDtorName &&
- !isa<ObjCInterfaceDecl, UnresolvedUsingIfExistsDecl>(IIDecl)) {
- if (WantNontrivialTypeSourceInfo) {
- // Construct a type with type-source information.
- TypeLocBuilder Builder;
- Builder.pushTypeSpec(T).setNameLoc(NameLoc);
-
- T = getElaboratedType(ETK_None, *SS, T);
- ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
- ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
- return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
- } else {
- T = getElaboratedType(ETK_None, *SS, T);
- }
- }
-
- return ParsedType::make(T);
+ return buildNamedType(*this, SS, T, NameLoc, WantNontrivialTypeSourceInfo);
}
// Builds a fake NNS for the given decl context.
@@ -1147,17 +1184,7 @@ Corrected:
QualType T = Context.getTypeDeclType(Type);
if (const auto *USD = dyn_cast<UsingShadowDecl>(Found))
T = Context.getUsingType(USD, T);
-
- if (SS.isEmpty()) // No elaborated type, trivial location info
- return ParsedType::make(T);
-
- TypeLocBuilder Builder;
- Builder.pushTypeSpec(T).setNameLoc(NameLoc);
- T = getElaboratedType(ETK_None, SS, T);
- ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
- ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
- return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+ return buildNamedType(*this, &SS, T, NameLoc);
};
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
@@ -1221,7 +1248,8 @@ Corrected:
// member accesses, as we need to defer certain access checks until we know
// the context.
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
- if (Result.isSingleResult() && !ADL && !FirstDecl->isCXXClassMember())
+ if (Result.isSingleResult() && !ADL &&
+ (!FirstDecl->isCXXClassMember() || isa<EnumConstantDecl>(FirstDecl)))
return NameClassification::NonType(Result.getRepresentativeDecl());
// Otherwise, this is an overload set that we will need to resolve later.
@@ -1266,7 +1294,7 @@ ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
Result.resolveKind();
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
- return BuildDeclarationNameExpr(SS, Result, ADL);
+ return BuildDeclarationNameExpr(SS, Result, ADL, /*AcceptInvalidDecl=*/true);
}
ExprResult Sema::ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *E) {
@@ -1635,9 +1663,11 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
// 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()))
- return NewM->getPrimaryModuleInterfaceName() ==
- OldM->getPrimaryModuleInterfaceName();
+ if (NewM && OldM &&
+ (NewM->isModulePartition() || OldM->isModulePartition()) &&
+ NewM->getPrimaryModuleInterfaceName() ==
+ OldM->getPrimaryModuleInterfaceName())
+ return false;
bool NewIsModuleInterface = NewM && NewM->isModulePurview();
bool OldIsModuleInterface = OldM && OldM->isModulePurview();
@@ -1711,6 +1741,80 @@ bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) {
return false;
}
+// Check the redefinition in C++20 Modules.
+//
+// [basic.def.odr]p14:
+// For any definable item D with definitions in multiple translation units,
+// - if D is a non-inline non-templated function or variable, or
+// - if the definitions in different translation units do not satisfy the
+// following requirements,
+// the program is ill-formed; a diagnostic is required only if the definable
+// item is attached to a named module and a prior definition is reachable at
+// the point where a later definition occurs.
+// - Each such definition shall not be attached to a named module
+// ([module.unit]).
+// - Each such definition shall consist of the same sequence of tokens, ...
+// ...
+//
+// Return true if the redefinition is not allowed. Return false otherwise.
+bool Sema::IsRedefinitionInModule(const NamedDecl *New,
+ const NamedDecl *Old) const {
+ assert(getASTContext().isSameEntity(New, Old) &&
+ "New and Old are not the same definition, we should diagnostic it "
+ "immediately instead of checking it.");
+ assert(const_cast<Sema *>(this)->isReachable(New) &&
+ const_cast<Sema *>(this)->isReachable(Old) &&
+ "We shouldn't see unreachable definitions here.");
+
+ Module *NewM = New->getOwningModule();
+ Module *OldM = Old->getOwningModule();
+
+ // We only checks for named modules here. The header like modules is skipped.
+ // FIXME: This is not right if we import the header like modules in the module
+ // purview.
+ //
+ // For example, assuming "header.h" provides definition for `D`.
+ // ```C++
+ // //--- M.cppm
+ // export module M;
+ // import "header.h"; // or #include "header.h" but import it by clang modules
+ // actually.
+ //
+ // //--- Use.cpp
+ // import M;
+ // import "header.h"; // or uses clang modules.
+ // ```
+ //
+ // In this case, `D` has multiple definitions in multiple TU (M.cppm and
+ // Use.cpp) and `D` is attached to a named module `M`. The compiler should
+ // reject it. But the current implementation couldn't detect the case since we
+ // don't record the information about the importee modules.
+ //
+ // But this might not be painful in practice. Since the design of C++20 Named
+ // Modules suggests us to use headers in global module fragment instead of
+ // module purview.
+ if (NewM && NewM->isHeaderLikeModule())
+ NewM = nullptr;
+ if (OldM && OldM->isHeaderLikeModule())
+ OldM = nullptr;
+
+ if (!NewM && !OldM)
+ return true;
+
+ // [basic.def.odr]p14.3
+ // Each such definition shall not be attached to a named module
+ // ([module.unit]).
+ if ((NewM && NewM->isModulePurview()) || (OldM && OldM->isModulePurview()))
+ return true;
+
+ // Then New and Old lives in the same TU if their share one same module unit.
+ if (NewM)
+ NewM = NewM->getTopLevelModule();
+ if (OldM)
+ OldM = OldM->getTopLevelModule();
+ return OldM == NewM;
+}
+
static bool isUsingDecl(NamedDecl *D) {
return isa<UsingShadowDecl>(D) ||
isa<UnresolvedUsingTypenameDecl>(D) ||
@@ -1773,7 +1877,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
// FIXME: This needs to be refactored; some other isInMainFile users want
// these semantics.
static bool isMainFileLoc(const Sema &S, SourceLocation Loc) {
- if (S.TUKind != TU_Complete)
+ if (S.TUKind != TU_Complete || S.getLangOpts().IsHeaderFile)
return false;
return S.SourceMgr.isInMainFile(Loc);
}
@@ -1990,20 +2094,31 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
}
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
+ DiagnoseUnusedNestedTypedefs(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
+void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D,
+ DiagReceiverTy DiagReceiver) {
if (D->getTypeForDecl()->isDependentType())
return;
for (auto *TmpD : D->decls()) {
if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
- DiagnoseUnusedDecl(T);
+ DiagnoseUnusedDecl(T, DiagReceiver);
else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
- DiagnoseUnusedNestedTypedefs(R);
+ DiagnoseUnusedNestedTypedefs(R, DiagReceiver);
}
}
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ DiagnoseUnusedDecl(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
-void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) {
if (!ShouldDiagnoseUnusedDecl(D))
return;
@@ -2025,10 +2140,11 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
else
DiagID = diag::warn_unused_variable;
- Diag(D->getLocation(), DiagID) << D << Hint;
+ DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint);
}
-void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
+void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
+ DiagReceiverTy DiagReceiver) {
// If it's not referenced, it can't be set. If it has the Cleanup attribute,
// it's not really unused.
if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() ||
@@ -2074,10 +2190,11 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
return;
unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter
: diag::warn_unused_but_set_variable;
- Diag(VD->getLocation(), DiagID) << VD;
+ DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD);
}
-static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
+static void CheckPoppedLabel(LabelDecl *L, Sema &S,
+ Sema::DiagReceiverTy DiagReceiver) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt which is also not a resolved
@@ -2088,7 +2205,8 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
else
Diagnose = L->getStmt() == nullptr;
if (Diagnose)
- S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L;
+ DiagReceiver(L->getLocation(), S.PDiag(diag::err_undeclared_label_use)
+ << L);
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -2098,6 +2216,24 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
"Scope shouldn't contain decls!");
+ /// We visit the decls in non-deterministic order, but we want diagnostics
+ /// emitted in deterministic order. Collect any diagnostic that may be emitted
+ /// and sort the diagnostics before emitting them, after we visited all decls.
+ struct LocAndDiag {
+ SourceLocation Loc;
+ std::optional<SourceLocation> PreviousDeclLoc;
+ PartialDiagnostic PD;
+ };
+ SmallVector<LocAndDiag, 16> DeclDiags;
+ auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, std::nullopt, std::move(PD)});
+ };
+ auto addDiagWithPrev = [&DeclDiags](SourceLocation Loc,
+ SourceLocation PreviousDeclLoc,
+ PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, PreviousDeclLoc, std::move(PD)});
+ };
+
for (auto *TmpD : S->decls()) {
assert(TmpD && "This decl didn't get pushed??");
@@ -2106,11 +2242,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Diagnose unused variables in this scope.
if (!S->hasUnrecoverableErrorOccurred()) {
- DiagnoseUnusedDecl(D);
+ DiagnoseUnusedDecl(D, addDiag);
if (const auto *RD = dyn_cast<RecordDecl>(D))
- DiagnoseUnusedNestedTypedefs(RD);
+ DiagnoseUnusedNestedTypedefs(RD, addDiag);
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- DiagnoseUnusedButSetDecl(VD);
+ DiagnoseUnusedButSetDecl(VD, addDiag);
RefsMinusAssignments.erase(VD);
}
}
@@ -2119,7 +2255,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
- CheckPoppedLabel(LD, *this);
+ CheckPoppedLabel(LD, *this, addDiag);
// Remove this name from our lexical scope, and warn on it if we haven't
// already.
@@ -2127,13 +2263,27 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
auto ShadowI = ShadowingDecls.find(D);
if (ShadowI != ShadowingDecls.end()) {
if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) {
- Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field)
- << D << FD << FD->getParent();
- Diag(FD->getLocation(), diag::note_previous_declaration);
+ addDiagWithPrev(D->getLocation(), FD->getLocation(),
+ PDiag(diag::warn_ctor_parm_shadows_field)
+ << D << FD << FD->getParent());
}
ShadowingDecls.erase(ShadowI);
}
}
+
+ llvm::sort(DeclDiags,
+ [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
+ // The particular order for diagnostics is not important, as long
+ // as the order is deterministic. Using the raw location is going
+ // to generally be in source order unless there are macro
+ // expansions involved.
+ return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
+ });
+ for (const LocAndDiag &D : DeclDiags) {
+ Diag(D.Loc, D.PD);
+ if (D.PreviousDeclLoc)
+ Diag(*D.PreviousDeclLoc, diag::note_previous_declaration);
+ }
}
/// Look for an Objective-C class in the translation unit.
@@ -2949,7 +3099,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
continue;
} else if (isa<OMPDeclareVariantAttr>(NewAttribute)) {
// We allow to add OMP[Begin]DeclareVariantAttr to be added to
- // declarations after defintions.
+ // declarations after definitions.
++I;
continue;
}
@@ -3249,8 +3399,8 @@ static bool EquivalentArrayTypes(QualType Old, QualType New,
static void mergeParamDeclTypes(ParmVarDecl *NewParam,
const ParmVarDecl *OldParam,
Sema &S) {
- if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) {
- if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) {
+ if (auto Oldnullability = OldParam->getType()->getNullability()) {
+ if (auto Newnullability = NewParam->getType()->getNullability()) {
if (*Oldnullability != *Newnullability) {
S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr)
<< DiagNullabilityKind(
@@ -3960,7 +4110,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// default argument promotion rules were already checked by
// ASTContext::typesAreCompatible().
if (Old->hasPrototype() && !New->hasWrittenPrototype() && NewDeclIsDefn &&
- Old->getNumParams() != New->getNumParams()) {
+ Old->getNumParams() != New->getNumParams() && !Old->isImplicit()) {
if (Old->hasInheritedPrototype())
Old = Old->getCanonicalDecl();
Diag(New->getLocation(), diag::err_conflicting_types) << New;
@@ -4026,10 +4176,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
- NewQType =
- Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
- OldProto->getExtProtoInfo());
+ NewQType = Context.getFunctionType(NewFuncType->getReturnType(),
+ OldProto->getParamTypes(),
+ OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -4657,6 +4806,7 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
if (!hasVisibleDefinition(Old) &&
(New->getFormalLinkage() == InternalLinkage ||
New->isInline() ||
+ isa<VarTemplateSpecializationDecl>(New) ||
New->getDescribedVarTemplate() ||
New->getNumTemplateParameterLists() ||
New->getDeclContext()->isDependentContext())) {
@@ -5840,7 +5990,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_underlyingType:
+ case DeclSpec::TST_typeof_unqualType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case DeclSpec::TST_atomic: {
// Grab the type from the parser.
TypeSourceInfo *TSI = nullptr;
@@ -5864,6 +6016,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
}
case DeclSpec::TST_decltype:
+ case DeclSpec::TST_typeof_unqualExpr:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
ExprResult Result = S.RebuildExprInCurrentInstantiation(E);
@@ -6502,8 +6655,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 1 << static_cast<int>(D.getDeclSpec().getConstexprSpecifier());
- if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
- if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
+ if (D.getName().getKind() != UnqualifiedIdKind::IK_Identifier) {
+ if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName)
Diag(D.getName().StartLocation,
diag::err_deduction_guide_invalid_specifier)
<< "typedef";
@@ -6939,13 +7092,24 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
(!IsInline || (IsMicrosoftABI && IsTemplate)) && !IsStaticDataMember &&
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
if (IsMicrosoftABI && IsDefinition) {
- S.Diag(NewDecl->getLocation(),
- diag::warn_redeclaration_without_import_attribute)
- << NewDecl;
- S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
- NewDecl->dropAttr<DLLImportAttr>();
- NewDecl->addAttr(
- DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange()));
+ if (IsSpecialization) {
+ S.Diag(
+ NewDecl->getLocation(),
+ diag::err_attribute_dllimport_function_specialization_definition);
+ S.Diag(OldImportAttr->getLocation(), diag::note_attribute);
+ NewDecl->dropAttr<DLLImportAttr>();
+ } else {
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_redeclaration_without_import_attribute)
+ << NewDecl;
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ NewDecl->dropAttr<DLLImportAttr>();
+ NewDecl->addAttr(DLLExportAttr::CreateImplicit(
+ S.Context, NewImportAttr->getRange()));
+ }
+ } else if (IsMicrosoftABI && IsSpecialization) {
+ assert(!IsDefinition);
+ // MSVC allows this. Keep the inherited attribute.
} else {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
@@ -7039,6 +7203,9 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
return true;
if (DC->isRecord())
return false;
+ if (DC->getDeclKind() == Decl::HLSLBuffer)
+ return false;
+
if (isa<RequiresExprBodyDecl>(DC))
return false;
llvm_unreachable("Unexpected context");
@@ -7212,6 +7379,36 @@ static void copyAttrFromTypedefToDecl(Sema &S, Decl *D, const TypedefType *TT) {
}
}
+// This function emits warning and a corresponding note based on the
+// ReadOnlyPlacementAttr attribute. The warning checks that all global variable
+// declarations of an annotated type must be const qualified.
+void emitReadOnlyPlacementAttrWarning(Sema &S, const VarDecl *VD) {
+ QualType VarType = VD->getType().getCanonicalType();
+
+ // Ignore local declarations (for now) and those with const qualification.
+ // TODO: Local variables should not be allowed if their type declaration has
+ // ReadOnlyPlacementAttr attribute. To be handled in follow-up patch.
+ if (!VD || VD->hasLocalStorage() || VD->getType().isConstQualified())
+ return;
+
+ if (VarType->isArrayType()) {
+ // Retrieve element type for array declarations.
+ VarType = S.getASTContext().getBaseElementType(VarType);
+ }
+
+ const RecordDecl *RD = VarType->getAsRecordDecl();
+
+ // Check if the record declaration is present and if it has any attributes.
+ if (RD == nullptr)
+ return;
+
+ if (const auto *ConstDecl = RD->getAttr<ReadOnlyPlacementAttr>()) {
+ S.Diag(VD->getLocation(), diag::warn_var_decl_not_read_only) << RD;
+ S.Diag(ConstDecl->getLocation(), diag::note_enforce_read_only_placement);
+ return;
+ }
+}
+
NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists,
@@ -7555,7 +7752,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diag::err_constexpr_wrong_decl_kind)
<< static_cast<int>(D.getDeclSpec().getConstexprSpecifier());
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ConstexprSpecKind::Constexpr:
NewVD->setConstexpr(true);
@@ -7876,6 +8073,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (IsMemberSpecialization && !NewVD->isInvalidDecl())
CompleteMemberSpecialization(NewVD, Previous);
+ emitReadOnlyPlacementAttrWarning(*this, NewVD);
+
return NewVD;
}
@@ -8003,7 +8202,7 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
if (shadowedVar->isExternC()) {
// For shadowing external vars, make sure that we point to the global
// declaration, not a locally scoped extern declaration.
- for (auto I : shadowedVar->redecls())
+ for (auto *I : shadowedVar->redecls())
if (I->isFileVarDecl()) {
ShadowedDecl = I;
break;
@@ -8492,6 +8691,19 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
+
+ // Check that SVE types are only used in functions with SVE available.
+ if (T->isSVESizelessBuiltinType() && CurContext->isFunctionOrMethod()) {
+ const FunctionDecl *FD = cast<FunctionDecl>(CurContext);
+ llvm::StringMap<bool> CallerFeatureMap;
+ Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+ if (!Builtin::evaluateRequiredTargetFeatures(
+ "sve", CallerFeatureMap)) {
+ Diag(NewVD->getLocation(), diag::err_sve_vector_in_non_sve_target) << T;
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
}
/// Perform semantic checking on a newly-created variable
@@ -9069,10 +9281,23 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
// reference if an implementation supports them in kernel parameters.
if (S.getLangOpts().OpenCLCPlusPlus &&
!S.getOpenCLOptions().isAvailableOption(
- "__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) &&
- !PointeeType->isAtomicType() && !PointeeType->isVoidType() &&
- !PointeeType->isStandardLayoutType())
+ "__cl_clang_non_portable_kernel_param_types", S.getLangOpts())) {
+ auto CXXRec = PointeeType.getCanonicalType()->getAsCXXRecordDecl();
+ bool IsStandardLayoutType = true;
+ if (CXXRec) {
+ // If template type is not ODR-used its definition is only available
+ // in the template definition not its instantiation.
+ // FIXME: This logic doesn't work for types that depend on template
+ // parameter (PR58590).
+ if (!CXXRec->hasDefinition())
+ CXXRec = CXXRec->getTemplateInstantiationPattern();
+ if (!CXXRec || !CXXRec->hasDefinition() || !CXXRec->isStandardLayout())
+ IsStandardLayoutType = false;
+ }
+ if (!PointeeType->isAtomicType() && !PointeeType->isVoidType() &&
+ !IsStandardLayoutType)
return InvalidKernelParam;
+ }
return PtrKernelParam;
}
@@ -9419,7 +9644,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules ||
!NewFD->getOwningModule() ||
NewFD->getOwningModule()->isGlobalModule() ||
- NewFD->getOwningModule()->isModuleMapModule();
+ NewFD->getOwningModule()->isHeaderLikeModule();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
@@ -9755,6 +9980,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setType(Context.getFunctionType(
FPT->getReturnType(), FPT->getParamTypes(),
FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept)));
+
+ // C++20 [dcl.inline]/7
+ // If an inline function or variable that is attached to a named module
+ // is declared in a definition domain, it shall be defined in that
+ // domain.
+ // So, if the current declaration does not have a definition, we must
+ // check at the end of the TU (or when the PMF starts) to see that we
+ // have a definition at that point.
+ if (isInline && !D.isFunctionDefinition() && getLangOpts().CPlusPlus20 &&
+ NewFD->hasOwningModule() &&
+ NewFD->getOwningModule()->isModulePurview()) {
+ PendingInlineFuncDecls.insert(NewFD);
+ }
}
// Filter out previous declarations that don't match the scope.
@@ -9900,6 +10138,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->dropAttr<SectionAttr>();
}
+ // Apply an implicit StrictGuardStackCheckAttr if #pragma strict_gs_check is
+ // active.
+ if (StrictGuardStackCheckStack.CurrentValue && D.isFunctionDefinition() &&
+ !NewFD->hasAttr<StrictGuardStackCheckAttr>())
+ NewFD->addAttr(StrictGuardStackCheckAttr::CreateImplicit(
+ Context, PragmaClangTextSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
+
// Apply an implicit CodeSegAttr from class declspec or
// apply an implicit SectionAttr from #pragma code_seg if active.
if (!NewFD->hasAttr<CodeSegAttr>()) {
@@ -9911,14 +10157,49 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
+ if (NewTVA && !NewTVA->isDefaultVersion() &&
+ !Context.getTargetInfo().hasFeature("fmv")) {
+ // Don't add to scope fmv functions declarations if fmv disabled
+ AddToScope = false;
+ return NewFD;
+ }
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
if (AddressSpace != LangAS::Default) {
- Diag(NewFD->getLocation(),
- diag::err_opencl_return_value_with_address_space);
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
+ NewFD->setInvalidDecl();
+ }
+ }
+
+ if (getLangOpts().HLSL) {
+ auto &TargetInfo = getASTContext().getTargetInfo();
+ // Skip operator overload which not identifier.
+ // Also make sure NewFD is in translation-unit scope.
+ if (!NewFD->isInvalidDecl() && Name.isIdentifier() &&
+ NewFD->getName() == TargetInfo.getTargetOpts().HLSLEntry &&
+ S->getDepth() == 0) {
+ 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);
+ }
+ }
+ // HLSL does not support specifying an address space on a function return
+ // type.
+ LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
+ if (AddressSpace != LangAS::Default) {
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
NewFD->setInvalidDecl();
}
}
@@ -10091,7 +10372,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setRedeclaration(true);
}
- assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
+ assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() ||
+ !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
@@ -10253,16 +10535,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(NewFD->getLocation(),
diag::err_attribute_overloadable_no_prototype)
<< NewFD;
-
- // Turn this into a variadic function with no parameters.
- const auto *FT = NewFD->getType()->castAs<FunctionType>();
- FunctionProtoType::ExtProtoInfo EPI(
- Context.getDefaultCallingConvention(true, false));
- EPI.Variadic = true;
- EPI.ExtInfo = FT->getExtInfo();
-
- QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI);
- NewFD->setType(R);
+ NewFD->dropAttr<OverloadableAttr>();
}
// If there's a #pragma GCC visibility in scope, and this isn't a class
@@ -10344,7 +10617,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
llvm::SmallPtrSet<const Type *, 16> ValidTypes;
- for (auto Param : NewFD->parameters())
+ for (auto *Param : NewFD->parameters())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
if (getLangOpts().OpenCLCPlusPlus) {
@@ -10360,6 +10633,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (getLangOpts().CPlusPlus) {
+ // Precalculate whether this is a friend function template with a constraint
+ // that depends on an enclosing template, per [temp.friend]p9.
+ if (isFriend && FunctionTemplate &&
+ FriendConstraintsDependOnEnclosingTemplate(NewFD))
+ NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
+
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
@@ -10482,7 +10761,7 @@ static Attr *getImplicitCodeSegAttrFromClass(Sema &S, const FunctionDecl *FD) {
/// (from the current #pragma code-seg value).
///
/// \param FD Function being declared.
-/// \param IsDefinition Whether it is a definition or just a declarartion.
+/// \param IsDefinition Whether it is a definition or just a declaration.
/// \returns A CodeSegAttr or SectionAttr to apply to the function or
/// nullptr if no attribute should be added.
Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
@@ -10566,37 +10845,53 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
PrevVD->getType());
}
-/// Check the target attribute of the function for MultiVersion
-/// validity.
+/// Check the target or target_version attribute of the function for
+/// MultiVersion validity.
///
/// Returns true if there was an error, false otherwise.
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
const auto *TA = FD->getAttr<TargetAttr>();
- assert(TA && "MultiVersion Candidate requires a target attribute");
- ParsedTargetAttr ParseInfo = TA->parse();
+ const auto *TVA = FD->getAttr<TargetVersionAttr>();
+ assert(
+ (TA || TVA) &&
+ "MultiVersion candidate requires a target or target_version attribute");
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
enum ErrType { Feature = 0, Architecture = 1 };
- if (!ParseInfo.Architecture.empty() &&
- !TargetInfo.validateCpuIs(ParseInfo.Architecture)) {
- S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Architecture << ParseInfo.Architecture;
- return true;
- }
-
- for (const auto &Feat : ParseInfo.Features) {
- auto BareFeat = StringRef{Feat}.substr(1);
- if (Feat[0] == '-') {
+ if (TA) {
+ ParsedTargetAttr ParseInfo =
+ S.getASTContext().getTargetInfo().parseTargetAttr(TA->getFeaturesStr());
+ if (!ParseInfo.CPU.empty() && !TargetInfo.validateCpuIs(ParseInfo.CPU)) {
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Feature << ("no-" + BareFeat).str();
+ << Architecture << ParseInfo.CPU;
return true;
}
+ for (const auto &Feat : ParseInfo.Features) {
+ auto BareFeat = StringRef{Feat}.substr(1);
+ if (Feat[0] == '-') {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << ("no-" + BareFeat).str();
+ return true;
+ }
- if (!TargetInfo.validateCpuSupports(BareFeat) ||
- !TargetInfo.isValidFeatureName(BareFeat)) {
- S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Feature << BareFeat;
- return true;
+ if (!TargetInfo.validateCpuSupports(BareFeat) ||
+ !TargetInfo.isValidFeatureName(BareFeat)) {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << BareFeat;
+ return true;
+ }
+ }
+ }
+
+ if (TVA) {
+ llvm::SmallVector<StringRef, 8> Feats;
+ TVA->getFeatures(Feats);
+ for (const auto &Feat : Feats) {
+ if (!TargetInfo.validateCpuSupports(Feat)) {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << Feat;
+ return true;
+ }
}
}
return false;
@@ -10643,6 +10938,10 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S,
if (MVKind != MultiVersionKind::Target)
return Diagnose(S, A);
break;
+ case attr::TargetVersion:
+ if (MVKind != MultiVersionKind::TargetVersion)
+ return Diagnose(S, A);
+ break;
case attr::TargetClones:
if (MVKind != MultiVersionKind::TargetClones)
return Diagnose(S, A);
@@ -10815,18 +11114,18 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
/// This sets NewFD->isInvalidDecl() to true if there was an error.
///
/// Returns true if there was an error, false otherwise.
-static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD,
- MultiVersionKind MVKind,
- const TargetAttr *TA) {
+static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
+ MultiVersionKind MVKind = FD->getMultiVersionKind();
assert(MVKind != MultiVersionKind::None &&
"Function lacks multiversion attribute");
-
- // Target only causes MV if it is default, otherwise this is a normal
- // function.
- if (MVKind == MultiVersionKind::Target && !TA->isDefaultVersion())
+ const auto *TA = FD->getAttr<TargetAttr>();
+ const auto *TVA = FD->getAttr<TargetVersionAttr>();
+ // Target and target_version only causes MV if it is default, otherwise this
+ // is a normal function.
+ if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion()))
return false;
- if (MVKind == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) {
+ if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
return true;
}
@@ -10849,23 +11148,27 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
return false;
}
-static bool CheckTargetCausesMultiVersioning(
- Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA,
- bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
+static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
+ FunctionDecl *NewFD,
+ bool &Redeclaration,
+ NamedDecl *&OldDecl,
+ LookupResult &Previous) {
+ const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *OldTA = OldFD->getAttr<TargetAttr>();
- ParsedTargetAttr NewParsed = NewTA->parse();
- // Sort order doesn't matter, it just needs to be consistent.
- llvm::sort(NewParsed.Features);
-
+ const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
- if (!NewTA->isDefaultVersion() &&
- (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
+ if ((NewTA && !NewTA->isDefaultVersion() &&
+ (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) ||
+ (NewTVA && !NewTVA->isDefaultVersion() &&
+ (!OldTVA || OldTVA->getName() == NewTVA->getName())))
return false;
// Otherwise, this decl causes MultiVersioning.
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true,
- MultiVersionKind::Target)) {
+ NewTVA ? MultiVersionKind::TargetVersion
+ : MultiVersionKind::Target)) {
NewFD->setInvalidDecl();
return true;
}
@@ -10876,7 +11179,9 @@ static bool CheckTargetCausesMultiVersioning(
}
// If this is 'default', permit the forward declaration.
- if (!OldFD->isMultiVersion() && !OldTA && NewTA->isDefaultVersion()) {
+ if (!OldFD->isMultiVersion() &&
+ ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
+ (NewTVA && NewTVA->isDefaultVersion() && !OldTVA))) {
Redeclaration = true;
OldDecl = OldFD;
OldFD->setIsMultiVersion();
@@ -10890,23 +11195,50 @@ static bool CheckTargetCausesMultiVersioning(
return true;
}
- ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>());
+ if (NewTA) {
+ ParsedTargetAttr OldParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ OldTA->getFeaturesStr());
+ llvm::sort(OldParsed.Features);
+ ParsedTargetAttr NewParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ NewTA->getFeaturesStr());
+ // Sort order doesn't matter, it just needs to be consistent.
+ llvm::sort(NewParsed.Features);
+ if (OldParsed == NewParsed) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
+ }
- if (OldParsed == NewParsed) {
- S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
- S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
- NewFD->setInvalidDecl();
- return true;
+ if (NewTVA) {
+ llvm::SmallVector<StringRef, 8> Feats;
+ OldTVA->getFeatures(Feats);
+ llvm::sort(Feats);
+ llvm::SmallVector<StringRef, 8> NewFeats;
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+
+ if (Feats == NewFeats) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
}
for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
+ const auto *CurTVA = FD->getAttr<TargetVersionAttr>();
// We allow forward declarations before ANY multiversioning attributes, but
// nothing after the fact.
if (PreviousDeclsHaveMultiVersionAttribute(FD) &&
- (!CurTA || CurTA->isInherited())) {
+ ((NewTA && (!CurTA || CurTA->isInherited())) ||
+ (NewTVA && (!CurTVA || CurTVA->isInherited())))) {
S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl)
- << 0;
+ << (NewTA ? 0 : 2);
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
NewFD->setInvalidDecl();
return true;
@@ -10937,11 +11269,11 @@ static bool MultiVersionTypesCompatible(MultiVersionKind Old,
/// multiversioned declaration collection.
static bool CheckMultiVersionAdditionalDecl(
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD,
- MultiVersionKind NewMVKind, const TargetAttr *NewTA,
- const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec,
- const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl,
- LookupResult &Previous) {
-
+ MultiVersionKind NewMVKind, const CPUDispatchAttr *NewCPUDisp,
+ const CPUSpecificAttr *NewCPUSpec, const TargetClonesAttr *NewClones,
+ bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
+ const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
MultiVersionKind OldMVKind = OldFD->getMultiVersionKind();
// Disallow mixing of multiversioning types.
if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) {
@@ -10953,9 +11285,15 @@ static bool CheckMultiVersionAdditionalDecl(
ParsedTargetAttr NewParsed;
if (NewTA) {
- NewParsed = NewTA->parse();
+ NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr(
+ NewTA->getFeaturesStr());
llvm::sort(NewParsed.Features);
}
+ llvm::SmallVector<StringRef, 8> NewFeats;
+ if (NewTVA) {
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+ }
bool UseMemberUsingDeclRules =
S.CurContext->isRecord() && !NewFD->getFriendObjectKind();
@@ -10963,16 +11301,30 @@ static bool CheckMultiVersionAdditionalDecl(
bool MayNeedOverloadableChecks =
AllowOverloadingOfFunction(Previous, S.Context, NewFD);
- // Next, check ALL non-overloads to see if this is a redeclaration of a
- // previous member of the MultiVersion set.
+ // Next, check ALL non-invalid non-overloads to see if this is a redeclaration
+ // of a previous member of the MultiVersion set.
for (NamedDecl *ND : Previous) {
FunctionDecl *CurFD = ND->getAsFunction();
- if (!CurFD)
+ if (!CurFD || CurFD->isInvalidDecl())
continue;
if (MayNeedOverloadableChecks &&
S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
continue;
+ if (NewMVKind == MultiVersionKind::None &&
+ OldMVKind == MultiVersionKind::TargetVersion) {
+ NewFD->addAttr(TargetVersionAttr::CreateImplicit(
+ S.Context, "default", NewFD->getSourceRange(),
+ AttributeCommonInfo::AS_GNU));
+ NewFD->setIsMultiVersion();
+ NewMVKind = MultiVersionKind::TargetVersion;
+ if (!NewTVA) {
+ NewTVA = NewFD->getAttr<TargetVersionAttr>();
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+ }
+ }
+
switch (NewMVKind) {
case MultiVersionKind::None:
assert(OldMVKind == MultiVersionKind::TargetClones &&
@@ -10987,7 +11339,10 @@ static bool CheckMultiVersionAdditionalDecl(
return false;
}
- ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>());
+ ParsedTargetAttr CurParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ CurTA->getFeaturesStr());
+ llvm::sort(CurParsed.Features);
if (CurParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
@@ -10996,6 +11351,27 @@ static bool CheckMultiVersionAdditionalDecl(
}
break;
}
+ case MultiVersionKind::TargetVersion: {
+ const auto *CurTVA = CurFD->getAttr<TargetVersionAttr>();
+ if (CurTVA->getName() == NewTVA->getName()) {
+ NewFD->setIsMultiVersion();
+ Redeclaration = true;
+ OldDecl = ND;
+ return false;
+ }
+ llvm::SmallVector<StringRef, 8> CurFeats;
+ if (CurTVA) {
+ CurTVA->getFeatures(CurFeats);
+ llvm::sort(CurFeats);
+ }
+ if (CurFeats == NewFeats) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
+ break;
+ }
case MultiVersionKind::TargetClones: {
const auto *CurClones = CurFD->getAttr<TargetClonesAttr>();
Redeclaration = true;
@@ -11078,7 +11454,8 @@ static bool CheckMultiVersionAdditionalDecl(
// Else, this is simply a non-redecl case. Checking the 'value' is only
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
// handled in the attribute adding step.
- if (NewMVKind == MultiVersionKind::Target &&
+ if ((NewMVKind == MultiVersionKind::TargetVersion ||
+ NewMVKind == MultiVersionKind::Target) &&
CheckMultiVersionValue(S, NewFD)) {
NewFD->setInvalidDecl();
return true;
@@ -11116,16 +11493,20 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
bool &Redeclaration, NamedDecl *&OldDecl,
LookupResult &Previous) {
const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>();
const auto *NewClones = NewFD->getAttr<TargetClonesAttr>();
MultiVersionKind MVKind = NewFD->getMultiVersionKind();
// Main isn't allowed to become a multiversion function, however it IS
- // permitted to have 'main' be marked with the 'target' optimization hint.
+ // permitted to have 'main' be marked with the 'target' optimization hint,
+ // for 'target_version' only default is allowed.
if (NewFD->isMain()) {
if (MVKind != MultiVersionKind::None &&
- !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion())) {
+ !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion()) &&
+ !(MVKind == MultiVersionKind::TargetVersion &&
+ NewTVA->isDefaultVersion())) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main);
NewFD->setInvalidDecl();
return true;
@@ -11140,18 +11521,34 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
// multiversioning, this isn't an error condition.
if (MVKind == MultiVersionKind::None)
return false;
- return CheckMultiVersionFirstFunction(S, NewFD, MVKind, NewTA);
+ return CheckMultiVersionFirstFunction(S, NewFD);
}
FunctionDecl *OldFD = OldDecl->getAsFunction();
- if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
+ if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) {
+ // No target_version attributes mean default
+ if (!NewTVA) {
+ const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
+ if (OldTVA) {
+ NewFD->addAttr(TargetVersionAttr::CreateImplicit(
+ S.Context, "default", NewFD->getSourceRange(),
+ AttributeCommonInfo::AS_GNU));
+ NewFD->setIsMultiVersion();
+ OldFD->setIsMultiVersion();
+ OldDecl = OldFD;
+ Redeclaration = true;
+ return true;
+ }
+ }
return false;
+ }
// Multiversioned redeclarations aren't allowed to omit the attribute, except
- // for target_clones.
+ // for target_clones and target_version.
if (OldFD->isMultiVersion() && MVKind == MultiVersionKind::None &&
- OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) {
+ OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones &&
+ OldFD->getMultiVersionKind() != MultiVersionKind::TargetVersion) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl)
<< (OldFD->getMultiVersionKind() != MultiVersionKind::Target);
NewFD->setInvalidDecl();
@@ -11161,8 +11558,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
if (!OldFD->isMultiVersion()) {
switch (MVKind) {
case MultiVersionKind::Target:
- return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
- Redeclaration, OldDecl, Previous);
+ case MultiVersionKind::TargetVersion:
+ return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration,
+ OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
@@ -11170,6 +11568,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
}
OldFD->setIsMultiVersion();
break;
+
case MultiVersionKind::CPUDispatch:
case MultiVersionKind::CPUSpecific:
case MultiVersionKind::None:
@@ -11180,9 +11579,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
// At this point, we have a multiversion function decl (in OldFD) AND an
// appropriate attribute in the current function decl. Resolve that these are
// still compatible with previous declarations.
- return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewTA,
- NewCPUDisp, NewCPUSpec, NewClones,
- Redeclaration, OldDecl, Previous);
+ return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewCPUDisp,
+ NewCPUSpec, NewClones, Redeclaration,
+ OldDecl, Previous);
}
/// Perform semantic checking of a new function declaration.
@@ -11410,16 +11809,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
} else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = Destructor->getParent();
- QualType ClassType = Context.getTypeDeclType(Record);
-
- // FIXME: Shouldn't we be able to perform this check even when the class
- // type is dependent? Both gcc and edg can handle that.
- if (!ClassType->isDependentType()) {
- DeclarationName Name
- = Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(ClassType));
+ dyn_cast<CXXDestructorDecl>(NewFD)) {
+ // We check here for invalid destructor names.
+ // If we have a friend destructor declaration that is dependent, we can't
+ // diagnose right away because cases like this are still valid:
+ // template <class T> struct A { friend T::X::~Y(); };
+ // struct B { struct Y { ~Y(); }; using X = Y; };
+ // template struct A<B>;
+ if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None ||
+ !Destructor->getThisType()->isDependentType()) {
+ CXXRecordDecl *Record = Destructor->getParent();
+ QualType ClassType = Context.getTypeDeclType(Record);
+
+ DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
if (NewFD->getDeclName() != Name) {
Diag(NewFD->getLocation(), diag::err_destructor_name);
NewFD->setInvalidDecl();
@@ -11756,6 +12159,34 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
}
}
+void Sema::CheckHLSLEntryPoint(FunctionDecl *FD) {
+ auto &TargetInfo = getASTContext().getTargetInfo();
+ auto const Triple = TargetInfo.getTriple();
+ switch (Triple.getEnvironment()) {
+ default:
+ // FIXME: check all shader profiles.
+ break;
+ case llvm::Triple::EnvironmentType::Compute:
+ if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
+ Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
+ << Triple.getEnvironmentName();
+ FD->setInvalidDecl();
+ }
+ break;
+ }
+
+ for (const auto *Param : FD->parameters()) {
+ if (!Param->hasAttr<HLSLAnnotationAttr>()) {
+ // FIXME: Handle struct parameters where annotations are on struct fields.
+ // See: https://github.com/llvm/llvm-project/issues/57875
+ Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
+ Diag(Param->getLocation(), diag::note_previous_decl) << Param;
+ FD->setInvalidDecl();
+ }
+ }
+ // FIXME: Verify return type semantic annotation.
+}
+
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
// FIXME: Need strict checking. In C89, we need to check for
// any assignment, increment, decrement, function-calls, or
@@ -11822,7 +12253,7 @@ namespace {
// Track and increment the index here.
isInitList = true;
InitFieldIndex.push_back(0);
- for (auto Child : InitList->children()) {
+ for (auto *Child : InitList->children()) {
CheckExpr(cast<Expr>(Child));
++InitFieldIndex.back();
}
@@ -12224,7 +12655,10 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
Type.getQualifiers());
QualType DeducedType;
- if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+ TemplateDeductionInfo Info(DeduceInit->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) {
if (!IsInitCapture)
DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
else if (isa<InitListExpr>(Init))
@@ -12303,7 +12737,7 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
InitType.hasNonTrivialToPrimitiveCopyCUnion()) &&
"shouldn't be called if type doesn't have a non-trivial C struct");
if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
- for (auto I : ILE->inits()) {
+ for (auto *I : ILE->inits()) {
if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() &&
!I->getType().hasNonTrivialToPrimitiveCopyCUnion())
continue;
@@ -12621,8 +13055,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}
+ // C99 6.7.8p5. If the declaration of an identifier has block scope, and
+ // the identifier has external or internal linkage, the declaration shall
+ // have no initializer for the identifier.
+ // C++14 [dcl.init]p5 is the same restriction for C++.
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
- // C99 6.7.8p5. C++ has no such restriction, but that is a defect.
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
VDecl->setInvalidDecl();
return;
@@ -12648,6 +13085,16 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
VDecl->setInvalidDecl();
}
+ // C++ [module.import/6] external definitions are not permitted in header
+ // units.
+ if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
+ VDecl->isThisDeclarationADefinition() &&
+ VDecl->getFormalLinkage() == Linkage::ExternalLinkage &&
+ !VDecl->isInline()) {
+ Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit);
+ VDecl->setInvalidDecl();
+ }
+
// If adding the initializer will turn this declaration into a definition,
// and we already have a definition for this variable, diagnose or otherwise
// handle the situation.
@@ -12722,6 +13169,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Perform the initialization.
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+ bool IsParenListInit = false;
if (!VDecl->isInvalidDecl()) {
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
InitializationKind Kind = InitializationKind::CreateForInit(
@@ -12764,6 +13212,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
Init = Result.getAs<Expr>();
+ IsParenListInit = !InitSeq.steps().empty() &&
+ InitSeq.step_begin()->Kind ==
+ InitializationSequence::SK_ParenthesizedListInit;
}
// Check for self-references within variable initializers.
@@ -13012,7 +13463,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// class type.
if (CXXDirectInit) {
assert(DirectInit && "Call-style initializer must be direct init.");
- VDecl->setInitStyle(VarDecl::CallInit);
+ VDecl->setInitStyle(IsParenListInit ? VarDecl::ParenListInit
+ : VarDecl::CallInit);
} else if (DirectInit) {
// This must be list-initialization. No other way is direct-initialization.
VDecl->setInitStyle(VarDecl::ListInit);
@@ -13177,7 +13629,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// that has an in-class initializer, so we type-check this like
// a declaration.
//
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case VarDecl::DeclarationOnly:
// It's only a declaration.
@@ -13247,8 +13699,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// Provide a specific diagnostic for uninitialized variable
// definitions with incomplete array type.
if (Type->isIncompleteArrayType()) {
- Diag(Var->getLocation(),
- diag::err_typecheck_incomplete_array_needs_initializer);
+ if (Var->isConstexpr())
+ Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init)
+ << Var;
+ else
+ Diag(Var->getLocation(),
+ diag::err_typecheck_incomplete_array_needs_initializer);
Var->setInvalidDecl();
return;
}
@@ -13332,8 +13788,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
InitializationKind Kind
= InitializationKind::CreateDefault(Var->getLocation());
- InitializationSequence InitSeq(*this, Entity, Kind, None);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None);
+ InitializationSequence InitSeq(*this, Entity, Kind, std::nullopt);
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, std::nullopt);
if (Init.get()) {
Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
@@ -13499,7 +13955,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
// Cache the result of checking for constant initialization.
- Optional<bool> CacheHasConstInit;
+ std::optional<bool> CacheHasConstInit;
const Expr *CacheCulprit = nullptr;
auto checkConstInit = [&]() mutable {
if (!CacheHasConstInit)
@@ -13770,6 +14226,26 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
}
}
+void Sema::CheckThreadLocalForLargeAlignment(VarDecl *VD) {
+ assert(VD->getTLSKind());
+
+ // Perform TLS alignment check here after attributes attached to the variable
+ // which may affect the alignment have been processed. Only perform the check
+ // if the target has a maximum TLS alignment (zero means no constraints).
+ if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+ // Protect the check so that it's not performed on dependent types and
+ // dependent alignments (we can't determine the alignment in that case).
+ if (!VD->hasDependentAlignment()) {
+ CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
+ if (Context.getDeclAlign(VD) > MaxAlignChars) {
+ Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
+ << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
+ << (unsigned)MaxAlignChars.getQuantity();
+ }
+ }
+ }
+}
+
/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
/// any semantic actions necessary after any initializer has been attached.
void Sema::FinalizeDeclaration(Decl *ThisDecl) {
@@ -13813,25 +14289,12 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
checkAttributesAfterMerging(*this, *VD);
- // Perform TLS alignment check here after attributes attached to the variable
- // which may affect the alignment have been processed. Only perform the check
- // if the target has a maximum TLS alignment (zero means no constraints).
- if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
- // Protect the check so that it's not performed on dependent types and
- // dependent alignments (we can't determine the alignment in that case).
- if (VD->getTLSKind() && !VD->hasDependentAlignment()) {
- CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
- if (Context.getDeclAlign(VD) > MaxAlignChars) {
- Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
- << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
- << (unsigned)MaxAlignChars.getQuantity();
- }
- }
- }
-
if (VD->isStaticLocal())
CheckStaticLocalForDllExport(VD);
+ if (VD->getTLSKind())
+ CheckThreadLocalForLargeAlignment(VD);
+
// Perform check for initializers of device-side global variables.
// CUDA allows empty constructors as initializers (see E.2.3.1, CUDA
// 7.5). We must also apply the same checks to all __shared__
@@ -13917,7 +14380,7 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!MagicValueExpr) {
continue;
}
- Optional<llvm::APSInt> MagicValueInt;
+ std::optional<llvm::APSInt> MagicValueInt;
if (!(MagicValueInt = MagicValueExpr->getIntegerConstantExpr(Context))) {
Diag(I->getRange().getBegin(),
diag::err_type_tag_for_datatype_not_ice)
@@ -14462,6 +14925,21 @@ void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
Consumer.HandleInlineFunctionDefinition(D);
}
+static bool FindPossiblePrototype(const FunctionDecl *FD,
+ const FunctionDecl *&PossiblePrototype) {
+ for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ // Ignore any declarations that occur in function or method
+ // scope, because they aren't visible from the header.
+ if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
+ continue;
+
+ PossiblePrototype = Prev;
+ return Prev->getType()->isFunctionProtoType();
+ }
+ return false;
+}
+
static bool
ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
const FunctionDecl *&PossiblePrototype) {
@@ -14508,16 +14986,9 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (!FD->isExternallyVisible())
return false;
- for (const FunctionDecl *Prev = FD->getPreviousDecl();
- Prev; Prev = Prev->getPreviousDecl()) {
- // Ignore any declarations that occur in function or method
- // scope, because they aren't visible from the header.
- if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
- continue;
-
- PossiblePrototype = Prev;
- return Prev->getType()->isFunctionNoProtoType();
- }
+ // If we were able to find a potential prototype, don't warn.
+ if (FindPossiblePrototype(FD, PossiblePrototype))
+ return false;
return true;
}
@@ -14604,7 +15075,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
auto I = LambdaClass->field_begin();
for (const auto &C : LambdaClass->captures()) {
if (C.capturesVariable()) {
- VarDecl *VD = C.getCapturedVar();
+ ValueDecl *VD = C.getCapturedVar();
if (VD->isInitCapture())
S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
const bool ByRef = C.getCaptureKind() == LCK_ByRef;
@@ -14646,8 +15117,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// Do not push if it is a lambda because one is already pushed when building
// the lambda in ActOnStartOfLambdaDefinition().
if (!isLambdaCallOperator(FD))
+ // [expr.const]/p14.1
+ // An expression or conversion is in an immediate function context if it is
+ // potentially evaluated and either: its innermost enclosing non-block scope
+ // is a function parameter scope of an immediate function.
PushExpressionEvaluationContext(
- FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated
+ FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext
: ExprEvalContexts.back().Context);
// Check for defining attributes before the check for redefinition.
@@ -14661,6 +15136,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
FD->dropAttr<IFuncAttr>();
FD->setInvalidDecl();
}
+ if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
+ if (!Context.getTargetInfo().hasFeature("fmv") &&
+ !Attr->isDefaultVersion()) {
+ // If function multi versioning disabled skip parsing function body
+ // defined with non-default target_version attribute
+ if (SkipBody)
+ SkipBody->ShouldSkip = true;
+ return nullptr;
+ }
+ }
if (auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
if (Ctor->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
@@ -14757,7 +15242,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
}
// Introduce our parameters into the function scope
- for (auto Param : FD->parameters()) {
+ for (auto *Param : FD->parameters()) {
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
@@ -14768,6 +15253,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
}
}
+ // C++ [module.import/6] external definitions are not permitted in header
+ // units. Deleted and Defaulted functions are implicitly inline (but the
+ // inline state is not set at this point, so check the BodyKind explicitly).
+ // FIXME: Consider an alternate location for the test where the inlined()
+ // state is complete.
+ if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
+ FD->getFormalLinkage() == Linkage::ExternalLinkage &&
+ !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete &&
+ BodyKind != FnBodyKind::Default && !FD->isInlined()) {
+ assert(FD->isThisDeclarationADefinition());
+ Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
+ FD->setInvalidDecl();
+ }
+
// Ensure that the function's exception specification is instantiated.
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(D->getLocation(), FPT);
@@ -15081,6 +15580,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
}
+ // We might not have found a prototype because we didn't wish to warn on
+ // the lack of a missing prototype. Try again without the checks for
+ // whether we want to warn on the missing prototype.
+ if (!PossiblePrototype)
+ (void)FindPossiblePrototype(FD, PossiblePrototype);
+
// If the function being defined does not have a prototype, then we may
// need to diagnose it as changing behavior in C2x because we now know
// whether the function accepts arguments or not. This only handles the
@@ -15405,8 +15910,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// Because typo correction is expensive, only do it if the implicit
// function declaration is going to be treated as an error.
//
- // Perform the corection before issuing the main diagnostic, as some consumers
- // use typo-correction callbacks to enhance the main diagnostic.
+ // Perform the correction before issuing the main diagnostic, as some
+ // consumers use typo-correction callbacks to enhance the main diagnostic.
if (S && !ExternCPrev &&
(Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error)) {
DeclFilterCCC<FunctionDecl> CCC{};
@@ -15459,8 +15964,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
- /*DeclsInPrototype=*/None, Loc,
- Loc, D),
+ /*DeclsInPrototype=*/std::nullopt,
+ Loc, Loc, D),
std::move(DS.getAttributes()), SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -15488,7 +15993,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
FD->getDeclName().getCXXOverloadedOperator() != OO_Array_New)
return;
- Optional<unsigned> AlignmentParam;
+ std::optional<unsigned> AlignmentParam;
bool IsNothrow = false;
if (!FD->isReplaceableGlobalAllocationFunction(&AlignmentParam, &IsNothrow))
return;
@@ -15529,7 +16034,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
// specified by the value of this argument.
if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) {
FD->addAttr(AllocAlignAttr::CreateImplicit(
- Context, ParamIdx(AlignmentParam.value(), FD), FD->getLocation()));
+ Context, ParamIdx(*AlignmentParam, FD), FD->getLocation()));
}
// FIXME:
@@ -15594,11 +16099,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->addAttr(CallbackAttr::CreateImplicit(
Context, Encoding.data(), Encoding.size(), FD->getLocation()));
- // Mark const if we don't care about errno and that is the only thing
- // preventing the function from being const. This allows IRgen to use LLVM
- // intrinsics for such functions.
- if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() &&
- Context.BuiltinInfo.isConstWithoutErrno(BuiltinID))
+ // Mark const if we don't care about errno and/or floating point exceptions
+ // that are the only thing preventing the function from being const. This
+ // allows IRgen to use LLVM intrinsics for such functions.
+ bool NoExceptions =
+ getLangOpts().getDefaultExceptionMode() == LangOptions::FPE_Ignore;
+ bool ConstWithoutErrnoAndExceptions =
+ Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
+ bool ConstWithoutExceptions =
+ Context.BuiltinInfo.isConstWithoutExceptions(BuiltinID);
+ if (!FD->hasAttr<ConstAttr>() &&
+ (ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) &&
+ (!ConstWithoutErrnoAndExceptions ||
+ (!getLangOpts().MathErrno && NoExceptions)) &&
+ (!ConstWithoutExceptions || NoExceptions))
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
// We make "fma" on GNU or Windows const because we know it does not set
@@ -15674,6 +16188,24 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
default:
break;
}
+
+ // Add lifetime attribute to std::move, std::fowrard et al.
+ switch (BuiltinID) {
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BI__builtin_addressof:
+ case Builtin::BIas_const:
+ case Builtin::BIforward:
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ if (ParmVarDecl *P = FD->getParamDecl(0u);
+ !P->hasAttr<LifetimeBoundAttr>())
+ P->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ break;
+ default:
+ break;
+ }
}
AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
@@ -16075,17 +16607,17 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC,
///
/// \param SkipBody If non-null, will be set to indicate if the caller should
/// skip the definition of this tag and treat it as if it were a declaration.
-Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
- const ParsedAttributesView &Attrs, AccessSpecifier AS,
- SourceLocation ModulePrivateLoc,
- MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent,
- SourceLocation ScopedEnumKWLoc,
- bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
- bool IsTypeSpecifier, bool IsTemplateParamOrArg,
- SkipBodyInfo *SkipBody) {
+DeclResult
+Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
+ CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
+ const ParsedAttributesView &Attrs, AccessSpecifier AS,
+ SourceLocation ModulePrivateLoc,
+ MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl,
+ bool &IsDependent, SourceLocation ScopedEnumKWLoc,
+ bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ OffsetOfKind OOK, UsingShadowDecl *&FoundUsingShadow,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -16111,7 +16643,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TUK == TUK_Friend, isMemberSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
- return nullptr;
+ return true;
}
if (TemplateParams->size() > 0) {
@@ -16119,7 +16651,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// be a member of another template).
if (Invalid)
- return nullptr;
+ return true;
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(
@@ -16138,7 +16670,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!TemplateParameterLists.empty() && isMemberSpecialization &&
CheckTemplateDeclScope(S, TemplateParameterLists.back()))
- return nullptr;
+ return true;
}
// Figure out the underlying type if this a enum declaration. We need to do
@@ -16210,7 +16742,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
else
ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
QualType EnumTy = ED->getIntegerType();
- ED->setPromotionType(EnumTy->isPromotableIntegerType()
+ ED->setPromotionType(Context.isPromotableIntegerType(EnumTy)
? Context.getPromotedIntegerType(EnumTy)
: EnumTy);
}
@@ -16254,26 +16786,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DC = computeDeclContext(SS, false);
if (!DC) {
IsDependent = true;
- return nullptr;
+ return true;
}
} else {
DC = computeDeclContext(SS, true);
if (!DC) {
Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
<< SS.getRange();
- return nullptr;
+ return true;
}
}
if (RequireCompleteDeclContext(SS, DC))
- return nullptr;
+ return true;
SearchDC = DC;
// Look-up name inside 'foo::'.
LookupQualifiedName(Previous, DC);
if (Previous.isAmbiguous())
- return nullptr;
+ return true;
if (Previous.empty()) {
// Name lookup did not find anything. However, if the
@@ -16285,7 +16817,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.wasNotFoundInCurrentInstantiation() &&
(TUK == TUK_Reference || TUK == TUK_Friend)) {
IsDependent = true;
- return nullptr;
+ return true;
}
// A tag 'foo::bar' must already exist.
@@ -16302,7 +16834,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// -- every member of class T that is itself a type
if (TUK != TUK_Reference && TUK != TUK_Friend &&
DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc)))
- return nullptr;
+ return true;
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
@@ -16366,7 +16898,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
- return nullptr;
+ return true;
if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated
@@ -16520,6 +17052,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// 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(
@@ -16836,7 +17369,7 @@ CreateNewDecl:
else
ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
QualType EnumTy = ED->getIntegerType();
- ED->setPromotionType(EnumTy->isPromotableIntegerType()
+ ED->setPromotionType(Context.isPromotableIntegerType(EnumTy)
? Context.getPromotedIntegerType(EnumTy)
: EnumTy);
assert(ED->isComplete() && "enum with type should be complete");
@@ -16858,10 +17391,14 @@ CreateNewDecl:
cast_or_null<RecordDecl>(PrevDecl));
}
+ if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus)
+ Diag(New->getLocation(), diag::ext_type_defined_in_offsetof)
+ << (OOK == OOK_Macro) << New->getSourceRange();
+
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
- TUK == TUK_Definition) {
+ if (!Invalid && getLangOpts().CPlusPlus &&
+ (IsTypeSpecifier || IsTemplateParamOrArg) && TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
@@ -17017,7 +17554,7 @@ CreateNewDecl:
if (New->isBeingDefined())
if (auto RD = dyn_cast<RecordDecl>(New))
RD->completeDefinition();
- return nullptr;
+ return true;
} else if (SkipBody && SkipBody->ShouldSkip) {
return SkipBody->Previous;
} else {
@@ -17805,7 +18342,6 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
AllIvarDecls.push_back(Ivar);
}
-namespace {
/// [class.dtor]p4:
/// At the end of the definition of a class, overload resolution is
/// performed among the prospective destructors declared in that class with
@@ -17814,7 +18350,7 @@ namespace {
///
/// We do the overload resolution here, then mark the selected constructor in the AST.
/// Later CXXRecordDecl::getDestructor() will return the selected constructor.
-void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
+static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
if (!Record->hasUserDeclaredDestructor()) {
return;
}
@@ -17872,7 +18408,145 @@ void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(OCS.begin()->Function));
}
}
-} // namespace
+
+/// [class.mem.special]p5
+/// Two special member functions are of the same kind if:
+/// - they are both default constructors,
+/// - they are both copy or move constructors with the same first parameter
+/// type, or
+/// - they are both copy or move assignment operators with the same first
+/// parameter type and the same cv-qualifiers and ref-qualifier, if any.
+static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context,
+ CXXMethodDecl *M1,
+ CXXMethodDecl *M2,
+ Sema::CXXSpecialMember CSM) {
+ // We don't want to compare templates to non-templates: See
+ // https://github.com/llvm/llvm-project/issues/59206
+ if (CSM == Sema::CXXDefaultConstructor)
+ return bool(M1->getDescribedFunctionTemplate()) ==
+ bool(M2->getDescribedFunctionTemplate());
+ if (!Context.hasSameType(M1->getParamDecl(0)->getType(),
+ M2->getParamDecl(0)->getType()))
+ return false;
+ if (!Context.hasSameType(M1->getThisType(), M2->getThisType()))
+ return false;
+
+ return true;
+}
+
+/// [class.mem.special]p6:
+/// An eligible special member function is a special member function for which:
+/// - the function is not deleted,
+/// - the associated constraints, if any, are satisfied, and
+/// - no special member function of the same kind whose associated constraints
+/// [CWG2595], if any, are satisfied is more constrained.
+static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
+ ArrayRef<CXXMethodDecl *> Methods,
+ Sema::CXXSpecialMember CSM) {
+ SmallVector<bool, 4> SatisfactionStatus;
+
+ for (CXXMethodDecl *Method : Methods) {
+ const Expr *Constraints = Method->getTrailingRequiresClause();
+ if (!Constraints)
+ SatisfactionStatus.push_back(true);
+ else {
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckFunctionConstraints(Method, Satisfaction))
+ SatisfactionStatus.push_back(false);
+ else
+ SatisfactionStatus.push_back(Satisfaction.IsSatisfied);
+ }
+ }
+
+ for (size_t i = 0; i < Methods.size(); i++) {
+ if (!SatisfactionStatus[i])
+ continue;
+ CXXMethodDecl *Method = Methods[i];
+ CXXMethodDecl *OrigMethod = Method;
+ if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction())
+ OrigMethod = cast<CXXMethodDecl>(MF);
+
+ const Expr *Constraints = OrigMethod->getTrailingRequiresClause();
+ bool AnotherMethodIsMoreConstrained = false;
+ for (size_t j = 0; j < Methods.size(); j++) {
+ if (i == j || !SatisfactionStatus[j])
+ continue;
+ CXXMethodDecl *OtherMethod = Methods[j];
+ if (FunctionDecl *MF = OtherMethod->getInstantiatedFromMemberFunction())
+ OtherMethod = cast<CXXMethodDecl>(MF);
+
+ if (!AreSpecialMemberFunctionsSameKind(S.Context, OrigMethod, OtherMethod,
+ CSM))
+ continue;
+
+ const Expr *OtherConstraints = OtherMethod->getTrailingRequiresClause();
+ if (!OtherConstraints)
+ continue;
+ if (!Constraints) {
+ AnotherMethodIsMoreConstrained = true;
+ break;
+ }
+ if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod,
+ {Constraints},
+ AnotherMethodIsMoreConstrained)) {
+ // There was an error with the constraints comparison. Exit the loop
+ // and don't consider this function eligible.
+ AnotherMethodIsMoreConstrained = true;
+ }
+ if (AnotherMethodIsMoreConstrained)
+ break;
+ }
+ // FIXME: Do not consider deleted methods as eligible after implementing
+ // DR1734 and DR1496.
+ if (!AnotherMethodIsMoreConstrained) {
+ Method->setIneligibleOrNotSelected(false);
+ Record->addedEligibleSpecialMemberFunction(Method, 1 << CSM);
+ }
+ }
+}
+
+static void ComputeSpecialMemberFunctionsEligiblity(Sema &S,
+ CXXRecordDecl *Record) {
+ SmallVector<CXXMethodDecl *, 4> DefaultConstructors;
+ SmallVector<CXXMethodDecl *, 4> CopyConstructors;
+ SmallVector<CXXMethodDecl *, 4> MoveConstructors;
+ SmallVector<CXXMethodDecl *, 4> CopyAssignmentOperators;
+ SmallVector<CXXMethodDecl *, 4> MoveAssignmentOperators;
+
+ for (auto *Decl : Record->decls()) {
+ auto *MD = dyn_cast<CXXMethodDecl>(Decl);
+ if (!MD) {
+ auto *FTD = dyn_cast<FunctionTemplateDecl>(Decl);
+ if (FTD)
+ MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
+ }
+ if (!MD)
+ continue;
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (CD->isInvalidDecl())
+ continue;
+ if (CD->isDefaultConstructor())
+ DefaultConstructors.push_back(MD);
+ else if (CD->isCopyConstructor())
+ CopyConstructors.push_back(MD);
+ else if (CD->isMoveConstructor())
+ MoveConstructors.push_back(MD);
+ } else if (MD->isCopyAssignmentOperator()) {
+ CopyAssignmentOperators.push_back(MD);
+ } else if (MD->isMoveAssignmentOperator()) {
+ MoveAssignmentOperators.push_back(MD);
+ }
+ }
+
+ SetEligibleMethods(S, Record, DefaultConstructors,
+ Sema::CXXDefaultConstructor);
+ SetEligibleMethods(S, Record, CopyConstructors, Sema::CXXCopyConstructor);
+ SetEligibleMethods(S, Record, MoveConstructors, Sema::CXXMoveConstructor);
+ SetEligibleMethods(S, Record, CopyAssignmentOperators,
+ Sema::CXXCopyAssignment);
+ SetEligibleMethods(S, Record, MoveAssignmentOperators,
+ Sema::CXXMoveAssignment);
+}
void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
ArrayRef<Decl *> Fields, SourceLocation LBrac,
@@ -17900,9 +18574,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(EnclosingDecl);
- if (CXXRecord && !CXXRecord->isDependentType())
- ComputeSelectedDestructor(*this, CXXRecord);
-
// Start counting up the number of named members; make sure to include
// members of anonymous structs and unions in the total.
unsigned NumNamedMembers = 0;
@@ -18188,6 +18859,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Completed = true;
}
}
+ ComputeSelectedDestructor(*this, CXXRecord);
+ ComputeSpecialMemberFunctionsEligiblity(*this, CXXRecord);
}
}
@@ -18910,7 +19583,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
}
}
- // If we have have an empty set of enumerators we still need one bit.
+ // If we have an empty set of enumerators we still need one bit.
// From [dcl.enum]p8
// If the enumerator-list is empty, the values of the enumeration are as if
// the enumeration had a single enumerator with value 0
@@ -18942,7 +19615,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// target, promote that type instead of analyzing the enumerators.
if (Enum->isComplete()) {
BestType = Enum->getIntegerType();
- if (BestType->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(BestType))
BestPromotionType = Context.getPromotedIntegerType(BestType);
else
BestPromotionType = BestType;
@@ -19107,6 +19780,12 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
+Decl *Sema::ActOnTopLevelStmtDecl(Stmt *Statement) {
+ auto *New = TopLevelStmtDecl::Create(Context, Statement);
+ Context.getTranslationUnitDecl()->addDecl(New);
+ return New;
+}
+
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,
@@ -19129,7 +19808,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
else
Diag(PrevDecl->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/(isa<FunctionDecl>(PrevDecl) ? 0 : 1) << PrevDecl;
- // Otherwise, add a label atttibute to ExtnameUndeclaredIdentifiers.
+ // Otherwise, add a label attribute to ExtnameUndeclaredIdentifiers.
} else
(void)ExtnameUndeclaredIdentifiers.insert(std::make_pair(Name, Attr));
}
@@ -19195,7 +19874,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
if (LangOpts.OpenMPIsDevice) {
// In OpenMP device mode we will not emit host only functions, or functions
// we don't need due to their linkage.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
// DevTy may be changed later by
// #pragma omp declare target to(*) device_type(*).
@@ -19217,7 +19896,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
// In OpenMP host compilation prior to 5.0 everything was an emitted host
// function. In 5.0, no_host was introduced which might cause a function to
// be ommitted.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
if (DevTy)
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 838fd48357fb..a303c7f57280 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DarwinSDKInfo.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -38,7 +39,6 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Assumptions.h"
@@ -46,6 +46,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -201,7 +202,7 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
/// A helper function to provide Attribute Location for the Attr types
/// AND the ParsedAttr.
template <typename AttrInfo>
-static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>
+static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation>
getAttrLoc(const AttrInfo &AL) {
return AL.getLocation();
}
@@ -216,7 +217,7 @@ template <typename AttrInfo>
static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
uint32_t &Val, unsigned Idx = UINT_MAX,
bool StrictlyUnsigned = false) {
- Optional<llvm::APSInt> I = llvm::APSInt(32);
+ std::optional<llvm::APSInt> I = llvm::APSInt(32);
if (Expr->isTypeDependent() ||
!(I = Expr->getIntegerConstantExpr(S.Context))) {
if (Idx != UINT_MAX)
@@ -308,7 +309,7 @@ static bool checkFunctionOrMethodParameterIndex(
unsigned NumParams =
(HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
- Optional<llvm::APSInt> IdxInt;
+ std::optional<llvm::APSInt> IdxInt;
if (IdxExpr->isTypeDependent() ||
!(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) {
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
@@ -1689,7 +1690,7 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
}
if (!E->isValueDependent()) {
- Optional<llvm::APSInt> I = llvm::APSInt(64);
+ std::optional<llvm::APSInt> I = llvm::APSInt(64);
if (!(I = E->getIntegerConstantExpr(Context))) {
if (OE)
Diag(AttrLoc, diag::err_attribute_argument_n_type)
@@ -1876,8 +1877,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
// Cannot have two ownership attributes of different kinds for the same
// index.
- if (I->getOwnKind() != K && I->args_end() !=
- std::find(I->args_begin(), I->args_end(), Idx)) {
+ if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I;
return;
} else if (K == OwnershipAttr::Returns &&
@@ -2329,6 +2329,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t priority = ConstructorAttr::DefaultPriority;
+ if (S.getLangOpts().HLSL && AL.getNumArgs()) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
+ return;
+ }
if (AL.getNumArgs() &&
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
@@ -2630,7 +2634,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (II->isStr("fuchsia")) {
- Optional<unsigned> Min, Sub;
+ std::optional<unsigned> Min, Sub;
if ((Min = Introduced.Version.getMinor()) ||
(Sub = Introduced.Version.getSubminor())) {
S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor);
@@ -2672,8 +2676,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (IOSToWatchOSMapping) {
if (auto MappedVersion = IOSToWatchOSMapping->map(
- Version, MinimumWatchOSVersion, None)) {
- return MappedVersion.value();
+ Version, MinimumWatchOSVersion, std::nullopt)) {
+ return *MappedVersion;
}
}
@@ -2682,10 +2686,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewMajor >= 2) {
if (Version.getMinor()) {
if (Version.getSubminor())
- return VersionTuple(NewMajor, Version.getMinor().value(),
- Version.getSubminor().value());
+ return VersionTuple(NewMajor, *Version.getMinor(),
+ *Version.getSubminor());
else
- return VersionTuple(NewMajor, Version.getMinor().value());
+ return VersionTuple(NewMajor, *Version.getMinor());
}
return VersionTuple(NewMajor);
}
@@ -2727,8 +2731,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return Version;
if (IOSToTvOSMapping) {
- if (auto MappedVersion =
- IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) {
+ if (auto MappedVersion = IOSToTvOSMapping->map(
+ Version, VersionTuple(0, 0), std::nullopt)) {
return *MappedVersion;
}
}
@@ -2791,24 +2795,25 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// attributes that are inferred from 'ios'.
NewII = &S.Context.Idents.get("maccatalyst");
auto RemapMacOSVersion =
- [&](const VersionTuple &V) -> Optional<VersionTuple> {
+ [&](const VersionTuple &V) -> std::optional<VersionTuple> {
if (V.empty())
- return None;
+ return std::nullopt;
// API_TO_BE_DEPRECATED is 100000.
if (V.getMajor() == 100000)
return VersionTuple(100000);
// The minimum iosmac version is 13.1
- return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), None);
+ return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1),
+ std::nullopt);
};
- Optional<VersionTuple> NewIntroduced =
- RemapMacOSVersion(Introduced.Version),
- NewDeprecated =
- RemapMacOSVersion(Deprecated.Version),
- NewObsoleted =
- RemapMacOSVersion(Obsoleted.Version);
+ std::optional<VersionTuple> NewIntroduced =
+ RemapMacOSVersion(Introduced.Version),
+ NewDeprecated =
+ RemapMacOSVersion(Deprecated.Version),
+ NewObsoleted =
+ RemapMacOSVersion(Obsoleted.Version);
if (NewIntroduced || NewDeprecated || NewObsoleted) {
auto VersionOrEmptyVersion =
- [](const Optional<VersionTuple> &V) -> VersionTuple {
+ [](const std::optional<VersionTuple> &V) -> VersionTuple {
return V ? *V : VersionTuple();
};
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
@@ -3032,7 +3037,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
if (AL.getNumArgs() > 0) {
Expr *E = AL.getArgAsExpr(0);
- Optional<llvm::APSInt> Idx = llvm::APSInt(32);
+ std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -3051,7 +3056,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos;
if (AL.getNumArgs() > 1) {
Expr *E = AL.getArgAsExpr(1);
- Optional<llvm::APSInt> Idx = llvm::APSInt(32);
+ std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -3146,7 +3151,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
if (LO.CPlusPlus && !LO.CPlusPlus20)
S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL;
- // Since this this is spelled [[nodiscard]], get the optional string
+ // Since this is spelled [[nodiscard]], get the optional string
// literal. If in C++ mode, but not in C++2a mode, diagnose as an
// extension.
// FIXME: C2x should support this feature as well, even as an extension.
@@ -3391,7 +3396,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// handled later in the process, once we know how many exist.
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
enum FirstParam { Unsupported, Duplicate, Unknown };
- enum SecondParam { None, Architecture, Tune };
+ enum SecondParam { None, CPU, Tune };
enum ThirdParam { Target, TargetClones };
if (AttrStr.contains("fpmath="))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
@@ -3403,24 +3408,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "tune=" << Target;
- ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+ ParsedTargetAttr ParsedAttrs =
+ Context.getTargetInfo().parseTargetAttr(AttrStr);
- if (!ParsedAttrs.Architecture.empty() &&
- !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
+ if (!ParsedAttrs.CPU.empty() &&
+ !Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Unknown << Architecture << ParsedAttrs.Architecture << Target;
+ << Unknown << CPU << ParsedAttrs.CPU << Target;
if (!ParsedAttrs.Tune.empty() &&
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unknown << Tune << ParsedAttrs.Tune << Target;
- if (ParsedAttrs.DuplicateArchitecture)
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Duplicate << None << "arch=" << Target;
- if (ParsedAttrs.DuplicateTune)
+ if (ParsedAttrs.Duplicate != "")
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Duplicate << None << "tune=" << Target;
+ << Duplicate << None << ParsedAttrs.Duplicate << Target;
for (const auto &Feature : ParsedAttrs.Features) {
auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
@@ -3434,8 +3437,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
if (ParsedAttrs.BranchProtection.empty())
return false;
if (!Context.getTargetInfo().validateBranchProtection(
- ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI,
- DiagMsg)) {
+ ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) {
if (DiagMsg.empty())
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "branch-protection" << Target;
@@ -3448,6 +3450,42 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return false;
}
+// Check Target Version attrs
+bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr,
+ bool &isDefault) {
+ enum FirstParam { Unsupported };
+ enum SecondParam { None };
+ enum ThirdParam { Target, TargetClones, TargetVersion };
+ if (AttrStr.trim() == "default")
+ isDefault = true;
+ llvm::SmallVector<StringRef, 8> Features;
+ AttrStr.split(Features, "+");
+ for (auto &CurFeature : Features) {
+ CurFeature = CurFeature.trim();
+ if (CurFeature == "default")
+ continue;
+ if (!Context.getTargetInfo().validateCpuSupports(CurFeature))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature << TargetVersion;
+ }
+ return false;
+}
+
+static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ bool isDefault = false;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
+ S.checkTargetVersionAttr(LiteralLoc, Str, isDefault))
+ return;
+ // Do not create default only target_version attribute
+ if (!isDefault) {
+ TargetVersionAttr *NewAttr =
+ ::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
+ D->addAttr(NewAttr);
+ }
+}
+
static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
@@ -3459,12 +3497,12 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
-bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
- const StringLiteral *Literal,
- bool &HasDefault, bool &HasCommas,
- SmallVectorImpl<StringRef> &Strings) {
+bool Sema::checkTargetClonesAttrString(
+ SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal,
+ bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
+ SmallVectorImpl<SmallString<64>> &StringsBuffer) {
enum FirstParam { Unsupported, Duplicate, Unknown };
- enum SecondParam { None, Architecture, Tune };
+ enum SecondParam { None, CPU, Tune };
enum ThirdParam { Target, TargetClones };
HasCommas = HasCommas || Str.contains(',');
// Warn on empty at the beginning of a string.
@@ -3481,29 +3519,75 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
getLangOpts(), Context.getTargetInfo());
bool DefaultIsDupe = false;
+ bool HasCodeGenImpact = false;
if (Cur.empty())
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "" << TargetClones;
- if (Cur.startswith("arch=")) {
- if (!Context.getTargetInfo().isValidCPUName(
- Cur.drop_front(sizeof("arch=") - 1)))
+ if (Context.getTargetInfo().getTriple().isAArch64()) {
+ // AArch64 target clones specific
+ if (Cur == "default") {
+ DefaultIsDupe = HasDefault;
+ HasDefault = true;
+ if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ else
+ StringsBuffer.push_back(Cur);
+ } else {
+ std::pair<StringRef, StringRef> CurParts = {{}, Cur};
+ llvm::SmallVector<StringRef, 8> CurFeatures;
+ while (!CurParts.second.empty()) {
+ CurParts = CurParts.second.split('+');
+ StringRef CurFeature = CurParts.first.trim();
+ if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) {
+ Diag(CurLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature << TargetClones;
+ continue;
+ }
+ std::string Options;
+ if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options))
+ HasCodeGenImpact = true;
+ CurFeatures.push_back(CurFeature);
+ }
+ // Canonize TargetClones Attributes
+ llvm::sort(CurFeatures);
+ SmallString<64> Res;
+ for (auto &CurFeat : CurFeatures) {
+ if (!Res.equals(""))
+ Res.append("+");
+ Res.append(CurFeat);
+ }
+ if (llvm::is_contained(StringsBuffer, Res) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ else if (!HasCodeGenImpact)
+ // Ignore features in target_clone attribute that don't impact
+ // code generation
+ Diag(CurLoc, diag::warn_target_clone_no_impact_options);
+ else if (!Res.empty()) {
+ StringsBuffer.push_back(Res);
+ HasNotDefault = true;
+ }
+ }
+ } else {
+ // Other targets ( currently X86 )
+ if (Cur.startswith("arch=")) {
+ if (!Context.getTargetInfo().isValidCPUName(
+ Cur.drop_front(sizeof("arch=") - 1)))
+ return Diag(CurLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1)
+ << TargetClones;
+ } else if (Cur == "default") {
+ DefaultIsDupe = HasDefault;
+ HasDefault = true;
+ } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << Architecture
- << Cur.drop_front(sizeof("arch=") - 1) << TargetClones;
- } else if (Cur == "default") {
- DefaultIsDupe = HasDefault;
- HasDefault = true;
- } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
- return Diag(CurLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << None << Cur << TargetClones;
-
- if (llvm::is_contained(Strings, Cur) || DefaultIsDupe)
- Diag(CurLoc, diag::warn_target_clone_duplicate_options);
- // Note: Add even if there are duplicates, since it changes name mangling.
- Strings.push_back(Cur);
+ << Unsupported << None << Cur << TargetClones;
+ if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ // Note: Add even if there are duplicates, since it changes name mangling.
+ StringsBuffer.push_back(Cur);
+ }
}
-
if (Str.rtrim().endswith(","))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "" << TargetClones;
@@ -3511,6 +3595,10 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
}
static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (S.Context.getTargetInfo().getTriple().isAArch64() &&
+ !S.Context.getTargetInfo().hasFeature("fmv"))
+ return;
+
// Ensure we don't combine these with themselves, since that causes some
// confusing behavior.
if (const auto *Other = D->getAttr<TargetClonesAttr>()) {
@@ -3522,7 +3610,8 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
SmallVector<StringRef, 2> Strings;
- bool HasCommas = false, HasDefault = false;
+ SmallVector<SmallString<64>, 2> StringsBuffer;
+ bool HasCommas = false, HasDefault = false, HasNotDefault = false;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
StringRef CurStr;
@@ -3531,13 +3620,21 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.checkTargetClonesAttrString(
LiteralLoc, CurStr,
cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()),
- HasDefault, HasCommas, Strings))
+ HasDefault, HasCommas, HasNotDefault, StringsBuffer))
return;
}
+ for (auto &SmallStr : StringsBuffer)
+ Strings.push_back(SmallStr.str());
if (HasCommas && AL.getNumArgs() > 1)
S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values);
+ if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) {
+ // Add default attribute if there is no one
+ HasDefault = true;
+ Strings.push_back("default");
+ }
+
if (!HasDefault) {
S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default);
return;
@@ -3554,6 +3651,10 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+ // No multiversion if we have default version only.
+ if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasNotDefault)
+ return;
+
cast<FunctionDecl>(D)->setIsMultiVersion();
TargetClonesAttr *NewAttr = ::new (S.Context)
TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size());
@@ -3730,6 +3831,11 @@ 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;
+ }
if (S.getCurFunctionOrMethodDecl()) {
S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
@@ -3884,27 +3990,38 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3))
return;
- // check if the function is variadic if the 3rd argument non-zero
+ // FirstArg == 0 is is always valid.
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(D))
- ++NumArgs; // +1 for ...
- else
- S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
- }
-
- // strftime requires FirstArg to be 0 because it doesn't read from any
- // variable the input is just the current time + the format string.
- if (Kind == StrftimeFormat) {
- if (FirstArg != 0) {
+ if (Kind == StrftimeFormat) {
+ // If the kind is strftime, FirstArg must be 0 because strftime does not
+ // use any variadic arguments.
S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter)
- << FirstArgExpr->getSourceRange();
- return;
+ << FirstArgExpr->getSourceRange()
+ << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), "0");
+ return;
+ } else if (isFunctionOrMethodVariadic(D)) {
+ // Else, if the function is variadic, then FirstArg must be 0 or the
+ // "position" of the ... parameter. It's unusual to use 0 with variadic
+ // functions, so the fixit proposes the latter.
+ if (FirstArg != NumArgs + 1) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << 3 << FirstArgExpr->getSourceRange()
+ << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(),
+ std::to_string(NumArgs + 1));
+ return;
+ }
+ } else {
+ // Inescapable GCC compatibility diagnostic.
+ S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
+ if (FirstArg <= Idx) {
+ // Else, the function is not variadic, and FirstArg must be 0 or any
+ // parameter after the format parameter. We don't offer a fixit because
+ // there are too many possible good values.
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << 3 << FirstArgExpr->getSourceRange();
+ return;
+ }
}
- // if 0 it disables parameter checking (to use with e.g. va_list)
- } else if (FirstArg != 0 && FirstArg != NumArgs) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << 3 << FirstArgExpr->getSourceRange();
- return;
}
FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
@@ -4335,7 +4452,7 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
}
const auto *VD = dyn_cast<VarDecl>(D);
- if (VD && Context.getTargetInfo().isTLSSupported()) {
+ if (VD) {
unsigned MaxTLSAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign())
.getQuantity();
@@ -4500,7 +4617,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
break;
case 7:
if (Str == "pointer")
- DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ DestWidth = S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
break;
case 11:
if (Str == "unwind_word")
@@ -5388,7 +5505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
if (E->isValueDependent())
return E;
- Optional<llvm::APSInt> I = llvm::APSInt(64);
+ std::optional<llvm::APSInt> I = llvm::APSInt(64);
if (!(I = E->getIntegerConstantExpr(S.Context))) {
S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type)
<< &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -5543,9 +5660,10 @@ static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
const char *IntrinNames) {
if (AliasName.startswith("__arm_"))
AliasName = AliasName.substr(6);
- const IntrinToName *It = std::lower_bound(
- Map.begin(), Map.end(), BuiltinID,
- [](const IntrinToName &L, unsigned Id) { return L.Id < Id; });
+ const IntrinToName *It =
+ llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
+ return L.Id < Id;
+ });
if (It == Map.end() || It->Id != BuiltinID)
return false;
StringRef FullName(&IntrinNames[It->FullName]);
@@ -6433,9 +6551,9 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
}
StringRef CurrentParam;
- llvm::Optional<unsigned> SelfLocation;
+ std::optional<unsigned> SelfLocation;
unsigned NewValueCount = 0;
- llvm::Optional<unsigned> NewValueLocation;
+ std::optional<unsigned> NewValueLocation;
do {
std::tie(CurrentParam, Parameters) = Parameters.split(':');
@@ -6813,12 +6931,12 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
using llvm::Triple;
Triple Target = S.Context.getTargetInfo().getTriple();
+ auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification,
Triple::Library},
- Target.getEnvironment())) {
+ Env)) {
uint32_t Pipeline =
- (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
- (uint32_t)llvm::Triple::Pixel;
+ static_cast<uint32_t>(hlsl::getStageFromEnvironment(Env));
S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
<< AL << Pipeline << "Compute, Amplification, Mesh or Library";
return;
@@ -6885,8 +7003,35 @@ HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
using llvm::Triple;
+ auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
+ if (Env != Triple::Compute && Env != Triple::Library) {
+ // FIXME: it is OK for a compute shader entry and pixel shader entry live in
+ // same HLSL file. Issue https://github.com/llvm/llvm-project/issues/57880.
+ ShaderStage Pipeline = hlsl::getStageFromEnvironment(Env);
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
+ << AL << (uint32_t)Pipeline << "Compute";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
+}
+
+static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
+ if (!T->hasUnsignedIntegerRepresentation())
+ return false;
+ if (const auto *VT = T->getAs<VectorType>())
+ return VT->getNumElements() <= 3;
+ return true;
+}
+
+static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ using llvm::Triple;
Triple Target = S.Context.getTargetInfo().getTriple();
- if (Target.getEnvironment() != Triple::Compute) {
+ // FIXME: it is OK for a compute shader entry and pixel shader entry live in
+ // same HLSL file.Issue https://github.com/llvm/llvm-project/issues/57880.
+ if (Target.getEnvironment() != Triple::Compute &&
+ Target.getEnvironment() != Triple::Library) {
uint32_t Pipeline =
(uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
(uint32_t)llvm::Triple::Pixel;
@@ -6895,7 +7040,25 @@ static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
+ // FIXME: report warning and ignore semantic when cannot apply on the Decl.
+ // See https://github.com/llvm/llvm-project/issues/57916.
+
+ // FIXME: support semantic on field.
+ // See https://github.com/llvm/llvm-project/issues/57889.
+ if (isa<FieldDecl>(D)) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
+ << AL << "parameter";
+ return;
+ }
+
+ auto *VD = cast<ValueDecl>(D);
+ if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
+ << AL << "uint/uint2/uint3";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
}
static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6905,7 +7068,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
HLSLShaderAttr::ShaderType ShaderType;
- if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
+ if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType) ||
+ // Library is added to help convert HLSLShaderAttr::ShaderType to
+ // llvm::Triple::EnviromentType. It is not a legal
+ // HLSLShaderAttr::ShaderType.
+ ShaderType == HLSLShaderAttr::Library) {
S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
<< AL << Str << ArgLoc;
return;
@@ -6931,6 +7098,78 @@ Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
return HLSLShaderAttr::Create(Context, ShaderType, AL);
}
+static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ StringRef Space = "space0";
+ StringRef Slot = "";
+
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *Loc = AL.getArgAsIdent(0);
+ StringRef Str = Loc->Ident->getName();
+ SourceLocation ArgLoc = Loc->Loc;
+
+ SourceLocation SpaceArgLoc;
+ if (AL.getNumArgs() == 2) {
+ Slot = Str;
+ if (!AL.isArgIdent(1)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *Loc = AL.getArgAsIdent(1);
+ Space = Loc->Ident->getName();
+ SpaceArgLoc = Loc->Loc;
+ } else {
+ Slot = Str;
+ }
+
+ // Validate.
+ if (!Slot.empty()) {
+ switch (Slot[0]) {
+ case 'u':
+ case 'b':
+ case 's':
+ case 't':
+ break;
+ default:
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
+ << Slot.substr(0, 1);
+ return;
+ }
+
+ StringRef SlotNum = Slot.substr(1);
+ unsigned Num = 0;
+ if (SlotNum.getAsInteger(10, Num)) {
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
+ return;
+ }
+ }
+
+ if (!Space.startswith("space")) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNum = Space.substr(5);
+ unsigned Num = 0;
+ if (SpaceNum.getAsInteger(10, Num)) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+
+ // FIXME: check reg type match decl. Issue
+ // https://github.com/llvm/llvm-project/issues/57886.
+ HLSLResourceBindingAttr *NewAttr =
+ HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
@@ -7050,7 +7289,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- Optional<llvm::APSInt> NumParams = llvm::APSInt(32);
+ std::optional<llvm::APSInt> NumParams = llvm::APSInt(32);
if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant
@@ -7252,7 +7491,7 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
// Add preserve_access_index attribute to all fields and inner records.
- for (auto D : RD->decls()) {
+ for (auto *D : RD->decls()) {
if (D->hasAttr<BPFPreserveAccessIndexAttr>())
continue;
@@ -7874,8 +8113,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SanitizerName != "coverage")
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName))
- S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedFunctionOrMethod;
+ S.Diag(D->getLocation(), diag::warn_attribute_type_not_supported_global)
+ << AL << SanitizerName;
Sanitizers.push_back(SanitizerName);
}
@@ -8458,6 +8697,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_X86ForceAlignArgPointer:
handleX86ForceAlignArgPointerAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ReadOnlyPlacement:
+ handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_DLLExport:
case ParsedAttr::AT_DLLImport:
handleDLLAttr(S, D, AL);
@@ -8634,6 +8876,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_NoEscape:
handleNoEscapeAttr(S, D, AL);
break;
+ case ParsedAttr::AT_MaybeUndef:
+ handleSimpleAttribute<MaybeUndefAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_AssumeAligned:
handleAssumeAlignedAttr(S, D, AL);
break;
@@ -8761,6 +9006,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Target:
handleTargetAttr(S, D, AL);
break;
+ case ParsedAttr::AT_TargetVersion:
+ handleTargetVersionAttr(S, D, AL);
+ break;
case ParsedAttr::AT_TargetClones:
handleTargetClonesAttr(S, D, AL);
break;
@@ -8904,9 +9152,15 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_GroupIndex:
handleHLSLSVGroupIndexAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
+ break;
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLResourceBinding:
+ handleHLSLResourceBindingAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 221cbd14da97..348092fc62e8 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17,6 +17,8 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -44,6 +46,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include <map>
+#include <optional>
#include <set>
using namespace clang;
@@ -86,7 +89,11 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
/// determine whether this declaration can be used in the default
/// argument expression.
bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
- const NamedDecl *Decl = DRE->getDecl();
+ const ValueDecl *Decl = dyn_cast<ValueDecl>(DRE->getDecl());
+
+ if (!isa<VarDecl, BindingDecl>(Decl))
+ return false;
+
if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
// C++ [dcl.fct.default]p9:
// [...] parameters of a function shall not be used in default
@@ -100,7 +107,7 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
- } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) {
+ } else if (auto *VD = Decl->getPotentiallyDecomposedVarDecl()) {
// C++ [dcl.fct.default]p7:
// Local variables shall not be used in default argument
// expressions.
@@ -110,14 +117,14 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
// expression in a default argument.
//
// C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346):
- // Note: A local variable cannot be odr-used (6.3) in a default argument.
+ // Note: A local variable cannot be odr-used (6.3) in a default
+ // argument.
//
- if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
+ if (VD->isLocalVarDecl() && !DRE->isNonOdrUse())
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_local)
- << VDecl->getDeclName() << DefaultArg->getSourceRange();
+ << Decl << DefaultArg->getSourceRange();
}
-
return false;
}
@@ -147,13 +154,20 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
}
bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
- // C++11 [expr.lambda.prim]p13:
- // A lambda-expression appearing in a default argument shall not
- // implicitly or explicitly capture any entity.
- if (Lambda->capture_begin() == Lambda->capture_end())
- return false;
-
- return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg);
+ // [expr.prim.lambda.capture]p9
+ // a lambda-expression appearing in a default argument cannot implicitly or
+ // explicitly capture any local entity. Such a lambda-expression can still
+ // have an init-capture if any full-expression in its initializer satisfies
+ // the constraints of an expression appearing in a default argument.
+ bool Invalid = false;
+ for (const LambdaCapture &LC : Lambda->captures()) {
+ if (!Lambda->isInitCapture(&LC))
+ return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg);
+ // Init captures are always VarDecl.
+ auto *D = cast<VarDecl>(LC.getCapturedVar());
+ Invalid |= Visit(D->getInit());
+ }
+ return Invalid;
}
} // namespace
@@ -744,11 +758,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// C++17 [dcl.dcl]/8:
// The decl-specifier-seq shall contain only the type-specifier auto
// and cv-qualifiers.
- // C++2a [dcl.dcl]/8:
+ // 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:
+ // 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();
{
+ // Note: While constrained-auto needs to be checked, we do so separately so
+ // we can emit a better diagnostic.
SmallVector<StringRef, 8> BadSpecifiers;
SmallVector<SourceLocation, 8> BadSpecifierLocs;
SmallVector<StringRef, 8> CPlusPlus20Specifiers;
@@ -775,6 +794,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
BadSpecifiers.push_back("inline");
BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
}
+
if (!BadSpecifiers.empty()) {
auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
Err << (int)BadSpecifiers.size()
@@ -835,6 +855,20 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
D.setInvalidType();
}
+ // Constrained auto is prohibited by [decl.pre]p6, so check that here.
+ if (DS.isConstrainedAuto()) {
+ TemplateIdAnnotation *TemplRep = DS.getRepAsTemplateId();
+ assert(TemplRep->Kind == TNK_Concept_template &&
+ "No other template kind should be possible for a constrained auto");
+
+ SourceRange TemplRange{TemplRep->TemplateNameLoc,
+ TemplRep->RAngleLoc.isValid()
+ ? TemplRep->RAngleLoc
+ : TemplRep->TemplateNameLoc};
+ Diag(TemplRep->TemplateNameLoc, diag::err_decomp_decl_constraint)
+ << TemplRange << FixItHint::CreateRemoval(TemplRange);
+ }
+
// Build the BindingDecls.
SmallVector<BindingDecl*, 8> Bindings;
@@ -1229,7 +1263,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
- E = S.BuildCallExpr(nullptr, E.get(), Loc, None, Loc);
+ E = S.BuildCallExpr(nullptr, E.get(), Loc, std::nullopt, Loc);
} else {
// Otherwise, the initializer is get<i-1>(e), where get is looked up
// in the associated namespaces.
@@ -3084,7 +3118,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
return;
if (MD && !MD->isVirtual()) {
- // If we have a non-virtual method, check if if hides a virtual method.
+ // If we have a non-virtual method, check if it hides a virtual method.
// (In that case, it's most likely the method has the wrong type.)
SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
FindHiddenVirtualMethods(MD, OverloadedMethods);
@@ -3776,7 +3810,7 @@ namespace {
void CheckInitListExpr(InitListExpr *ILE) {
InitFieldIndex.push_back(0);
- for (auto Child : ILE->children()) {
+ for (auto *Child : ILE->children()) {
if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) {
CheckInitListExpr(SubList);
} else {
@@ -3847,7 +3881,7 @@ namespace {
Expr *Callee = E->getCallee();
if (isa<MemberExpr>(Callee)) {
HandleValue(Callee, false /*AddressOf*/);
- for (auto Arg : E->arguments())
+ for (auto *Arg : E->arguments())
Visit(Arg);
return;
}
@@ -3872,7 +3906,7 @@ namespace {
return Inherited::VisitCXXOperatorCallExpr(E);
Visit(Callee);
- for (auto Arg : E->arguments())
+ for (auto *Arg : E->arguments())
HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/);
}
@@ -4023,6 +4057,21 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) {
return ConstraintExpr;
}
+ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD,
+ Expr *InitExpr,
+ SourceLocation InitLoc) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
+ InitializationKind Kind =
+ FD->getInClassInitStyle() == ICIS_ListInit
+ ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(),
+ InitExpr->getBeginLoc(),
+ InitExpr->getEndLoc())
+ : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc);
+ InitializationSequence Seq(*this, Entity, Kind, InitExpr);
+ return Seq.Perform(*this, Entity, Kind, InitExpr);
+}
+
/// This is invoked after parsing an in-class initializer for a
/// non-static C++ class member, and after instantiating an in-class initializer
/// in a class template. Such actions are deferred until the class is complete.
@@ -4049,36 +4098,23 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
return;
}
- ExprResult Init = InitExpr;
- if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
- InitializationKind Kind =
- FD->getInClassInitStyle() == ICIS_ListInit
- ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(),
- InitExpr->getBeginLoc(),
- InitExpr->getEndLoc())
- : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc);
- InitializationSequence Seq(*this, Entity, Kind, InitExpr);
- Init = Seq.Perform(*this, Entity, Kind, InitExpr);
+ ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr,
+ /*RecoverUncorrectedTypos=*/true);
+ assert(Init.isUsable() && "Init should at least have a RecoveryExpr");
+ if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) {
+ Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc);
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ if (!Init.isInvalid())
+ Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false);
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
}
}
- // C++11 [class.base.init]p7:
- // The initialization of each base and member constitutes a
- // full-expression.
- Init = ActOnFinishFullExpr(Init.get(), InitLoc, /*DiscardedValue*/ false);
- if (Init.isInvalid()) {
- FD->setInvalidDecl();
- return;
- }
-
- InitExpr = Init.get();
-
- FD->setInClassInitializer(InitExpr);
+ FD->setInClassInitializer(Init.get());
}
/// Find the direct and/or virtual base specifiers that
@@ -4308,11 +4344,21 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) {
- auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>();
- if (UnqualifiedBase) {
- Diag(IdLoc, diag::ext_unqualified_base_class)
- << SourceRange(IdLoc, Init->getSourceRange().getEnd());
- BaseType = UnqualifiedBase->getInjectedClassNameSpecialization();
+ if (auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>()) {
+ auto *TempSpec = cast<TemplateSpecializationType>(
+ UnqualifiedBase->getInjectedClassNameSpecialization());
+ TemplateName TN = TempSpec->getTemplateName();
+ for (auto const &Base : ClassDecl->bases()) {
+ auto BaseTemplate =
+ Base.getType()->getAs<TemplateSpecializationType>();
+ if (BaseTemplate && Context.hasSameTemplateName(
+ BaseTemplate->getTemplateName(), TN)) {
+ Diag(IdLoc, diag::ext_unqualified_base_class)
+ << SourceRange(IdLoc, Init->getSourceRange().getEnd());
+ BaseType = Base.getType();
+ break;
+ }
+ }
}
}
@@ -4362,17 +4408,13 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
if (BaseType.isNull()) {
- BaseType = Context.getTypeDeclType(TyD);
+ BaseType = getElaboratedType(ETK_None, SS, Context.getTypeDeclType(TyD));
MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false);
- if (SS.isSet()) {
- BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(),
- BaseType);
- TInfo = Context.CreateTypeSourceInfo(BaseType);
- ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
- TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
- TL.setElaboratedKeywordLoc(SourceLocation());
- TL.setQualifierLoc(SS.getWithLocInContext(Context));
- }
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
}
}
@@ -4468,10 +4510,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
CXXRecordDecl *ClassDecl) {
- SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation NameLoc = TInfo->getTypeLoc().getSourceRange().getBegin();
if (!LangOpts.CPlusPlus11)
return Diag(NameLoc, diag::err_delegating_ctor)
- << TInfo->getTypeLoc().getLocalSourceRange();
+ << TInfo->getTypeLoc().getSourceRange();
Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);
bool InitList = true;
@@ -4532,12 +4574,11 @@ MemInitResult
Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
Expr *Init, CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc) {
- SourceLocation BaseLoc
- = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getBeginLoc();
if (!BaseType->isDependentType() && !BaseType->isRecordType())
return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -4595,8 +4636,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
Dependent = true;
else
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << Context.getTypeDeclType(ClassDecl)
- << BaseTInfo->getTypeLoc().getLocalSourceRange();
+ << BaseType << Context.getTypeDeclType(ClassDecl)
+ << BaseTInfo->getTypeLoc().getSourceRange();
}
}
@@ -4670,10 +4711,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Create a static_cast\<T&&>(expr).
-static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
- if (T.isNull()) T = E->getType();
- QualType TargetType = SemaRef.BuildReferenceType(
- T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
+static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
+ QualType TargetType =
+ SemaRef.BuildReferenceType(E->getType(), /*SpelledAsLValue*/ false,
+ SourceLocation(), DeclarationName());
SourceLocation ExprLoc = E->getBeginLoc();
TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
TargetType, ExprLoc);
@@ -4709,8 +4750,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt);
break;
}
@@ -4874,9 +4915,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt);
ExprResult MemberInit =
- InitSeq.Perform(SemaRef, InitEntity, InitKind, None);
+ InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt);
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
@@ -5644,7 +5685,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
continue;
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
- assert(Dtor && "No dtor found for FieldClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
CheckDestructorAccess(Field->getLocation(), Dtor,
PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
@@ -5690,7 +5733,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
- assert(Dtor && "No dtor found for BaseClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base.getBeginLoc(), Dtor,
@@ -5727,7 +5772,9 @@ void Sema::MarkVirtualBaseDestructorsReferenced(
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
- assert(Dtor && "No dtor found for BaseClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
if (CheckDestructorAccess(
ClassDecl->getLocation(), Dtor,
PDiag(diag::err_access_dtor_vbase)
@@ -6612,7 +6659,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
bool DtorIsTrivialForCall = false;
- // If a class has at least one non-deleted, trivial copy constructor, it
+ // If a class has at least one eligible, trivial copy constructor, it
// is passed according to the C ABI. Otherwise, it is passed indirectly.
//
// Note: This permits classes with non-trivial copy or move ctors to be
@@ -6627,7 +6674,8 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
}
} else {
for (const CXXConstructorDecl *CD : D->ctors()) {
- if (CD->isCopyConstructor() && !CD->isDeleted()) {
+ if (CD->isCopyConstructor() && !CD->isDeleted() &&
+ !CD->isIneligibleOrNotSelected()) {
if (CD->isTrivial())
CopyCtorIsTrivial = true;
if (CD->isTrivialForCall())
@@ -6947,7 +6995,8 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// Define defaulted constexpr virtual functions that override a base class
// function right away.
// FIXME: We can defer doing this until the vtable is marked as used.
- if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
+ if (CSM != CXXInvalid && !M->isDeleted() && M->isDefaulted() &&
+ M->isConstexpr() && M->size_overridden_methods())
DefineDefaultedFunction(*this, M, M->getLocation());
if (!Incomplete)
@@ -7178,6 +7227,11 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
bool ConstRHS,
CXXConstructorDecl *InheritedCtor = nullptr,
Sema::InheritedConstructorInfo *Inherited = nullptr) {
+ // Suppress duplicate constraint checking here, in case a constraint check
+ // caused us to decide to do this. Any truely recursive checks will get
+ // caught during these checks anyway.
+ Sema::SatisfactionStackResetRAII SSRAII{S};
+
// If we're inheriting a constructor, see if we need to call it for this base
// class.
if (InheritedCtor) {
@@ -7274,8 +7328,8 @@ static bool defaultedSpecialMemberIsConstexpr(
// class is a constexpr function, and
for (const auto &B : ClassDecl->bases()) {
const RecordType *BaseType = B.getType()->getAs<RecordType>();
- if (!BaseType) continue;
-
+ if (!BaseType)
+ continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
InheritedCtor, Inherited))
@@ -7402,13 +7456,15 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
if (DefKind.isSpecialMember()
? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
- DefKind.asSpecialMember())
+ DefKind.asSpecialMember(),
+ FD->getDefaultLoc())
: CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison()))
FD->setInvalidDecl();
}
bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
- CXXSpecialMember CSM) {
+ CXXSpecialMember CSM,
+ SourceLocation DefaultLoc) {
CXXRecordDecl *RD = MD->getParent();
assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
@@ -7470,6 +7526,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
ReturnType = Type->getReturnType();
QualType DeclType = Context.getTypeDeclType(RD);
+ DeclType = Context.getElaboratedType(ETK_None, nullptr, DeclType, nullptr);
DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace());
QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType);
@@ -7544,6 +7601,17 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
// FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
+
+ // C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358):
+ // If the instantiated template specialization of a constexpr function
+ // template or member function of a class template would fail to satisfy
+ // the requirements for a constexpr function or constexpr constructor, that
+ // specialization is still a constexpr function or constexpr constructor,
+ // even though a call to such a function cannot appear in a constant
+ // expression.
+ if (MD->isTemplateInstantiation() && MD->isConstexpr())
+ Constexpr = true;
+
if ((getLangOpts().CPlusPlus20 ||
(getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
: isa<CXXConstructorDecl>(MD))) &&
@@ -7575,10 +7643,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = MD;
- MD->setType(Context.getFunctionType(ReturnType,
- llvm::makeArrayRef(&ArgType,
- ExpectedParams),
- EPI));
+ MD->setType(Context.getFunctionType(
+ ReturnType, llvm::ArrayRef(&ArgType, ExpectedParams), EPI));
}
}
@@ -7589,8 +7655,11 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM;
if (ShouldDeleteForTypeMismatch) {
Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM;
- } else {
- ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
+ } else if (ShouldDeleteSpecialMember(MD, CSM, nullptr,
+ /*Diagnose*/ true) &&
+ DefaultLoc.isValid()) {
+ Diag(DefaultLoc, diag::note_replace_equals_default_to_delete)
+ << FixItHint::CreateReplacement(DefaultLoc, "delete");
}
}
if (ShouldDeleteForTypeMismatch && !HadError) {
@@ -7848,7 +7917,8 @@ private:
OverloadCandidateSet CandidateSet(
FD->getLocation(), OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(
- OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
+ OO, FD->getLocation(),
+ /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
/// C++2a [class.compare.default]p1 [P2002R0]:
/// [...] the defaulted function itself is never a candidate for overload
@@ -7987,7 +8057,7 @@ private:
"invalid builtin comparison");
if (NeedsDeducing) {
- Optional<ComparisonCategoryType> Cat =
+ std::optional<ComparisonCategoryType> Cat =
getComparisonCategoryForBuiltinCmp(T);
assert(Cat && "no category for builtin comparison?");
R.Category = *Cat;
@@ -8642,10 +8712,11 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
// C++2a [class.spaceship]p2 [P2002R0]:
// Let R be the declared return type [...]. If R is auto, [...]. Otherwise,
// R shall not contain a placeholder type.
- if (DCK == DefaultedComparisonKind::ThreeWay &&
- FD->getDeclaredReturnType()->getContainedDeducedType() &&
- !Context.hasSameType(FD->getDeclaredReturnType(),
- Context.getAutoDeductType())) {
+ if (QualType RT = FD->getDeclaredReturnType();
+ DCK == DefaultedComparisonKind::ThreeWay &&
+ RT->getContainedDeducedType() &&
+ (!Context.hasSameType(RT, Context.getAutoDeductType()) ||
+ RT->getContainedAutoType()->isConstrained())) {
Diag(FD->getLocation(),
diag::err_defaulted_comparison_deduced_return_type_not_auto)
<< (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy
@@ -8664,10 +8735,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
bool First = FD == FD->getCanonicalDecl();
- // If we want to delete the function, then do so; there's nothing else to
- // check in that case.
- if (Info.Deleted) {
- if (!First) {
+ if (!First) {
+ if (Info.Deleted) {
// C++11 [dcl.fct.def.default]p4:
// [For a] user-provided explicitly-defaulted function [...] if such a
// function is implicitly defined as deleted, the program is ill-formed.
@@ -8681,7 +8750,21 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
.visit();
return true;
}
+ if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ // C++20 [class.compare.default]p1:
+ // [...] A definition of a comparison operator as defaulted that appears
+ // in a class shall be the first declaration of that function.
+ Diag(FD->getLocation(), diag::err_non_first_default_compare_in_class)
+ << (int)DCK;
+ Diag(FD->getCanonicalDecl()->getLocation(),
+ diag::note_previous_declaration);
+ return true;
+ }
+ }
+ // If we want to delete the function, then do so; there's nothing else to
+ // check in that case.
+ if (Info.Deleted) {
SetDeclDeleted(FD, FD->getLocation());
if (!inTemplateInstantiation() && !FD->isImplicit()) {
Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted)
@@ -8689,6 +8772,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
DefaultedComparisonAnalyzer::ExplainDeleted)
.visit();
+ if (FD->getDefaultLoc().isValid())
+ Diag(FD->getDefaultLoc(), diag::note_replace_equals_default_to_delete)
+ << FixItHint::CreateReplacement(FD->getDefaultLoc(), "delete");
}
return false;
}
@@ -10130,10 +10216,12 @@ void Sema::ActOnFinishCXXMemberSpecification(
Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL;
}
- ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
- // strict aliasing violation!
- reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
- FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
+ ActOnFields(S, RLoc, TagDecl,
+ llvm::ArrayRef(
+ // strict aliasing violation!
+ reinterpret_cast<Decl **>(FieldCollector->getCurFields()),
+ FieldCollector->getCurNumFields()),
+ LBrac, RBrac, AttrList);
CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl));
}
@@ -10699,7 +10787,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
EPI.Variadic = false;
EPI.TypeQuals = Qualifiers();
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, None, EPI);
+ return Context.getFunctionType(Context.VoidTy, std::nullopt, EPI);
}
static void extendLeft(SourceRange &R, SourceRange Before) {
@@ -10802,7 +10890,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
PastFunctionChunk = true;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::Array:
NeedsTypedef = true;
extendRight(After, Chunk.getSourceRange());
@@ -10875,7 +10963,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// of the errors above fired) and with the conversion type as the
// return type.
if (D.isInvalidType())
- R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
+ R = Context.getFunctionType(ConvType, std::nullopt,
+ Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20)
@@ -11037,6 +11126,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
// Check that the return type is written as a specialization of
// the template specified as the deduction-guide's name.
+ // The template name may not be qualified. [temp.deduct.guide]
ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
TypeSourceInfo *TSI = nullptr;
QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
@@ -11044,13 +11134,17 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
bool AcceptableReturnType = false;
bool MightInstantiateToSpecialization = false;
if (auto RetTST =
- TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
+ TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches =
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
- // FIXME: We should consider other template kinds (using, qualified),
- // otherwise we will emit bogus diagnostics.
- if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
+ auto TKind = SpecifiedName.getKind();
+ // A Using TemplateName can't actually be valid (either it's qualified, or
+ // we're in the wrong scope). But we have diagnosed these problems
+ // already.
+ bool SimplyWritten = TKind == TemplateName::Template ||
+ TKind == TemplateName::UsingTemplate;
+ if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
@@ -11111,10 +11205,13 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
-Decl *Sema::ActOnStartNamespaceDef(
- Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc,
- SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace,
- const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) {
+Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
+ SourceLocation InlineLoc,
+ SourceLocation NamespaceLoc,
+ SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation LBrace,
+ const ParsedAttributesView &AttrList,
+ UsingDirectiveDecl *&UD, bool IsNested) {
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
@@ -11184,8 +11281,8 @@ Decl *Sema::ActOnStartNamespaceDef(
&IsInline, PrevNS);
}
- NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
- StartLoc, Loc, II, PrevNS);
+ NamespaceDecl *Namespc = NamespaceDecl::Create(
+ Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS, IsNested);
if (IsInvalid)
Namespc->setInvalidDecl();
@@ -11446,12 +11543,11 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
NamespaceDecl *Sema::getOrCreateStdNamespace() {
if (!StdNamespace) {
// The "std" namespace has not yet been defined, so build one implicitly.
- StdNamespace = NamespaceDecl::Create(Context,
- Context.getTranslationUnitDecl(),
- /*Inline=*/false,
- SourceLocation(), SourceLocation(),
- &PP.getIdentifierTable().get("std"),
- /*PrevDecl=*/nullptr);
+ StdNamespace = NamespaceDecl::Create(
+ Context, Context.getTranslationUnitDecl(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
+ &PP.getIdentifierTable().get("std"),
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
getStdNamespace()->setImplicit(true);
}
@@ -11484,7 +11580,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
Ty->getAs<TemplateSpecializationType>()) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
- Arguments = TST->getArgs();
+ Arguments = TST->template_arguments().begin();
}
if (!Template)
return false;
@@ -11563,7 +11659,9 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
Context.getTrivialTypeSourceInfo(Element,
Loc)));
- return Context.getCanonicalType(
+ return Context.getElaboratedType(
+ ElaboratedTypeKeyword::ETK_None,
+ NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()),
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
@@ -11825,30 +11923,40 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
- const DeclSpec &DS) {
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_error:
- // This will already have been diagnosed
+ SourceLocation IdentLoc,
+ IdentifierInfo &II, CXXScopeSpec *SS) {
+ assert(!SS->isInvalid() && "ScopeSpec is invalid");
+ TypeSourceInfo *TSI = nullptr;
+ QualType EnumTy = GetTypeFromParser(
+ getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
+ /*HasTrailingDot=*/false,
+ /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true),
+ &TSI);
+ if (EnumTy.isNull()) {
+ Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
+ ? diag::err_using_enum_is_dependent
+ : diag::err_unknown_typename)
+ << II.getName()
+ << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc);
return nullptr;
+ }
- case DeclSpec::TST_enum:
- break;
-
- case DeclSpec::TST_typename:
- Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent);
+ auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl());
+ if (!Enum) {
+ Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy;
return nullptr;
-
- default:
- llvm_unreachable("unexpected DeclSpec type");
}
- // As with enum-decls, we ignore attributes for now.
- auto *Enum = cast<EnumDecl>(DS.getRepAsDecl());
if (auto *Def = Enum->getDefinition())
Enum = Def;
- auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc,
- DS.getTypeSpecTypeNameLoc(), Enum);
+ if (TSI == nullptr)
+ TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc);
+
+ auto *UD =
+ BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum);
+
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
@@ -12540,6 +12648,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
SourceLocation NameLoc,
+ TypeSourceInfo *EnumType,
EnumDecl *ED) {
bool Invalid = false;
@@ -12566,7 +12675,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
Invalid = true;
UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc,
- EnumLoc, NameLoc, ED);
+ EnumLoc, NameLoc, EnumType);
UD->setAccess(AS);
CurContext->addDecl(UD);
@@ -12908,7 +13017,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
// Salient point: SS doesn't have to name a base class as long as
// lookup only finds members from base classes. Therefore we can
- // diagnose here only if we can prove that that can't happen,
+ // diagnose here only if we can prove that can't happen,
// i.e. if the class hierarchies provably don't intersect.
// TODO: it would be nice if "definitely valid" results were cached
@@ -12988,7 +13097,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
Previous.clear();
}
- assert(Name.Kind == UnqualifiedIdKind::IK_Identifier &&
+ assert(Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
"name in alias declaration must be an identifier");
TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc,
Name.StartLocation,
@@ -13443,7 +13552,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
- setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None);
+ setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt);
if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor,
@@ -13723,7 +13832,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
- setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None);
+ setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt);
if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor,
@@ -13884,7 +13993,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
+ Destructor->setType(
+ Context.getFunctionType(Context.VoidTy, std::nullopt, EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -14332,6 +14442,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -14410,13 +14521,10 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
CXXRecordDecl *RD = CopyOp->getParent();
CXXMethodDecl *UserDeclaredOperation = nullptr;
- // In Microsoft mode, assignment operations don't affect constructors and
- // vice versa.
if (RD->hasUserDeclaredDestructor()) {
UserDeclaredOperation = RD->getDestructor();
} else if (!isa<CXXConstructorDecl>(CopyOp) &&
- RD->hasUserDeclaredCopyConstructor() &&
- !S.getLangOpts().MSVCCompat) {
+ RD->hasUserDeclaredCopyConstructor()) {
// Find any user-declared copy constructor.
for (auto *I : RD->ctors()) {
if (I->isCopyConstructor()) {
@@ -14426,8 +14534,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
}
assert(UserDeclaredOperation);
} else if (isa<CXXConstructorDecl>(CopyOp) &&
- RD->hasUserDeclaredCopyAssignment() &&
- !S.getLangOpts().MSVCCompat) {
+ RD->hasUserDeclaredCopyAssignment()) {
// Find any user-declared move assignment operator.
for (auto *I : RD->methods()) {
if (I->isCopyAssignmentOperator()) {
@@ -14612,7 +14719,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup);
- MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup);
+ MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/!LangOpts.HLSL,
+ MemberLookup);
// Build the copy of this field.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
@@ -14630,9 +14738,16 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+ Expr *ThisExpr = nullptr;
+ if (!LangOpts.HLSL) {
+ ExprResult ThisObj =
+ CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+ ThisExpr = ThisObj.get();
+ } else {
+ ThisExpr = This.build(*this, Loc);
+ }
- StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
+ StmtResult Return = BuildReturnStmt(Loc, ThisExpr);
if (Return.isInvalid())
Invalid = true;
else
@@ -14670,6 +14785,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -15042,6 +15158,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
bool Const = ClassDecl->implicitCopyConstructorHasConstParam();
if (Const)
ArgType = ArgType.withConst();
@@ -15165,7 +15282,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
: CopyConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(
- ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
+ ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false)
+ .getAs<Stmt>());
CopyConstructor->markUsed(Context);
}
@@ -15185,6 +15303,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ClassType, AS);
@@ -15290,8 +15409,9 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
? MoveConstructor->getEndLoc()
: MoveConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
- MoveConstructor->setBody(ActOnCompoundStmt(
- Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
+ MoveConstructor->setBody(
+ ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false)
+ .getAs<Stmt>());
MoveConstructor->markUsed(Context);
}
@@ -15316,7 +15436,8 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
CXXRecordDecl *Lambda = Conv->getParent();
FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
- FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC);
+ FunctionDecl *Invoker =
+ CallOp->isStatic() ? CallOp : Lambda->getLambdaStaticInvoker(CC);
if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
CallOp = InstantiateFunctionDeclaration(
@@ -15324,10 +15445,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
if (!CallOp)
return;
- Invoker = InstantiateFunctionDeclaration(
- Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation);
- if (!Invoker)
- return;
+ if (CallOp != Invoker) {
+ Invoker = InstantiateFunctionDeclaration(
+ Invoker->getDescribedFunctionTemplate(), TemplateArgs,
+ CurrentLocation);
+ if (!Invoker)
+ return;
+ }
}
if (CallOp->isInvalidDecl())
@@ -15340,17 +15464,19 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- // Fill in the __invoke function with a dummy implementation. IR generation
- // will fill in the actual details. Update its type in case it contained
- // an 'auto'.
- Invoker->markUsed(Context);
- Invoker->setReferenced();
- Invoker->setType(Conv->getReturnType()->getPointeeType());
- Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ if (Invoker != CallOp) {
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details. Update its type in case it contained
+ // an 'auto'.
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setType(Conv->getReturnType()->getPointeeType());
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ }
// Construct the body of the conversion function { return __invoke; }.
- Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation());
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue,
+ Conv->getLocation());
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(),
@@ -15360,16 +15486,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
- L->CompletedImplicitDefinition(Invoker);
+ if (Invoker != CallOp)
+ L->CompletedImplicitDefinition(Invoker);
}
}
-
-
void Sema::DefineImplicitLambdaToBlockPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
+ SourceLocation CurrentLocation, CXXConversionDecl *Conv) {
assert(!Conv->getParent()->isGenericLambda());
SynthesizedFunctionScope Scope(*this, Conv);
@@ -15429,7 +15552,7 @@ static bool hasOneRealArgument(MultiExprArg Args) {
if (!Args[1]->isDefaultArgument())
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 1:
return !Args[0]->isDefaultArgument();
}
@@ -15498,7 +15621,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
SourceRange ParenRange) {
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
- if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
+ // The only way to get here is if we did overlaod resolution to find the
+ // shadow decl, so we don't need to worry about re-checking the trailing
+ // requires clause.
+ if (DiagnoseUseOfOverloadedDecl(Constructor, ConstructLoc))
return ExprError();
}
@@ -15542,70 +15668,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Constructor);
}
-ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
- assert(Field->hasInClassInitializer());
-
- // If we already have the in-class initializer nothing needs to be done.
- if (Field->getInClassInitializer())
- return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
-
- // If we might have already tried and failed to instantiate, don't try again.
- if (Field->isInvalidDecl())
- return ExprError();
-
- // Maybe we haven't instantiated the in-class initializer. Go check the
- // pattern FieldDecl to see if it has one.
- CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent());
-
- if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
- CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
- DeclContext::lookup_result Lookup =
- ClassPattern->lookup(Field->getDeclName());
-
- FieldDecl *Pattern = nullptr;
- for (auto L : Lookup) {
- if (isa<FieldDecl>(L)) {
- Pattern = cast<FieldDecl>(L);
- break;
- }
- }
- assert(Pattern && "We must have set the Pattern!");
-
- if (!Pattern->hasInClassInitializer() ||
- InstantiateInClassInitializer(Loc, Field, Pattern,
- getTemplateInstantiationArgs(Field))) {
- // Don't diagnose this again.
- Field->setInvalidDecl();
- return ExprError();
- }
- return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
- }
-
- // DR1351:
- // If the brace-or-equal-initializer of a non-static data member
- // invokes a defaulted default constructor of its class or of an
- // enclosing class in a potentially evaluated subexpression, the
- // program is ill-formed.
- //
- // This resolution is unworkable: the exception specification of the
- // default constructor can be needed in an unevaluated context, in
- // particular, in the operand of a noexcept-expression, and we can be
- // unable to compute an exception specification for an enclosed class.
- //
- // Any attempt to resolve the exception specification of a defaulted default
- // constructor before the initializer is lexically complete will ultimately
- // come here at which point we can diagnose it.
- RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext();
- Diag(Loc, diag::err_default_member_initializer_not_yet_parsed)
- << OutermostClass << Field;
- Diag(Field->getEndLoc(),
- diag::note_default_member_initializer_not_yet_parsed);
- // Recover by marking the field invalid, unless we're in a SFINAE context.
- if (!isSFINAEContext())
- Field->setInvalidDecl();
- return ExprError();
-}
-
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
// If initializing the variable failed, don't also diagnose problems with
@@ -15690,19 +15752,16 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
SmallVector<Expr *, 8> AllArgs;
- bool Invalid = GatherArgumentsForCall(Loc, Constructor,
- Proto, 0,
- llvm::makeArrayRef(Args, NumArgs),
- AllArgs,
- CallType, AllowExplicit,
- IsListInitialization);
+ bool Invalid = GatherArgumentsForCall(
+ Loc, Constructor, Proto, 0, llvm::ArrayRef(Args, NumArgs), AllArgs,
+ CallType, AllowExplicit, IsListInitialization);
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
DiagnoseSentinelCalls(Constructor, Loc, AllArgs);
CheckConstructorCall(Constructor, DeclInitType,
- llvm::makeArrayRef(AllArgs.data(), AllArgs.size()),
- Proto, Loc);
+ llvm::ArrayRef(AllArgs.data(), AllArgs.size()), Proto,
+ Loc);
return Invalid;
}
@@ -15901,18 +15960,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if (Op == OO_New || Op == OO_Array_New)
return CheckOperatorNewDeclaration(*this, FnDecl);
- // C++ [over.oper]p6:
- // An operator function shall either be a non-static member
- // function or be a non-member function and have at least one
- // parameter whose type is a class, a reference to a class, an
- // enumeration, or a reference to an enumeration.
+ // C++ [over.oper]p7:
+ // An operator function shall either be a member function or
+ // be a non-member function and have at least one parameter
+ // whose type is a class, a reference to a class, an enumeration,
+ // or a reference to an enumeration.
+ // Note: Before C++23, a member function could not be static. The only member
+ // function allowed to be static is the call operator function.
if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (MethodDecl->isStatic())
- return Diag(FnDecl->getLocation(),
- diag::err_operator_overload_static) << FnDecl->getDeclName();
+ if (MethodDecl->isStatic()) {
+ if (Op == OO_Call || Op == OO_Subscript)
+ Diag(FnDecl->getLocation(),
+ (LangOpts.CPlusPlus2b
+ ? diag::warn_cxx20_compat_operator_overload_static
+ : diag::ext_operator_overload_static))
+ << FnDecl;
+ else
+ return Diag(FnDecl->getLocation(), diag::err_operator_overload_static)
+ << FnDecl;
+ }
} else {
bool ClassOrEnumParam = false;
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
QualType ParamType = Param->getType().getNonReferenceType();
if (ParamType->isDependentType() || ParamType->isRecordType() ||
ParamType->isEnumeralType()) {
@@ -15935,7 +16004,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// operator (CWG2507) allow default arguments.
if (Op != OO_Call) {
ParmVarDecl *FirstDefaultedParam = nullptr;
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
FirstDefaultedParam = Param;
break;
@@ -16008,7 +16077,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
<< FnDecl->getDeclName();
}
- // Some operators must be non-static member functions.
+ // Some operators must be member functions.
if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) {
return Diag(FnDecl->getLocation(),
diag::err_operator_overload_must_be_member)
@@ -16241,7 +16310,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
Diag(Param->getDefaultArgRange().getBegin(),
diag::err_literal_operator_default_argument)
@@ -16559,6 +16628,137 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
AssertMessage, RParenLoc, false);
}
+/// Convert \V to a string we can present to the user in a diagnostic
+/// \T is the type of the expression that has been evaluated into \V
+static bool ConvertAPValueToString(const APValue &V, QualType T,
+ SmallVectorImpl<char> &Str) {
+ if (!V.hasValue())
+ return false;
+
+ switch (V.getKind()) {
+ case APValue::ValueKind::Int:
+ if (T->isBooleanType()) {
+ // Bools are reduced to ints during evaluation, but for
+ // diagnostic purposes we want to print them as
+ // true or false.
+ int64_t BoolValue = V.getInt().getExtValue();
+ assert((BoolValue == 0 || BoolValue == 1) &&
+ "Bool type, but value is not 0 or 1");
+ llvm::raw_svector_ostream OS(Str);
+ OS << (BoolValue ? "true" : "false");
+ } else if (T->isCharType()) {
+ // Same is true for chars.
+ Str.push_back('\'');
+ Str.push_back(V.getInt().getExtValue());
+ Str.push_back('\'');
+ } else
+ V.getInt().toString(Str);
+
+ break;
+
+ case APValue::ValueKind::Float:
+ V.getFloat().toString(Str);
+ break;
+
+ case APValue::ValueKind::LValue:
+ if (V.isNullPointer()) {
+ llvm::raw_svector_ostream OS(Str);
+ OS << "nullptr";
+ } else
+ return false;
+ break;
+
+ case APValue::ValueKind::ComplexFloat: {
+ llvm::raw_svector_ostream OS(Str);
+ OS << '(';
+ V.getComplexFloatReal().toString(Str);
+ OS << " + ";
+ V.getComplexFloatImag().toString(Str);
+ OS << "i)";
+ } break;
+
+ case APValue::ValueKind::ComplexInt: {
+ llvm::raw_svector_ostream OS(Str);
+ OS << '(';
+ V.getComplexIntReal().toString(Str);
+ OS << " + ";
+ V.getComplexIntImag().toString(Str);
+ OS << "i)";
+ } break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/// Some Expression types are not useful to print notes about,
+/// e.g. literals and values that have already been expanded
+/// before such as int-valued template parameters.
+static bool UsefulToPrintExpr(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ // Literals are pretty easy for humans to understand.
+ if (isa<IntegerLiteral, FloatingLiteral, CharacterLiteral, CXXBoolLiteralExpr,
+ CXXNullPtrLiteralExpr, FixedPointLiteral, ImaginaryLiteral>(E))
+ return false;
+
+ // These have been substituted from template parameters
+ // and appear as literals in the static assert error.
+ if (isa<SubstNonTypeTemplateParmExpr>(E))
+ return false;
+
+ // -5 is also simple to understand.
+ if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
+ return UsefulToPrintExpr(UnaryOp->getSubExpr());
+
+ // Ignore nested binary operators. This could be a FIXME for improvements
+ // to the diagnostics in the future.
+ if (isa<BinaryOperator>(E))
+ return false;
+
+ return true;
+}
+
+/// 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)) {
+ const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts();
+ const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts();
+
+ // Ignore comparisons of boolean expressions with a boolean literal.
+ if ((isa<CXXBoolLiteralExpr>(LHS) && RHS->getType()->isBooleanType()) ||
+ (isa<CXXBoolLiteralExpr>(RHS) && LHS->getType()->isBooleanType()))
+ return;
+
+ // Don't print obvious expressions.
+ if (!UsefulToPrintExpr(LHS) && !UsefulToPrintExpr(RHS))
+ return;
+
+ struct {
+ const clang::Expr *Cond;
+ Expr::EvalResult Result;
+ SmallString<12> ValueString;
+ bool Print;
+ } DiagSide[2] = {{LHS, Expr::EvalResult(), {}, false},
+ {RHS, Expr::EvalResult(), {}, false}};
+ for (unsigned I = 0; I < 2; I++) {
+ const Expr *Side = DiagSide[I].Cond;
+
+ Side->EvaluateAsRValue(DiagSide[I].Result, Context, true);
+
+ DiagSide[I].Print = ConvertAPValueToString(
+ DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString);
+ }
+ if (DiagSide[0].Print && DiagSide[1].Print) {
+ Diag(Op->getExprLoc(), diag::note_expr_evaluates_to)
+ << DiagSide[0].ValueString << Op->getOpcodeStr()
+ << DiagSide[1].ValueString << Op->getSourceRange();
+ }
+ }
+}
+
Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
StringLiteral *AssertMessage,
@@ -16583,10 +16783,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
AssertExpr = FullAssertExpr.get();
llvm::APSInt Cond;
+ Expr *BaseExpr = AssertExpr;
+ AllowFoldKind FoldKind = NoFold;
+
+ if (!getLangOpts().CPlusPlus) {
+ // In C mode, allow folding as an extension for better compatibility with
+ // C++ in terms of expressions like static_assert("test") or
+ // static_assert(nullptr).
+ FoldKind = AllowFold;
+ }
+
if (!Failed && VerifyIntegerConstantExpression(
- AssertExpr, &Cond,
- diag::err_static_assert_expression_is_not_constant)
- .isInvalid())
+ BaseExpr, &Cond,
+ diag::err_static_assert_expression_is_not_constant,
+ FoldKind).isInvalid())
Failed = true;
if (!Failed && !Cond) {
@@ -16617,6 +16827,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
+ DiagnoseStaticAssertDetails(InnerCond);
} else {
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
@@ -16650,7 +16861,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
QualType T = TSInfo->getType();
- SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
// C++03 [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
@@ -16716,12 +16927,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
/// Handle a friend tag declaration where the scope specifier was
/// templated.
-Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
- unsigned TagSpec, SourceLocation TagLoc,
- CXXScopeSpec &SS, IdentifierInfo *Name,
- SourceLocation NameLoc,
- const ParsedAttributesView &Attr,
- MultiTemplateParamsArg TempParamLists) {
+DeclResult Sema::ActOnTemplatedFriendTag(
+ Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc,
+ CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
+ const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
bool IsMemberSpecialization = false;
@@ -16734,7 +16943,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
- return nullptr;
+ return true;
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name,
NameLoc, Attr, TemplateParams, AS_public,
@@ -16749,7 +16958,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
}
}
- if (Invalid) return nullptr;
+ if (Invalid) return true;
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
@@ -16768,15 +16977,16 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (SS.isEmpty()) {
bool Owned = false;
bool IsDependent = false;
- return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc,
- Attr, AS_public,
+ UsingShadowDecl* FoundUsing = nullptr;
+ return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr,
+ AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
/*IsTypeSpecifier=*/false,
- /*IsTemplateParamOrArg=*/false);
+ /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside, FoundUsing);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -16785,7 +16995,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc,
*Name, NameLoc);
if (T.isNull())
- return nullptr;
+ return true;
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
@@ -17353,6 +17563,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
FD->setDefaulted();
FD->setExplicitlyDefaulted();
+ FD->setDefaultLoc(DefaultLoc);
// Defer checking functions that are defaulted in a dependent context.
if (FD->isDependentContext())
@@ -17392,7 +17603,8 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
} else {
auto *MD = cast<CXXMethodDecl>(FD);
- if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
+ if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember(),
+ DefaultLoc))
MD->setInvalidDecl();
else
DefineDefaultedFunction(*this, MD, DefaultLoc);
@@ -17817,7 +18029,7 @@ bool Sema::DefineUsedVTables() {
// definition.
bool IsExplicitInstantiationDeclaration =
ClassTSK == TSK_ExplicitInstantiationDeclaration;
- for (auto R : Class->redecls()) {
+ for (auto *R : Class->redecls()) {
TemplateSpecializationKind TSK
= cast<CXXRecordDecl>(R)->getTemplateSpecializationKind();
if (TSK == TSK_ExplicitInstantiationDeclaration)
@@ -17929,9 +18141,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
InitializationKind InitKind =
InitializationKind::CreateDefault(ObjCImplementation->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, std::nullopt);
ExprResult MemberInit =
- InitSeq.Perform(*this, InitEntity, InitKind, None);
+ InitSeq.Perform(*this, InitEntity, InitKind, std::nullopt);
MemberInit = MaybeCreateExprWithCleanups(MemberInit);
// Note, MemberInit could actually come back empty if no initialization
// is required (e.g., because it would call a trivial default constructor)
@@ -18032,8 +18244,8 @@ void Sema::CheckDelegatingCtorCycles() {
llvm::SmallPtrSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
for (DelegatingCtorDeclsType::iterator
- I = DelegatingCtorDecls.begin(ExternalSource),
- E = DelegatingCtorDecls.end();
+ I = DelegatingCtorDecls.begin(ExternalSource.get()),
+ E = DelegatingCtorDecls.end();
I != E; ++I)
DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
@@ -18123,7 +18335,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_NoexceptTrue:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_Dynamic:
for (const auto &E : Proto->exceptions()) {
@@ -18149,27 +18361,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
else if (const auto *G = dyn_cast<PtGuardedByAttr>(A))
Arg = G->getArg();
else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A))
- Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size());
+ Args = llvm::ArrayRef(AA->args_begin(), AA->args_size());
else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
- Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size());
+ Args = llvm::ArrayRef(AB->args_begin(), AB->args_size());
else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
Arg = ETLF->getSuccessValue();
- Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size());
+ Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size());
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
Arg = STLF->getSuccessValue();
- Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size());
+ Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size());
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
Arg = LR->getArg();
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
- Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size());
+ Args = llvm::ArrayRef(LE->args_begin(), LE->args_size());
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
- Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
+ Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
- Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
+ Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
- Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
+ Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
- Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
+ Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
if (Arg && !Finder.TraverseStmt(Arg))
return true;
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index a574a5539330..fdfc6d312b38 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -782,7 +782,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
// scope until later (after the instance variable block), but we want the
// diagnostics to occur right after we parse the type parameter list.
llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams;
- for (auto typeParam : typeParams) {
+ for (auto *typeParam : typeParams) {
auto known = knownParams.find(typeParam->getIdentifier());
if (known != knownParams.end()) {
Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl)
@@ -803,7 +803,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
}
void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) {
- for (auto typeParam : *typeParamList) {
+ for (auto *typeParam : *typeParamList) {
if (!typeParam->isInvalidDecl()) {
S->RemoveDecl(typeParam);
IdResolver.RemoveDecl(typeParam);
@@ -978,7 +978,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange,
Decl *const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
- const ParsedAttributesView &AttrList) {
+ const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) {
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
@@ -1029,7 +1029,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
// Clone the type parameter list.
SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
- for (auto typeParam : *prevTypeParamList) {
+ for (auto *typeParam : *prevTypeParamList) {
clonedTypeParams.push_back(
ObjCTypeParamDecl::Create(
Context,
@@ -1057,10 +1057,16 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
- Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
- << PrevIDecl->getDeclName();
- Diag(Def->getLocation(), diag::note_previous_definition);
- IDecl->setInvalidDecl();
+ if (SkipBody && !hasVisibleDefinition(Def)) {
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = IDecl;
+ SkipBody->Previous = Def;
+ } else {
+ Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
+ << PrevIDecl->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ IDecl->setInvalidDecl();
+ }
}
}
@@ -1075,7 +1081,9 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
// Start the definition of this class. If we're in a redefinition case, there
// may already be a definition, so we'll end up adding to it.
- if (!IDecl->hasDefinition())
+ if (SkipBody && SkipBody->CheckSameAsPrevious)
+ IDecl->startDuplicateDefinitionForComparison();
+ else if (!IDecl->hasDefinition())
IDecl->startDefinition();
if (SuperName) {
@@ -1213,7 +1221,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName,
SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
- const ParsedAttributesView &AttrList) {
+ const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) {
bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
@@ -1221,23 +1229,29 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl = nullptr;
if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) {
- // If we already have a definition, complain.
- Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
- Diag(Def->getLocation(), diag::note_previous_definition);
-
// Create a new protocol that is completely distinct from previous
// declarations, and do not make this protocol available for name lookup.
// That way, we'll end up completely ignoring the duplicate.
// FIXME: Can we turn this into an error?
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
ProtocolLoc, AtProtoInterfaceLoc,
- /*PrevDecl=*/nullptr);
+ /*PrevDecl=*/Def);
+
+ if (SkipBody && !hasVisibleDefinition(Def)) {
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = PDecl;
+ SkipBody->Previous = Def;
+ } else {
+ // If we already have a definition, complain.
+ Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
// If we are using modules, add the decl to the context in order to
// serialize something meaningful.
if (getLangOpts().Modules)
PushOnScopeChains(PDecl, TUScope);
- PDecl->startDefinition();
+ PDecl->startDuplicateDefinitionForComparison();
} else {
if (PrevDecl) {
// Check for circular dependencies among protocol declarations. This can
@@ -1502,7 +1516,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols;
Context.CollectInheritedProtocols(baseClass, knownProtocols);
bool allProtocolsDeclared = true;
- for (auto proto : protocols) {
+ for (auto *proto : protocols) {
if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) {
allProtocolsDeclared = false;
break;
@@ -2355,21 +2369,17 @@ static bool CheckMethodOverrideReturn(Sema &S,
!S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(),
MethodDecl->getReturnType(),
false)) {
- auto nullabilityMethodImpl =
- *MethodImpl->getReturnType()->getNullability(S.Context);
- auto nullabilityMethodDecl =
- *MethodDecl->getReturnType()->getNullability(S.Context);
- S.Diag(MethodImpl->getLocation(),
- diag::warn_conflicting_nullability_attr_overriding_ret_types)
- << DiagNullabilityKind(
- nullabilityMethodImpl,
- ((MethodImpl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0))
- << DiagNullabilityKind(
- nullabilityMethodDecl,
- ((MethodDecl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0));
- S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
+ auto nullabilityMethodImpl = *MethodImpl->getReturnType()->getNullability();
+ auto nullabilityMethodDecl = *MethodDecl->getReturnType()->getNullability();
+ S.Diag(MethodImpl->getLocation(),
+ diag::warn_conflicting_nullability_attr_overriding_ret_types)
+ << DiagNullabilityKind(nullabilityMethodImpl,
+ ((MethodImpl->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0))
+ << DiagNullabilityKind(nullabilityMethodDecl,
+ ((MethodDecl->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0));
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
}
if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(),
@@ -2447,14 +2457,12 @@ static bool CheckMethodOverrideParam(Sema &S,
!S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) {
S.Diag(ImplVar->getLocation(),
diag::warn_conflicting_nullability_attr_overriding_param_types)
- << DiagNullabilityKind(
- *ImplTy->getNullability(S.Context),
- ((ImplVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0))
- << DiagNullabilityKind(
- *IfaceTy->getNullability(S.Context),
- ((IfaceVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0));
+ << DiagNullabilityKind(*ImplTy->getNullability(),
+ ((ImplVar->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0))
+ << DiagNullabilityKind(*IfaceTy->getNullability(),
+ ((IfaceVar->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0));
S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration);
}
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
@@ -3754,7 +3762,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
/// DiagnoseDuplicateIvars -
/// Check for duplicate ivars in the entire class at the start of
-/// \@implementation. This becomes necesssary because class extension can
+/// \@implementation. This becomes necessary because class extension can
/// add ivars to a class in random order which will not be known until
/// class's \@implementation is seen.
void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
@@ -3855,7 +3863,7 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
// Check if variable sized ivar is in interface and visible to subclasses.
if (!isa<ObjCInterfaceDecl>(OCD)) {
- for (auto ivar : Ivars) {
+ for (auto *ivar : Ivars) {
if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) {
S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility)
<< ivar->getDeclName() << ivar->getType();
@@ -3990,7 +3998,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
// they are overridden by an explicit method that is encountered
// later.
if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) {
- for (auto PropImpl : OID->property_impls()) {
+ for (auto *PropImpl : OID->property_impls()) {
if (auto *Getter = PropImpl->getGetterMethodDecl())
if (Getter->isSynthesizedAccessorStub())
OID->addDecl(Getter);
@@ -4432,6 +4440,11 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ResultTypeCompatibilityKind RTC) {
if (!ObjCMethod)
return;
+ auto IsMethodInCurrentClass = [CurrentClass](const ObjCMethodDecl *M) {
+ // Checking canonical decl works across modules.
+ return M->getClassInterface()->getCanonicalDecl() ==
+ CurrentClass->getCanonicalDecl();
+ };
// Search for overridden methods and merge information down from them.
OverrideSearch overrides(*this, ObjCMethod);
// Keep track if the method overrides any method in the class's base classes,
@@ -4443,8 +4456,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
for (ObjCMethodDecl *overridden : overrides) {
if (!hasOverriddenMethodsInBaseOrProtocol) {
if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
- CurrentClass != overridden->getClassInterface() ||
- overridden->isOverriding()) {
+ !IsMethodInCurrentClass(overridden) || overridden->isOverriding()) {
CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
hasOverriddenMethodsInBaseOrProtocol = true;
} else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
@@ -4469,7 +4481,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
OverrideSearch overrides(*this, overridden);
for (ObjCMethodDecl *SuperOverridden : overrides) {
if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
- CurrentClass != SuperOverridden->getClassInterface()) {
+ !IsMethodInCurrentClass(SuperOverridden)) {
CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
hasOverriddenMethodsInBaseOrProtocol = true;
overridden->setOverriding(true);
@@ -4533,8 +4545,8 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
QualType prevType,
bool prevUsesCSKeyword) {
// Determine the nullability of both types.
- auto nullability = type->getNullability(S.Context);
- auto prevNullability = prevType->getNullability(S.Context);
+ auto nullability = type->getNullability();
+ auto prevNullability = prevType->getNullability();
// Easy case: both have nullability.
if (nullability.has_value() == prevNullability.has_value()) {
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index d8344cfd01f9..a5a57c38bb48 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include <optional>
namespace clang {
@@ -1289,6 +1290,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::StmtExprClass:
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
+ case Expr::CXXParenListInitExprClass:
return canSubStmtsThrow(*this, S);
case Expr::CompoundLiteralExprClass:
@@ -1494,6 +1496,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPTaskLoopSimdDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPErrorDirectiveClass:
case Stmt::OMPTeamsDirectiveClass:
case Stmt::OMPTeamsDistributeDirectiveClass:
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
@@ -1545,7 +1548,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// For 'if constexpr', consider only the non-discarded case.
// FIXME: We should add a DiscardedStmt marker to the AST.
- if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
+ if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
CanThrowResult Then = canThrow(IS->getThen());
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0f79978b0911..2842add2cc4a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -56,6 +56,7 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/TypeSize.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -136,7 +137,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
/// Determine whether a FunctionDecl was ever declared with an
/// explicit storage class.
static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
- for (auto I : D->redecls()) {
+ for (auto *I : D->redecls()) {
if (I->getStorageClass() != SC_None)
return true;
}
@@ -222,7 +223,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks,
- ObjCInterfaceDecl *ClassReceiver) {
+ ObjCInterfaceDecl *ClassReceiver,
+ bool SkipTrailingRequiresClause) {
SourceLocation Loc = Locs.front();
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
@@ -281,9 +283,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// See if this is a function with constraints that need to be satisfied.
// Check this before deducing the return type, as it might instantiate the
// definition.
- if (FD->getTrailingRequiresClause()) {
+ if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+ if (CheckFunctionConstraints(FD, Satisfaction, Loc,
+ /*ForOverloadResolution*/ true))
// A diagnostic will have already been generated (non-constant
// constraint expression, for example)
return true;
@@ -349,7 +352,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions
// List-items in map clauses on this construct may only refer to the declared
// variable var and entities that could be referenced by a procedure defined
- // at the same location
+ // at the same location.
+ // [OpenMP 5.2] Also allow iterator declared variables.
if (LangOpts.OpenMP && isa<VarDecl>(D) &&
!isOpenMPDeclareMapperVarDeclAllowed(cast<VarDecl>(D))) {
Diag(Loc, diag::err_omp_declare_mapper_wrong_var)
@@ -837,7 +841,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
E = ImpCastExprToType(E, PTy, CK_IntegralCast).get();
return E;
}
- if (Ty->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(Ty)) {
QualType PT = Context.getPromotedIntegerType(Ty);
E = ImpCastExprToType(E, PT, CK_IntegralCast).get();
return E;
@@ -976,7 +980,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
DiagRuntimeBehavior(
E->getBeginLoc(), nullptr,
PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case VAK_Valid:
if (Ty->isRecordType()) {
// This is unlikely to be what the user intended. If the class has a
@@ -1056,7 +1060,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return ExprError();
ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(),
- None, E->getEndLoc());
+ std::nullopt, E->getEndLoc());
if (Call.isInvalid())
return ExprError();
@@ -1088,7 +1092,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
if (SkipCast) return false;
if (IntTy->isIntegerType()) {
- QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
+ QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
@@ -1100,60 +1104,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
return false;
}
+// This handles complex/complex, complex/float, or float/complex.
+// When both operands are complex, the shorter operand is converted to the
+// type of the longer, and that is the type of the result. This corresponds
+// to what is done when combining two real floating-point operands.
+// The fun begins when size promotion occur across type domains.
+// From H&S 6.3.4: When one operand is complex and the other is a real
+// floating-point type, the less precise type is converted, within it's
+// real or complex domain, to the precision of the other type. For example,
+// when combining a "long double" with a "double _Complex", the
+// "double _Complex" is promoted to "long double _Complex".
+static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter,
+ QualType ShorterType,
+ QualType LongerType,
+ bool PromotePrecision) {
+ bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType());
+ QualType Result =
+ LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType);
+
+ if (PromotePrecision) {
+ if (isa<ComplexType>(ShorterType.getCanonicalType())) {
+ Shorter =
+ S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast);
+ } else {
+ if (LongerIsComplex)
+ LongerType = LongerType->castAs<ComplexType>()->getElementType();
+ Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast);
+ }
+ }
+ return Result;
+}
+
/// Handle arithmetic conversion with complex types. Helper function of
/// UsualArithmeticConversions()
-static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType,
- bool IsCompAssign) {
+static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType, bool IsCompAssign) {
// if we have an integer operand, the result is the complex type.
if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
- /*skipCast*/false))
+ /*SkipCast=*/false))
return LHSType;
if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
- /*skipCast*/IsCompAssign))
+ /*SkipCast=*/IsCompAssign))
return RHSType;
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
-
// Compute the rank of the two types, regardless of whether they are complex.
int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
-
- auto *LHSComplexType = dyn_cast<ComplexType>(LHSType);
- auto *RHSComplexType = dyn_cast<ComplexType>(RHSType);
- QualType LHSElementType =
- LHSComplexType ? LHSComplexType->getElementType() : LHSType;
- QualType RHSElementType =
- RHSComplexType ? RHSComplexType->getElementType() : RHSType;
-
- QualType ResultType = S.Context.getComplexType(LHSElementType);
- if (Order < 0) {
+ if (Order < 0)
// Promote the precision of the LHS if not an assignment.
- ResultType = S.Context.getComplexType(RHSElementType);
- if (!IsCompAssign) {
- if (LHSComplexType)
- LHS =
- S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast);
- else
- LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast);
- }
- } else if (Order > 0) {
- // Promote the precision of the RHS.
- if (RHSComplexType)
- RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast);
- else
- RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast);
- }
- return ResultType;
+ return handleComplexFloatConversion(S, LHS, LHSType, RHSType,
+ /*PromotePrecision=*/!IsCompAssign);
+ // Promote the precision of the RHS unless it is already the same as the LHS.
+ return handleComplexFloatConversion(S, RHS, RHSType, LHSType,
+ /*PromotePrecision=*/Order > 0);
}
/// Handle arithmetic conversion from integer to float. Helper function
@@ -1539,18 +1542,16 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
- QualType LHSType =
- Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
- QualType RHSType =
- Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
// For conversion purposes, we ignore any atomic qualifier on the LHS.
if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>())
LHSType = AtomicLHS->getValueType();
// If both types are identical, no conversion is needed.
- if (LHSType == RHSType)
- return LHSType;
+ if (Context.hasSameType(LHSType, RHSType))
+ return Context.getCommonSugaredType(LHSType, RHSType);
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
// The caller can deal with this (e.g. pointer + int).
@@ -1559,7 +1560,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Apply unary and bitfield promotions to the LHS's type.
QualType LHSUnpromotedType = LHSType;
- if (LHSType->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(LHSType))
LHSType = Context.getPromotedIntegerType(LHSType);
QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
if (!LHSBitfieldPromoteTy.isNull())
@@ -1568,8 +1569,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
// If both types are identical, no conversion is needed.
- if (LHSType == RHSType)
- return LHSType;
+ if (Context.hasSameType(LHSType, RHSType))
+ return Context.getCommonSugaredType(LHSType, RHSType);
// At this point, we have two different arithmetic types.
@@ -1580,8 +1581,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Handle complex types first (C99 6.3.1.8p1).
if (LHSType->isComplexType() || RHSType->isComplexType())
- return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
- ACK == ACK_CompAssign);
+ return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType,
+ ACK == ACK_CompAssign);
// Now handle "real" floating types (i.e. float, double, long double).
if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
@@ -1624,10 +1625,9 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
Types[i] = nullptr;
}
- ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
- ControllingExpr,
- llvm::makeArrayRef(Types, NumAssocs),
- ArgExprs);
+ ExprResult ER =
+ CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr,
+ llvm::ArrayRef(Types, NumAssocs), ArgExprs);
delete [] Types;
return ER;
}
@@ -1839,7 +1839,7 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
- if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
+ if (S.LookupLiteralOperator(Scope, R, llvm::ArrayRef(ArgTy, Args.size()),
/*AllowRaw*/ false, /*AllowTemplate*/ false,
/*AllowStringTemplatePack*/ false,
/*DiagnoseMissing*/ true) == Sema::LOLR_Error)
@@ -1964,8 +1964,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
TemplateArgument Arg(Lit);
TemplateArgumentLocInfo ArgInfo(Lit);
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
- return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
- &ExplicitArgs);
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt,
+ StringTokLocs.back(), &ExplicitArgs);
}
case LOLR_StringTemplatePack: {
@@ -1985,8 +1985,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
- &ExplicitArgs);
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt,
+ StringTokLocs.back(), &ExplicitArgs);
}
case LOLR_Raw:
case LOLR_ErrorNoDiagnostic:
@@ -2082,9 +2082,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
NestedNameSpecifierLoc NNS, NamedDecl *FoundD,
SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo *TemplateArgs) {
- bool RefersToCapturedVariable =
- isa<VarDecl>(D) &&
- NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
+ bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) &&
+ NeedToCaptureVariable(D, NameInfo.getLoc());
DeclRefExpr *E = DeclRefExpr::Create(
Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
@@ -2626,7 +2625,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// a template name, but we happen to have always already looked up the name
// before we get here if it must be a template name.
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
- None, &TE)) {
+ std::nullopt, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();
@@ -2738,6 +2737,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
ExprResult Sema::BuildQualifiedDeclarationNameExpr(
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) {
+ if (NameInfo.getName().isDependentName())
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/nullptr);
+
DeclContext *DC = computeDeclContext(SS, false);
if (!DC)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
@@ -2947,7 +2950,7 @@ ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
getCurFunction()->recordUseOfWeak(Result);
}
- if (getLangOpts().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount && !isUnevaluatedContext())
if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
@@ -3187,8 +3190,9 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
/// as an expression. This is only actually called for lookups that
/// were not overloaded, and it doesn't promise that the declaration
/// will in fact be used.
-static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
- if (D->isInvalidDecl())
+static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D,
+ bool AcceptInvalid) {
+ if (D->isInvalidDecl() && !AcceptInvalid)
return true;
if (isa<TypedefNameDecl>(D)) {
@@ -3234,7 +3238,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// result, because in the overloaded case the results can only be
// functions and function templates.
if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) &&
- CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
+ CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl(),
+ AcceptInvalidDecl))
return ExprError();
// Otherwise, just build an unresolved lookup expression. Suppress
@@ -3252,8 +3257,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return ULE;
}
-static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- ValueDecl *var);
+static void diagnoseUncapturableValueReferenceOrBinding(Sema &S,
+ SourceLocation loc,
+ ValueDecl *var);
/// Complete semantic analysis for a reference to the given declaration.
ExprResult Sema::BuildDeclarationNameExpr(
@@ -3265,7 +3271,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
"Cannot refer unambiguously to a function template");
SourceLocation Loc = NameInfo.getLoc();
- if (CheckDeclInExpr(*this, Loc, D)) {
+ if (CheckDeclInExpr(*this, Loc, D, AcceptInvalidDecl)) {
// Recovery from invalid cases (e.g. D is an invalid Decl).
// We use the dependent type for the RecoveryExpr to prevent bogus follow-up
// diagnostics, as invalid decls use int as a fallback type.
@@ -3391,7 +3397,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_PRValue;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::ImplicitParam:
case Decl::ParmVar: {
@@ -3411,20 +3417,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
- case Decl::Binding: {
+ case Decl::Binding:
// These are always lvalues.
valueKind = VK_LValue;
type = type.getNonReferenceType();
- // FIXME: Support lambda-capture of BindingDecls, once CWG actually
- // decides how that's supposed to work.
- auto *BD = cast<BindingDecl>(VD);
- if (BD->getDeclContext() != CurContext) {
- auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
- if (DD && DD->hasLocalStorage())
- diagnoseUncapturableValueReference(*this, Loc, BD);
- }
break;
- }
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
@@ -3497,7 +3494,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_LValue;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::CXXConversion:
case Decl::CXXDestructor:
@@ -3506,9 +3503,16 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
- /*FIXME: TemplateKWLoc*/ SourceLocation(),
- TemplateArgs);
+ auto *E =
+ BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+ /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs);
+ // Clang AST consumers assume a DeclRefExpr refers to a valid decl. We
+ // wrap a DeclRefExpr referring to an invalid decl with a dependent-type
+ // RecoveryExpr to avoid follow-up semantic analysis (thus prevent bogus
+ // diagnostics).
+ if (VD->isInvalidDecl() && E)
+ return CreateRecoveryExpr(E->getBeginLoc(), E->getEndLoc(), {E});
+ return E;
}
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
@@ -3856,7 +3860,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc,
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, TokLoc,
&ExplicitArgs);
}
case LOLR_StringTemplatePack:
@@ -3949,16 +3953,6 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
QualType Ty;
- // 'long long' is a C99 or C++11 feature.
- if (!getLangOpts().C99 && Literal.isLongLong) {
- if (getLangOpts().CPlusPlus)
- Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
- else
- Diag(Tok.getLocation(), diag::ext_c99_longlong);
- }
-
// 'z/uz' literals are a C++2b feature.
if (Literal.isSizeT)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus
@@ -4125,6 +4119,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
else if (AllowUnsigned)
Ty = Context.UnsignedLongLongTy;
Width = LongLongSize;
+
+ // 'long long' is a C99 or C++11 feature, whether the literal
+ // explicitly specified 'long long' or we needed the extra width.
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_longlong
+ : diag::ext_cxx11_longlong);
+ else if (!getLangOpts().C99)
+ Diag(Tok.getLocation(), diag::ext_c99_longlong);
}
}
@@ -4504,7 +4507,6 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::ConstantMatrix:
case Type::Record:
case Type::Enum:
- case Type::Elaborated:
case Type::TemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
@@ -4513,6 +4515,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::Pipe:
case Type::BitInt:
llvm_unreachable("type class is never variably-modified!");
+ case Type::Elaborated:
+ T = cast<ElaboratedType>(Ty)->getNamedType();
+ break;
case Type::Adjusted:
T = cast<AdjustedType>(Ty)->getOriginalType();
break;
@@ -5011,7 +5016,7 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
return nullptr;
}
- if (Optional<llvm::APSInt> Idx =
+ if (std::optional<llvm::APSInt> Idx =
IndexExpr->getIntegerConstantExpr(Context)) {
if ((*Idx < 0 || *Idx >= Dim)) {
Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range)
@@ -5415,6 +5420,10 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc,
} else {
CurContext->addDecl(VD);
}
+
+ /// Act on the iterator variable declaration.
+ ActOnOpenMPIteratorVarDecl(VD);
+
Expr *Begin = D.Range.Begin;
if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) {
ExprResult BeginRes =
@@ -5434,7 +5443,8 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc,
IsCorrect = false;
continue;
}
- Optional<llvm::APSInt> Result = Step->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> Result =
+ Step->getIntegerConstantExpr(Context);
// OpenMP 5.0, 2.1.6 Iterators, Restrictions
// If the step expression of a range-specification equals zero, the
// behavior is unspecified.
@@ -5856,8 +5866,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param) {
+ ParmVarDecl *Param, Expr *RewrittenInit,
+ bool SkipImmediateInvocations) {
if (Param->hasUnparsedDefaultArg()) {
+ assert(!RewrittenInit && "Should not have a rewritten init expression yet");
// If we've already cleared out the location for the default argument,
// that means we're parsing it right now.
if (!UnparsedDefaultArgLocs.count(Param)) {
@@ -5874,11 +5886,14 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
return true;
}
- if (Param->hasUninstantiatedDefaultArg() &&
- InstantiateDefaultArgument(CallLoc, FD, Param))
- return true;
+ if (Param->hasUninstantiatedDefaultArg()) {
+ assert(!RewrittenInit && "Should not have a rewitten init expression yet");
+ if (InstantiateDefaultArgument(CallLoc, FD, Param))
+ return true;
+ }
- assert(Param->hasInit() && "default argument but no initializer?");
+ Expr *Init = RewrittenInit ? RewrittenInit : Param->getInit();
+ assert(Init && "default argument but no initializer?");
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
@@ -5887,34 +5902,258 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// bound temporaries; see the comment in PR5810.
// We don't need to do that with block decls, though, because
// blocks in default argument expression can never capture anything.
- if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) {
+ if (auto *InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) {
// Set the "needs cleanups" bit regardless of whether there are
// any explicit objects.
- Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects());
-
+ Cleanup.setExprNeedsCleanups(InitWithCleanup->cleanupsHaveSideEffects());
// Append all the objects to the cleanup list. Right now, this
// should always be a no-op, because blocks in default argument
// expressions should never be able to capture anything.
- assert(!Init->getNumObjects() &&
+ assert(!InitWithCleanup->getNumObjects() &&
"default argument expression has capturing blocks?");
}
-
- // We already type-checked the argument, so we know it works.
- // Just mark all of the declarations in this potentially-evaluated expression
- // as being "referenced".
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
- MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
- /*SkipLocalVariables=*/true);
+ ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
+ SkipImmediateInvocations;
+ MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true);
return false;
}
+struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
+ bool HasImmediateCalls = false;
+
+ bool shouldVisitImplicitCode() const { return true; }
+
+ bool VisitCallExpr(CallExpr *E) {
+ if (const FunctionDecl *FD = E->getDirectCallee())
+ HasImmediateCalls |= FD->isConsteval();
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+
+ // SourceLocExpr are not immediate invocations
+ // but CXXDefaultInitExpr/CXXDefaultArgExpr containing a SourceLocExpr
+ // need to be rebuilt so that they refer to the correct SourceLocation and
+ // DeclContext.
+ bool VisitSourceLocExpr(SourceLocExpr *E) {
+ HasImmediateCalls = true;
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+
+ // A nested lambda might have parameters with immediate invocations
+ // in their default arguments.
+ // The compound statement is not visited (as it does not constitute a
+ // subexpression).
+ // FIXME: We should consider visiting and transforming captures
+ // with init expressions.
+ bool VisitLambdaExpr(LambdaExpr *E) {
+ return VisitCXXMethodDecl(E->getCallOperator());
+ }
+
+ // Blocks don't support default parameters, and, as for lambdas,
+ // we don't consider their body a subexpression.
+ bool VisitBlockDecl(BlockDecl *B) { return false; }
+
+ bool VisitCompoundStmt(CompoundStmt *B) { return false; }
+
+ bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ return TraverseStmt(E->getExpr());
+ }
+
+ bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ return TraverseStmt(E->getExpr());
+ }
+};
+
+struct EnsureImmediateInvocationInDefaultArgs
+ : TreeTransform<EnsureImmediateInvocationInDefaultArgs> {
+ EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef)
+ : TreeTransform(SemaRef) {}
+
+ // Lambda can only have immediate invocations in the default
+ // args of their parameters, which is transformed upon calling the closure.
+ // The body is not a subexpression, so we have nothing to do.
+ // FIXME: Immediate calls in capture initializers should be transformed.
+ ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; }
+ ExprResult TransformBlockExpr(BlockExpr *E) { return E; }
+
+ // Make sure we don't rebuild the this pointer as it would
+ // cause it to incorrectly point it to the outermost class
+ // in the case of nested struct initialization.
+ ExprResult TransformCXXThisExpr(CXXThisExpr *E) { return E; }
+};
+
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
- FunctionDecl *FD, ParmVarDecl *Param) {
+ FunctionDecl *FD, ParmVarDecl *Param,
+ Expr *Init) {
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
- if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+
+ bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
+
+ std::optional<ExpressionEvaluationContextRecord::InitializationContext>
+ InitializationContext =
+ OutermostDeclarationWithDelayedImmediateInvocations();
+ if (!InitializationContext.has_value())
+ InitializationContext.emplace(CallLoc, Param, CurContext);
+
+ if (!Init && !Param->hasUnparsedDefaultArg()) {
+ // Mark that we are replacing a default argument first.
+ // If we are instantiating a template we won't have to
+ // retransform immediate calls.
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+
+ if (Param->hasUninstantiatedDefaultArg()) {
+ if (InstantiateDefaultArgument(CallLoc, FD, Param))
+ return ExprError();
+ }
+ // CWG2631
+ // 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;
+ 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);
+ if (Res.isInvalid())
+ return ExprError();
+ Res = ConvertParamDefaultArgument(Param, Res.get(),
+ Res.get()->getBeginLoc());
+ if (Res.isInvalid())
+ return ExprError();
+ Init = Res.get();
+ }
+ }
+
+ if (CheckCXXDefaultArgExpr(
+ CallLoc, FD, Param, Init,
+ /*SkipImmediateInvocations=*/NestedDefaultChecking))
return ExprError();
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
+
+ return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param,
+ Init, InitializationContext->Context);
+}
+
+ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
+ assert(Field->hasInClassInitializer());
+
+ // If we might have already tried and failed to instantiate, don't try again.
+ if (Field->isInvalidDecl())
+ return ExprError();
+
+ auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
+
+ std::optional<ExpressionEvaluationContextRecord::InitializationContext>
+ InitializationContext =
+ OutermostDeclarationWithDelayedImmediateInvocations();
+ if (!InitializationContext.has_value())
+ InitializationContext.emplace(Loc, Field, CurContext);
+
+ Expr *Init = nullptr;
+
+ bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
+
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
+
+ if (!Field->getInClassInitializer()) {
+ // Maybe we haven't instantiated the in-class initializer. Go check the
+ // pattern FieldDecl to see if it has one.
+ if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
+ CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
+ DeclContext::lookup_result Lookup =
+ ClassPattern->lookup(Field->getDeclName());
+
+ FieldDecl *Pattern = nullptr;
+ for (auto *L : Lookup) {
+ if ((Pattern = dyn_cast<FieldDecl>(L)))
+ break;
+ }
+ assert(Pattern && "We must have set the Pattern!");
+ if (!Pattern->hasInClassInitializer() ||
+ InstantiateInClassInitializer(Loc, Field, Pattern,
+ getTemplateInstantiationArgs(Field))) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ }
+ }
+
+ // CWG2631
+ // 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 [...] a constructor
+ // definition, or an aggregate initialization.
+ ImmediateCallVisitor V;
+ if (!NestedDefaultChecking)
+ V.TraverseDecl(Field);
+ if (V.HasImmediateCalls) {
+ ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
+ CurContext};
+ ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
+ NestedDefaultChecking;
+
+ EnsureImmediateInvocationInDefaultArgs Immediate(*this);
+
+ ExprResult Res =
+ Immediate.TransformInitializer(Field->getInClassInitializer(),
+ /*CXXDirectInit=*/false);
+ if (!Res.isInvalid())
+ Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
+ if (Res.isInvalid()) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ Init = Res.get();
+ }
+
+ if (Field->getInClassInitializer()) {
+ Expr *E = Init ? Init : Field->getInClassInitializer();
+ if (!NestedDefaultChecking)
+ MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false);
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ ExprResult Res = ActOnFinishFullExpr(E, /*DiscardedValue=*/false);
+ if (Res.isInvalid()) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ Init = Res.get();
+
+ return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc,
+ Field, InitializationContext->Context,
+ Init);
+ }
+
+ // DR1351:
+ // If the brace-or-equal-initializer of a non-static data member
+ // invokes a defaulted default constructor of its class or of an
+ // enclosing class in a potentially evaluated subexpression, the
+ // program is ill-formed.
+ //
+ // This resolution is unworkable: the exception specification of the
+ // default constructor can be needed in an unevaluated context, in
+ // particular, in the operand of a noexcept-expression, and we can be
+ // unable to compute an exception specification for an enclosed class.
+ //
+ // Any attempt to resolve the exception specification of a defaulted default
+ // constructor before the initializer is lexically complete will ultimately
+ // come here at which point we can diagnose it.
+ RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext();
+ Diag(Loc, diag::err_default_member_initializer_not_yet_parsed)
+ << OutermostClass << Field;
+ Diag(Field->getEndLoc(),
+ diag::note_default_member_initializer_not_yet_parsed);
+ // Recover by marking the field invalid, unless we're in a SFINAE context.
+ if (!isSFINAEContext())
+ Field->setInvalidDecl();
+ return ExprError();
}
Sema::VariadicCallType
@@ -6287,9 +6526,10 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc,
return;
}
- Optional<CharUnits> ArgSize =
+ std::optional<CharUnits> ArgSize =
getASTContext().getTypeSizeInCharsIfKnown(ArgCAT);
- Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT);
+ std::optional<CharUnits> ParmSize =
+ getASTContext().getTypeSizeInCharsIfKnown(CAT);
if (ArgSize && ParmSize && *ArgSize < *ParmSize) {
Diag(CallLoc, diag::warn_static_array_too_small)
<< ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity()
@@ -6762,8 +7002,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
nullptr, DRE->isNonOdrUse());
}
}
- } else if (isa<MemberExpr>(NakedFn))
- NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
+ } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn))
+ NDecl = ME->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable(
@@ -7035,7 +7275,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
TheCall = dyn_cast<CallExpr>(Result.get());
bool CorrectedTypos = TheCall != TheOldCall;
if (!TheCall) return Result;
- Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
+ Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
// A new call expression node was created if some typos were corrected.
// However it may not have been constructed with enough storage. In this
@@ -8165,23 +8405,6 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
return true;
}
-/// Handle when one or both operands are void type.
-static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
- ExprResult &RHS) {
- Expr *LHSExpr = LHS.get();
- Expr *RHSExpr = RHS.get();
-
- if (!LHSExpr->getType()->isVoidType())
- S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
- << RHSExpr->getSourceRange();
- if (!RHSExpr->getType()->isVoidType())
- S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
- << LHSExpr->getSourceRange();
- LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid);
- RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid);
- return S.Context.VoidTy;
-}
-
/// Return false if the NullExpr can be promoted to PointerTy,
/// true otherwise.
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
@@ -8205,7 +8428,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
if (S.Context.hasSameType(LHSTy, RHSTy)) {
// Two identical pointers types are always compatible.
- return LHSTy;
+ return S.Context.getCommonSugaredType(LHSTy, RHSTy);
}
QualType lhptee, rhptee;
@@ -8275,7 +8498,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
- QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
+ QualType CompositeTy = S.Context.mergeTypes(
+ lhptee, rhptee, /*OfBlockPointer=*/false, /*Unqualified=*/false,
+ /*BlockReturnType=*/false, /*IsConditionalOperator=*/true);
if (CompositeTy.isNull()) {
// In this situation, we assume void* type. No especially good
@@ -8707,7 +8932,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// And if they're both bfloat (which isn't arithmetic), that's fine too.
if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) {
- return LHSTy;
+ return Context.getCommonSugaredType(LHSTy, RHSTy);
}
// If both operands are the same structure or union type, the result is that
@@ -8717,16 +8942,37 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHSRT->getDecl() == RHSRT->getDecl())
// "If both the operands have structure or union type, the result has
// that type." This implies that CV qualifiers are dropped.
- return LHSTy.getUnqualifiedType();
+ return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(),
+ RHSTy.getUnqualifiedType());
// FIXME: Type of conditional expression must be complete in C mode.
}
// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
- return checkConditionalVoidType(*this, LHS, RHS);
+ QualType ResTy;
+ if (LHSTy->isVoidType() && RHSTy->isVoidType()) {
+ ResTy = Context.getCommonSugaredType(LHSTy, RHSTy);
+ } else if (RHSTy->isVoidType()) {
+ ResTy = RHSTy;
+ Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
+ << RHS.get()->getSourceRange();
+ } else {
+ ResTy = LHSTy;
+ Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
+ << LHS.get()->getSourceRange();
+ }
+ LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid);
+ RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid);
+ return ResTy;
}
+ // C2x 6.5.15p7:
+ // ... if both the second and third operands have nullptr_t type, the
+ // result also has that type.
+ if (LHSTy->isNullPtrType() && Context.hasSameType(LHSTy, RHSTy))
+ return ResTy;
+
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy;
@@ -8763,7 +9009,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// Allow ?: operations in which both operands have the same
// built-in sizeless type.
if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy))
- return LHSTy;
+ return Context.getCommonSugaredType(LHSTy, RHSTy);
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is not a pointer type. In this case, the user most
@@ -9061,8 +9307,8 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
if (!ResTy->isAnyPointerType())
return ResTy;
- auto GetNullability = [&Ctx](QualType Ty) {
- Optional<NullabilityKind> Kind = Ty->getNullability(Ctx);
+ auto GetNullability = [](QualType Ty) {
+ std::optional<NullabilityKind> Kind = Ty->getNullability();
if (Kind) {
// For our purposes, treat _Nullable_result as _Nullable.
if (*Kind == NullabilityKind::NullableResult)
@@ -9099,7 +9345,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
return ResTy;
// Strip all nullability from ResTy.
- while (ResTy->getNullability(Ctx))
+ while (ResTy->getNullability())
ResTy = ResTy.getSingleStepDesugaredType(Ctx);
// Create a new AttributedType with the new nullability kind.
@@ -9236,7 +9482,8 @@ static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType,
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
static Sema::AssignConvertType
-checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
+checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
+ SourceLocation Loc) {
assert(LHSType.isCanonical() && "LHS not canonicalized!");
assert(RHSType.isCanonical() && "RHS not canonicalized!");
@@ -9305,6 +9552,13 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
return Sema::FunctionVoidPointer;
}
+ if (!S.Diags.isIgnored(
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict,
+ Loc) &&
+ RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() &&
+ !S.IsFunctionConversion(RHSType, LHSType, RHSType))
+ return Sema::IncompatibleFunctionPointerStrict;
+
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0);
@@ -9656,7 +9910,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
Kind = CK_NoOp;
else
Kind = CK_BitCast;
- return checkPointerTypesForAssignment(*this, LHSType, RHSType);
+ return checkPointerTypesForAssignment(*this, LHSType, RHSType,
+ RHS.get()->getBeginLoc());
}
// int -> T*
@@ -9984,6 +10239,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
return Incompatible;
}
+ // This check seems unnatural, however it is necessary to ensure the proper
+ // conversion of functions/arrays. If the conversion were done for all
+ // DeclExpr's (created by ActOnIdExpression), it would mess up the unary
+ // expressions that suppress this implicit conversion (&, sizeof). This needs
+ // to happen before we check for null pointer conversions because C does not
+ // undergo the same implicit conversions as C++ does above (by the calls to
+ // TryImplicitConversion() and PerformImplicitConversion()) which insert the
+ // lvalue to rvalue cast before checking for null pointer constraints. This
+ // addresses code like: nullptr_t val; int *ptr; ptr = val;
+ //
+ // Suppress this for references: C++ 8.5.3p5.
+ if (!LHSType->isReferenceType()) {
+ // FIXME: We potentially allocate here even if ConvertRHS is false.
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
+ if (RHS.isInvalid())
+ return Incompatible;
+ }
+
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() ||
@@ -10008,18 +10281,6 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
return Compatible;
}
- // This check seems unnatural, however it is necessary to ensure the proper
- // conversion of functions/arrays. If the conversion were done for all
- // DeclExpr's (created by ActOnIdExpression), it would mess up the unary
- // expressions that suppress this implicit conversion (&, sizeof).
- //
- // Suppress this for references: C++ 8.5.3p5.
- if (!LHSType->isReferenceType()) {
- // FIXME: We potentially allocate here even if ConvertRHS is false.
- RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
- if (RHS.isInvalid())
- return Incompatible;
- }
CastKind Kind;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
@@ -10434,7 +10695,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
// If the vector types are identical, return.
if (Context.hasSameType(LHSType, RHSType))
- return LHSType;
+ return Context.getCommonSugaredType(LHSType, RHSType);
// If we have compatible AltiVec and GCC vector types, use the AltiVec type.
if (LHSVecType && RHSVecType &&
@@ -11249,7 +11510,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
QualType LHSTy = Context.isPromotableBitField(LHS.get());
if (LHSTy.isNull()) {
LHSTy = LHS.get()->getType();
- if (LHSTy->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(LHSTy))
LHSTy = Context.getPromotedIntegerType(LHSTy);
}
*CompLHSTy = LHSTy;
@@ -12268,7 +12529,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
// promote the boolean type, and all other promotable integer types, to
// avoid this.
- if (IntType->isPromotableIntegerType())
+ if (S.Context.isPromotableIntegerType(IntType))
IntType = S.Context.getPromotedIntegerType(IntType);
LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast);
@@ -12285,7 +12546,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
- Optional<ComparisonCategoryType> CCT =
+ std::optional<ComparisonCategoryType> CCT =
getComparisonCategoryForBuiltinCmp(Type);
if (!CCT)
return S.InvalidOperands(Loc, LHS, RHS);
@@ -12429,7 +12690,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
QualType CompositeTy = LHS.get()->getType();
assert(!CompositeTy->isReferenceType());
- Optional<ComparisonCategoryType> CCT =
+ std::optional<ComparisonCategoryType> CCT =
getComparisonCategoryForBuiltinCmp(CompositeTy);
if (!CCT)
return InvalidOperands(Loc, LHS, RHS);
@@ -12574,34 +12835,54 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return computeResultTy();
}
- if (getLangOpts().CPlusPlus) {
- // C++ [expr.eq]p4:
- // Two operands of type std::nullptr_t or one operand of type
- // std::nullptr_t and the other a null pointer constant compare equal.
- if (!IsOrdered && LHSIsNull && RHSIsNull) {
- if (LHSType->isNullPtrType()) {
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return computeResultTy();
- }
- if (RHSType->isNullPtrType()) {
- LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return computeResultTy();
- }
- }
- // Comparison of Objective-C pointers and block pointers against nullptr_t.
- // These aren't covered by the composite pointer type rules.
- if (!IsOrdered && RHSType->isNullPtrType() &&
- (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
+ // C++ [expr.eq]p4:
+ // Two operands of type std::nullptr_t or one operand of type
+ // std::nullptr_t and the other a null pointer constant compare
+ // equal.
+ // C2x 6.5.9p5:
+ // If both operands have type nullptr_t or one operand has type nullptr_t
+ // and the other is a null pointer constant, they compare equal.
+ if (!IsOrdered && LHSIsNull && RHSIsNull) {
+ if (LHSType->isNullPtrType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsOrdered && LHSType->isNullPtrType() &&
- (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
+ if (RHSType->isNullPtrType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
}
+ }
+
+ if (!getLangOpts().CPlusPlus && !IsOrdered && (LHSIsNull || RHSIsNull)) {
+ // C2x 6.5.9p6:
+ // Otherwise, at least one operand is a pointer. If one is a pointer and
+ // the other is a null pointer constant, the null pointer constant is
+ // converted to the type of the pointer.
+ if (LHSIsNull && RHSType->isPointerType()) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (RHSIsNull && LHSType->isPointerType()) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ }
+
+ // Comparison of Objective-C pointers and block pointers against nullptr_t.
+ // These aren't covered by the composite pointer type rules.
+ if (!IsOrdered && RHSType->isNullPtrType() &&
+ (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (!IsOrdered && LHSType->isNullPtrType() &&
+ (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (getLangOpts().CPlusPlus) {
if (IsRelational &&
((LHSType->isNullPtrType() && RHSType->isPointerType()) ||
(RHSType->isNullPtrType() && LHSType->isPointerType()))) {
@@ -13152,7 +13433,7 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
if (Context.hasSameType(LHSType, RHSType))
- return LHSType;
+ return Context.getCommonSugaredType(LHSType, RHSType);
// Type conversion may change LHS/RHS. Keep copies to the original results, in
// case we have to return InvalidOperands.
@@ -13196,13 +13477,19 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS,
if (LHSMatType->getNumColumns() != RHSMatType->getNumRows())
return InvalidOperands(Loc, LHS, RHS);
- if (!Context.hasSameType(LHSMatType->getElementType(),
- RHSMatType->getElementType()))
+ if (Context.hasSameType(LHSMatType, RHSMatType))
+ return Context.getCommonSugaredType(
+ LHS.get()->getType().getUnqualifiedType(),
+ RHS.get()->getType().getUnqualifiedType());
+
+ QualType LHSELTy = LHSMatType->getElementType(),
+ RHSELTy = RHSMatType->getElementType();
+ if (!Context.hasSameType(LHSELTy, RHSELTy))
return InvalidOperands(Loc, LHS, RHS);
- return Context.getConstantMatrixType(LHSMatType->getElementType(),
- LHSMatType->getNumRows(),
- RHSMatType->getNumColumns());
+ return Context.getConstantMatrixType(
+ Context.getCommonSugaredType(LHSELTy, RHSELTy),
+ LHSMatType->getNumRows(), RHSMatType->getNumColumns());
}
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
}
@@ -13937,19 +14224,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// type is deprecated unless the assignment is either a discarded-value
// expression or an unevaluated operand
ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
- } else {
- // C++20 [expr.ass]p6:
- // [Compound-assignment] expressions are deprecated if E1 has
- // volatile-qualified type and op is not one of the bitwise
- // operators |, &, ˆ.
- switch (Opc) {
- case BO_OrAssign:
- case BO_AndAssign:
- case BO_XorAssign:
- break;
- default:
- Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
- }
}
}
@@ -13964,8 +14238,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
return getLangOpts().CPlusPlus ? LHSType : LHSType.getAtomicUnqualifiedType();
}
-// Only ignore explicit casts to void.
-static bool IgnoreCommaOperand(const Expr *E) {
+// Scenarios to ignore if expression E is:
+// 1. an explicit cast expression into void
+// 2. a function call expression that returns void
+static bool IgnoreCommaOperand(const Expr *E, const ASTContext &Context) {
E = E->IgnoreParens();
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
@@ -13980,6 +14256,8 @@ static bool IgnoreCommaOperand(const Expr *E) {
}
}
+ if (const auto *CE = dyn_cast<CallExpr>(E))
+ return CE->getCallReturnType(Context)->isVoidType();
return false;
}
@@ -14021,7 +14299,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
}
// Only allow some expressions on LHS to not warn.
- if (IgnoreCommaOperand(LHS))
+ if (IgnoreCommaOperand(LHS, Context))
return;
Diag(Loc, diag::warn_comma_operator);
@@ -14486,7 +14764,8 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
/// CheckIndirectionOperand - Type check unary indirection (prefix '*').
static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
- SourceLocation OpLoc) {
+ SourceLocation OpLoc,
+ bool IsAfterAmp = false) {
if (Op->isTypeDependent())
return S.Context.DependentTy;
@@ -14523,18 +14802,18 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
return QualType();
}
- // Note that per both C89 and C99, indirection is always legal, even if Result
- // is an incomplete type or void. It would be possible to warn about
- // dereferencing a void pointer, but it's completely well-defined, and such a
- // warning is unlikely to catch any mistakes. In C++, indirection is not valid
- // for pointers to 'void' but is fine for any other pointer type:
- //
- // C++ [expr.unary.op]p1:
- // [...] the expression to which [the unary * operator] is applied shall
- // be a pointer to an object type, or a pointer to a function type
- if (S.getLangOpts().CPlusPlus && Result->isVoidType())
- S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer)
- << OpTy << Op->getSourceRange();
+ if (Result->isVoidType()) {
+ // C++ [expr.unary.op]p1:
+ // [...] the expression to which [the unary * operator] is applied shall
+ // 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)
+ << OpTy << Op->getSourceRange();
+ else if (!(LO.C99 && IsAfterAmp) && !S.isUnevaluatedContext())
+ S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer)
+ << OpTy << Op->getSourceRange();
+ }
// Dereferences are usually l-values...
VK = VK_LValue;
@@ -14968,7 +15247,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_Xor:
case BO_Or:
ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
@@ -15020,7 +15299,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_AndAssign:
case BO_OrAssign: // fallthrough
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
@@ -15163,38 +15442,21 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
Bop->getSourceRange());
}
-/// Returns true if the given expression can be evaluated as a constant
-/// 'true'.
-static bool EvaluatesAsTrue(Sema &S, Expr *E) {
- bool Res;
- return !E->isValueDependent() &&
- E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res;
-}
-
-/// Returns true if the given expression can be evaluated as a constant
-/// 'false'.
-static bool EvaluatesAsFalse(Sema &S, Expr *E) {
- bool Res;
- return !E->isValueDependent() &&
- E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res;
-}
-
/// Look for '&&' in the left hand of a '||' expr.
static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
- // If it's "a && b || 0" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, RHSExpr))
- return;
- // If it's "1 && a || b" don't warn since the precedence doesn't matter.
- if (!EvaluatesAsTrue(S, Bop->getLHS()))
+ // If it's "string_literal && a || b" don't warn since the precedence
+ // doesn't matter.
+ if (!isa<StringLiteral>(Bop->getLHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop);
} else if (Bop->getOpcode() == BO_LOr) {
if (BinaryOperator *RBop = dyn_cast<BinaryOperator>(Bop->getRHS())) {
- // If it's "a || b && 1 || c" we didn't warn earlier for
- // "a || b && 1", but warn now.
- if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS()))
+ // If it's "a || b && string_literal || c" we didn't warn earlier for
+ // "a || b && string_literal", but warn now.
+ if (RBop->getOpcode() == BO_LAnd &&
+ isa<StringLiteral>(RBop->getRHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop);
}
}
@@ -15206,11 +15468,9 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
- // If it's "0 || a && b" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, LHSExpr))
- return;
- // If it's "a || b && 1" don't warn since the precedence doesn't matter.
- if (!EvaluatesAsTrue(S, Bop->getRHS()))
+ // If it's "a || b && string_literal" don't warn since the precedence
+ // doesn't matter.
+ if (!isa<StringLiteral>(Bop->getRHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop);
}
}
@@ -15516,15 +15776,15 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
if (T.isNull() || T->isDependentType())
return false;
- if (!T->isPromotableIntegerType())
+ if (!Ctx.isPromotableIntegerType(T))
return true;
return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy);
}
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
- UnaryOperatorKind Opc,
- Expr *InputExpr) {
+ UnaryOperatorKind Opc, Expr *InputExpr,
+ bool IsAfterAmp) {
ExprResult Input = InputExpr;
ExprValueKind VK = VK_PRValue;
ExprObjectKind OK = OK_Ordinary;
@@ -15546,7 +15806,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && OpLoc.isValid()) {
if (Opc == UO_AddrOf)
return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0);
if (Opc == UO_Deref)
@@ -15574,7 +15834,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.get());
if (Input.isInvalid()) return ExprError();
- resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
+ resultType =
+ CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp);
break;
}
case UO_Plus:
@@ -15603,6 +15864,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool))
break;
+ else if (resultType->isVLSTBuiltinType()) // SVE vectors allow + and -
+ break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
Opc == UO_Plus &&
resultType->isPointerType())
@@ -15792,7 +16055,8 @@ bool Sema::isQualifiedMemberAccess(Expr *E) {
}
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
- UnaryOperatorKind Opc, Expr *Input) {
+ UnaryOperatorKind Opc, Expr *Input,
+ bool IsAfterAmp) {
// First things first: handle placeholders so that the
// overloaded-operator check considers the right type.
if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) {
@@ -15831,13 +16095,14 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input);
}
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input, IsAfterAmp);
}
// Unary Operators. 'Tok' is the token for the operator.
-ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
- tok::TokenKind Op, Expr *Input) {
- return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input);
+ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op,
+ Expr *Input, bool IsAfterAmp) {
+ return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input,
+ IsAfterAmp);
}
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
@@ -15845,8 +16110,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) {
TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'.
- return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
- Context.getPointerType(Context.VoidTy));
+ auto *Res = new (Context) AddrLabelExpr(
+ OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy));
+
+ if (getCurFunction())
+ getCurFunction()->AddrLabels.push_back(Res);
+
+ return Res;
}
void Sema::ActOnStartStmtExpr() {
@@ -16203,7 +16473,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals.addConst();
- T = Context.getFunctionType(Context.DependentTy, None, EPI);
+ T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
@@ -16290,7 +16560,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
// Put the parameter variables in scope.
- for (auto AI : CurBlock->TheDecl->parameters()) {
+ for (auto *AI : CurBlock->TheDecl->parameters()) {
AI->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
@@ -16353,10 +16623,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, None, EPI);
+ BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI);
- // Otherwise, if we don't need to change anything about the function type,
- // preserve its sugar structure.
+ // Otherwise, if we don't need to change anything about the function type,
+ // preserve its sugar structure.
} else if (FTy->getReturnType() == RetTy &&
(!NoReturn || FTy->getNoReturnAttr())) {
BlockTy = BSI->FunctionType;
@@ -16374,7 +16644,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
} else {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
- BlockTy = Context.getFunctionType(RetTy, None, EPI);
+ BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI);
}
DiagnoseUnusedParameters(BD->parameters());
@@ -16409,8 +16679,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (Capture &Cap : BSI->Captures) {
if (Cap.isInvalid() || Cap.isThisCapture())
continue;
-
- VarDecl *Var = Cap.getVariable();
+ // Cap.getVariable() is always a VarDecl because
+ // blocks cannot capture structured bindings or other ValueDecl kinds.
+ auto *Var = cast<VarDecl>(Cap.getVariable());
Expr *CopyExpr = nullptr;
if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
if (const RecordType *Record =
@@ -16603,7 +16874,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// Check for va_arg where arguments of the given type will be promoted
// (i.e. this va_arg is guaranteed to have undefined behavior).
QualType PromoteType;
- if (TInfo->getType()->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(TInfo->getType())) {
PromoteType = Context.getPromotedIntegerType(TInfo->getType());
// [cstdarg.syn]p1 defers the C++ behavior to what the C standard says,
// and C2x 7.16.1.1p2 says, in part:
@@ -16664,7 +16935,7 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
// The type of __null will be int or long, depending on the size of
// pointers on the target.
QualType Ty;
- unsigned pw = Context.getTargetInfo().getPointerWidth(0);
+ unsigned pw = Context.getTargetInfo().getPointerWidth(LangAS::Default);
if (pw == Context.getTargetInfo().getIntWidth())
Ty = Context.IntTy;
else if (pw == Context.getTargetInfo().getLongWidth())
@@ -16902,6 +17173,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
break;
+ case IncompatibleFunctionPointerStrict:
+ DiagKind =
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
+ break;
case IncompatibleFunctionPointer:
if (getLangOpts().CPlusPlus) {
DiagKind = diag::err_typecheck_convert_incompatible_function_pointer;
@@ -17492,6 +17769,7 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
!Decl->isConsteval() || isConstantEvaluated() ||
+ isCheckingDefaultArgumentOrInitializer() ||
RebuildingImmediateInvocation || isImmediateFunctionContext())
return E;
@@ -17537,8 +17815,14 @@ static void EvaluateAndDiagnoseImmediateInvocation(
FD = Call->getConstructor();
else
llvm_unreachable("unhandled decl kind");
- assert(FD->isConsteval());
+ assert(FD && FD->isConsteval());
SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD;
+ 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);
+ }
for (auto &Note : Notes)
SemaRef.Diag(Note.first, Note.second);
return;
@@ -17598,6 +17882,11 @@ static void RemoveNestedImmediateInvocation(
DRSet.erase(E);
return E;
}
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Do not rebuild lambdas to avoid creating a new type.
+ // Lambdas have already been processed inside their eval context.
+ return E;
+ }
bool AlwaysRebuild() { return false; }
bool ReplacingOriginal() { return true; }
bool AllowSkippingCXXConstructExpr() {
@@ -17619,9 +17908,13 @@ static void RemoveNestedImmediateInvocation(
Transformer.AllowSkippingFirstCXXConstructExpr = false;
ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr());
- assert(Res.isUsable());
- Res = SemaRef.MaybeCreateExprWithCleanups(Res);
- It->getPointer()->setSubExpr(Res.get());
+ // The result may not be usable in case of previous compilation errors.
+ // In this case evaluation of the expression may result in crash so just
+ // don't do anything further with the result.
+ if (Res.isUsable()) {
+ Res = SemaRef.MaybeCreateExprWithCleanups(Res);
+ It->getPointer()->setSubExpr(Res.get());
+ }
}
static void
@@ -17639,7 +17932,7 @@ HandleImmediateInvocations(Sema &SemaRef,
/// Prevent sema calls during the tree transform from adding pointers that
/// are already in the sets.
- llvm::SaveAndRestore<bool> DisableIITracking(
+ llvm::SaveAndRestore DisableIITracking(
SemaRef.RebuildingImmediateInvocation, true);
/// Prevent diagnostic during tree transfrom as they are duplicates
@@ -17665,7 +17958,7 @@ HandleImmediateInvocations(Sema &SemaRef,
for (auto CE : Rec.ImmediateInvocationCandidates)
if (!CE.getInt())
EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
- for (auto DR : Rec.ReferenceToConsteval) {
+ for (auto *DR : Rec.ReferenceToConsteval) {
auto *FD = cast<FunctionDecl>(DR->getDecl());
SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
<< FD;
@@ -18106,7 +18399,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
}
} else {
// Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
+ for (auto *i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
@@ -18114,6 +18407,16 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
});
}
+ // If a constructor was defined in the context of a default parameter
+ // or of another default member initializer (ie a PotentiallyEvaluatedIfUsed
+ // context), its initializers may not be referenced yet.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ for (CXXCtorInitializer *Init : Constructor->inits()) {
+ if (Init->isInClassMemberInitializer())
+ MarkDeclarationsReferencedInExpr(Init->getInit());
+ }
+ }
+
// C++14 [except.spec]p17:
// An exception-specification is considered to be needed when:
// - the function is odr-used or, if it appears in an unevaluated operand,
@@ -18173,10 +18476,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
/// - else capture it in the DeclContext that maps to the
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
static void
-MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
+MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef,
const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
+ VarDecl *Var = V->getPotentiallyDecomposedVarDecl();
+ assert(Var && "expected a capturable variable");
+
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
(!Var->isExternallyVisible() || Var->isInline() ||
SemaRef.isExternalWithNoLinkageType(Var)) &&
@@ -18187,12 +18493,11 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
}
QualType CaptureType, DeclRefType;
if (SemaRef.LangOpts.OpenMP)
- SemaRef.tryCaptureOpenMPLambdas(Var);
- SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,
- /*EllipsisLoc*/ SourceLocation(),
- /*BuildAndDiagnose*/ true,
- CaptureType, DeclRefType,
- FunctionScopeIndexToStopAt);
+ SemaRef.tryCaptureOpenMPLambdas(V);
+ SemaRef.tryCaptureVariable(V, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true, CaptureType,
+ DeclRefType, FunctionScopeIndexToStopAt);
if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) {
auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext);
@@ -18232,17 +18537,17 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
}
}
- Var->markUsed(SemaRef.Context);
+ V->markUsed(SemaRef.Context);
}
-void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
+void Sema::MarkCaptureUsedInEnclosingContext(ValueDecl *Capture,
SourceLocation Loc,
unsigned CapturingScopeIndex) {
MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
}
-static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- ValueDecl *var) {
+void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc,
+ ValueDecl *var) {
DeclContext *VarDC = var->getDeclContext();
// If the parameter still belongs to the translation unit, then
@@ -18282,12 +18587,12 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// capture.
}
-
-static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
- bool &SubCapturesAreNested,
- QualType &CaptureType,
- QualType &DeclRefType) {
- // Check whether we've already captured it.
+static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
+ ValueDecl *Var,
+ bool &SubCapturesAreNested,
+ QualType &CaptureType,
+ QualType &DeclRefType) {
+ // Check whether we've already captured it.
if (CSI->CaptureMap.count(Var)) {
// If we found a capture, any subcaptures are nested.
SubCapturesAreNested = true;
@@ -18314,14 +18619,18 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
-static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
- SourceLocation Loc,
- const bool Diagnose, Sema &S) {
+static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC,
+ ValueDecl *Var,
+ SourceLocation Loc,
+ const bool Diagnose,
+ Sema &S) {
if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
return getLambdaAwareParentOfDeclContext(DC);
- else if (Var->hasLocalStorage()) {
- if (Diagnose)
- diagnoseUncapturableValueReference(S, Loc, Var);
+
+ VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl();
+ if (Underlying) {
+ if (Underlying->hasLocalStorage() && Diagnose)
+ diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
}
return nullptr;
}
@@ -18329,9 +18638,12 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
// certain types of variables (unnamed, variably modified types etc.)
// so check for eligibility.
-static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
- SourceLocation Loc,
- const bool Diagnose, Sema &S) {
+static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var,
+ SourceLocation Loc, const bool Diagnose,
+ Sema &S) {
+
+ assert((isa<VarDecl, BindingDecl>(Var)) &&
+ "Only variables and structured bindings can be captured");
bool IsBlock = isa<BlockScopeInfo>(CSI);
bool IsLambda = isa<LambdaScopeInfo>(CSI);
@@ -18388,17 +18700,28 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
return false;
}
+ if (isa<BindingDecl>(Var)) {
+ if (!IsLambda || !S.getLangOpts().CPlusPlus) {
+ if (Diagnose)
+ diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
+ return false;
+ } else if (Diagnose && S.getLangOpts().CPlusPlus) {
+ S.Diag(Loc, S.LangOpts.CPlusPlus20
+ ? diag::warn_cxx17_compat_capture_binding
+ : diag::ext_capture_binding)
+ << Var;
+ S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
+ }
+ }
+
return true;
}
// Returns true if the capture by block was successful.
-static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
- SourceLocation Loc,
- const bool BuildAndDiagnose,
- QualType &CaptureType,
- QualType &DeclRefType,
- const bool Nested,
- Sema &S, bool Invalid) {
+static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var,
+ SourceLocation Loc, const bool BuildAndDiagnose,
+ QualType &CaptureType, QualType &DeclRefType,
+ const bool Nested, Sema &S, bool Invalid) {
bool ByRef = false;
// Blocks are not allowed to capture arrays, excepting OpenCL.
@@ -18462,10 +18785,9 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
return !Invalid;
}
-
/// Capture the given variable in the captured region.
static bool captureInCapturedRegion(
- CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc,
+ CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc,
const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType,
const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind,
bool IsTopScope, Sema &S, bool Invalid) {
@@ -18504,16 +18826,12 @@ static bool captureInCapturedRegion(
}
/// Capture the given variable in the lambda.
-static bool captureInLambda(LambdaScopeInfo *LSI,
- VarDecl *Var,
- SourceLocation Loc,
- const bool BuildAndDiagnose,
- QualType &CaptureType,
- QualType &DeclRefType,
+static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
+ SourceLocation Loc, const bool BuildAndDiagnose,
+ QualType &CaptureType, QualType &DeclRefType,
const bool RefersToCapturedVariable,
const Sema::TryCaptureKind Kind,
- SourceLocation EllipsisLoc,
- const bool IsTopScope,
+ SourceLocation EllipsisLoc, const bool IsTopScope,
Sema &S, bool Invalid) {
// Determine whether we are capturing by reference or by value.
bool ByRef = false;
@@ -18523,6 +18841,16 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
}
+ BindingDecl *BD = dyn_cast<BindingDecl>(Var);
+ // FIXME: We should support capturing structured bindings in OpenMP.
+ if (!Invalid && BD && S.LangOpts.OpenMP) {
+ if (BuildAndDiagnose) {
+ S.Diag(Loc, diag::err_capture_binding_openmp) << Var;
+ S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
+ }
+ Invalid = true;
+ }
+
// Compute the type of the field that will capture this variable.
if (ByRef) {
// C++11 [expr.prim.lambda]p15:
@@ -18603,7 +18931,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
return !Invalid;
}
-static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
+static bool canCaptureVariableByCopy(ValueDecl *Var,
+ const ASTContext &Context) {
// Offer a Copy fix even if the type is dependent.
if (Var->getType()->isDependentType())
return true;
@@ -18629,7 +18958,7 @@ static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
/// standard, for example we can't emit a default copy capture fix-it if we
/// already explicitly copy capture capture another variable.
static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
- VarDecl *Var) {
+ ValueDecl *Var) {
assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None);
// Don't offer Capture by copy of default capture by copy fixes if Var is
// known not to be copy constructible.
@@ -18705,14 +19034,20 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
}
bool Sema::tryCaptureVariable(
- VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
+ ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
// An init-capture is notionally from the context surrounding its
// declaration, but its parent DC is the lambda class.
DeclContext *VarDC = Var->getDeclContext();
- if (Var->isInitCapture())
- VarDC = VarDC->getParent();
+ const auto *VD = dyn_cast<VarDecl>(Var);
+ if (VD) {
+ if (VD->isInitCapture())
+ VarDC = VarDC->getParent();
+ } else {
+ VD = Var->getPotentiallyDecomposedVarDecl();
+ }
+ assert(VD && "Cannot capture a null variable");
DeclContext *DC = CurContext;
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
@@ -18734,12 +19069,14 @@ bool Sema::tryCaptureVariable(
// Capture global variables if it is required to use private copy of this
// variable.
- bool IsGlobal = !Var->hasLocalStorage();
+ bool IsGlobal = !VD->hasLocalStorage();
if (IsGlobal &&
!(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true,
MaxFunctionScopesIndex)))
return true;
- Var = Var->getCanonicalDecl();
+
+ if (isa<VarDecl>(Var))
+ Var = cast<VarDecl>(Var->getCanonicalDecl());
// Walk up the stack to determine whether we can capture the variable,
// performing the "simple" checks that don't depend on type. We stop when
@@ -18795,7 +19132,7 @@ bool Sema::tryCaptureVariable(
Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
buildLambdaCaptureFixit(*this, LSI, Var);
} else
- diagnoseUncapturableValueReference(*this, ExprLoc, Var);
+ diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var);
}
return true;
}
@@ -18943,7 +19280,7 @@ bool Sema::tryCaptureVariable(
return Invalid;
}
-bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
TryCaptureKind Kind, SourceLocation EllipsisLoc) {
QualType CaptureType;
QualType DeclRefType;
@@ -18952,7 +19289,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
DeclRefType, nullptr);
}
-bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
+bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
@@ -18960,7 +19297,7 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
DeclRefType, nullptr);
}
-QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
@@ -19382,6 +19719,38 @@ void Sema::CleanupVarDeclMarking() {
"MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?");
}
+static void DoMarkPotentialCapture(Sema &SemaRef, SourceLocation Loc,
+ ValueDecl *Var, Expr *E) {
+ VarDecl *VD = Var->getPotentiallyDecomposedVarDecl();
+ if (!VD)
+ return;
+
+ const bool RefersToEnclosingScope =
+ (SemaRef.CurContext != VD->getDeclContext() &&
+ VD->getDeclContext()->isFunctionOrMethod() && VD->hasLocalStorage());
+ if (RefersToEnclosingScope) {
+ LambdaScopeInfo *const LSI =
+ SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
+ if (LSI && (!LSI->CallOperator ||
+ !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any
+ // lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ //
+ // FIXME: We can simplify this a lot after implementing P0588R1.
+ assert(E && "Capture variable should be used in an expression.");
+ if (!Var->getType()->isReferenceType() ||
+ !VD->isUsableInConstantExpressions(SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ }
+}
+
static void DoMarkVarDeclReferenced(
Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E,
llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) {
@@ -19505,7 +19874,10 @@ static void DoMarkVarDeclReferenced(
switch (OdrUse) {
case OdrUseContext::None:
- assert((!E || isa<FunctionParmPackExpr>(E)) &&
+ // In some cases, a variable may not have been marked unevaluated, if it
+ // appears in a defaukt initializer.
+ assert((!E || isa<FunctionParmPackExpr>(E) ||
+ SemaRef.isUnevaluatedContext()) &&
"missing non-odr-use marking for unevaluated decl ref");
break;
@@ -19528,34 +19900,31 @@ static void DoMarkVarDeclReferenced(
// odr-used, but we may still need to track them for lambda capture.
// FIXME: Do we also need to do this inside dependent typeid expressions
// (which are modeled as unevaluated at this point)?
- const bool RefersToEnclosingScope =
- (SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
- if (RefersToEnclosingScope) {
- LambdaScopeInfo *const LSI =
- SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
- if (LSI && (!LSI->CallOperator ||
- !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
- // If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any
- // lvalue-to-rvalue
- // or discarded value conversions that would obviate odr-use.
- // Add it to the list of potential captures that will be analyzed
- // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
- // unless the variable is a reference that was initialized by a constant
- // expression (this will never need to be captured or odr-used).
- //
- // FIXME: We can simplify this a lot after implementing P0588R1.
- assert(E && "Capture variable should be used in an expression.");
- if (!Var->getType()->isReferenceType() ||
- !Var->isUsableInConstantExpressions(SemaRef.Context))
- LSI->addPotentialCapture(E->IgnoreParens());
- }
- }
+ DoMarkPotentialCapture(SemaRef, Loc, Var, E);
break;
}
}
+static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc,
+ BindingDecl *BD, Expr *E) {
+ BD->setReferenced();
+
+ if (BD->isInvalidDecl())
+ return;
+
+ OdrUseContext OdrUse = isOdrUseContext(SemaRef);
+ if (OdrUse == OdrUseContext::Used) {
+ QualType CaptureType, DeclRefType;
+ SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true, CaptureType,
+ DeclRefType,
+ /*FunctionScopeIndexToStopAt*/ nullptr);
+ } else if (OdrUse == OdrUseContext::Dependent) {
+ DoMarkPotentialCapture(SemaRef, Loc, BD, E);
+ }
+}
+
/// Mark a variable referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
/// used directly for normal expressions referring to VarDecl.
@@ -19575,6 +19944,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,
return;
}
+ if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) {
+ DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E);
+ return;
+ }
+
SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);
// If this is a call to a method via a cast, also mark the method in the
@@ -19615,7 +19989,9 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
if (!isUnevaluatedContext() && !isConstantEvaluated() &&
- FD->isConsteval() && !RebuildingImmediateInvocation)
+ !isImmediateFunctionContext() &&
+ !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() &&
+ !RebuildingImmediateInvocation && !FD->isDependentContext())
ExprEvalContexts.back().ReferenceToConsteval.insert(E);
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
RefsMinusAssignments);
@@ -19849,7 +20225,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts,
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD) {
return DiagRuntimeBehavior(
- Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD);
+ Loc, Statement ? llvm::ArrayRef(Statement) : std::nullopt, PD);
}
bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
@@ -20761,7 +21137,8 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc,
SourceLocation RParen) {
- auto FindSpecVersion = [&](StringRef Platform) -> Optional<VersionTuple> {
+ auto FindSpecVersion =
+ [&](StringRef Platform) -> std::optional<VersionTuple> {
auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
return Spec.getPlatform() == Platform;
});
@@ -20773,7 +21150,7 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
});
}
if (Spec == AvailSpecs.end())
- return None;
+ return std::nullopt;
return Spec->getVersion();
};
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5331193de863..e3eef9323b2f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -21,11 +21,13 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -42,6 +44,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TypeSize.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -241,7 +244,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
if (IsAcceptableResult(Type)) {
QualType T = Context.getTypeDeclType(Type);
MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
- return CreateParsedType(T,
+ return CreateParsedType(Context.getElaboratedType(ETK_None, nullptr, T),
Context.getTrivialTypeSourceInfo(T, NameLoc));
}
}
@@ -1388,6 +1391,13 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
bool IsImplicit) {
+ if (getLangOpts().HLSL && Type.getTypePtr()->isPointerType()) {
+ auto *This = new (Context)
+ CXXThisExpr(Loc, Type.getTypePtr()->getPointeeType(), IsImplicit);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ MarkThisReferenced(This);
+ return This;
+ }
auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit);
MarkThisReferenced(This);
return This;
@@ -1450,9 +1460,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
QualType Ty = TInfo->getType();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
- assert((!ListInitialization ||
- (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
- "List initialization must have initializer list as expression.");
+ assert((!ListInitialization || Exprs.size() == 1) &&
+ "List initialization must have exactly one expression.");
SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc);
InitializedEntity Entity =
@@ -1506,12 +1515,17 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
<< ListInitialization << Ty << FullRange);
QualType DeducedType;
- if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
+ TemplateDeductionInfo Info(Deduce->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
<< Ty << Deduce->getType() << FullRange
<< Deduce->getSourceRange());
- if (DeducedType.isNull())
+ if (DeducedType.isNull()) {
+ assert(Result == TDK_AlreadyDiagnosed);
return ExprError();
+ }
Ty = DeducedType;
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
@@ -1832,7 +1846,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, Expr *Initializer) {
- Optional<Expr *> ArraySize;
+ std::optional<Expr *> ArraySize;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
@@ -1924,7 +1938,7 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const {
return false;
if (FD.isDefined())
return false;
- Optional<unsigned> AlignmentParam;
+ std::optional<unsigned> AlignmentParam;
if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) &&
AlignmentParam)
return true;
@@ -1950,17 +1964,14 @@ void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
}
}
-ExprResult
-Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
- SourceLocation PlacementLParen,
- MultiExprArg PlacementArgs,
- SourceLocation PlacementRParen,
- SourceRange TypeIdParens,
- QualType AllocType,
- TypeSourceInfo *AllocTypeInfo,
- Optional<Expr *> ArraySize,
- SourceRange DirectInitRange,
- Expr *Initializer) {
+ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ SourceRange TypeIdParens, QualType AllocType,
+ TypeSourceInfo *AllocTypeInfo,
+ std::optional<Expr *> ArraySize,
+ SourceRange DirectInitRange, Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();
@@ -2045,12 +2056,17 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
<< Braced << AllocType << TypeRange);
QualType DeducedType;
- if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
+ TemplateDeductionInfo Info(Deduce->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
- << AllocType << Deduce->getType()
- << TypeRange << Deduce->getSourceRange());
- if (DeducedType.isNull())
+ << AllocType << Deduce->getType() << TypeRange
+ << Deduce->getSourceRange());
+ if (DeducedType.isNull()) {
+ assert(Result == TDK_AlreadyDiagnosed);
return ExprError();
+ }
AllocType = DeducedType;
}
@@ -2069,6 +2085,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
+ if (ArraySize && !checkArrayElementAlignment(AllocType, TypeRange.getBegin()))
+ return ExprError();
+
// In ARC, infer 'retaining' for the allocated
if (getLangOpts().ObjCAutoRefCount &&
AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -2092,7 +2111,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// conversion function to integral or unscoped enumeration type exists.
// C++1y [expr.new]p6: The expression [...] is implicitly converted to
// std::size_t.
- llvm::Optional<uint64_t> KnownArraySize;
+ std::optional<uint64_t> KnownArraySize;
if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus14) {
@@ -2186,7 +2205,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// FIXME: Per CWG1464, we are required to check the value prior to
// converting to size_t. This will never find a negative array size in
// C++14 onwards, because Value is always unsigned here!
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
(*ArraySize)->getIntegerConstantExpr(Context)) {
if (Value->isSigned() && Value->isNegative()) {
return ExprError(Diag((*ArraySize)->getBeginLoc(),
@@ -2273,7 +2292,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity());
// How many bytes do we want to allocate here?
- llvm::Optional<llvm::APInt> AllocationSize;
+ std::optional<llvm::APInt> AllocationSize;
if (!ArraySize && !AllocType->isDependentType()) {
// For non-array operator new, we only want to allocate one element.
AllocationSize = SingleEltSize;
@@ -2632,7 +2651,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// 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(0)),
+ Context,
+ llvm::APInt::getZero(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default)),
Context.getSizeType(), SourceLocation());
AllocArgs.push_back(&Size);
@@ -2950,6 +2971,14 @@ void Sema::DeclareGlobalNewDelete() {
if (getLangOpts().OpenCLCPlusPlus)
return;
+ // C++ [basic.stc.dynamic.general]p2:
+ // The library provides default definitions for the global allocation
+ // and deallocation functions. Some global allocation and deallocation
+ // functions are replaceable ([new.delete]); these are attached to the
+ // global module ([module.unit]).
+ if (getLangOpts().CPlusPlusModules && getCurrentModule())
+ PushGlobalModuleFragment(SourceLocation(), /*IsImplicit=*/true);
+
// C++ [basic.std.dynamic]p2:
// [...] The following allocation and deallocation functions (18.4) are
// implicitly declared in global scope in each translation unit of a
@@ -2989,6 +3018,14 @@ void Sema::DeclareGlobalNewDelete() {
&PP.getIdentifierTable().get("bad_alloc"),
nullptr);
getStdBadAlloc()->setImplicit(true);
+
+ // The implicitly declared "std::bad_alloc" should live in global module
+ // fragment.
+ if (GlobalModuleFragment) {
+ getStdBadAlloc()->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ getStdBadAlloc()->setLocalOwningModule(GlobalModuleFragment);
+ }
}
if (!StdAlignValT && getLangOpts().AlignedAllocation) {
// The "std::align_val_t" enum class has not yet been declared, so build it
@@ -2996,9 +3033,19 @@ void Sema::DeclareGlobalNewDelete() {
auto *AlignValT = EnumDecl::Create(
Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true);
+
+ // The implicitly declared "std::align_val_t" should live in global module
+ // fragment.
+ if (GlobalModuleFragment) {
+ AlignValT->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ AlignValT->setLocalOwningModule(GlobalModuleFragment);
+ }
+
AlignValT->setIntegerType(Context.getSizeType());
AlignValT->setPromotionType(Context.getSizeType());
AlignValT->setImplicit(true);
+
StdAlignValT = AlignValT;
}
@@ -3040,6 +3087,9 @@ void Sema::DeclareGlobalNewDelete() {
DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT);
DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr);
DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr);
+
+ if (getLangOpts().CPlusPlusModules && getCurrentModule())
+ PopGlobalModuleFragment();
}
/// DeclareGlobalAllocationFunction - Declares a single implicit global
@@ -3061,7 +3111,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
for (auto *P : Func->parameters())
FuncParams.push_back(
Context.getCanonicalType(P->getType().getUnqualifiedType()));
- if (llvm::makeArrayRef(FuncParams) == Params) {
+ if (llvm::ArrayRef(FuncParams) == Params) {
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
@@ -3084,7 +3134,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
assert(StdBadAlloc && "Must have std::bad_alloc declared");
EPI.ExceptionSpec.Type = EST_Dynamic;
- EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType);
+ EPI.ExceptionSpec.Exceptions = llvm::ArrayRef(BadAllocType);
}
if (getLangOpts().NewInfallible) {
EPI.ExceptionSpec.Type = EST_DynamicNone;
@@ -3108,6 +3158,22 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->addAttr(
ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation()));
+ // C++ [basic.stc.dynamic.general]p2:
+ // The library provides default definitions for the global allocation
+ // and deallocation functions. Some global allocation and deallocation
+ // functions are replaceable ([new.delete]); these are attached to the
+ // global module ([module.unit]).
+ //
+ // In the language wording, these functions are attched to the global
+ // 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) {
+ Alloc->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ Alloc->setLocalOwningModule(GlobalModuleFragment);
+ }
+
Alloc->addAttr(VisibilityAttr::CreateImplicit(
Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
? VisibilityAttr::Hidden
@@ -3176,7 +3242,8 @@ FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl *&Operator, bool Diagnose) {
+ FunctionDecl *&Operator, bool Diagnose,
+ bool WantSize, bool WantAligned) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@@ -3186,13 +3253,14 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Found.suppressDiagnostics();
- bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD));
+ bool Overaligned =
+ WantAligned || hasNewExtendedAlignment(*this, Context.getRecordType(RD));
// C++17 [expr.delete]p10:
// If the deallocation functions have class scope, the one without a
// parameter of type std::size_t is selected.
llvm::SmallVector<UsualDeallocFnInfo, 4> Matches;
- resolveDeallocationOverload(*this, Found, /*WantSize*/ false,
+ resolveDeallocationOverload(*this, Found, /*WantSize*/ WantSize,
/*WantAlign*/ Overaligned, &Matches);
// If we could find an overload, use it.
@@ -4170,7 +4238,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
- llvm_unreachable("Cannot perform an ellipsis conversion");
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
+ llvm_unreachable("bad conversion");
case ImplicitConversionSequence::BadConversion:
Sema::AssignConvertType ConvTy =
@@ -4740,12 +4809,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsIntegral:
case UTT_IsFloatingPoint:
case UTT_IsArray:
+ case UTT_IsBoundedArray:
case UTT_IsPointer:
+ case UTT_IsNullPointer:
+ case UTT_IsReferenceable:
case UTT_IsLvalueReference:
case UTT_IsRvalueReference:
case UTT_IsMemberFunctionPointer:
case UTT_IsMemberObjectPointer:
case UTT_IsEnum:
+ case UTT_IsScopedEnum:
case UTT_IsUnion:
case UTT_IsClass:
case UTT_IsFunction:
@@ -4766,6 +4839,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsConst:
case UTT_IsVolatile:
case UTT_IsSigned:
+ case UTT_IsUnboundedArray:
case UTT_IsUnsigned:
// This type trait always returns false, checking the type is moot.
@@ -4792,9 +4866,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
return true;
+ // LWG3823: T shall be an array type, a complete type, or cv void.
+ case UTT_IsAggregate:
+ if (ArgTy->isArrayType() || ArgTy->isVoidType())
+ return true;
+
+ return !S.RequireCompleteType(
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+
// C++1z [meta.unary.prop]:
// remove_all_extents_t<T> shall be a complete type or cv void.
- case UTT_IsAggregate:
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
@@ -4817,7 +4898,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// C++1z [meta.unary.prop]:
// T shall be a complete type, cv void, or an array of unknown bound.
@@ -4885,8 +4966,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return T->isFloatingType();
case UTT_IsArray:
return T->isArrayType();
+ case UTT_IsBoundedArray:
+ if (!T->isVariableArrayType()) {
+ return T->isArrayType() && !T->isIncompleteArrayType();
+ }
+
+ Self.Diag(KeyLoc, diag::err_vla_unsupported)
+ << 1 << tok::kw___is_bounded_array;
+ return false;
+ case UTT_IsUnboundedArray:
+ if (!T->isVariableArrayType()) {
+ return T->isIncompleteArrayType();
+ }
+
+ Self.Diag(KeyLoc, diag::err_vla_unsupported)
+ << 1 << tok::kw___is_unbounded_array;
+ return false;
case UTT_IsPointer:
return T->isAnyPointerType();
+ case UTT_IsNullPointer:
+ return T->isNullPtrType();
case UTT_IsLvalueReference:
return T->isLValueReferenceType();
case UTT_IsRvalueReference:
@@ -4897,6 +4996,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return T->isMemberDataPointerType();
case UTT_IsEnum:
return T->isEnumeralType();
+ case UTT_IsScopedEnum:
+ return T->isScopedEnumeralType();
case UTT_IsUnion:
return T->isUnionType();
case UTT_IsClass:
@@ -5268,6 +5369,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return C.hasUniqueObjectRepresentations(T);
case UTT_IsTriviallyRelocatable:
return T.isTriviallyRelocatableType(C);
+ case UTT_IsReferenceable:
+ return T.isReferenceable();
}
}
@@ -5412,6 +5515,8 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
Replacement = BTT_IsTriviallyAssignable;
break;
case UTT_HasTrivialCopy:
+ Replacement = UTT_IsTriviallyCopyable;
+ break;
case UTT_HasTrivialDefaultConstructor:
case UTT_HasTrivialMoveConstructor:
Replacement = TT_IsTriviallyConstructible;
@@ -5427,9 +5532,26 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
}
}
+bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
+ if (Arity && N != Arity) {
+ Diag(Loc, diag::err_type_trait_arity)
+ << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
+ return false;
+ }
+
+ if (!Arity && N == 0) {
+ Diag(Loc, diag::err_type_trait_arity)
+ << 1 << 1 << 1 << (int)N << SourceRange(Loc);
+ return false;
+ }
+ return true;
+}
+
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(
@@ -6186,7 +6308,7 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
<< LHSType << RHSType;
return {};
}
- ResultType = LHSType;
+ ResultType = Context.getCommonSugaredType(LHSType, RHSType);
} else if (LHSVT || RHSVT) {
ResultType = CheckVectorOperands(
LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
@@ -6197,15 +6319,13 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
return {};
} else {
// Both are scalar.
- QualType ResultElementTy;
- LHSType = LHSType.getCanonicalType().getUnqualifiedType();
- RHSType = RHSType.getCanonicalType().getUnqualifiedType();
-
- if (Context.hasSameType(LHSType, RHSType))
- ResultElementTy = LHSType;
- else
- ResultElementTy =
- UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
+ LHSType = LHSType.getUnqualifiedType();
+ RHSType = RHSType.getUnqualifiedType();
+ QualType ResultElementTy =
+ Context.hasSameType(LHSType, RHSType)
+ ? Context.getCommonSugaredType(LHSType, RHSType)
+ : UsualArithmeticConversions(LHS, RHS, QuestionLoc,
+ ACK_Conditional);
if (ResultElementTy->isEnumeralType()) {
Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
@@ -6425,7 +6545,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// -- Both the second and third operands have type void; the result is of
// type void and is a prvalue.
if (LVoid && RVoid)
- return Context.VoidTy;
+ return Context.getCommonSugaredType(LTy, RTy);
// Neither holds, error.
Diag(QuestionLoc, diag::err_conditional_void_nonvoid)
@@ -6531,21 +6651,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHS.get()->getObjectKind() == OK_BitField ||
RHS.get()->getObjectKind() == OK_BitField)
OK = OK_BitField;
-
- // If we have function pointer types, unify them anyway to unify their
- // exception specifications, if any.
- if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) {
- Qualifiers Qs = LTy.getQualifiers();
- LTy = FindCompositePointerType(QuestionLoc, LHS, RHS,
- /*ConvertArgs*/false);
- LTy = Context.getQualifiedType(LTy, Qs);
-
- assert(!LTy.isNull() && "failed to find composite pointer type for "
- "canonically equivalent function ptr types");
- assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type");
- }
-
- return LTy;
+ return Context.getCommonSugaredType(LTy, RTy);
}
// C++11 [expr.cond]p5
@@ -6575,36 +6681,23 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// is a prvalue temporary of the result type, which is
// copy-initialized from either the second operand or the third
// operand depending on the value of the first operand.
- if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
+ if (Context.hasSameType(LTy, RTy)) {
if (LTy->isRecordType()) {
// The operands have class type. Make a temporary copy.
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
-
- ExprResult LHSCopy = PerformCopyInitialization(Entity,
- SourceLocation(),
- LHS);
+ ExprResult LHSCopy = PerformCopyInitialization(
+ InitializedEntity::InitializeTemporary(LTy), SourceLocation(), LHS);
if (LHSCopy.isInvalid())
return QualType();
- ExprResult RHSCopy = PerformCopyInitialization(Entity,
- SourceLocation(),
- RHS);
+ ExprResult RHSCopy = PerformCopyInitialization(
+ InitializedEntity::InitializeTemporary(RTy), SourceLocation(), RHS);
if (RHSCopy.isInvalid())
return QualType();
LHS = LHSCopy;
RHS = RHSCopy;
}
-
- // If we have function pointer types, unify them anyway to unify their
- // exception specifications, if any.
- if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) {
- LTy = FindCompositePointerType(QuestionLoc, LHS, RHS);
- assert(!LTy.isNull() && "failed to find composite pointer type for "
- "canonically equivalent function ptr types");
- }
-
- return LTy;
+ return Context.getCommonSugaredType(LTy, RTy);
}
// Extension: conditional operator involving vector types.
@@ -6669,79 +6762,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
return QualType();
}
-static FunctionProtoType::ExceptionSpecInfo
-mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
- FunctionProtoType::ExceptionSpecInfo ESI2,
- SmallVectorImpl<QualType> &ExceptionTypeStorage) {
- ExceptionSpecificationType EST1 = ESI1.Type;
- ExceptionSpecificationType EST2 = ESI2.Type;
-
- // If either of them can throw anything, that is the result.
- if (EST1 == EST_None) return ESI1;
- if (EST2 == EST_None) return ESI2;
- if (EST1 == EST_MSAny) return ESI1;
- if (EST2 == EST_MSAny) return ESI2;
- if (EST1 == EST_NoexceptFalse) return ESI1;
- if (EST2 == EST_NoexceptFalse) return ESI2;
-
- // If either of them is non-throwing, the result is the other.
- if (EST1 == EST_NoThrow) return ESI2;
- if (EST2 == EST_NoThrow) return ESI1;
- if (EST1 == EST_DynamicNone) return ESI2;
- if (EST2 == EST_DynamicNone) return ESI1;
- if (EST1 == EST_BasicNoexcept) return ESI2;
- if (EST2 == EST_BasicNoexcept) return ESI1;
- if (EST1 == EST_NoexceptTrue) return ESI2;
- if (EST2 == EST_NoexceptTrue) return ESI1;
-
- // If we're left with value-dependent computed noexcept expressions, we're
- // stuck. Before C++17, we can just drop the exception specification entirely,
- // since it's not actually part of the canonical type. And this should never
- // happen in C++17, because it would mean we were computing the composite
- // pointer type of dependent types, which should never happen.
- if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
- assert(!S.getLangOpts().CPlusPlus17 &&
- "computing composite pointer type of dependent types");
- return FunctionProtoType::ExceptionSpecInfo();
- }
-
- // Switch over the possibilities so that people adding new values know to
- // update this function.
- switch (EST1) {
- case EST_None:
- case EST_DynamicNone:
- case EST_MSAny:
- case EST_BasicNoexcept:
- case EST_DependentNoexcept:
- case EST_NoexceptFalse:
- case EST_NoexceptTrue:
- case EST_NoThrow:
- llvm_unreachable("handled above");
-
- case EST_Dynamic: {
- // This is the fun case: both exception specifications are dynamic. Form
- // the union of the two lists.
- assert(EST2 == EST_Dynamic && "other cases should already be handled");
- llvm::SmallPtrSet<QualType, 8> Found;
- for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions})
- for (QualType E : Exceptions)
- if (Found.insert(S.Context.getCanonicalType(E)).second)
- ExceptionTypeStorage.push_back(E);
-
- FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
- Result.Exceptions = ExceptionTypeStorage;
- return Result;
- }
-
- case EST_Unevaluated:
- case EST_Uninstantiated:
- case EST_Unparsed:
- llvm_unreachable("shouldn't see unresolved exception specifications here");
- }
-
- llvm_unreachable("invalid ExceptionSpecificationType");
-}
-
/// Find a merged pointer type and convert the two expressions to it.
///
/// This finds the composite pointer type for \p E1 and \p E2 according to
@@ -7045,9 +7065,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// The result is nothrow if both operands are.
SmallVector<QualType, 8> ExceptionTypeStorage;
- EPI1.ExceptionSpec = EPI2.ExceptionSpec =
- mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec,
- ExceptionTypeStorage);
+ EPI1.ExceptionSpec = EPI2.ExceptionSpec = Context.mergeExceptionSpecs(
+ EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage,
+ getLangOpts().CPlusPlus17);
Composite1 = Context.getFunctionType(FPT1->getReturnType(),
FPT1->getParamTypes(), EPI1);
@@ -7091,7 +7111,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
Steps[I].Quals.addConst();
// Rebuild the composite type.
- QualType Composite = Composite1;
+ QualType Composite = Context.getCommonSugaredType(Composite1, Composite2);
for (auto &S : llvm::reverse(Steps))
Composite = S.rebuild(Context, Composite);
@@ -7308,8 +7328,8 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
if (!Cleanup.exprNeedsCleanups())
return SubExpr;
- auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
- ExprCleanupObjects.size() - FirstCleanup);
+ auto Cleanups = llvm::ArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+ ExprCleanupObjects.size() - FirstCleanup);
auto *E = ExprWithCleanups::Create(
Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups);
@@ -7381,7 +7401,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma,
BO->getType(), BO->getValueKind(),
BO->getObjectKind(), BO->getOperatorLoc(),
- BO->getFPFeatures(getLangOpts()));
+ BO->getFPFeatures());
}
}
@@ -7713,8 +7733,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
// designated by the pseudo-destructor-name shall be the same type.
if (DestructedTypeInfo) {
QualType DestructedType = DestructedTypeInfo->getType();
- SourceLocation DestructedTypeStart
- = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation DestructedTypeStart =
+ DestructedTypeInfo->getTypeLoc().getBeginLoc();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
// Detect dot pseudo destructor calls on pointer objects, e.g.:
@@ -7739,7 +7759,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
} else {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
// Recover by setting the destructed type to the object type.
DestructedType = ObjectType;
@@ -7755,8 +7775,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
// type.
} else {
Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
}
// Recover by setting the destructed type to the object type.
@@ -7780,10 +7800,10 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(ScopeType, ObjectType)) {
- Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(),
+ Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << ScopeType << Base->getSourceRange()
- << ScopeTypeInfo->getTypeLoc().getLocalSourceRange();
+ << ObjectType << ScopeType << Base->getSourceRange()
+ << ScopeTypeInfo->getTypeLoc().getSourceRange();
ScopeType = QualType();
ScopeTypeInfo = nullptr;
@@ -8254,7 +8274,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
- CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
+ CurrentLSI->visitPotentialCaptures([&](ValueDecl *Var, Expr *VarExpr) {
// If the variable is clearly identified as non-odr-used and the full
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -8270,14 +8290,18 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
!IsFullExprInstantiationDependent)
return;
+ VarDecl *UnderlyingVar = Var->getPotentiallyDecomposedVarDecl();
+ if (!UnderlyingVar)
+ return;
+
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
- if (const Optional<unsigned> Index =
+ if (const std::optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, Var, S))
S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), *Index);
const bool IsVarNeverAConstantExpression =
- VariableCanNeverBeAConstantExpression(Var, S.Context);
+ VariableCanNeverBeAConstantExpression(UnderlyingVar, S.Context);
if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
// This full expression is not instantiation dependent or the variable
// can not be used in a constant expression - which means
@@ -8305,7 +8329,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
if (CurrentLSI->hasPotentialThisCapture()) {
// If we have a capture-capable lambda for 'this', go ahead and capture
// 'this' in that lambda (and all its enclosing lambdas).
- if (const Optional<unsigned> Index =
+ if (const std::optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) {
const unsigned FunctionScopeIndexOfCapturableLambda = *Index;
@@ -8448,7 +8472,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
///
/// Returns true if there are any untried correction combinations.
bool CheckAndAdvanceTypoExprCorrectionStreams() {
- for (auto TE : TypoExprs) {
+ for (auto *TE : TypoExprs) {
auto &State = SemaRef.getTypoExprState(TE);
TransformCache.erase(TE);
if (!State.Consumer->hasMadeAnyCorrectionProgress())
@@ -8470,7 +8494,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return DRE->getFoundDecl();
if (auto *ME = dyn_cast<MemberExpr>(E))
return ME->getFoundDecl();
- // FIXME: Add any other expr types that could be be seen by the delayed typo
+ // FIXME: Add any other expr types that could be seen by the delayed typo
// correction TreeTransform for which the corresponding TypoCorrection could
// contain multiple decls.
return nullptr;
@@ -8515,7 +8539,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
// TypoExprs were created recursively and thus won't be in our
// Sema's TypoExprs - they were created in our `RecursiveTransformLoop`.
auto &SemaTypoExprs = SemaRef.TypoExprs;
- for (auto TE : TypoExprs) {
+ for (auto *TE : TypoExprs) {
TransformCache.erase(TE);
SemaRef.clearDelayedTypo(TE);
@@ -8744,14 +8768,14 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl,
}
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
- bool DiscardedValue,
- bool IsConstexpr) {
+ bool DiscardedValue, bool IsConstexpr,
+ bool IsTemplateArgument) {
ExprResult FullExpr = FE;
if (!FullExpr.get())
return ExprError();
- if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+ if (!IsTemplateArgument && DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
if (DiscardedValue) {
@@ -8998,13 +9022,14 @@ Sema::BuildExprRequirement(
Context.getReferenceQualifiedType(E).getCanonicalType();
llvm::SmallVector<TemplateArgument, 1> Args;
Args.push_back(TemplateArgument(MatchedType));
+
+ auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
+
TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
- MultiLevelTemplateArgumentList MLTAL(TAL);
- for (unsigned I = 0; I < TPL->getDepth(); ++I)
- MLTAL.addOuterRetainedLevel();
- Expr *IDC =
- cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint()
- ->getImmediatelyDeclaredConstraint();
+ MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(),
+ /*Final=*/false);
+ MLTAL.addOuterRetainedLevels(TPL->getDepth());
+ Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint();
ExprResult Constraint = SubstExpr(IDC, MLTAL);
if (Constraint.isInvalid()) {
Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
@@ -9057,9 +9082,11 @@ Sema::BuildNestedRequirement(Expr *Constraint) {
}
concepts::NestedRequirement *
-Sema::BuildNestedRequirement(
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
- return new (Context) concepts::NestedRequirement(SubstDiag);
+Sema::BuildNestedRequirement(StringRef InvalidConstraintEntity,
+ const ASTConstraintSatisfaction &Satisfaction) {
+ return new (Context) concepts::NestedRequirement(
+ InvalidConstraintEntity,
+ ASTConstraintSatisfaction::Rebuild(Context, Satisfaction));
}
RequiresExprBodyDecl *
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index c9d9ef31f3ee..a3420ac6fdd2 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -249,7 +249,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IMA_Static:
case IMA_Abstract:
case IMA_Mixed_StaticContext:
@@ -1161,10 +1161,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
- return BuildMemberExpr(
- BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
- /*HadMultipleCandidates=*/false, MemberNameInfo,
- Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
+ FoundDecl, /*HadMultipleCandidates=*/false,
+ MemberNameInfo, Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary, TemplateArgs);
}
// We found something that we didn't expect. Complain.
@@ -1621,16 +1621,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (BaseType->isExtVectorType()) {
// FIXME: this expr should store IsArrow.
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK;
- if (IsArrow)
- VK = VK_LValue;
- else {
- if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(BaseExpr.get()))
- VK = POE->getSyntacticForm()->getValueKind();
- else
- VK = BaseExpr.get()->getValueKind();
- }
-
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
@@ -1903,6 +1894,14 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true);
+ if (getLangOpts().HLSL && ThisTy.getTypePtr()->isPointerType()) {
+ ThisTy = ThisTy.getTypePtr()->getPointeeType();
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ false, SS, TemplateKWLoc,
+ /*FirstQualifierInScope*/ nullptr, R,
+ TemplateArgs, S);
+ }
}
return BuildMemberReferenceExpr(baseExpr, ThisTy,
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index a6c92d1a338d..a4372349fff7 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -27,10 +27,11 @@
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ConvertUTF.h"
+#include <optional>
using namespace clang;
using namespace sema;
-using llvm::makeArrayRef;
+using llvm::ArrayRef;
ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings) {
@@ -243,7 +244,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
QualType NumberType,
bool isLiteral = false,
SourceRange R = SourceRange()) {
- Optional<NSAPI::NSNumberLiteralMethodKind> Kind =
+ std::optional<NSAPI::NSNumberLiteralMethodKind> Kind =
S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
if (!Kind) {
@@ -298,7 +299,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
&CX.Idents.get("value"),
NumberType, /*TInfo=*/nullptr,
SC_None, nullptr);
- Method->setMethodParams(S.Context, value, None);
+ Method->setMethodParams(S.Context, value, std::nullopt);
}
if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
@@ -577,7 +578,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
Context.getPointerType(ConstCharType),
/*TInfo=*/nullptr,
SC_None, nullptr);
- M->setMethodParams(Context, value, None);
+ M->setMethodParams(Context, value, std::nullopt);
BoxingMethod = M;
}
@@ -591,8 +592,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = StringWithUTF8StringMethod;
BoxedType = NSStringPointer;
// Transfer the nullability from method's return type.
- Optional<NullabilityKind> Nullability =
- BoxingMethod->getReturnType()->getNullability(Context);
+ std::optional<NullabilityKind> Nullability =
+ BoxingMethod->getReturnType()->getNullability();
if (Nullability)
BoxedType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
@@ -705,7 +706,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
SC_None, nullptr);
Params.push_back(type);
- M->setMethodParams(Context, Params, None);
+ M->setMethodParams(Context, Params, std::nullopt);
BoxingMethod = M;
}
@@ -833,7 +834,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
/*TInfo=*/nullptr, SC_None,
nullptr);
Params.push_back(cnt);
- Method->setMethodParams(Context, Params, None);
+ Method->setMethodParams(Context, Params, std::nullopt);
}
if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method))
@@ -1003,7 +1004,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
/*TInfo=*/nullptr, SC_None,
nullptr);
Params.push_back(cnt);
- Method->setMethodParams(Context, Params, None);
+ Method->setMethodParams(Context, Params, std::nullopt);
}
if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel,
@@ -1037,12 +1038,9 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
if (ObjCProtocolDecl *NSCopyingPDecl =
LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
- QIDNSCopying =
- Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
- llvm::makeArrayRef(
- (ObjCProtocolDecl**) PQ,
- 1),
- false);
+ QIDNSCopying = Context.getObjCObjectType(
+ Context.ObjCBuiltinIdTy, {},
+ llvm::ArrayRef((ObjCProtocolDecl **)PQ, 1), false);
QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
}
}
@@ -1466,8 +1464,8 @@ static QualType getBaseMessageSendResultType(Sema &S,
// result type to the returned result.
auto transferNullability = [&](QualType type) -> QualType {
// If the method's result type has nullability, extract it.
- if (auto nullability = Method->getSendResultType(ReceiverType)
- ->getNullability(Context)){
+ if (auto nullability =
+ Method->getSendResultType(ReceiverType)->getNullability()) {
// Strip off any outer nullability sugar from the provided type.
(void)AttributedType::stripOuterNullability(type);
@@ -1546,7 +1544,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
assert(MD->isClassMethod() && "expected a class method");
QualType NewResultType = Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(MD->getClassInterface()));
- if (auto Nullability = resultType->getNullability(Context))
+ if (auto Nullability = resultType->getNullability())
NewResultType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability),
NewResultType, NewResultType);
@@ -1563,16 +1561,16 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
// Map the nullability of the result into a table index.
unsigned receiverNullabilityIdx = 0;
- if (Optional<NullabilityKind> nullability =
- ReceiverType->getNullability(Context)) {
+ if (std::optional<NullabilityKind> nullability =
+ ReceiverType->getNullability()) {
if (*nullability == NullabilityKind::NullableResult)
nullability = NullabilityKind::Nullable;
receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
}
unsigned resultNullabilityIdx = 0;
- if (Optional<NullabilityKind> nullability =
- resultType->getNullability(Context)) {
+ if (std::optional<NullabilityKind> nullability =
+ resultType->getNullability()) {
if (*nullability == NullabilityKind::NullableResult)
nullability = NullabilityKind::Nullable;
resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
@@ -1605,7 +1603,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
} else {
resultType = resultType.getDesugaredType(Context);
}
- } while (resultType->getNullability(Context));
+ } while (resultType->getNullability());
// Add nullability back if needed.
if (newResultNullabilityIdx > 0) {
@@ -1808,8 +1806,8 @@ bool Sema::CheckMessageArgumentTypes(
// Compute the set of type arguments to be substituted into each parameter
// type.
- Optional<ArrayRef<QualType>> typeArgs
- = ReceiverType->getObjCSubstitutions(Method->getDeclContext());
+ std::optional<ArrayRef<QualType>> typeArgs =
+ ReceiverType->getObjCSubstitutions(Method->getDeclContext());
bool IsError = false;
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
@@ -1909,8 +1907,8 @@ bool Sema::CheckMessageArgumentTypes(
DiagnoseSentinelCalls(Method, SelLoc, Args);
// Do additional checkings on method.
- IsError |= CheckObjCMethodCall(
- Method, SelLoc, makeArrayRef(Args.data(), Args.size()));
+ IsError |=
+ CheckObjCMethodCall(Method, SelLoc, ArrayRef(Args.data(), Args.size()));
return IsError;
}
@@ -2633,10 +2631,10 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return ObjCMessageExpr::Create(
- Context, ReceiverType, VK_PRValue, LBracLoc, ReceiverTypeInfo, Sel,
- SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ return ObjCMessageExpr::Create(Context, ReceiverType, VK_PRValue, LBracLoc,
+ ReceiverTypeInfo, Sel, SelectorLocs,
+ /*Method=*/nullptr, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
}
// Find the class to which we are sending this message.
@@ -2735,21 +2733,19 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// Construct the appropriate ObjCMessageExpr.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, SelectorLocs,
- Method, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
else {
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- ReceiverTypeInfo, Sel, SelectorLocs,
- Method, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLocs,
+ Method, ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
if (Method)
- checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
ReceiverType, /*IsClassObjectCall=*/true);
return MaybeBindToTemporary(Result);
}
@@ -2888,8 +2884,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return ObjCMessageExpr::Create(
Context, Context.DependentTy, VK_PRValue, LBracLoc, Receiver, Sel,
- SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ SelectorLocs, /*Method=*/nullptr, ArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
}
// If necessary, apply function/array conversion to the receiver.
@@ -3326,16 +3322,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Construct the appropriate ObjCMessageExpr instance.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
else {
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- Receiver, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLocs, Method,
+ ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
@@ -3356,7 +3350,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
}
- checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
ReceiverType, IsClassObjectCall);
}
@@ -3860,7 +3854,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) {
static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
TypedefNameDecl *&TDNDecl) {
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TDNDecl = TD->getDecl();
if (ObjCBridgeRelatedAttr *ObjCBAttr =
getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD))
@@ -4007,7 +4001,7 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
bool &HadTheAttribute, bool warn) {
QualType T = castExpr->getType();
HadTheAttribute = false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
@@ -4070,7 +4064,7 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr,
bool &HadTheAttribute, bool warn) {
QualType T = castType;
HadTheAttribute = false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
@@ -4377,11 +4371,9 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- ExprResult msg =
- BuildInstanceMessageImplicit(SrcExpr, SrcType,
- InstanceMethod->getLocation(),
- InstanceMethod->getSelector(),
- InstanceMethod, None);
+ ExprResult msg = BuildInstanceMessageImplicit(
+ SrcExpr, SrcType, InstanceMethod->getLocation(),
+ InstanceMethod->getSelector(), InstanceMethod, std::nullopt);
SrcExpr = msg.get();
}
return true;
diff --git a/clang/lib/Sema/SemaFixItUtils.cpp b/clang/lib/Sema/SemaFixItUtils.cpp
index 2910a56f866b..2c85a5319430 100644
--- a/clang/lib/Sema/SemaFixItUtils.cpp
+++ b/clang/lib/Sema/SemaFixItUtils.cpp
@@ -124,7 +124,7 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
// Check if the pointer to the argument needs to be passed:
// (type -> type *) or (type & -> type *).
- if (isa<PointerType>(ToQTy)) {
+ if (const auto *ToPtrTy = dyn_cast<PointerType>(ToQTy)) {
bool CanConvert = false;
OverloadFixItKind FixKind = OFIK_TakeAddress;
@@ -132,6 +132,10 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
return false;
+ // Do no take address of const pointer to get void*
+ if (isa<PointerType>(FromQTy) && ToPtrTy->isVoidPointerType())
+ return false;
+
CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S,
Begin, VK_PRValue);
if (CanConvert) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
new file mode 100644
index 000000000000..cf82cc9bccdf
--- /dev/null
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -0,0 +1,34 @@
+//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for HLSL constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+
+Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *Ident,
+ SourceLocation IdentLoc,
+ SourceLocation LBrace) {
+ // For anonymous namespace, take the location of the left brace.
+ DeclContext *LexicalParent = getCurLexicalContext();
+ HLSLBufferDecl *Result = HLSLBufferDecl::Create(
+ Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
+
+ PushOnScopeChains(Result, BufferScope);
+ PushDeclContext(BufferScope, Result);
+
+ return Result;
+}
+
+void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
+ auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
+ BufDecl->setRBraceLoc(RBrace);
+ PopDeclContext();
+}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index d3b454843234..ddb2b5cf5cd1 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -81,12 +81,22 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
const QualType ElemTy =
Context.getCanonicalType(AT->getElementType()).getUnqualifiedType();
+ auto IsCharOrUnsignedChar = [](const QualType &T) {
+ const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr());
+ return BT && BT->isCharType() && BT->getKind() != BuiltinType::SChar;
+ };
+
switch (SL->getKind()) {
case StringLiteral::UTF8:
// char8_t array can be initialized with a UTF-8 string.
- if (ElemTy->isChar8Type())
+ // - C++20 [dcl.init.string] (DR)
+ // Additionally, an array of char or unsigned char may be initialized
+ // by a UTF-8 string literal.
+ if (ElemTy->isChar8Type() ||
+ (Context.getLangOpts().Char8 &&
+ IsCharOrUnsignedChar(ElemTy.getCanonicalType())))
return SIF_None;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case StringLiteral::Ordinary:
// char array can be initialized with a narrow string.
// Only allow char x[] = "foo"; not char x[] = L"foo";
@@ -229,6 +239,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
if (StrLength > CAT->getSize().getZExtValue())
S.Diag(Str->getBeginLoc(),
diag::err_initializer_string_for_char_array_too_long)
+ << CAT->getSize().getZExtValue() << StrLength
<< Str->getSourceRange();
} else {
// C99 6.7.8p14.
@@ -493,7 +504,7 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
true);
MultiExprArg SubInit;
Expr *InitExpr;
- InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
+ InitListExpr DummyInitList(SemaRef.Context, Loc, std::nullopt, Loc);
// C++ [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
@@ -512,8 +523,10 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
//
// Only do this if we're initializing a class type, to avoid filling in
// the initializer list where possible.
- InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context)
- InitListExpr(SemaRef.Context, Loc, None, Loc);
+ InitExpr = VerifyOnly
+ ? &DummyInitList
+ : new (SemaRef.Context)
+ InitListExpr(SemaRef.Context, Loc, std::nullopt, Loc);
InitExpr->setType(SemaRef.Context.VoidTy);
SubInit = InitExpr;
Kind = InitializationKind::CreateCopy(Loc, Loc);
@@ -695,10 +708,10 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// member of reference type uninitialized, the program is
// ill-formed.
SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
+ << Field->getType()
+ << (ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm())
+ ->getSourceRange();
+ SemaRef.Diag(Field->getLocation(), diag::note_uninit_reference_member);
}
hadError = true;
return;
@@ -1518,8 +1531,8 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
// As an extension, clang supports complex initializers, which initialize
// a complex number component-wise. When an explicit initializer list for
- // a complex number contains two two initializers, this extension kicks in:
- // it exepcts the initializer list to contain two elements convertible to
+ // a complex number contains two initializers, this extension kicks in:
+ // it expects the initializer list to contain two elements convertible to
// the element type of the complex type. The first element initializes
// the real part, and the second element intitializes the imaginary part.
@@ -2934,7 +2947,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Compute the type of the integer literals.
QualType PromotedCharTy = CharTy;
- if (CharTy->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(CharTy))
PromotedCharTy = Context.getPromotedIntegerType(CharTy);
unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy);
@@ -3110,10 +3123,8 @@ InitListExpr *
InitListChecker::createInitListExpr(QualType CurrentObjectType,
SourceRange InitRange,
unsigned ExpectedNumInits) {
- InitListExpr *Result
- = new (SemaRef.Context) InitListExpr(SemaRef.Context,
- InitRange.getBegin(), None,
- InitRange.getEnd());
+ InitListExpr *Result = new (SemaRef.Context) InitListExpr(
+ SemaRef.Context, InitRange.getBegin(), std::nullopt, InitRange.getEnd());
QualType ResultType = CurrentObjectType;
if (!ResultType->isArrayType())
@@ -3519,6 +3530,7 @@ void InitializationSequence::Step::Destroy() {
case SK_StdInitializerListConstructorCall:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType:
+ case SK_ParenthesizedListInit:
break;
case SK_ConversionSequence:
@@ -3578,6 +3590,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_PlaceholderType:
case FK_ExplicitConstructor:
case FK_AddressOfUnaddressableFunction:
+ case FK_ParenthesizedListInitFailed:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -3813,6 +3826,13 @@ void InitializationSequence::AddOCLZeroOpaqueTypeStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddParenthesizedListInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_ParenthesizedListInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
@@ -5227,7 +5247,7 @@ static void TryDefaultInitialization(Sema &S,
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) {
- TryConstructorInitialization(S, Entity, Kind, None, DestType,
+ TryConstructorInitialization(S, Entity, Kind, std::nullopt, DestType,
Entity.getType(), Sequence);
return;
}
@@ -5250,6 +5270,208 @@ static void TryDefaultInitialization(Sema &S,
}
}
+static void TryOrBuildParenListInitialization(
+ Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
+ ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
+ ExprResult *Result = nullptr) {
+ unsigned ArgIndexToProcess = 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);
+
+ 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());
+ }
+ } 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());
+ }
+ }
+ }
+ return true;
+ };
+
+ if (const ArrayType *AT =
+ S.getASTContext().getAsArrayType(Entity.getType())) {
+
+ SmallVector<InitializedEntity, 4> ElementEntities;
+ uint64_t ArrayLength;
+ // 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. If
+ // the destination type is an array of unknown bound, it is define as
+ // having k elements.
+ if (const ConstantArrayType *CAT =
+ S.getASTContext().getAsConstantArrayType(Entity.getType()))
+ ArrayLength = CAT->getSize().getZExtValue();
+ else
+ ArrayLength = Args.size();
+
+ if (ArrayLength >= Args.size()) {
+ for (uint64_t I = 0; I < ArrayLength; ++I)
+ ElementEntities.push_back(
+ InitializedEntity::InitializeElement(S.getASTContext(), I, Entity));
+
+ if (!ProcessEntities(ElementEntities))
+ return;
+
+ ResultType = S.Context.getConstantArrayType(
+ AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength),
+ nullptr, ArrayType::Normal, 0);
+ }
+ } else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
+ 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 (!ProcessEntities(BaseRange))
+ return;
+
+ if (!ProcessEntities(FieldRange))
+ return;
+
+ 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()) {
+ 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(),
+ Args.back()->getEndLoc());
+ S.Diag(Kind.getLocation(), diag::err_excess_initializers)
+ << InitKind << ExcessInitSR;
+ }
+ return;
+ }
+
+ if (VerifyOnly) {
+ Sequence.setSequenceKind(InitializationSequence::NormalSequence);
+ Sequence.AddParenthesizedListInitStep(Entity.getType());
+ } else if (Result) {
+ SourceRange SR = Kind.getParenOrBraceRange();
+ auto *CPLIE = CXXParenListInitExpr::Create(
+ S.getASTContext(), InitExprs, ResultType, Args.size(),
+ Kind.getLocation(), SR.getBegin(), SR.getEnd());
+ if (ArrayFiller)
+ CPLIE->setArrayFiller(ArrayFiller);
+ if (InitializedFieldInUnion)
+ CPLIE->setInitializedFieldInUnion(InitializedFieldInUnion);
+ *Result = CPLIE;
+ S.Diag(Kind.getLocation(),
+ diag::warn_cxx17_compat_aggregate_init_paren_list)
+ << Kind.getLocation() << SR << ResultType;
+ }
+
+ return;
+}
+
/// Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
@@ -5905,7 +6127,11 @@ void InitializationSequence::InitializeFrom(Sema &S,
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
*this, TreatUnavailableAsInvalid);
AddParenthesizedArrayInitStep(DestType);
- } else if (DestAT->getElementType()->isCharType())
+ } else if (S.getLangOpts().CPlusPlus20 && !TopLevelOfInitList &&
+ Kind.getKind() == InitializationKind::IK_Direct)
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/true);
+ else if (DestAT->getElementType()->isCharType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
else if (IsWideCharCompatible(DestAT->getElementType(), Context))
SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
@@ -5952,18 +6178,53 @@ 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))))
- TryConstructorInitialization(S, Entity, Kind, Args,
- DestType, DestType, *this);
- // - Otherwise (i.e., for the remaining copy-initialization cases),
- // user-defined conversion sequences that can convert from the source
- // type to the destination type or (when a conversion 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).
- else
+ S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) {
+ TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
+ *this);
+
+ // We fall back to the "no matching constructor" path if the
+ // failed candidate set has functions other than the three default
+ // constructors. For example, conversion function.
+ if (const auto *RD =
+ dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl());
+ // In general, we should call isCompleteType for RD to check its
+ // completeness, we don't call it here as it was already called in the
+ // above TryConstructorInitialization.
+ S.getLangOpts().CPlusPlus20 && RD && RD->hasDefinition() &&
+ RD->isAggregate() && Failed() &&
+ getFailureKind() == FK_ConstructorOverloadFailed) {
+ // Do not attempt paren list initialization if overload resolution
+ // resolves to a deleted function .
+ //
+ // We may reach this condition if we have a union wrapping a class with
+ // a non-trivial copy or move constructor and we call one of those two
+ // constructors. The union is an aggregate, but the matched constructor
+ // is implicitly deleted, so we need to prevent aggregate initialization
+ // (otherwise, it'll attempt aggregate initialization by initializing
+ // the first element with a reference to the union).
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OR = getFailedCandidateSet().BestViableFunction(
+ S, Kind.getLocation(), Best);
+ if (OR != OverloadingResult::OR_Deleted) {
+ // C++20 [dcl.init] 17.6.2.2:
+ // - Otherwise, if no constructor is viable, the destination type is
+ // an
+ // aggregate class, and the initializer is a parenthesized
+ // expression-list.
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/true);
+ }
+ }
+ } else {
+ // - Otherwise (i.e., for the remaining copy-initialization cases),
+ // user-defined conversion sequences that can convert from the
+ // source type to the destination type or (when a conversion
+ // 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).
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
+ }
return;
}
@@ -5977,7 +6238,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
llvm::SmallVector<Expr *> InitArgs;
- for (auto Arg : Args) {
+ for (auto *Arg : Args) {
if (Arg->getType()->isExtVectorType()) {
const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
unsigned Elm = VTy->getNumElements();
@@ -7085,11 +7346,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
if (auto *CE = dyn_cast<CallExpr>(Call)) {
Callee = CE->getDirectCallee();
- Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs());
+ Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
} else {
auto *CCE = cast<CXXConstructExpr>(Call);
Callee = CCE->getConstructor();
- Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs());
+ Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs());
}
if (!Callee)
return;
@@ -7572,7 +7833,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::VarInit:
if (cast<VarDecl>(Path[I].D)->isImplicit())
return SourceRange();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
@@ -7586,15 +7847,15 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
}
static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
- for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
- if (It->Kind == IndirectLocalPathEntry::VarInit)
+ for (const auto &It : llvm::reverse(Path)) {
+ if (It.Kind == IndirectLocalPathEntry::VarInit)
continue;
- if (It->Kind == IndirectLocalPathEntry::AddressOf)
+ if (It.Kind == IndirectLocalPathEntry::AddressOf)
continue;
- if (It->Kind == IndirectLocalPathEntry::LifetimeBoundCall)
+ if (It.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
continue;
- return It->Kind == IndirectLocalPathEntry::GslPointerInit ||
- It->Kind == IndirectLocalPathEntry::GslReferenceInit;
+ return It.Kind == IndirectLocalPathEntry::GslPointerInit ||
+ It.Kind == IndirectLocalPathEntry::GslReferenceInit;
}
return false;
}
@@ -7846,7 +8107,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
break;
// FIXME: We can't easily tell apart an init-capture from a nested
// capture of an init-capture.
- const VarDecl *VD = Elem.Capture->getCapturedVar();
+ const ValueDecl *VD = Elem.Capture->getCapturedVar();
Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer)
<< VD << VD->isInitCapture() << Elem.Capture->isExplicit()
<< (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD
@@ -8053,19 +8314,29 @@ ExprResult InitializationSequence::Perform(Sema &S,
return ExprError();
}
if (!ZeroInitializationFixit.empty()) {
- unsigned DiagID = diag::err_default_init_const;
- if (Decl *D = Entity.getDecl())
- if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
- DiagID = diag::ext_default_init_const;
+ const Decl *D = Entity.getDecl();
+ const auto *VD = dyn_cast_or_null<VarDecl>(D);
+ QualType DestType = Entity.getType();
// The initialization would have succeeded with this fixit. Since the fixit
// is on the error, we need to build a valid AST in this case, so this isn't
// handled in the Failed() branch above.
- QualType DestType = Entity.getType();
- S.Diag(Kind.getLocation(), DiagID)
- << DestType << (bool)DestType->getAs<RecordType>()
- << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
- ZeroInitializationFixit);
+ if (!DestType->isRecordType() && VD && VD->isConstexpr()) {
+ // Use a more useful diagnostic for constexpr variables.
+ S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VD
+ << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+ ZeroInitializationFixit);
+ } else {
+ unsigned DiagID = diag::err_default_init_const;
+ if (S.getLangOpts().MSVCCompat && D && D->hasAttr<SelectAnyAttr>())
+ DiagID = diag::ext_default_init_const;
+
+ S.Diag(Kind.getLocation(), DiagID)
+ << DestType << (bool)DestType->getAs<RecordType>()
+ << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+ ZeroInitializationFixit);
+ }
}
if (getKind() == DependentSequence) {
@@ -8213,6 +8484,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitializationFromList:
case SK_StdInitializerListConstructorCall:
case SK_ZeroInitialization:
+ case SK_ParenthesizedListInit:
break;
}
@@ -8739,7 +9011,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
<< Step->Type << CurInit.get()->getType()
<< CurInit.get()->getSourceRange();
updateGNUCompoundLiteralRValue(CurInit.get());
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_ArrayInit:
// If the destination type is an incomplete array type, update the
// type accordingly.
@@ -8902,6 +9174,14 @@ ExprResult InitializationSequence::Perform(Sema &S,
CurInit.get()->getValueKind());
break;
}
+ case SK_ParenthesizedListInit: {
+ CurInit = nullptr;
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/false, &CurInit);
+ if (CurInit.get() && ResultType)
+ *ResultType = CurInit.get()->getType();
+ break;
+ }
}
}
@@ -9104,9 +9384,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< FixItHint::CreateInsertion(Args.front()->getBeginLoc(), "u8");
break;
case FK_UTF8StringIntoPlainChar:
- S.Diag(Kind.getLocation(),
- diag::err_array_init_utf8_string_into_char)
- << S.getLangOpts().CPlusPlus20;
+ S.Diag(Kind.getLocation(), diag::err_array_init_utf8_string_into_char)
+ << DestType->isSignedIntegerType() << S.getLangOpts().CPlusPlus20;
break;
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
@@ -9201,7 +9480,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FK_NonConstLValueReferenceBindingToUnrelated:
S.Diag(Kind.getLocation(),
@@ -9464,6 +9743,10 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Entity.getName();
S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
<< Entity.getName();
+ } else if (const auto *VD = dyn_cast_if_present<VarDecl>(Entity.getDecl());
+ VD && VD->isConstexpr()) {
+ S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VD;
} else {
S.Diag(Kind.getLocation(), diag::err_default_init_const)
<< DestType << (bool)DestType->getAs<RecordType>();
@@ -9500,6 +9783,11 @@ bool InitializationSequence::Diagnose(Sema &S,
diag::note_explicit_ctor_deduction_guide_here) << false;
break;
}
+
+ case FK_ParenthesizedListInitFailed:
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/false);
+ break;
}
PrintInitLocationNote(S, Entity);
@@ -9666,6 +9954,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case FK_ExplicitConstructor:
OS << "list copy initialization chose explicit constructor";
break;
+
+ case FK_ParenthesizedListInitFailed:
+ OS << "parenthesized list initialization failed";
+ break;
}
OS << '\n';
return;
@@ -9837,6 +10129,9 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_OCLZeroOpaqueType:
OS << "OpenCL opaque type from zero";
break;
+ case SK_ParenthesizedListInit:
+ OS << "initialization from a parenthesized list of values";
+ break;
}
OS << " [" << S->Type << ']';
@@ -9868,6 +10163,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
SCS = &ICS.UserDefined.After;
break;
case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::BadConversion:
return;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index afc2f3ef4d76..00ab6ba580bf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -54,17 +55,17 @@ using namespace sema;
/// is at the top of the stack and has the highest index.
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-ready. If the return value evaluates to 'false' then
-/// no lambda is capture-ready for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-ready. If the return value evaluates to 'false'
+/// then no lambda is capture-ready for \p VarToCapture.
-static inline Optional<unsigned>
+static inline std::optional<unsigned>
getStackIndexOfNearestEnclosingCaptureReadyLambda(
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture) {
+ ValueDecl *VarToCapture) {
// Label failure to capture.
- const Optional<unsigned> NoLambdaIsCaptureReady;
+ const std::optional<unsigned> NoLambdaIsCaptureReady;
// Ignore all inner captured regions.
unsigned CurScopeIndex = FunctionScopes.size() - 1;
@@ -165,18 +166,19 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda(
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-capable. If the return value evaluates to 'false' then
-/// no lambda is capture-capable for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-capable. If the return value evaluates to 'false'
+/// then no lambda is capture-capable for \p VarToCapture.
-Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
+std::optional<unsigned>
+clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture, Sema &S) {
+ ValueDecl *VarToCapture, Sema &S) {
- const Optional<unsigned> NoLambdaIsCaptureCapable;
+ const std::optional<unsigned> NoLambdaIsCaptureCapable;
- const Optional<unsigned> OptionalStackIndex =
+ const std::optional<unsigned> OptionalStackIndex =
getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
VarToCapture);
if (!OptionalStackIndex)
@@ -282,7 +284,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
DataMember,
StaticDataMember,
InlineVariable,
- VariableTemplate
+ VariableTemplate,
+ Concept
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -307,6 +310,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
+ } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
+ Kind = Concept;
}
}
@@ -330,12 +335,17 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
return std::make_tuple(nullptr, nullptr);
}
+ case Concept:
+ // Concept definitions aren't code generated and thus aren't mangled,
+ // 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.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DataMember:
// -- the in-class initializers of class members
@@ -354,13 +364,11 @@ 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,
- Expr *TrailingRequiresClause) {
+CXXMethodDecl *Sema::startLambdaDefinition(
+ CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
+ StorageClass SC, Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -390,7 +398,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
Context, Class, EndLoc,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
- MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(),
+ MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
@@ -418,7 +426,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
CheckParmsForFunctionDef(Params,
/*CheckParameterNames=*/false);
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
P->setOwningFunction(Method);
}
@@ -427,7 +435,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
- Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
+ std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
if (Mangling) {
bool HasKnownInternalLinkage;
unsigned ManglingNumber, DeviceManglingNumber;
@@ -769,8 +777,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (Context.getCanonicalFunctionResultType(ReturnType) ==
Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
// Use the return type with the strictest possible nullability annotation.
- auto RetTyNullability = ReturnType->getNullability(Ctx);
- auto BlockNullability = CSI.ReturnType->getNullability(Ctx);
+ auto RetTyNullability = ReturnType->getNullability();
+ auto BlockNullability = CSI.ReturnType->getNullability();
if (BlockNullability &&
(!RetTyNullability ||
hasWeakerNullability(*RetTyNullability, *BlockNullability)))
@@ -789,8 +797,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
QualType Sema::buildLambdaInitCaptureInitialization(
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
- Expr *&Init) {
+ std::optional<unsigned> NumExpansions, IdentifierInfo *Id,
+ bool IsDirectInit, Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -881,11 +889,12 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
return NewVD;
}
-void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
+void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var,
+ bool isReferenceType) {
assert(Var->isInitCapture() && "init capture flag should be set");
- LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
- /*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), /*Invalid*/false);
+ LSI->addCapture(Var, /*isBlock*/ false, isReferenceType,
+ /*isNested*/ false, Var->getLocation(), SourceLocation(),
+ Var->getType(), /*Invalid*/ false);
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
@@ -917,6 +926,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
SmallVector<ParmVarDecl *, 8> Params;
+
+ assert(
+ (ParamInfo.getDeclSpec().getStorageClassSpec() ==
+ DeclSpec::SCS_unspecified ||
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) &&
+ "Unexpected storage specifier");
+ bool IsLambdaStatic =
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static;
+
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -938,8 +956,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
QualType DefaultTypeForNoTrailingReturn =
getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
: Context.DependentTy;
- QualType MethodTy =
- Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
+ QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn,
+ std::nullopt, EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -953,7 +971,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// 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()) {
+ if (!FTI.hasMutableQualifier() && !IsLambdaStatic) {
FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
SourceLocation());
}
@@ -964,6 +982,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType = FTI.hasTrailingReturnType();
+ if (ExplicitResultType && 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);
+ }
+ }
+
if (FTIHasNonVoidParameters(FTI)) {
Params.reserve(FTI.NumParams);
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
@@ -981,6 +1011,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ IsLambdaStatic ? SC_Static : SC_None,
ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1088,7 +1119,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.isInvalid())
continue;
- VarDecl *Var = nullptr;
+ ValueDecl *Var = nullptr;
if (C->Init.isUsable()) {
Diag(C->Loc, getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_init_capture
@@ -1166,7 +1197,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- Var = R.getAsSingle<VarDecl>();
+ if (auto *BD = R.getAsSingle<BindingDecl>())
+ Var = BD;
+ else
+ Var = R.getAsSingle<VarDecl>();
if (Var && DiagnoseUseOfDecl(Var, C->Loc))
continue;
}
@@ -1200,7 +1234,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (Var->isInvalidDecl())
continue;
- if (!Var->hasLocalStorage()) {
+ VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl();
+
+ if (!Underlying->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
continue;
@@ -1224,7 +1260,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
if (C->Init.isUsable()) {
- addInitCapture(LSI, Var);
+ addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
} else {
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
@@ -1374,7 +1410,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
ConvExtInfo.TypeQuals.addConst();
ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
QualType ConvTy =
- S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
+ S.Context.getFunctionType(PtrToFunctionTy, std::nullopt, ConvExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName ConversionName
@@ -1470,45 +1506,50 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
Class->addDecl(ConversionTemplate);
} else
Class->addDecl(Conversion);
- // Add a non-static member function that will be the result of
- // the conversion with a certain unique ID.
- DeclarationName InvokerName = &S.Context.Idents.get(
- getLambdaStaticInvokerName());
- // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
- // we should get a prebuilt TrivialTypeSourceInfo from Context
- // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
- // then rewire the parameters accordingly, by hoisting up the InvokeParams
- // loop below and then use its Params to set Invoke->setParams(...) below.
- // This would avoid the 'const' qualifier of the calloperator from
- // contaminating the type of the invoker, which is currently adjusted
- // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
- // trailing return type of the invoker would require a visitor to rebuild
- // the trailing return type and adjusting all back DeclRefExpr's to refer
- // to the new static invoker parameters - not the call operator's.
- CXXMethodDecl *Invoke = CXXMethodDecl::Create(
- S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
- InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- S.getCurFPFeatures().isFPConstrained(),
- /*isInline=*/true, ConstexprSpecKind::Unspecified,
- CallOperator->getBody()->getEndLoc());
- for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
- InvokerParams[I]->setOwningFunction(Invoke);
- Invoke->setParams(InvokerParams);
- Invoke->setAccess(AS_private);
- Invoke->setImplicit(true);
- if (Class->isGenericLambda()) {
- FunctionTemplateDecl *TemplateCallOperator =
- CallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
- S.Context, Class, Loc, InvokerName,
- TemplateCallOperator->getTemplateParameters(),
- Invoke);
- StaticInvokerTemplate->setAccess(AS_private);
- StaticInvokerTemplate->setImplicit(true);
- Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
- Class->addDecl(StaticInvokerTemplate);
- } else
- Class->addDecl(Invoke);
+
+ // If the lambda is not static, we need to add a static member
+ // function that will be the result of the conversion with a
+ // certain unique ID.
+ // When it is static we just return the static call operator instead.
+ if (CallOperator->isInstance()) {
+ DeclarationName InvokerName =
+ &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
+ // trailing return type of the invoker would require a visitor to rebuild
+ // the trailing return type and adjusting all back DeclRefExpr's to refer
+ // to the new static invoker parameters - not the call operator's.
+ CXXMethodDecl *Invoke = CXXMethodDecl::Create(
+ S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
+ InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
+ S.getCurFPFeatures().isFPConstrained(),
+ /*isInline=*/true, ConstexprSpecKind::Unspecified,
+ CallOperator->getBody()->getEndLoc());
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
+ InvokerParams[I]->setOwningFunction(Invoke);
+ Invoke->setParams(InvokerParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate =
+ FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, InvokerName,
+ TemplateCallOperator->getTemplateParameters(), Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
+ }
}
/// Add a lambda's conversion to function pointers, as described in
@@ -1546,7 +1587,8 @@ static void addBlockPointerConversion(Sema &S,
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
ConversionEPI.TypeQuals = Qualifiers();
ConversionEPI.TypeQuals.addConst();
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ConversionEPI);
+ QualType ConvTy =
+ S.Context.getFunctionType(BlockPtrTy, std::nullopt, ConversionEPI);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -1574,7 +1616,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
// An init-capture is initialized directly from its stored initializer.
if (Cap.isInitCapture())
- return Cap.getVariable()->getInit();
+ return cast<VarDecl>(Cap.getVariable())->getInit();
// For anything else, build an initialization expression. For an implicit
// capture, the capture notionally happens at the capture-default, so use
@@ -1605,7 +1647,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
Init = This;
} else {
assert(Cap.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = Cap.getVariable();
+ ValueDecl *Var = Cap.getVariable();
Name = Var->getIdentifier();
Init = BuildDeclarationNameExpr(
CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
@@ -1654,7 +1696,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
bool Sema::CaptureHasSideEffects(const Capture &From) {
if (From.isInitCapture()) {
- Expr *Init = From.getVariable()->getInit();
+ Expr *Init = cast<VarDecl>(From.getVariable())->getInit();
if (Init && Init->HasSideEffects(Context))
return true;
}
@@ -1704,9 +1746,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
TypeSourceInfo *TSI = nullptr;
if (Capture.isVariableCapture()) {
- auto *Var = Capture.getVariable();
- if (Var->isInitCapture())
- TSI = Capture.getVariable()->getTypeSourceInfo();
+ const auto *Var = dyn_cast_or_null<VarDecl>(Capture.getVariable());
+ if (Var && Var->isInitCapture())
+ TSI = Var->getTypeSourceInfo();
}
// FIXME: Should we really be doing this? A null TypeSourceInfo seems more
@@ -1854,7 +1896,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
} else {
assert(From.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = From.getVariable();
+ ValueDecl *Var = From.getVariable();
LambdaCaptureKind Kind =
From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 68158ec977cf..b2e943699c5f 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -40,10 +40,12 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/edit_distance.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <iterator>
#include <list>
+#include <optional>
#include <set>
#include <utility>
#include <vector>
@@ -156,7 +158,7 @@ namespace {
void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) {
SmallVector<DeclContext*, 4> queue;
while (true) {
- for (auto UD : DC->using_directives()) {
+ for (auto *UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
addUsingDirective(UD, EffectiveDC);
@@ -519,12 +521,13 @@ void LookupResult::resolveKind() {
D = cast<NamedDecl>(D->getCanonicalDecl());
// Ignore an invalid declaration unless it's the only one left.
- if (D->isInvalidDecl() && !(I == 0 && N == 1)) {
+ // 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];
continue;
}
- llvm::Optional<unsigned> ExistingI;
+ 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
@@ -939,11 +942,9 @@ bool Sema::LookupBuiltin(LookupResult &R) {
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
- // predefined library functions like 'malloc'. Instead, we'll just
- // error.
- if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL ||
- getLangOpts().C2x) &&
+ // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
+ // library functions like 'malloc'. Instead, we'll just error.
+ if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
@@ -1179,9 +1180,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
EPI.ExceptionSpec = EST_None;
- QualType ExpectedType
- = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- None, EPI);
+ QualType ExpectedType = R.getSema().Context.getFunctionType(
+ R.getLookupName().getCXXNameType(), std::nullopt, EPI);
// Perform template argument deduction against the type that we would
// expect the function to have.
@@ -1624,10 +1624,8 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D,
if (!D->hasDefaultArgument())
return false;
- llvm::SmallDenseSet<const ParmDecl *, 4> Visited;
- while (D && !Visited.count(D)) {
- Visited.insert(D);
-
+ llvm::SmallPtrSet<const ParmDecl *, 4> Visited;
+ while (D && Visited.insert(D).second) {
auto &DefaultArg = D->getDefaultArgStorage();
if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind))
return true;
@@ -1920,12 +1918,7 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
// 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.
- //
- // FIXME: It would look better if we have direct method to judge whether D is
- // in another TU.
- if (SemaRef.getCurrentModule() &&
- SemaRef.getCurrentModule()->getTopLevelModule() ==
- DeclModule->getTopLevelModule())
+ if (SemaRef.isModuleUnitOfCurrentTU(DeclModule))
return true;
// [module.reach]/p3:
@@ -2023,7 +2016,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D,
unsigned IDNS) {
assert(!LookupResult::isAvailableForLookup(SemaRef, D) && "not in slow case");
- for (auto RD : D->redecls()) {
+ for (auto *RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
if (RD == D)
continue;
@@ -2107,6 +2100,22 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
if (auto *DeductionGuide = ND->getDeclName().getCXXDeductionGuideTemplate())
return SemaRef.hasReachableDefinition(DeductionGuide);
+ // FIXME: The lookup for allocation function is a standalone process.
+ // (We can find the logics in Sema::FindAllocationFunctions)
+ //
+ // Such structure makes it a problem when we instantiate a template
+ // declaration using placement allocation function if the placement
+ // allocation function is invisible.
+ // (See https://github.com/llvm/llvm-project/issues/59601)
+ //
+ // Here we workaround it by making the placement allocation functions
+ // always acceptable. The downside is that we can't diagnose the direct
+ // use of the invisible placement allocation functions. (Although such uses
+ // should be rare).
+ if (auto *FD = dyn_cast<FunctionDecl>(ND);
+ FD && FD->isReservedGlobalPlacementOperator())
+ return true;
+
auto *DC = ND->getDeclContext();
// If ND is not visible and it is at namespace scope, it shouldn't be found
// by name lookup.
@@ -2367,7 +2376,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
continue;
}
- for (auto I : ND->using_directives()) {
+ for (auto *I : ND->using_directives()) {
NamespaceDecl *Nom = I->getNominatedNamespace();
if (S.isVisible(I) && Visited.insert(Nom).second)
Queue.push_back(Nom);
@@ -3147,7 +3156,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
for (const auto &Arg : Proto->param_types())
Queue.push_back(Arg.getTypePtr());
// fallthrough
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::FunctionNoProto: {
const FunctionType *FnType = cast<FunctionType>(T);
@@ -3477,27 +3486,27 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
- llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ llvm::ArrayRef(&Arg, NumArgs), OCS,
/*SuppressUserConversions*/ true);
else
- AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ AddOverloadCandidate(M, Cand, llvm::ArrayRef(&Arg, NumArgs), OCS,
/*SuppressUserConversions*/ true);
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodTemplateCandidate(
- Tmpl, Cand, RD, nullptr, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddMethodTemplateCandidate(Tmpl, Cand, RD, nullptr, ThisTy,
+ Classification,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
- AddTemplateOverloadCandidate(
- CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddTemplateOverloadCandidate(CtorInfo.ConstructorTmpl,
+ CtorInfo.FoundDecl, nullptr,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else
- AddTemplateOverloadCandidate(
- Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddTemplateOverloadCandidate(Tmpl, Cand, nullptr,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
} else {
assert(isa<UsingDecl>(Cand.getDecl()) &&
"illegal Kind of operator = Decl");
@@ -3620,9 +3629,10 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
///
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
- return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
- false, false, false,
- false, false).getMethod());
+ return cast_or_null<CXXDestructorDecl>(
+ LookupSpecialMember(Class, CXXDestructor, false, false, false, false,
+ false)
+ .getMethod());
}
/// LookupLiteralOperator - Determine which literal operator should be used for
@@ -3696,11 +3706,11 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
// is a well-formed template argument for the template parameter.
if (StringLit) {
SFINAETrap Trap(*this);
- SmallVector<TemplateArgument, 1> Checked;
+ SmallVector<TemplateArgument, 1> SugaredChecked, CanonicalChecked;
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
- if (CheckTemplateArgument(Params->getParam(0), Arg, FD,
- R.getNameLoc(), R.getNameLoc(), 0,
- Checked) ||
+ if (CheckTemplateArgument(
+ Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
+ 0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
Trap.hasErrorOccurred())
IsTemplate = false;
}
@@ -4166,7 +4176,7 @@ private:
// Traverse using directives for qualified name lookup.
if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- for (auto I : Ctx->using_directives()) {
+ for (auto *I : Ctx->using_directives()) {
if (!Result.getSema().isVisible(I))
continue;
lookupInDeclContext(I->getNominatedNamespace(), Result,
@@ -4939,9 +4949,9 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
if (NNS && !CurNameSpecifierIdentifiers.empty()) {
SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers;
getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
- NumSpecifiers = llvm::ComputeEditDistance(
- llvm::makeArrayRef(CurNameSpecifierIdentifiers),
- llvm::makeArrayRef(NewNameSpecifierIdentifiers));
+ NumSpecifiers =
+ llvm::ComputeEditDistance(llvm::ArrayRef(CurNameSpecifierIdentifiers),
+ llvm::ArrayRef(NewNameSpecifierIdentifiers));
}
SpecifierInfo SI = {Ctx, NNS, NumSpecifiers};
@@ -5028,9 +5038,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
"extern", "inline", "static", "typedef"
};
- const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs);
- for (unsigned I = 0; I != NumCTypeSpecs; ++I)
- Consumer.addKeywordResult(CTypeSpecs[I]);
+ for (const auto *CTS : CTypeSpecs)
+ Consumer.addKeywordResult(CTS);
if (SemaRef.getLangOpts().C99)
Consumer.addKeywordResult("restrict");
@@ -5082,9 +5091,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
static const char *const CXXExprs[] = {
"delete", "new", "operator", "throw", "typeid"
};
- const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs);
- for (unsigned I = 0; I != NumCXXExprs; ++I)
- Consumer.addKeywordResult(CXXExprs[I]);
+ for (const auto *CE : CXXExprs)
+ Consumer.addKeywordResult(CE);
if (isa<CXXMethodDecl>(SemaRef.CurContext) &&
cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
@@ -5108,9 +5116,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
// Statements.
static const char *const CStmts[] = {
"do", "else", "for", "goto", "if", "return", "switch", "while" };
- const unsigned NumCStmts = llvm::array_lengthof(CStmts);
- for (unsigned I = 0; I != NumCStmts; ++I)
- Consumer.addKeywordResult(CStmts[I]);
+ for (const auto *CS : CStmts)
+ Consumer.addKeywordResult(CS);
if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("catch");
@@ -5699,7 +5706,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
llvm::SmallVector<Module*, 8> UniqueModules;
llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;
for (auto *M : Modules) {
- if (M->Kind == Module::GlobalModuleFragment)
+ if (M->isGlobalModule() || M->isPrivateModule())
continue;
if (UniqueModuleSet.insert(M).second)
UniqueModules.push_back(M);
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index f5c24bd10daa..f52c0247f01c 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 <optional>
using namespace clang;
using namespace sema;
@@ -119,12 +120,12 @@ void Sema::HandleStartOfHeaderUnit() {
// TODO: Make the C++20 header lookup independent.
// When the input is pre-processed source, we need a file ref to the original
// file for the header map.
- auto F = SourceMgr.getFileManager().getFile(HUName);
+ auto F = SourceMgr.getFileManager().getOptionalFileRef(HUName);
// For the sake of error recovery (if someone has moved the original header
// after creating the pre-processed output) fall back to obtaining the file
// ref for the input file, which must be present.
if (!F)
- F = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ F = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID());
assert(F && "failed to find the header unit source?");
Module::Header H{HUName.str(), HUName.str(), *F};
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
@@ -144,6 +145,36 @@ void Sema::HandleStartOfHeaderUnit() {
TU->setLocalOwningModule(Mod);
}
+/// Tests whether the given identifier is reserved as a module name and
+/// diagnoses if it is. Returns true if a diagnostic is emitted and false
+/// otherwise.
+static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II,
+ SourceLocation Loc) {
+ enum {
+ Valid = -1,
+ Invalid = 0,
+ Reserved = 1,
+ } Reason = Valid;
+
+ if (II->isStr("module") || II->isStr("import"))
+ Reason = Invalid;
+ else if (II->isReserved(S.getLangOpts()) !=
+ ReservedIdentifierStatus::NotReserved)
+ Reason = Reserved;
+
+ // If the identifier is reserved (not invalid) but is in a system header,
+ // we do not diagnose (because we expect system headers to use reserved
+ // identifiers).
+ 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;
+ }
+ return false;
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
ModuleDeclKind MDK, ModuleIdPath Path,
@@ -195,9 +226,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
return nullptr;
- case LangOptions::CMK_HeaderModule:
case LangOptions::CMK_HeaderUnit:
- Diag(ModuleLoc, diag::err_module_decl_in_header_module);
+ Diag(ModuleLoc, diag::err_module_decl_in_header_unit);
return nullptr;
}
@@ -207,22 +237,15 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// here, in order to support macro import.
// Only one module-declaration is permitted per source file.
- if (!ModuleScopes.empty() &&
- ModuleScopes.back().Module->isModulePurview()) {
+ if (isCurrentModulePurview()) {
Diag(ModuleLoc, diag::err_module_redeclaration);
Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
diag::note_prev_module_declaration);
return nullptr;
}
- // Find the global module fragment we're adopting into this module, if any.
- Module *GlobalModuleFragment = nullptr;
- if (!ModuleScopes.empty() &&
- ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
- GlobalModuleFragment = ModuleScopes.back().Module;
-
assert((!getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS ||
- SeenGMF == (bool)GlobalModuleFragment) &&
+ SeenGMF == (bool)this->GlobalModuleFragment) &&
"mismatched global module state");
// In C++20, the module-declaration must be the first declaration if there
@@ -239,6 +262,32 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
}
+ // C++2b [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
+ // ([lex.name]) are reserved and shall not be specified in a
+ // module-declaration; no diagnostic is required.
+
+ // Test the first part of the path to see if it's std[0-9]+ but allow the
+ // name in a system header.
+ StringRef FirstComponentName = Path[0].first->getName();
+ 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;
+ }
+
+ // Then test all of the components in the path to see if any of them are
+ // using another kind of reserved or invalid identifier.
+ for (auto Part : Path) {
+ if (DiagReservedModuleName(*this, Part.first, Part.second))
+ return nullptr;
+ }
+
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
// modules, the dots here are just another character that can appear in a
// module name.
@@ -272,7 +321,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
if (M->DefinitionLoc.isValid())
Diag(M->DefinitionLoc, diag::note_prev_module_definition);
- else if (Optional<FileEntryRef> FE = M->getASTFile())
+ else if (OptionalFileEntryRef FE = M->getASTFile())
Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
<< FE->getName();
Mod = M;
@@ -280,8 +329,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
// Create a Module for the module that we're defining.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
if (MDK == ModuleDeclKind::PartitionInterface)
Mod->Kind = Module::ModulePartitionInterface;
assert(Mod && "module creation should not fail");
@@ -301,21 +349,19 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
if (!Mod) {
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
// Create an empty module interface unit for error recovery.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
}
} break;
case ModuleDeclKind::PartitionImplementation:
// Create an interface, but note that it is an implementation
// unit.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
Mod->Kind = Module::ModulePartitionImplementation;
break;
}
- if (!GlobalModuleFragment) {
+ if (!this->GlobalModuleFragment) {
ModuleScopes.push_back({});
if (getLangOpts().ModulesLocalVisibility)
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
@@ -495,7 +541,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->getTopLevelModuleName() == getLangOpts().CurrentModule &&
+ if (Mod->isForBuilding(getLangOpts()) &&
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
Diag(ImportLoc, getLangOpts().isCompilingModule()
? diag::err_module_self_import
@@ -545,9 +591,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
(ModuleScopes.back().ModuleInterface ||
(getLangOpts().CPlusPlusModules &&
ModuleScopes.back().Module->isGlobalModule()))) {
- assert((!ModuleScopes.back().Module->isGlobalModule() ||
- Mod->Kind == Module::ModuleKind::ModuleHeaderUnit) &&
- "should only be importing a header unit into the GMF");
// Re-export the module if the imported module is exported.
// Note that we don't need to add re-exported module to Imports field
// since `Exports` implies the module is imported already.
@@ -562,11 +605,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
Diag(ExportLoc, diag::err_export_not_in_module_interface)
<< (!ModuleScopes.empty() &&
!ModuleScopes.back().ImplicitGlobalModuleFragment);
- } else if (getLangOpts().isCompilingModule()) {
- Module *ThisModule = PP.getHeaderSearchInfo().lookupModule(
- getLangOpts().CurrentModule, ExportLoc, false, false);
- (void)ThisModule;
- assert(ThisModule && "was expecting a module if building one");
}
// In some cases we need to know if an entity was present in a directly-
@@ -717,7 +755,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
// An export-declaration shall appear only [...] in the purview of a module
// interface unit. An export-declaration shall not appear directly or
// indirectly within [...] a private-module-fragment.
- if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) {
+ if (!isCurrentModulePurview()) {
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
D->setInvalidDecl();
return D;
@@ -786,7 +824,7 @@ enum class UnnamedDeclKind {
};
}
-static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
+static std::optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
if (isa<EmptyDecl>(D))
return UnnamedDeclKind::Empty;
if (isa<StaticAssertDecl>(D))
@@ -796,7 +834,7 @@ static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
if (isa<UsingDirectiveDecl>(D))
return UnnamedDeclKind::UsingDirective;
// Everything else either introduces one or more names or is ill-formed.
- return llvm::None;
+ return std::nullopt;
}
unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
@@ -911,6 +949,17 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, 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
+ // is declared in a definition domain, it shall be defined in that
+ // domain.
+ // So, if the current declaration does not have a definition, we must
+ // check at the end of the TU (or when the PMF starts) to see that we
+ // have a definition at that point.
+ if (FD->isInlineSpecified() && !FD->isDefined())
+ PendingInlineFuncDecls.insert(FD);
+ }
}
}
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 118afb81dd72..584c4a31793c 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -1028,7 +1028,7 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
// Find the corresponding property in the primary class definition.
auto OrigClass = Category->getClassInterface();
- for (auto Found : OrigClass->lookup(Prop->getDeclName())) {
+ for (auto *Found : OrigClass->lookup(Prop->getDeclName())) {
if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
}
@@ -1822,9 +1822,8 @@ CollectImmediateProperties(ObjCContainerDecl *CDecl,
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
while (SDecl) {
- SDecl->collectPropertiesToImplement(PropMap, PO);
+ SDecl->collectPropertiesToImplement(PropMap);
SDecl = SDecl->getSuperClass();
}
}
@@ -1889,15 +1888,14 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
ObjCInterfaceDecl *IDecl,
SourceLocation AtEnd) {
ObjCInterfaceDecl::PropertyMap PropMap;
- ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
- IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
+ IDecl->collectPropertiesToImplement(PropMap);
if (PropMap.empty())
return;
ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
- ObjCPropertyDecl *Prop = PropertyOrder[i];
+ for (const auto &PropEntry : PropMap) {
+ ObjCPropertyDecl *Prop = PropEntry.second;
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->isClassProperty() ||
@@ -2046,8 +2044,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// its primary class (and its super classes) if property is
// declared in one of those containers.
if ((IDecl = C->getClassInterface())) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
- IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
+ IDecl->collectPropertiesToImplement(NoNeedToImplPropMap);
}
}
if (IDecl)
@@ -2574,7 +2571,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
/*TInfo=*/nullptr,
SC_None,
nullptr);
- SetterMethod->setMethodParams(Context, Argument, None);
+ SetterMethod->setMethodParams(Context, Argument, std::nullopt);
AddPropertyAttrs(*this, SetterMethod, property);
@@ -2757,7 +2754,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if (Attributes & ObjCPropertyAttribute::kind_weak) {
// 'weak' and 'nonnull' are mutually exclusive.
- if (auto nullability = PropertyTy->getNullability(Context)) {
+ if (auto nullability = PropertyTy->getNullability()) {
if (*nullability == NullabilityKind::NonNull)
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "nonnull" << "weak";
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index dc1470bf7a9d..c767341d922b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -39,6 +39,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <optional>
#include <set>
using namespace clang;
@@ -172,7 +173,8 @@ private:
/// First argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
- llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
+ std::optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
+ bool RegionHasOrderConcurrent = false;
unsigned AssociatedLoops = 1;
bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
@@ -213,6 +215,7 @@ private:
llvm::SmallVector<ImplicitDefaultFDInfoTy, 8>
ImplicitDefaultFirstprivateFDs;
Expr *DeclareMapperVar = nullptr;
+ SmallVector<VarDecl *, 16> IteratorVarDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -847,7 +850,7 @@ public:
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
if (Top->OrderedRegion)
- return Top->OrderedRegion.value();
+ return *Top->OrderedRegion;
return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
@@ -862,9 +865,20 @@ public:
getParentOrderedRegionParam() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
if (Parent->OrderedRegion)
- return Parent->OrderedRegion.value();
+ return *Parent->OrderedRegion;
return std::make_pair(nullptr, nullptr);
}
+ /// Marks current region as having an 'order' clause.
+ void setRegionHasOrderConcurrent(bool HasOrderConcurrent) {
+ getTopOfStack().RegionHasOrderConcurrent = HasOrderConcurrent;
+ }
+ /// Returns true, if parent region is order (has associated
+ /// 'order' clause), false - otherwise.
+ bool isParentOrderConcurrent() const {
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->RegionHasOrderConcurrent;
+ return false;
+ }
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
getTopOfStack().NowaitRegion = IsNowait;
@@ -1114,19 +1128,20 @@ public:
}
/// Checks if specified decl is used in uses allocator clause as the
/// allocator.
- Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level,
- const Decl *D) const {
+ std::optional<UsesAllocatorsDeclKind>
+ isUsesAllocatorsDecl(unsigned Level, const Decl *D) const {
const SharingMapTy &StackElem = getTopOfStack();
auto I = StackElem.UsesAllocatorsDecls.find(D);
if (I == StackElem.UsesAllocatorsDecls.end())
- return None;
+ return std::nullopt;
return I->getSecond();
}
- Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const {
+ std::optional<UsesAllocatorsDeclKind>
+ isUsesAllocatorsDecl(const Decl *D) const {
const SharingMapTy &StackElem = getTopOfStack();
auto I = StackElem.UsesAllocatorsDecls.find(D);
if (I == StackElem.UsesAllocatorsDecls.end())
- return None;
+ return std::nullopt;
return I->getSecond();
}
@@ -1138,6 +1153,22 @@ public:
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->DeclareMapperVar : nullptr;
}
+
+ /// Add a new iterator variable.
+ void addIteratorVarDecl(VarDecl *VD) {
+ SharingMapTy &StackElem = getTopOfStack();
+ StackElem.IteratorVarDecls.push_back(VD->getCanonicalDecl());
+ }
+ /// Check if variable declaration is an iterator VarDecl.
+ bool isIteratorVarDecl(const VarDecl *VD) const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ if (!Top)
+ return false;
+
+ return llvm::any_of(Top->IteratorVarDecls, [VD](const VarDecl *IteratorVD) {
+ return IteratorVD == VD->getCanonicalDecl();
+ });
+ }
/// get captured field from ImplicitDefaultFirstprivateFDs
VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const {
const_iterator I = begin();
@@ -2093,7 +2124,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
//
// =========================================================================
// | type | defaultmap | pvt | first | is_device_ptr | map | res. |
- // | |(tofrom:scalar)| | pvt | | | |
+ // | |(tofrom:scalar)| | pvt | |has_dv_adr| |
// =========================================================================
// | scl | | | | - | | bycopy|
// | scl | | - | x | - | - | bycopy|
@@ -2154,10 +2185,11 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
D](OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
- // Only the map clause information influences how a variable is
- // captured. E.g. is_device_ptr does not require changing the default
- // behavior.
- if (WhereFoundClauseKind != OMPC_map)
+ // Both map and has_device_addr clauses information influences how a
+ // variable is captured. E.g. is_device_ptr does not require changing
+ // the default behavior.
+ if (WhereFoundClauseKind != OMPC_map &&
+ WhereFoundClauseKind != OMPC_has_device_addr)
return false;
auto EI = MapExprComponents.rbegin();
@@ -2270,6 +2302,9 @@ bool Sema::isInOpenMPTargetExecutionDirective() const {
}
bool Sema::isOpenMPRebuildMemberExpr(ValueDecl *D) {
+ // Only rebuild for Field.
+ if (!dyn_cast<FieldDecl>(D))
+ return false;
DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
D,
[](OpenMPClauseKind C, bool AppliedToPointee,
@@ -2661,7 +2696,7 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
const FunctionDecl *Callee,
SourceLocation Loc) {
assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl());
// Ignore host functions during device analyzis.
if (LangOpts.OpenMPIsDevice &&
@@ -2686,6 +2721,24 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
}
if (!LangOpts.OpenMPIsDevice && !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) {
+ for (OMPDeclareVariantAttr *A :
+ Callee->specific_attrs<OMPDeclareVariantAttr>()) {
+ auto *DeclRefVariant = cast<DeclRefExpr>(A->getVariantFuncRef());
+ auto *VariantFD = cast<FunctionDecl>(DeclRefVariant->getDecl());
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(
+ VariantFD->getMostRecentDecl());
+ if (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return true;
+ }
+ return false;
+ };
+ if (getLangOpts().OpenMP >= 52 &&
+ Callee->hasAttr<OMPDeclareVariantAttr>() && HasHostAttr(Callee))
+ return;
// Diagnose nohost function called during host codegen.
StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
@@ -2715,7 +2768,8 @@ void Sema::EndOpenMPClause() {
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
- SourceRange &ERange, bool AllowArraySection = false);
+ SourceRange &ERange, bool AllowArraySection = false,
+ StringRef DiagType = "");
/// Check consistency of the reduction clauses.
static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
@@ -3226,13 +3280,15 @@ getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
Allocator->containsUnexpandedParameterPack())
return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ llvm::FoldingSetNodeID AEId;
const Expr *AE = Allocator->IgnoreParenImpCasts();
+ AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
- llvm::FoldingSetNodeID AEId, DAEId;
- AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
- DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true);
+ llvm::FoldingSetNodeID DAEId;
+ DefAllocator->IgnoreImpCasts()->Profile(DAEId, S.getASTContext(),
+ /*Canonical=*/true);
if (AEId == DAEId) {
AllocatorKindRes = AllocatorKind;
break;
@@ -3694,7 +3750,7 @@ public:
return;
// Skip internally declared static variables.
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
@@ -3764,9 +3820,8 @@ public:
bool IsModifierPresent = Stack->getDefaultmapModifier(ClauseKind) ==
OMPC_DEFAULTMAP_MODIFIER_present;
if (IsModifierPresent) {
- if (llvm::find(ImplicitMapModifier[ClauseKind],
- OMPC_MAP_MODIFIER_present) ==
- std::end(ImplicitMapModifier[ClauseKind])) {
+ if (!llvm::is_contained(ImplicitMapModifier[ClauseKind],
+ OMPC_MAP_MODIFIER_present)) {
ImplicitMapModifier[ClauseKind].push_back(
OMPC_MAP_MODIFIER_present);
}
@@ -3785,9 +3840,8 @@ public:
// Variable is used if it has been marked as an array, array
// section, array shaping or the variable iself.
return StackComponents.size() == 1 ||
- std::all_of(
- std::next(StackComponents.rbegin()),
- StackComponents.rend(),
+ llvm::all_of(
+ llvm::drop_begin(llvm::reverse(StackComponents)),
[](const OMPClauseMappableExprCommon::
MappableComponent &MC) {
return MC.getAssociatedDeclaration() ==
@@ -4032,9 +4086,13 @@ public:
Visit(C);
}
}
- if (Expr *Callee = S->getCallee())
- if (auto *CE = dyn_cast<MemberExpr>(Callee->IgnoreParenImpCasts()))
+ if (Expr *Callee = S->getCallee()) {
+ auto *CI = Callee->IgnoreParenImpCasts();
+ if (auto *CE = dyn_cast<MemberExpr>(CI))
Visit(CE->getBase());
+ else if (auto *CE = dyn_cast<DeclRefExpr>(CI))
+ Visit(CE);
+ }
}
void VisitStmt(Stmt *S) {
for (Stmt *C : S->children()) {
@@ -4529,6 +4587,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -4674,12 +4733,12 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
DSAStack->setForceCaptureByReferenceInTargetExecutable(
/*V=*/true);
if (RD->isLambda()) {
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
FieldDecl *ThisCapture;
RD->getCaptureFields(Captures, ThisCapture);
for (const LambdaCapture &LC : RD->captures()) {
if (LC.getCaptureKind() == LCK_ByRef) {
- VarDecl *VD = LC.getCapturedVar();
+ VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
DeclContext *VDC = VD->getDeclContext();
if (!VDC->Encloses(CurContext))
continue;
@@ -4939,6 +4998,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInTeamsRegion,
ShouldBeInLoopSimdRegion,
} Recommend = NoRecommend;
+ if (SemaRef.LangOpts.OpenMP >= 51 && Stack->isParentOrderConcurrent() &&
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_loop &&
+ CurrentRegion != OMPD_parallel &&
+ !isOpenMPCombinedParallelADirective(CurrentRegion)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_order)
+ << getOpenMPDirectiveName(CurrentRegion);
+ return true;
+ }
if (isOpenMPSimdDirective(ParentRegion) &&
((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
(SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
@@ -5277,7 +5344,8 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
SourceLocation &ELoc,
SourceRange &ERange,
- bool AllowArraySection) {
+ bool AllowArraySection,
+ StringRef DiagType) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
@@ -5322,6 +5390,12 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
if (IsArrayExpr != NoArrayExpr) {
S.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< IsArrayExpr << ERange;
+ } else if (!DiagType.empty()) {
+ unsigned DiagSelect = S.getLangOpts().CPlusPlus
+ ? (S.getCurrentThisType().isNull() ? 1 : 2)
+ : 0;
+ S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr_with_type)
+ << DiagSelect << DiagType << ERange;
} else {
S.Diag(ELoc,
AllowArraySection
@@ -6021,7 +6095,7 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
if (OMPClause *NewClause = S.ActOnOpenMPMapClause(
- C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
+ nullptr, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
MapperIdScopeSpec, MapperId, C->getMapType(),
/*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
SubExprs, OMPVarListLocTy()))
@@ -6163,8 +6237,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- OMPC_MAP_MODIFIER_unknown, SourceLocation(), MapperIdScopeSpec,
- MapperId, OMPC_MAP_tofrom,
+ nullptr, OMPC_MAP_MODIFIER_unknown, SourceLocation(),
+ MapperIdScopeSpec, MapperId, OMPC_MAP_tofrom,
/*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
Exprs, OMPVarListLocTy(), /*NoDiagnose=*/true))
ClausesWithImplicit.emplace_back(Implicit);
@@ -6180,7 +6254,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
DeclarationNameInfo MapperId;
auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I],
+ nullptr, ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I],
MapperIdScopeSpec, MapperId, Kind, /*IsMapTypeImplicit=*/true,
SourceLocation(), SourceLocation(), ImplicitMap,
OMPVarListLocTy())) {
@@ -6295,6 +6369,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
"No associated statement allowed for 'omp taskyield' directive");
Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
break;
+ case OMPD_error:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp error' directive");
+ Res = ActOnOpenMPErrorDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
case OMPD_barrier:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp barrier' directive");
@@ -6703,6 +6782,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_device_type:
case OMPC_match:
case OMPC_when:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
default:
llvm_unreachable("Unexpected clause");
}
@@ -7176,6 +7258,13 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
if (!CalleeFnDecl)
return Call;
+ if (LangOpts.OpenMP >= 51 && CalleeFnDecl->getIdentifier() &&
+ CalleeFnDecl->getName().startswith_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);
+ }
+
if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>())
return Call;
@@ -7268,20 +7357,20 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0);
}
-Optional<std::pair<FunctionDecl *, Expr *>>
+std::optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, OMPTraitInfo &TI,
unsigned NumAppendArgs,
SourceRange SR) {
if (!DG || DG.get().isNull())
- return None;
+ return std::nullopt;
const int VariantId = 1;
// Must be applied only to single decl.
if (!DG.get().isSingleDecl()) {
Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
<< VariantId << SR;
- return None;
+ return std::nullopt;
}
Decl *ADecl = DG.get().getSingleDecl();
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
@@ -7292,7 +7381,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!FD) {
Diag(ADecl->getLocation(), diag::err_omp_function_expected)
<< VariantId << SR;
- return None;
+ return std::nullopt;
}
auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
@@ -7304,7 +7393,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (HasMultiVersionAttributes(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
<< SR;
- return None;
+ return std::nullopt;
}
// Allow #pragma omp declare variant only if the function is not used.
@@ -7322,7 +7411,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
// The VariantRef must point to function.
if (!VariantRef) {
Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId;
- return None;
+ return std::nullopt;
}
auto ShouldDelayChecks = [](Expr *&E, bool) {
@@ -7357,7 +7446,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return true;
};
if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions))
- return None;
+ return std::nullopt;
QualType AdjustedFnType = FD->getType();
if (NumAppendArgs) {
@@ -7365,7 +7454,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!PTy) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required)
<< SR;
- return None;
+ return std::nullopt;
}
// Adjust the function type to account for an extra omp_interop_t for each
// specified in the append_args clause.
@@ -7378,12 +7467,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
}
if (!TD) {
Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR;
- return None;
+ return std::nullopt;
}
QualType InteropType = Context.getTypeDeclType(TD);
if (PTy->isVariadic()) {
Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR;
- return None;
+ return std::nullopt;
}
llvm::SmallVector<QualType, 8> Params;
Params.append(PTy->param_type_begin(), PTy->param_type_end());
@@ -7413,7 +7502,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!ER.isUsable()) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
VariantRef = ER.get();
} else {
@@ -7433,12 +7522,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
<< VariantRef->getType()
<< ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
<< (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
VariantRefCast = PerformImplicitConversion(
VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting);
if (!VariantRefCast.isUsable())
- return None;
+ return std::nullopt;
}
// Drop previously built artificial addr_of unary op for member functions.
if (Method && !Method->isStatic()) {
@@ -7454,7 +7543,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
!ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
// The VariantRef must point to function.
@@ -7462,20 +7551,20 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!DRE) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
if (!NewFD) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
if (FD->getCanonicalDecl() == NewFD->getCanonicalDecl()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_same_base_function)
<< VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
// Check if function types are compatible in C.
@@ -7487,7 +7576,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
diag::err_omp_declare_variant_incompat_types)
<< NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0)
<< VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
if (NewType->isFunctionProtoType()) {
if (FD->getType()->isFunctionNoProtoType())
@@ -7505,7 +7594,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
SourceRange SR =
NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
- return None;
+ return std::nullopt;
}
enum DoesntSupport {
@@ -7521,38 +7610,38 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (CXXFD->isVirtual()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< VirtFuncs;
- return None;
+ return std::nullopt;
}
if (isa<CXXConstructorDecl>(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< Constructors;
- return None;
+ return std::nullopt;
}
if (isa<CXXDestructorDecl>(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< Destructors;
- return None;
+ return std::nullopt;
}
}
if (FD->isDeleted()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< DeletedFuncs;
- return None;
+ return std::nullopt;
}
if (FD->isDefaulted()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< DefaultedFuncs;
- return None;
+ return std::nullopt;
}
if (FD->isConstexpr()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
- return None;
+ return std::nullopt;
}
// Check general compatibility.
@@ -7568,7 +7657,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
<< FD->getLocation()),
/*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
/*CLinkageMayDiffer=*/true))
- return None;
+ return std::nullopt;
return std::make_pair(FD, cast<Expr>(DRE));
}
@@ -7576,9 +7665,8 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
ArrayRef<Expr *> AdjustArgsNothing,
ArrayRef<Expr *> AdjustArgsNeedDevicePtr,
- ArrayRef<OMPDeclareVariantAttr::InteropType> AppendArgs,
- SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc,
- SourceRange SR) {
+ ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc,
+ SourceLocation AppendArgsLoc, SourceRange SR) {
// OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
// An adjust_args clause or append_args clause can only be specified if the
@@ -7638,8 +7726,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
AdjustArgsNothing.size(),
const_cast<Expr **>(AdjustArgsNeedDevicePtr.data()),
AdjustArgsNeedDevicePtr.size(),
- const_cast<OMPDeclareVariantAttr::InteropType *>(AppendArgs.data()),
- AppendArgs.size(), SR);
+ const_cast<OMPInteropInfo *>(AppendArgs.data()), AppendArgs.size(), SR);
FD->addAttr(NewAttr);
}
@@ -7750,7 +7837,7 @@ class OpenMPIterationSpaceChecker {
/// UB > Var
/// UB >= Var
/// This will have no value when the condition is !=
- llvm::Optional<bool> TestIsLessOp;
+ std::optional<bool> TestIsLessOp;
/// This flag is true when condition is strict ( < or > ).
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
@@ -7759,12 +7846,13 @@ class OpenMPIterationSpaceChecker {
const ValueDecl *DepDecl = nullptr;
/// Contains number of loop (starts from 1) on which loop counter init
/// expression of this loop depends on.
- Optional<unsigned> InitDependOnLC;
+ std::optional<unsigned> InitDependOnLC;
/// Contains number of loop (starts from 1) on which loop counter condition
/// expression of this loop depends on.
- Optional<unsigned> CondDependOnLC;
+ std::optional<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
- Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
+ std::optional<unsigned> doesDependOnLoopCounter(const Stmt *S,
+ bool IsInitializer);
/// Original condition required for checking of the exit condition for
/// non-rectangular loop.
Expr *Condition = nullptr;
@@ -7847,7 +7935,7 @@ private:
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
bool EmitDiags);
/// Helper to set upper bound.
- bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
+ bool setUB(Expr *NewUB, std::optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
/// Helper to set loop increment.
bool setStep(Expr *NewStep, bool Subtract);
@@ -7885,8 +7973,7 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
return false;
}
-bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB,
- llvm::Optional<bool> LessOp,
+bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, std::optional<bool> LessOp,
bool StrictOp, SourceRange SR,
SourceLocation SL) {
// State consistency checking to ensure correct usage.
@@ -7929,7 +8016,7 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
// loop. If test-expr is of form b relational-op var and relational-op is
// > or >= then incr-expr must cause var to increase on each iteration of
// the loop.
- Optional<llvm::APSInt> Result =
+ std::optional<llvm::APSInt> Result =
NewStep->getIntegerConstantExpr(SemaRef.Context);
bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
bool IsConstNeg =
@@ -7941,19 +8028,18 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
// != with increment is treated as <; != with decrement is treated as >
if (!TestIsLessOp)
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
- if (UB &&
- (IsConstZero ||
- (TestIsLessOp.value() ? (IsConstNeg || (IsUnsigned && Subtract))
- : (IsConstPos || (IsUnsigned && !Subtract))))) {
+ if (UB && (IsConstZero ||
+ (*TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
- << LCDecl << TestIsLessOp.value() << NewStep->getSourceRange();
+ << LCDecl << *TestIsLessOp << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
- << TestIsLessOp.value() << ConditionSrcRange;
+ << *TestIsLessOp << ConditionSrcRange;
return true;
}
- if (TestIsLessOp.value() == Subtract) {
+ if (*TestIsLessOp == Subtract) {
NewStep =
SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep)
.get();
@@ -8064,7 +8150,7 @@ public:
};
} // namespace
-Optional<unsigned>
+std::optional<unsigned>
OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
bool IsInitializer) {
// Check for the non-rectangular loops.
@@ -8074,7 +8160,7 @@ OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
DepDecl = LoopStmtChecker.getDepDecl();
return LoopStmtChecker.getBaseLoopId();
}
- return llvm::None;
+ return std::nullopt;
}
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
@@ -8200,10 +8286,10 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
- auto &&CheckAndSetCond = [this, IneqCondIsCanonical](
- BinaryOperatorKind Opcode, const Expr *LHS,
- const Expr *RHS, SourceRange SR,
- SourceLocation OpLoc) -> llvm::Optional<bool> {
+ auto &&CheckAndSetCond =
+ [this, IneqCondIsCanonical](BinaryOperatorKind Opcode, const Expr *LHS,
+ const Expr *RHS, SourceRange SR,
+ SourceLocation OpLoc) -> std::optional<bool> {
if (BinaryOperator::isRelationalOp(Opcode)) {
if (getInitLCDecl(LHS) == LCDecl)
return setUB(const_cast<Expr *>(RHS),
@@ -8215,12 +8301,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
(Opcode == BO_LT || Opcode == BO_GT), SR, OpLoc);
} else if (IneqCondIsCanonical && Opcode == BO_NE) {
return setUB(const_cast<Expr *>(getInitLCDecl(LHS) == LCDecl ? RHS : LHS),
- /*LessOp=*/llvm::None,
+ /*LessOp=*/std::nullopt,
/*StrictOp=*/true, SR, OpLoc);
}
- return llvm::None;
+ return std::nullopt;
};
- llvm::Optional<bool> Res;
+ std::optional<bool> Res;
if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
CXXRewrittenBinaryOperator::DecomposedForm DF = RBO->getDecomposedForm();
Res = CheckAndSetCond(DF.Opcode, DF.LHS, DF.RHS, RBO->getSourceRange(),
@@ -8383,12 +8469,12 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
return nullptr;
llvm::APSInt LRes, SRes;
bool IsLowerConst = false, IsStepConst = false;
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Lower->getIntegerConstantExpr(SemaRef.Context)) {
LRes = *Res;
IsLowerConst = true;
}
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Step->getIntegerConstantExpr(SemaRef.Context)) {
SRes = *Res;
IsStepConst = true;
@@ -8427,7 +8513,7 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
}
llvm::APSInt URes;
bool IsUpperConst = false;
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Upper->getIntegerConstantExpr(SemaRef.Context)) {
URes = *Res;
IsUpperConst = true;
@@ -8708,8 +8794,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
UBVal = MinUB.get();
}
}
- Expr *UBExpr = TestIsLessOp.value() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.value() ? LBVal : UBVal;
+ Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal;
+ Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -8772,12 +8858,12 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
// init value.
Expr *MinExpr = nullptr;
Expr *MaxExpr = nullptr;
- Expr *LBExpr = TestIsLessOp.value() ? LB : UB;
- Expr *UBExpr = TestIsLessOp.value() ? UB : LB;
- bool LBNonRect = TestIsLessOp.value() ? InitDependOnLC.has_value()
- : CondDependOnLC.has_value();
- bool UBNonRect = TestIsLessOp.value() ? CondDependOnLC.has_value()
- : InitDependOnLC.has_value();
+ Expr *LBExpr = *TestIsLessOp ? LB : UB;
+ Expr *UBExpr = *TestIsLessOp ? UB : LB;
+ bool LBNonRect =
+ *TestIsLessOp ? InitDependOnLC.has_value() : CondDependOnLC.has_value();
+ bool UBNonRect =
+ *TestIsLessOp ? CondDependOnLC.has_value() : InitDependOnLC.has_value();
Expr *Lower =
LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
Expr *Upper =
@@ -8899,11 +8985,11 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
if (!NewLB.isUsable() || !NewUB.isUsable())
return nullptr;
- ExprResult CondExpr = SemaRef.BuildBinOp(
- S, DefaultLoc,
- TestIsLessOp.value() ? (TestIsStrictOp ? BO_LT : BO_LE)
- : (TestIsStrictOp ? BO_GT : BO_GE),
- NewLB.get(), NewUB.get());
+ ExprResult CondExpr =
+ SemaRef.BuildBinOp(S, DefaultLoc,
+ *TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE)
+ : (TestIsStrictOp ? BO_GT : BO_GE),
+ NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
SemaRef.Context.BoolTy))
@@ -8979,9 +9065,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
return nullptr;
// Upper - Lower
Expr *Upper =
- TestIsLessOp.value() ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
+ *TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
Expr *Lower =
- TestIsLessOp.value() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
+ *TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -9383,7 +9469,7 @@ static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) {
static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) {
if (E == nullptr)
return false;
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
E->getIntegerConstantExpr(SemaRef.Context))
return Signed ? Result->isSignedIntN(Bits) : Result->isIntN(Bits);
return false;
@@ -11012,9 +11098,50 @@ StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
return OMPBarrierDirective::Create(Context, StartLoc, EndLoc);
}
+StmtResult Sema::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ bool InExContext) {
+ const OMPAtClause *AtC =
+ OMPExecutableDirective::getSingleClause<OMPAtClause>(Clauses);
+
+ if (AtC && !InExContext && AtC->getAtKind() == OMPC_AT_execution) {
+ Diag(AtC->getAtKindKwLoc(), diag::err_omp_unexpected_execution_modifier);
+ return StmtError();
+ }
+
+ const OMPSeverityClause *SeverityC =
+ OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses);
+ const OMPMessageClause *MessageC =
+ OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses);
+ Expr *ME = MessageC ? MessageC->getMessageString() : nullptr;
+
+ if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) {
+ if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning)
+ Diag(SeverityC->getSeverityKindKwLoc(), diag::warn_diagnose_if_succeeded)
+ << (ME ? cast<StringLiteral>(ME)->getString() : "WARNING");
+ else
+ Diag(StartLoc, diag::err_diagnose_if_succeeded)
+ << (ME ? cast<StringLiteral>(ME)->getString() : "ERROR");
+ if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning)
+ return StmtError();
+ }
+ return OMPErrorDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
StmtResult Sema::ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
+ const OMPNowaitClause *NowaitC =
+ OMPExecutableDirective::getSingleClause<OMPNowaitClause>(Clauses);
+ bool HasDependC =
+ !OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)
+ .empty();
+ if (NowaitC && !HasDependC) {
+ Diag(StartLoc, diag::err_omp_nowait_clause_without_depend);
+ return StmtError();
+ }
+
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
@@ -11569,6 +11696,9 @@ protected:
static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
bool ShouldBeLValue, bool ShouldBeInteger = false) {
+ if (E->isInstantiationDependent())
+ return true;
+
if (ShouldBeLValue && !E->isLValue()) {
ErrorInfo.Error = ErrorTy::XNotLValue;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
@@ -11576,25 +11706,23 @@ protected:
return false;
}
- if (!E->isInstantiationDependent()) {
- QualType QTy = E->getType();
- if (!QTy->isScalarType()) {
- ErrorInfo.Error = ErrorTy::NotScalar;
- ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
- ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
- return false;
- }
- if (ShouldBeInteger && !QTy->isIntegerType()) {
- ErrorInfo.Error = ErrorTy::NotInteger;
- ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
- ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
- return false;
- }
+ QualType QTy = E->getType();
+ if (!QTy->isScalarType()) {
+ ErrorInfo.Error = ErrorTy::NotScalar;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
+ }
+ if (ShouldBeInteger && !QTy->isIntegerType()) {
+ ErrorInfo.Error = ErrorTy::NotInteger;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
}
return true;
}
-};
+ };
bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S,
ErrorInfoTy &ErrorInfo) {
@@ -12174,17 +12302,33 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
Stmt *UpdateStmt = nullptr;
Stmt *CondUpdateStmt = nullptr;
+ Stmt *CondExprStmt = nullptr;
if (auto *BO = dyn_cast<BinaryOperator>(S1)) {
- // { v = x; cond-update-stmt } or form 45.
- UpdateStmt = S1;
- CondUpdateStmt = S2;
- // Check if form 45.
- if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) &&
- isa<IfStmt>(S2))
- return checkForm45(CS, ErrorInfo);
- // It cannot be set before we the check for form45.
- IsPostfixUpdate = true;
+ // It could be one of the following cases:
+ // { v = x; cond-update-stmt }
+ // { v = x; cond-expr-stmt }
+ // { cond-expr-stmt; v = x; }
+ // form 45
+ if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) ||
+ isa<ConditionalOperator>(BO->getRHS()->IgnoreImpCasts())) {
+ // check if form 45
+ if (isa<IfStmt>(S2))
+ return checkForm45(CS, ErrorInfo);
+ // { cond-expr-stmt; v = x; }
+ CondExprStmt = S1;
+ UpdateStmt = S2;
+ } else {
+ IsPostfixUpdate = true;
+ UpdateStmt = S1;
+ if (isa<IfStmt>(S2)) {
+ // { v = x; cond-update-stmt }
+ CondUpdateStmt = S2;
+ } else {
+ // { v = x; cond-expr-stmt }
+ CondExprStmt = S2;
+ }
+ }
} else {
// { cond-update-stmt v = x; }
UpdateStmt = S2;
@@ -12200,10 +12344,7 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
return false;
}
- if (!checkCondUpdateStmt(IS, ErrorInfo))
- return false;
-
- return true;
+ return checkCondUpdateStmt(IS, ErrorInfo);
};
// CheckUpdateStmt has to be called *after* CheckCondUpdateStmt.
@@ -12236,7 +12377,9 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
return true;
};
- if (!CheckCondUpdateStmt(CondUpdateStmt))
+ if (CondUpdateStmt && !CheckCondUpdateStmt(CondUpdateStmt))
+ return false;
+ if (CondExprStmt && !checkCondExprStmt(CondExprStmt, ErrorInfo))
return false;
if (!CheckUpdateStmt(UpdateStmt))
return false;
@@ -12277,7 +12420,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
case OMPC_write:
case OMPC_update:
MutexClauseEncountered = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPC_capture:
case OMPC_compare: {
if (AtomicKind != OMPC_unknown && MutexClauseEncountered) {
@@ -15049,12 +15192,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_priority:
Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
- case OMPC_grainsize:
- Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
- case OMPC_num_tasks:
- Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_hint:
Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -15076,9 +15213,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_partial:
Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_message:
+ Res = ActOnOpenMPMessageClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_align:
Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_ompx_dyn_cgroup_mem:
+ Res = ActOnOpenMPXDynCGroupMemClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
case OMPC_device:
case OMPC_if:
case OMPC_default:
@@ -15135,6 +15280,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
case OMPC_destroy:
case OMPC_inclusive:
case OMPC_exclusive:
@@ -15166,7 +15313,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_loop:
@@ -15181,7 +15328,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
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.
@@ -15194,7 +15341,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_teams_distribute_parallel_for:
CaptureRegion = OMPD_teams;
break;
@@ -15289,6 +15436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15377,6 +15525,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15473,6 +15622,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15514,6 +15664,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
case OMPC_thread_limit:
switch (DKind) {
+ case OMPD_target:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
@@ -15555,7 +15706,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_loop:
- case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
@@ -15564,6 +15714,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15652,6 +15803,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15743,6 +15895,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15785,6 +15938,26 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
llvm_unreachable("Unknown OpenMP directive");
}
break;
+ case OMPC_ompx_dyn_cgroup_mem:
+ switch (DKind) {
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_teams:
+ case OMPD_target_parallel:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_loop:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_loop:
+ CaptureRegion = OMPD_target;
+ break;
+ default:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
case OMPC_device:
switch (DKind) {
case OMPD_target_update:
@@ -15837,6 +16010,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15928,6 +16102,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -16052,6 +16227,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_detach:
case OMPC_inclusive:
@@ -16190,7 +16368,7 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
ValExpr = Value.get();
// The expression must evaluate to a non-negative integer value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(SemaRef.Context)) {
if (Result->isSigned() &&
!((!StrictlyPositive && Result->isNonNegative()) ||
@@ -16320,10 +16498,22 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc,
/// Tries to find omp_allocator_handle_t type.
static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
DSAStackTy *Stack) {
- QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT();
- if (!OMPAllocatorHandleT.isNull())
+ if (!Stack->getOMPAllocatorHandleT().isNull())
return true;
- // Build the predefined allocator expressions.
+
+ // Set the allocator handle type.
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_allocator_handle_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ S.Diag(Loc, diag::err_omp_implied_type_not_found)
+ << "omp_allocator_handle_t";
+ return false;
+ }
+ QualType AllocatorHandleEnumTy = PT.get();
+ AllocatorHandleEnumTy.addConst();
+ Stack->setOMPAllocatorHandleT(AllocatorHandleEnumTy);
+
+ // Fill the predefined allocator map.
bool ErrorFound = false;
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
@@ -16343,9 +16533,10 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
ErrorFound = true;
break;
}
- if (OMPAllocatorHandleT.isNull())
- OMPAllocatorHandleT = AllocatorType;
- if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) {
+ Res = S.PerformImplicitConversion(Res.get(), AllocatorHandleEnumTy,
+ Sema::AA_Initializing,
+ /* AllowExplicit */ true);
+ if (!Res.isUsable()) {
ErrorFound = true;
break;
}
@@ -16356,8 +16547,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
<< "omp_allocator_handle_t";
return false;
}
- OMPAllocatorHandleT.addConst();
- Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT);
+
return true;
}
@@ -16442,10 +16632,6 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
- case OMPC_order:
- Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument),
- ArgumentLoc, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_update:
Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
@@ -16454,6 +16640,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
Res = ActOnOpenMPBindClause(static_cast<OpenMPBindClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_at:
+ Res = ActOnOpenMPAtClause(static_cast<OpenMPAtClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_severity:
+ Res = ActOnOpenMPSeverityClause(
+ static_cast<OpenMPSeverityClauseKind>(Argument), ArgumentLoc, StartLoc,
+ LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -16529,6 +16724,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_message:
default:
llvm_unreachable("Clause is not allowed.");
}
@@ -16537,13 +16733,12 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
static std::string
getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
- ArrayRef<unsigned> Exclude = llvm::None) {
+ ArrayRef<unsigned> Exclude = std::nullopt) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
unsigned Skipped = Exclude.size();
- auto S = Exclude.begin(), E = Exclude.end();
for (unsigned I = First; I < Last; ++I) {
- if (std::find(S, E, I) != E) {
+ if (llvm::is_contained(Exclude, I)) {
--Skipped;
continue;
}
@@ -16633,22 +16828,87 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind,
- SourceLocation KindKwLoc,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- if (Kind == OMPC_ORDER_unknown) {
+OMPClause *Sema::ActOnOpenMPAtClause(OpenMPAtClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_AT_unknown) {
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_at, /*First=*/0,
+ /*Last=*/OMPC_AT_unknown)
+ << getOpenMPClauseName(OMPC_at);
+ return nullptr;
+ }
+ return new (Context)
+ OMPAtClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPSeverityClause(OpenMPSeverityClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_SEVERITY_unknown) {
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_severity, /*First=*/0,
+ /*Last=*/OMPC_SEVERITY_unknown)
+ << getOpenMPClauseName(OMPC_severity);
+ return nullptr;
+ }
+ return new (Context)
+ OMPSeverityClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPMessageClause(Expr *ME, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ assert(ME && "NULL expr in Message clause");
+ if (!isa<StringLiteral>(ME)) {
+ Diag(ME->getBeginLoc(), diag::warn_clause_expected_string)
+ << getOpenMPClauseName(OMPC_message);
+ return nullptr;
+ }
+ return new (Context) OMPMessageClause(ME, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPOrderClause(
+ OpenMPOrderClauseModifier Modifier, OpenMPOrderClauseKind Kind,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
+ SourceLocation KindLoc, SourceLocation EndLoc) {
+ if (Kind != OMPC_ORDER_concurrent ||
+ (LangOpts.OpenMP < 51 && MLoc.isValid())) {
+ // Kind should be concurrent,
+ // Modifiers introduced in OpenMP 5.1
static_assert(OMPC_ORDER_unknown > 0,
"OMPC_ORDER_unknown not greater than 0");
- Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_order, /*First=*/0,
+
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_order,
+ /*First=*/0,
/*Last=*/OMPC_ORDER_unknown)
<< getOpenMPClauseName(OMPC_order);
return nullptr;
}
- return new (Context)
- OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+ if (LangOpts.OpenMP >= 51) {
+ if (Modifier == OMPC_ORDER_MODIFIER_unknown && MLoc.isValid()) {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_order,
+ /*First=*/OMPC_ORDER_MODIFIER_unknown + 1,
+ /*Last=*/OMPC_ORDER_MODIFIER_last)
+ << getOpenMPClauseName(OMPC_order);
+ } else {
+ DSAStack->setRegionHasOrderConcurrent(/*HasOrderConcurrent=*/true);
+ if (DSAStack->getCurScope()) {
+ // mark the current scope with 'order' flag
+ unsigned existingFlags = DSAStack->getCurScope()->getFlags();
+ DSAStack->getCurScope()->setFlags(existingFlags |
+ Scope::OpenMPOrderClauseScope);
+ }
+ }
+ }
+ return new (Context) OMPOrderClause(Kind, KindLoc, StartLoc, LParenLoc,
+ EndLoc, Modifier, MLoc);
}
OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
@@ -16760,12 +17020,33 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind],
EndLoc);
break;
+ case OMPC_order:
+ enum { OrderModifier, OrderKind };
+ Res = ActOnOpenMPOrderClause(
+ static_cast<OpenMPOrderClauseModifier>(Argument[OrderModifier]),
+ static_cast<OpenMPOrderClauseKind>(Argument[OrderKind]), StartLoc,
+ LParenLoc, ArgumentLoc[OrderModifier], ArgumentLoc[OrderKind], EndLoc);
+ break;
case OMPC_device:
assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
Res = ActOnOpenMPDeviceClause(
static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr,
StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
break;
+ case OMPC_grainsize:
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
+ "Modifier for grainsize clause and its location are expected.");
+ Res = ActOnOpenMPGrainsizeClause(
+ static_cast<OpenMPGrainsizeClauseModifier>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
+ break;
+ case OMPC_num_tasks:
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
+ "Modifier for num_tasks clause and its location are expected.");
+ Res = ActOnOpenMPNumTasksClause(
+ static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
+ break;
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -16811,9 +17092,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_unknown:
case OMPC_uniform:
@@ -16831,7 +17110,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
- case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:
@@ -16935,7 +17216,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(Context)) {
if (Result->isSigned() && !Result->isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
@@ -17088,6 +17369,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_novariants:
case OMPC_nocontext:
case OMPC_detach:
@@ -17096,6 +17380,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_ompx_dyn_cgroup_mem:
default:
llvm_unreachable("Clause is not allowed.");
}
@@ -17247,32 +17532,28 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
// Each interop-var may be specified for at most one action-clause of each
// interop construct.
- llvm::SmallPtrSet<const VarDecl *, 4> InteropVars;
- for (const OMPClause *C : Clauses) {
+ llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars;
+ for (OMPClause *C : Clauses) {
OpenMPClauseKind ClauseKind = C->getClauseKind();
- const DeclRefExpr *DRE = nullptr;
- SourceLocation VarLoc;
+ std::pair<ValueDecl *, bool> DeclResult;
+ SourceLocation ELoc;
+ SourceRange ERange;
if (ClauseKind == OMPC_init) {
- const auto *IC = cast<OMPInitClause>(C);
- VarLoc = IC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar());
+ auto *E = cast<OMPInitClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
} else if (ClauseKind == OMPC_use) {
- const auto *UC = cast<OMPUseClause>(C);
- VarLoc = UC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(UC->getInteropVar());
+ auto *E = cast<OMPUseClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
} else if (ClauseKind == OMPC_destroy) {
- const auto *DC = cast<OMPDestroyClause>(C);
- VarLoc = DC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(DC->getInteropVar());
+ auto *E = cast<OMPDestroyClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
}
- if (!DRE)
- continue;
-
- if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!InteropVars.insert(VD->getCanonicalDecl()).second) {
- Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD;
+ if (DeclResult.first) {
+ if (!InteropVars.insert(DeclResult.first).second) {
+ Diag(ELoc, diag::err_omp_interop_var_multiple_actions)
+ << DeclResult.first;
return StmtError();
}
}
@@ -17284,16 +17565,20 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
SourceLocation VarLoc,
OpenMPClauseKind Kind) {
- if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() ||
- InteropVarExpr->isInstantiationDependent() ||
- InteropVarExpr->containsUnexpandedParameterPack())
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *RefExpr = InteropVarExpr;
+ auto Res =
+ getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t");
+
+ if (Res.second) {
+ // It will be analyzed later.
return true;
+ }
- const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr);
- if (!DRE || !isa<VarDecl>(DRE->getDecl())) {
- SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0;
+ if (!Res.first)
return false;
- }
// Interop variable should be of type omp_interop_t.
bool HasError = false;
@@ -17335,8 +17620,7 @@ static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
}
OMPClause *
-Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
- bool IsTarget, bool IsTargetSync,
+Sema::ActOnOpenMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation VarLoc, SourceLocation EndLoc) {
@@ -17345,7 +17629,7 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
// Check prefer_type values. These foreign-runtime-id values are either
// string literals or constant integral expressions.
- for (const Expr *E : PrefExprs) {
+ for (const Expr *E : InteropInfo.PreferTypes) {
if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
continue;
@@ -17357,9 +17641,8 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
return nullptr;
}
- return OMPInitClause::Create(Context, InteropVar, PrefExprs, IsTarget,
- IsTargetSync, StartLoc, LParenLoc, VarLoc,
- EndLoc);
+ return OMPInitClause::Create(Context, InteropVar, InteropInfo, StartLoc,
+ LParenLoc, VarLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUseClause(Expr *InteropVar, SourceLocation StartLoc,
@@ -17549,7 +17832,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
"Unexpected map modifier.");
Res = ActOnOpenMPMapClause(
- Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
+ Data.IteratorExpr, Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId,
static_cast<OpenMPMapClauseKind>(ExtraModifier), Data.IsMapTypeImplicit,
ExtraModifierLoc, ColonLoc, VarList, Locs);
@@ -17644,6 +17927,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_device_type:
case OMPC_match:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:
@@ -18417,7 +18703,7 @@ static T filterLookupForUDReductionAndMapper(
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
- for (auto RD : D->redecls()) {
+ for (auto *RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
if (RD == D)
continue;
@@ -19744,7 +20030,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(
// Warn about zero linear step (it would be probably better specified as
// making corresponding variables 'const').
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
StepExpr->getIntegerConstantExpr(Context)) {
if (!Result->isNegative() && !Result->isStrictlyPositive())
Diag(StepLoc, diag::warn_omp_linear_step_zero)
@@ -20927,8 +21213,8 @@ public:
}
// Pointer arithmetic is the only thing we expect to happen here so after we
- // make sure the binary operator is a pointer type, the we only thing need
- // to to is to visit the subtree that has the same type as root (so that we
+ // make sure the binary operator is a pointer type, the only thing we need
+ // to do is to visit the subtree that has the same type as root (so that we
// know the other subtree is just an offset)
Expr *LE = BO->getLHS()->IgnoreParenImpCasts();
Expr *RE = BO->getRHS()->IgnoreParenImpCasts();
@@ -21403,7 +21689,7 @@ static void checkMappableExpressionList(
CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId,
ArrayRef<Expr *> UnresolvedMappers,
OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
- ArrayRef<OpenMPMapModifierKind> Modifiers = None,
+ ArrayRef<OpenMPMapModifierKind> Modifiers = std::nullopt,
bool IsMapTypeImplicit = false, bool NoDiagnose = false) {
// We only expect mappable expressions in 'to', 'from', and 'map' clauses.
assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) &&
@@ -21603,10 +21889,12 @@ static void checkMappableExpressionList(
// target enter data
// OpenMP [2.10.2, Restrictions, p. 99]
// A map-type must be specified in all map clauses and must be either
- // to or alloc.
+ // to or alloc. Starting with OpenMP 5.2 the default map type is `to` if
+ // no map type is present.
OpenMPDirectiveKind DKind = DSAS->getCurrentDirective();
if (DKind == OMPD_target_enter_data &&
- !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) {
+ !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc ||
+ SemaRef.getLangOpts().OpenMP >= 52)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
@@ -21617,10 +21905,11 @@ static void checkMappableExpressionList(
// target exit_data
// OpenMP [2.10.3, Restrictions, p. 102]
// A map-type must be specified in all map clauses and must be either
- // from, release, or delete.
+ // from, release, or delete. Starting with OpenMP 5.2 the default map
+ // type is `from` if no map type is present.
if (DKind == OMPD_target_exit_data &&
!(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release ||
- MapType == OMPC_MAP_delete)) {
+ MapType == OMPC_MAP_delete || SemaRef.getLangOpts().OpenMP >= 52)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
@@ -21698,7 +21987,7 @@ static void checkMappableExpressionList(
/*WhereFoundClauseKind=*/OMPC_map);
// Save the components and declaration to create the clause. For purposes of
- // the clause creation, any component list that has has base 'this' uses
+ // the clause creation, any component list that has base 'this' uses
// null as base declaration.
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().append(CurComponents.begin(),
@@ -21709,7 +21998,7 @@ static void checkMappableExpressionList(
}
OMPClause *Sema::ActOnOpenMPMapClause(
- ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc,
@@ -21719,9 +22008,14 @@ OMPClause *Sema::ActOnOpenMPMapClause(
OpenMPMapModifierKind Modifiers[] = {
OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
- OMPC_MAP_MODIFIER_unknown};
+ OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown};
SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers];
+ if (IteratorModifier && !IteratorModifier->getType()->isSpecificBuiltinType(
+ BuiltinType::OMPIterator))
+ Diag(IteratorModifier->getExprLoc(),
+ diag::err_omp_map_modifier_not_iterator);
+
// Process map-type-modifiers, flag errors for duplicate modifiers.
unsigned Count = 0;
for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) {
@@ -21745,11 +22039,11 @@ OMPClause *Sema::ActOnOpenMPMapClause(
// We need to produce a map clause even if we don't have variables so that
// other diagnostics related with non-existing map clauses are accurate.
- return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList,
- MVLI.VarBaseDeclarations, MVLI.VarComponents,
- MVLI.UDMapperList, Modifiers, ModifiersLoc,
- MapperIdScopeSpec.getWithLocInContext(Context),
- MapperId, MapType, IsMapTypeImplicit, MapLoc);
+ return OMPMapClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList, IteratorModifier, Modifiers,
+ ModifiersLoc, MapperIdScopeSpec.getWithLocInContext(Context), MapperId,
+ MapType, IsMapTypeImplicit, MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
@@ -22143,6 +22437,11 @@ Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(Scope *S, QualType MapperType,
return E;
}
+void Sema::ActOnOpenMPIteratorVarDecl(VarDecl *VD) {
+ if (DSAStack->getDeclareMapperVarRef())
+ DSAStack->addIteratorVarDecl(VD);
+}
+
bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
assert(LangOpts.OpenMP && "Expected OpenMP mode.");
const Expr *Ref = DSAStack->getDeclareMapperVarRef();
@@ -22151,6 +22450,8 @@ bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
return true;
if (VD->isUsableInConstantExpressions(Context))
return true;
+ if (LangOpts.OpenMP >= 52 && DSAStack->isIteratorVarDecl(VD))
+ return true;
return false;
}
return true;
@@ -22235,10 +22536,21 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPGrainsizeClause(
+ OpenMPGrainsizeClauseModifier Modifier, Expr *Grainsize,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) &&
+ "Unexpected grainsize modifier in OpenMP < 51.");
+
+ if (ModifierLoc.isValid() && Modifier == OMPC_GRAINSIZE_unknown) {
+ std::string Values = getListOfPossibleValues(OMPC_grainsize, /*First=*/0,
+ OMPC_GRAINSIZE_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_grainsize);
+ return nullptr;
+ }
+
Expr *ValExpr = Grainsize;
Stmt *HelperValStmt = nullptr;
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
@@ -22246,20 +22558,33 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the grainsize clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(
- ValExpr, *this, OMPC_grainsize,
- /*StrictlyPositive=*/true, /*BuildCapture=*/true,
- DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
+ if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true,
+ /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(),
+ &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPGrainsizeClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, ModifierLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPNumTasksClause(
+ OpenMPNumTasksClauseModifier Modifier, Expr *NumTasks,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) &&
+ "Unexpected num_tasks modifier in OpenMP < 51.");
+
+ if (ModifierLoc.isValid() && Modifier == OMPC_NUMTASKS_unknown) {
+ std::string Values = getListOfPossibleValues(OMPC_num_tasks, /*First=*/0,
+ OMPC_NUMTASKS_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_num_tasks);
+ return nullptr;
+ }
+
Expr *ValExpr = NumTasks;
Stmt *HelperValStmt = nullptr;
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
@@ -22273,8 +22598,9 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPNumTasksClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, ModifierLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
@@ -22384,7 +22710,7 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause(
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(Context)) {
if (Result->isSigned() && !Result->isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
@@ -22583,29 +22909,29 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
const unsigned Level = -1;
auto *VD = cast<ValueDecl>(ND);
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr && ActiveAttr.value()->getDevType() != DTCI.DT &&
- ActiveAttr.value()->getLevel() == Level) {
+ if (ActiveAttr && (*ActiveAttr)->getDevType() != DTCI.DT &&
+ (*ActiveAttr)->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
- ActiveAttr.value()->getDevType());
+ (*ActiveAttr)->getDevType());
return;
}
- if (ActiveAttr && ActiveAttr.value()->getMapType() != MT &&
- ActiveAttr.value()->getLevel() == Level) {
+ if (ActiveAttr && (*ActiveAttr)->getMapType() != MT &&
+ (*ActiveAttr)->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
return;
}
- if (ActiveAttr && ActiveAttr.value()->getLevel() == Level)
+ if (ActiveAttr && (*ActiveAttr)->getLevel() == Level)
return;
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.value();
+ IndirectE = *DTCI.Indirect;
if (!IndirectE)
IsIndirect = true;
}
@@ -22623,13 +22949,14 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
- Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (SemaRef.LangOpts.OpenMP >= 50 &&
(SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
VD->hasGlobalStorage()) {
- if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
+ if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To &&
+ *MapTy != OMPDeclareTargetDeclAttr::MT_Enter)) {
// OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
// If a lambda declaration and definition appears between a
// declare target directive and the matching end declare target
@@ -22678,7 +23005,7 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
Diag(IdLoc, diag::err_omp_function_in_link_clause);
@@ -22696,22 +23023,25 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
// Checking declaration inside declare target region.
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
unsigned Level = DeclareTargetNesting.size();
- if (ActiveAttr && ActiveAttr.value()->getLevel() >= Level)
+ if (ActiveAttr && (*ActiveAttr)->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.value();
+ IndirectE = *DTCI.Indirect;
if (!IndirectE)
IsIndirect = true;
}
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, IndirectE,
- IsIndirect, Level, SourceRange(DTCI.Loc, DTCI.Loc));
+ Context,
+ getLangOpts().OpenMP >= 52 ? OMPDeclareTargetDeclAttr::MT_Enter
+ : OMPDeclareTargetDeclAttr::MT_To,
+ DTCI.DT, IndirectE, IsIndirect, Level,
+ SourceRange(DTCI.Loc, DTCI.Loc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
@@ -23065,13 +23395,17 @@ OMPClause *Sema::ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList,
// Store the components in the stack so that they can be used to check
// against other clauses later on.
+ Expr *Component = SimpleRefExpr;
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) ||
+ isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts())))
+ Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get();
OMPClauseMappableExprCommon::MappableComponent MC(
- SimpleRefExpr, D, /*IsNonContiguous=*/false);
+ Component, D, /*IsNonContiguous=*/false);
DSAStack->addMappableExpressionComponents(
D, MC, /*WhereFoundClauseKind=*/OMPC_has_device_addr);
// Record the expression we've just processed.
- auto *VD = dyn_cast<VarDecl>(D);
if (!VD && !CurContext->isDependentContext()) {
DeclRefExpr *Ref =
buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
@@ -23336,17 +23670,26 @@ OMPClause *Sema::ActOnOpenMPUsesAllocatorClause(
AllocatorExpr = D.Allocator->IgnoreParenImpCasts();
auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr);
bool IsPredefinedAllocator = false;
- if (DRE)
- IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl());
- if (!DRE ||
- !(Context.hasSameUnqualifiedType(
- AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) ||
- Context.typesAreCompatible(AllocatorExpr->getType(),
- DSAStack->getOMPAllocatorHandleT(),
- /*CompareUnqualified=*/true)) ||
- (!IsPredefinedAllocator &&
- (AllocatorExpr->getType().isConstant(Context) ||
- !AllocatorExpr->isLValue()))) {
+ if (DRE) {
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorTy =
+ getAllocatorKind(*this, DSAStack, AllocatorExpr);
+ IsPredefinedAllocator =
+ AllocatorTy !=
+ OMPAllocateDeclAttr::AllocatorTypeTy::OMPUserDefinedMemAlloc;
+ }
+ QualType OMPAllocatorHandleT = DSAStack->getOMPAllocatorHandleT();
+ QualType AllocatorExprType = AllocatorExpr->getType();
+ bool IsTypeCompatible = IsPredefinedAllocator;
+ IsTypeCompatible = IsTypeCompatible ||
+ Context.hasSameUnqualifiedType(AllocatorExprType,
+ OMPAllocatorHandleT);
+ IsTypeCompatible =
+ IsTypeCompatible ||
+ Context.typesAreCompatible(AllocatorExprType, OMPAllocatorHandleT);
+ bool IsNonConstantLValue =
+ !AllocatorExprType.isConstant(Context) && AllocatorExpr->isLValue();
+ if (!DRE || !IsTypeCompatible ||
+ (!IsPredefinedAllocator && !IsNonConstantLValue)) {
Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected)
<< "omp_allocator_handle_t" << (DRE ? 1 : 0)
<< AllocatorExpr->getType() << D.Allocator->getSourceRange();
@@ -23480,3 +23823,31 @@ OMPClause *Sema::ActOnOpenMPBindClause(OpenMPBindClauseKind Kind,
return OMPBindClause::Create(Context, Kind, KindLoc, StartLoc, LParenLoc,
EndLoc);
}
+
+OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Size;
+ Stmt *HelperValStmt = nullptr;
+
+ // OpenMP [2.5, Restrictions]
+ // The ompx_dyn_cgroup_mem expression must evaluate to a positive integer
+ // value.
+ if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_ompx_dyn_cgroup_mem,
+ /*StrictlyPositive=*/false))
+ return nullptr;
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_ompx_dyn_cgroup_mem, LangOpts.OpenMP);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
+ ValExpr = MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
+
+ return new (Context) OMPXDynCGroupMemClause(
+ ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
+}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d72cc33ed0f5..d68337a26d97 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12,14 +12,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -30,12 +33,13 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cstdlib>
+#include <optional>
using namespace clang;
using namespace sema;
@@ -63,9 +67,8 @@ static ExprResult CreateFunctionRefExpr(
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
- DeclRefExpr *DRE =
- DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
- Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
+ DeclRefExpr *DRE = new (S.Context)
+ DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
@@ -355,7 +358,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- if (Optional<llvm::APSInt> IntConstantValue =
+ if (std::optional<llvm::APSInt> IntConstantValue =
Initializer->getIntegerConstantExpr(Ctx)) {
// Convert the integer to the floating type.
llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
@@ -438,7 +441,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- Optional<llvm::APSInt> OptInitializerValue;
+ std::optional<llvm::APSInt> OptInitializerValue;
if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
// Such conversions on variables are always narrowing.
return NK_Variable_Narrowing;
@@ -637,7 +640,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
auto *Saved = new (Context) DFIDeducedMismatchArgs;
Saved->FirstArg = Info.FirstArg;
Saved->SecondArg = Info.SecondArg;
- Saved->TemplateArgs = Info.take();
+ Saved->TemplateArgs = Info.takeSugared();
Saved->CallArgIndex = Info.CallArgIndex;
Result.Data = Saved;
break;
@@ -666,7 +669,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
}
case Sema::TDK_SubstitutionFailure:
- Result.Data = Info.take();
+ Result.Data = Info.takeSugared();
if (Info.hasSFINAEDiagnostic()) {
PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt(
SourceLocation(), PartialDiagnostic::NullDiagnostic());
@@ -677,7 +680,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_ConstraintsNotSatisfied: {
CNSInfo *Saved = new (Context) CNSInfo;
- Saved->TemplateArgs = Info.take();
+ Saved->TemplateArgs = Info.takeSugared();
Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction;
Result.Data = Saved;
break;
@@ -685,6 +688,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
llvm_unreachable("not a deduction failure");
}
@@ -734,6 +738,7 @@ void DeductionFailureInfo::Destroy() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
}
@@ -771,6 +776,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -806,6 +812,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -837,6 +844,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -868,24 +876,95 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
return nullptr;
}
-llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
+std::optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
default:
- return llvm::None;
+ return std::nullopt;
}
}
-bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+static bool FunctionsCorrespond(ASTContext &Ctx, const FunctionDecl *X,
+ const FunctionDecl *Y) {
+ if (!X || !Y)
+ return false;
+ if (X->getNumParams() != Y->getNumParams())
+ return false;
+ for (unsigned I = 0; I < X->getNumParams(); ++I)
+ if (!Ctx.hasSameUnqualifiedType(X->getParamDecl(I)->getType(),
+ Y->getParamDecl(I)->getType()))
+ return false;
+ if (auto *FTX = X->getDescribedFunctionTemplate()) {
+ auto *FTY = Y->getDescribedFunctionTemplate();
+ if (!FTY)
+ return false;
+ if (!Ctx.isSameTemplateParameterList(FTX->getTemplateParameters(),
+ FTY->getTemplateParameters()))
+ return false;
+ }
+ return true;
+}
+
+static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
+ Expr *FirstOperand, FunctionDecl *EqFD) {
+ assert(EqFD->getOverloadedOperator() ==
+ OverloadedOperatorKind::OO_EqualEqual);
+ // C++2a [over.match.oper]p4:
+ // A non-template function or function template F named operator== is a
+ // rewrite target with first operand o unless a search for the name operator!=
+ // in the scope S from the instantiation context of the operator expression
+ // finds a function or function template that would correspond
+ // ([basic.scope.scope]) to F if its name were operator==, where S is the
+ // scope of the class type of o if F is a class member, and the namespace
+ // scope of which F is a member otherwise. A function template specialization
+ // named operator== is a rewrite target if its function template is a rewrite
+ // target.
+ DeclarationName NotEqOp = S.Context.DeclarationNames.getCXXOperatorName(
+ OverloadedOperatorKind::OO_ExclaimEqual);
+ if (isa<CXXMethodDecl>(EqFD)) {
+ // If F is a class member, search scope is class type of first operand.
+ QualType RHS = FirstOperand->getType();
+ auto *RHSRec = RHS->getAs<RecordType>();
+ if (!RHSRec)
+ return true;
+ LookupResult Members(S, NotEqOp, OpLoc,
+ Sema::LookupNameKind::LookupMemberName);
+ S.LookupQualifiedName(Members, RHSRec->getDecl());
+ Members.suppressDiagnostics();
+ for (NamedDecl *Op : Members)
+ if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
+ return false;
+ return true;
+ }
+ // Otherwise the search scope is the namespace scope of which F is a member.
+ LookupResult NonMembers(S, NotEqOp, OpLoc,
+ Sema::LookupNameKind::LookupOperatorName);
+ S.LookupName(NonMembers,
+ S.getScopeForContext(EqFD->getEnclosingNamespaceContext()));
+ NonMembers.suppressDiagnostics();
+ for (NamedDecl *Op : NonMembers) {
+ auto *FD = Op->getAsFunction();
+ if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
+ FD = UD->getUnderlyingDecl()->getAsFunction();
+ if (FunctionsCorrespond(S.Context, EqFD, FD) &&
+ declaresSameEntity(cast<Decl>(EqFD->getDeclContext()),
+ cast<Decl>(Op->getDeclContext())))
+ return false;
+ }
+ return true;
+}
+
+bool OverloadCandidateSet::OperatorRewriteInfo::allowsReversed(
OverloadedOperatorKind Op) {
if (!AllowRewrittenCandidates)
return false;
@@ -893,14 +972,21 @@ bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
}
bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
- ASTContext &Ctx, const FunctionDecl *FD) {
- if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
+ Sema &S, ArrayRef<Expr *> OriginalArgs, FunctionDecl *FD) {
+ auto Op = FD->getOverloadedOperator();
+ if (!allowsReversed(Op))
return false;
+ if (Op == OverloadedOperatorKind::OO_EqualEqual) {
+ assert(OriginalArgs.size() == 2);
+ if (!shouldAddReversedEqEq(
+ S, OpLoc, /*FirstOperand in reversed args*/ OriginalArgs[1], FD))
+ return false;
+ }
// Don't bother adding a reversed candidate that can never be a better
// match than the non-reversed version.
return FD->getNumParams() != 2 ||
- !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
- FD->getParamDecl(1)->getType()) ||
+ !S.Context.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType()) ||
FD->hasAttr<EnableIfAttr>();
}
@@ -1069,6 +1155,15 @@ 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;
}
@@ -1185,25 +1280,52 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
!FunctionParamTypesAreEqual(OldType, NewType)))
return true;
- // C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
- // signature, its return type and its template parameter list. The names
- // of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
- // signature.
- //
- // We check the return type and template parameter lists for function
- // templates first; the remaining checks follow.
- //
- // However, we don't consider either of these when deciding whether
- // a member introduced by a shadow declaration is hidden.
- if (!UseMemberUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
- !Context.hasSameType(Old->getDeclaredReturnType(),
- New->getDeclaredReturnType())))
- return true;
+ if (NewTemplate) {
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ bool SameTemplateParameterList = TemplateParameterListsAreEqual(
+ NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch);
+ bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(),
+ New->getDeclaredReturnType());
+ // FIXME(GH58571): Match template parameter list even for non-constrained
+ // template heads. This currently ensures that the code prior to C++20 is
+ // not newly broken.
+ bool ConstraintsInTemplateHead =
+ NewTemplate->getTemplateParameters()->hasAssociatedConstraints() ||
+ OldTemplate->getTemplateParameters()->hasAssociatedConstraints();
+ // C++ [namespace.udecl]p11:
+ // The set of declarations named by a using-declarator that inhabits a
+ // class C does not include member functions and member function
+ // templates of a base class that "correspond" to (and thus would
+ // conflict with) a declaration of a function or function template in
+ // C.
+ // Comparing return types is not required for the "correspond" check to
+ // decide whether a member introduced by a shadow declaration is hidden.
+ if (UseMemberUsingDeclRules && ConstraintsInTemplateHead &&
+ !SameTemplateParameterList)
+ return true;
+ if (!UseMemberUsingDeclRules &&
+ (!SameTemplateParameterList || !SameReturnType))
+ return true;
+ }
+
+ if (ConsiderRequiresClauses) {
+ Expr *NewRC = New->getTrailingRequiresClause(),
+ *OldRC = Old->getTrailingRequiresClause();
+ if ((NewRC != nullptr) != (OldRC != nullptr))
+ return true;
+
+ if (NewRC && !AreConstraintExpressionsEqual(Old, OldRC, New, NewRC))
+ return true;
+ }
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) and ref-qualifier (if any) on the function itself.
@@ -1221,14 +1343,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (!UseMemberUsingDeclRules &&
(OldMethod->getRefQualifier() == RQ_None ||
NewMethod->getRefQualifier() == RQ_None)) {
- // C++0x [over.load]p2:
- // - Member function declarations with the same name and the same
- // parameter-type-list as well as member function template
- // declarations with the same name, the same parameter-type-list, and
- // the same template parameter lists cannot be overloaded if any of
- // them, but not all, have a ref-qualifier (8.3.5).
+ // C++20 [over.load]p2:
+ // - Member function declarations with the same name, the same
+ // parameter-type-list, and the same trailing requires-clause (if
+ // any), as well as member function template declarations with the
+ // same name, the same parameter-type-list, the same trailing
+ // requires-clause (if any), and the same template-head, cannot be
+ // overloaded if any of them, but not all, have a ref-qualifier.
Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
- << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
+ << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
Diag(OldMethod->getLocation(), diag::note_previous_declaration);
}
return true;
@@ -1292,23 +1415,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
}
}
- if (ConsiderRequiresClauses) {
- Expr *NewRC = New->getTrailingRequiresClause(),
- *OldRC = Old->getTrailingRequiresClause();
- if ((NewRC != nullptr) != (OldRC != nullptr))
- // RC are most certainly different - these are overloads.
- return true;
-
- if (NewRC) {
- llvm::FoldingSetNodeID NewID, OldID;
- NewRC->Profile(NewID, Context, /*Canonical=*/true);
- OldRC->Profile(OldID, Context, /*Canonical=*/true);
- if (NewID != OldID)
- // RCs are not equivalent - these are overloads.
- return true;
- }
- }
-
// The signatures match; this is not an overload.
return false;
}
@@ -1620,7 +1726,7 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
/// conversion.
static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
ImplicitConversionKind &ICK, Expr *From,
- bool InOverloadResolution) {
+ bool InOverloadResolution, bool CStyle) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
if (!ToType->isVectorType() && !FromType->isVectorType())
@@ -1665,7 +1771,7 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
if (S.isLaxVectorConversion(FromType, ToType) &&
S.anyAltivecTypes(FromType, ToType) &&
!S.areSameVectorElemTypes(FromType, ToType) &&
- !InOverloadResolution) {
+ !InOverloadResolution && !CStyle) {
S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all)
<< FromType << ToType;
}
@@ -1918,7 +2024,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
} else if (IsVectorConversion(S, FromType, ToType, SecondICK, From,
- InOverloadResolution)) {
+ InOverloadResolution, CStyle)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
@@ -2073,9 +2179,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// int can represent all the values of the source type; otherwise,
// the source rvalue can be converted to an rvalue of type unsigned
// int (C++ 4.5p1).
- if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() &&
+ if (Context.isPromotableIntegerType(FromType) && !FromType->isBooleanType() &&
!FromType->isEnumeralType()) {
- if (// We can promote any signed, promotable integer type to an int
+ if ( // We can promote any signed, promotable integer type to an int
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
// less than int to an int.
@@ -2187,7 +2293,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// compatibility.
if (From) {
if (FieldDecl *MemberDecl = From->getSourceBitField()) {
- Optional<llvm::APSInt> BitWidth;
+ std::optional<llvm::APSInt> BitWidth;
if (FromType->isIntegralType(Context) &&
(BitWidth =
MemberDecl->getBitWidth()->getIntegerConstantExpr(Context))) {
@@ -3506,7 +3612,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
- /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
+ /*ExplicitArgs*/ nullptr, llvm::ArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit == AllowedExplicit::All);
@@ -3514,8 +3620,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
- llvm::makeArrayRef(Args, NumArgs),
- CandidateSet, SuppressUserConversions,
+ llvm::ArrayRef(Args, NumArgs), CandidateSet,
+ SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit == AllowedExplicit::All);
}
@@ -4495,15 +4601,6 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
return ImplicitConversionSequence::Indistinguishable;
}
-/// Determine whether the given type is valid, e.g., it is not an invalid
-/// C++ class.
-static bool isTypeValid(QualType T) {
- if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
- return !Record->isInvalidDecl();
-
- return true;
-}
-
static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
if (!T.getQualifiers().hasUnaligned())
return T;
@@ -4553,7 +4650,6 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
- isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
@@ -5096,7 +5192,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
}
if (CT->getSize().ugt(e)) {
// Need an init from empty {}, is there one?
- InitListExpr EmptyList(S.Context, From->getEndLoc(), None,
+ InitListExpr EmptyList(S.Context, From->getEndLoc(), std::nullopt,
From->getEndLoc());
EmptyList.setType(S.Context.VoidTy);
DfltElt = TryListConversion(
@@ -5725,7 +5821,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
- llvm_unreachable("ellipsis conversion in converted constant expression");
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
+ llvm_unreachable("bad conversion in converted constant expression");
}
// Check that we would only use permitted conversions.
@@ -5760,9 +5857,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
// C++2a [intro.execution]p5:
// A full-expression is [...] a constant-expression [...]
- Result =
- S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
- /*DiscardedValue=*/false, /*IsConstexpr=*/true);
+ Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
+ /*DiscardedValue=*/false, /*IsConstexpr=*/true,
+ CCE == Sema::CCEKind::CCEK_TemplateArg);
if (Result.isInvalid())
return Result;
@@ -5909,6 +6006,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
case ImplicitConversionSequence::BadConversion:
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
break;
case ImplicitConversionSequence::UserDefinedConversion:
@@ -6242,7 +6340,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
HadMultipleCandidates,
ExplicitConversions))
return ExprError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OR_Deleted:
// We'll complain below about a non-integral condition type.
break;
@@ -6422,8 +6520,11 @@ void Sema::AddOverloadCandidate(
}
}
- if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
- !Function->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Function->isMultiVersion() &&
+ ((Function->hasAttr<TargetAttr>() &&
+ !Function->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Function->hasAttr<TargetVersionAttr>() &&
+ !Function->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
return;
@@ -6516,7 +6617,8 @@ void Sema::AddOverloadCandidate(
if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Function, Satisfaction) ||
+ if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {},
+ /*ForOverloadResolution*/ true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -6742,7 +6844,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function,
// very difficult. Ideally, we should handle them more gracefully.
if (EIA->getCond()->isValueDependent() ||
!EIA->getCond()->EvaluateWithSubstitution(
- Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
+ Result, Context, Function, llvm::ArrayRef(ConvertedArgs)))
return EIA;
if (!Result.isInt() || !Result.getInt().getBoolValue())
@@ -6914,7 +7016,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification, Args, CandidateSet,
- SuppressUserConversions, false, None, PO);
+ SuppressUserConversions, false, std::nullopt, PO);
}
}
@@ -6994,17 +7096,27 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.Viable = true;
- if (Method->isStatic() || ObjectType.isNull())
- // The implicit object argument is ignored.
+ unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ if (ObjectType.isNull())
Candidate.IgnoreObjectArgument = true;
- else {
- unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ else if (Method->isStatic()) {
+ // [over.best.ics.general]p8
+ // When the parameter is the implicit object parameter of a static member
+ // function, the implicit conversion sequence is a standard conversion
+ // sequence that is neither better nor worse than any other standard
+ // conversion sequence.
+ //
+ // This is a rule that was introduced in C++23 to support static lambdas. We
+ // apply it retroactively because we want to support static lambdas as an
+ // extension and it doesn't hurt previous code.
+ Candidate.Conversions[FirstConvIdx].setStaticObjectArgument();
+ } else {
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization(
+ Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Candidate.Conversions[ConvIdx].isBad()) {
+ if (Candidate.Conversions[FirstConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -7022,7 +7134,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Method, Satisfaction) ||
+ if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {},
+ /*ForOverloadResolution*/ true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7071,8 +7184,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
- if (Method->isMultiVersion() && Method->hasAttr<TargetAttr>() &&
- !Method->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Method->isMultiVersion() &&
+ ((Method->hasAttr<TargetAttr>() &&
+ !Method->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Method->hasAttr<TargetVersionAttr>() &&
+ !Method->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
@@ -7518,15 +7634,18 @@ void Sema::AddConversionCandidate(
}
if (EnableIfAttr *FailedAttr =
- CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
- if (Conversion->isMultiVersion() && Conversion->hasAttr<TargetAttr>() &&
- !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Conversion->isMultiVersion() &&
+ ((Conversion->hasAttr<TargetAttr>() &&
+ !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Conversion->hasAttr<TargetVersionAttr>() &&
+ !Conversion->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
@@ -7689,7 +7808,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
if (EnableIfAttr *FailedAttr =
- CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -7721,7 +7840,7 @@ void Sema::AddNonMemberOperatorCandidates(
if (FunTmpl) {
AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
FunctionArgs, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
AddTemplateOverloadCandidate(
FunTmpl, F.getPair(), ExplicitTemplateArgs,
{FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
@@ -7730,11 +7849,11 @@ void Sema::AddNonMemberOperatorCandidates(
if (ExplicitTemplateArgs)
continue;
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
- AddOverloadCandidate(FD, F.getPair(),
- {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
- false, false, true, false, ADLCallKind::NotADL,
- None, OverloadCandidateParamOrder::Reversed);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
+ AddOverloadCandidate(
+ FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
+ false, false, true, false, ADLCallKind::NotADL, std::nullopt,
+ OverloadCandidateParamOrder::Reversed);
}
}
}
@@ -7781,12 +7900,17 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
Operators.suppressDiagnostics();
for (LookupResult::iterator Oper = Operators.begin(),
- OperEnd = Operators.end();
- Oper != OperEnd;
- ++Oper)
+ OperEnd = Operators.end();
+ Oper != OperEnd; ++Oper) {
+ if (Oper->getAsFunction() &&
+ PO == OverloadCandidateParamOrder::Reversed &&
+ !CandidateSet.getRewriteInfo().shouldAddReversed(
+ *this, {Args[1], Args[0]}, Oper->getAsFunction()))
+ continue;
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
CandidateSet, /*SuppressUserConversion=*/false, PO);
+ }
}
}
@@ -9312,7 +9436,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Plus: // '+' is either unary or binary
if (Args.size() == 1)
OpBuilder.addUnaryPlusPointerOverloads();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_Minus: // '-' is either unary or binary
if (Args.size() == 1) {
@@ -9387,12 +9511,12 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Equal:
OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_PlusEqual:
case OO_MinusEqual:
OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_StarEqual:
case OO_SlashEqual:
@@ -9482,12 +9606,13 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
PartialOverloading, /*AllowExplicit=*/true,
/*AllowExplicitConversion=*/false, ADLCallKind::UsesADL);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) {
AddOverloadCandidate(
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
/*SuppressUserConversions=*/false, PartialOverloading,
/*AllowExplicit=*/true, /*AllowExplicitConversion=*/false,
- ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
+ ADLCallKind::UsesADL, std::nullopt,
+ OverloadCandidateParamOrder::Reversed);
}
} else {
auto *FTD = cast<FunctionTemplateDecl>(*I);
@@ -9496,7 +9621,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
/*SuppressUserConversions=*/false, PartialOverloading,
/*AllowExplicit=*/true, ADLCallKind::UsesADL);
if (CandidateSet.getRewriteInfo().shouldAddReversed(
- Context, FTD->getTemplatedDecl())) {
+ *this, Args, FTD->getTemplatedDecl())) {
AddTemplateOverloadCandidate(
FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
@@ -9538,8 +9663,8 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
for (auto Pair : zip_longest(Cand1Attrs, Cand2Attrs)) {
- Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
- Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
+ std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
+ std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
// It's impossible for Cand1 to be better than (or equal to) Cand2 if Cand1
// has fewer enable_if attributes than Cand2, and vice versa.
@@ -9617,12 +9742,12 @@ isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
}
/// Compute the type of the implicit object parameter for the given function,
-/// if any. Returns None if there is no implicit object parameter, and a null
-/// QualType if there is a 'matches anything' implicit object parameter.
-static Optional<QualType> getImplicitObjectParamType(ASTContext &Context,
- const FunctionDecl *F) {
+/// if any. Returns std::nullopt if there is no implicit object parameter, and a
+/// null QualType if there is a 'matches anything' implicit object parameter.
+static std::optional<QualType>
+getImplicitObjectParamType(ASTContext &Context, const FunctionDecl *F) {
if (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F))
- return llvm::None;
+ return std::nullopt;
auto *M = cast<CXXMethodDecl>(F);
// Static member functions' object parameters match all types.
@@ -9642,7 +9767,7 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) {
if (First) {
- if (Optional<QualType> T = getImplicitObjectParamType(Context, F))
+ if (std::optional<QualType> T = getImplicitObjectParamType(Context, F))
return *T;
}
assert(I < F->getNumParams());
@@ -9662,19 +9787,13 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
/// We're allowed to use constraints partial ordering only if the candidates
/// have the same parameter types:
-/// [temp.func.order]p6.2.2 [...] or if the function parameters that
-/// positionally correspond between the two templates are not of the same type,
-/// neither template is more specialized than the other.
/// [over.match.best]p2.6
/// F1 and F2 are non-template functions with the same parameter-type-lists,
/// and F1 is more constrained than F2 [...]
-static bool canCompareFunctionConstraints(Sema &S,
+static bool sameFunctionParameterTypeLists(Sema &S,
const OverloadCandidate &Cand1,
const OverloadCandidate &Cand2) {
- // FIXME: Per P2113R0 we also need to compare the template parameter lists
- // when comparing template functions.
- if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() &&
- Cand2.Function->hasPrototype()) {
+ if (Cand1.Function && Cand2.Function) {
auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
if (PT1->getNumParams() == PT2->getNumParams() &&
@@ -9767,7 +9886,7 @@ bool clang::isBetterOverloadCandidate(
}
}
- // C++ [over.match.best]p1:
+ // C++ [over.match.best]p1: (Changed in C++2b)
//
// -- if F is a static member function, ICS1(F) is defined such
// that ICS1(F) is neither better nor worse than ICS1(G) for
@@ -9917,22 +10036,28 @@ bool clang::isBetterOverloadCandidate(
isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
: TPOC_Call,
Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
- Cand1.isReversed() ^ Cand2.isReversed(),
- canCompareFunctionConstraints(S, Cand1, Cand2)))
+ Cand1.isReversed() ^ Cand2.isReversed()))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
// -— F1 and F2 are non-template functions with the same
// parameter-type-lists, and F1 is more constrained than F2 [...],
if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
- canCompareFunctionConstraints(S, Cand1, Cand2)) {
- Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
- Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
+ sameFunctionParameterTypeLists(S, Cand1, Cand2)) {
+ FunctionDecl *Function1 = Cand1.Function;
+ FunctionDecl *Function2 = Cand2.Function;
+ if (FunctionDecl *MF = Function1->getInstantiatedFromMemberFunction())
+ Function1 = MF;
+ if (FunctionDecl *MF = Function2->getInstantiatedFromMemberFunction())
+ Function2 = MF;
+
+ const Expr *RC1 = Function1->getTrailingRequiresClause();
+ const Expr *RC2 = Function2->getTrailingRequiresClause();
if (RC1 && RC2) {
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2},
+ if (S.IsAtLeastAsConstrained(Function1, RC1, Function2, RC2,
AtLeastAsConstrained1) ||
- S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1},
+ S.IsAtLeastAsConstrained(Function2, RC2, Function1, RC1,
AtLeastAsConstrained2))
return false;
if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
@@ -10103,6 +10228,13 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
}
}
+bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const {
+ return FailureKind == ovl_fail_bad_deduction &&
+ DeductionFailure.Result == Sema::TDK_ConstraintsNotSatisfied &&
+ static_cast<CNSInfo *>(DeductionFailure.Data)
+ ->Satisfaction.ContainsErrors;
+}
+
/// Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
@@ -10155,10 +10287,18 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Best = end();
for (auto *Cand : Candidates) {
Cand->Best = false;
- if (Cand->Viable)
+ if (Cand->Viable) {
if (Best == end() ||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
+ } else if (Cand->NotValidBecauseConstraintExprHasError()) {
+ // This candidate has constraint that we were unable to evaluate because
+ // it referenced an expression that contained an error. Rather than fall
+ // back onto a potentially unintended candidate (made worse by
+ // subsuming constraints), treat this as 'no viable candidate'.
+ Best = end();
+ return OR_No_Viable_Function;
+ }
}
// If we didn't find any viable functions, abort.
@@ -10431,6 +10571,9 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() &&
!Fn->getAttr<TargetAttr>()->isDefaultVersion())
return;
+ if (Fn->isMultiVersion() && Fn->hasAttr<TargetVersionAttr>() &&
+ !Fn->getAttr<TargetVersionAttr>()->isDefaultVersion())
+ return;
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
@@ -10774,10 +10917,13 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< ToTy << (unsigned)isObjectArgument << I + 1
<< (unsigned)(Cand->Fix.Kind);
- // If we can fix the conversion, suggest the FixIts.
- for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(),
- HE = Cand->Fix.Hints.end(); HI != HE; ++HI)
- FDiag << *HI;
+ // Check that location of Fn is not in system header.
+ if (!S.SourceMgr.isInSystemHeader(Fn->getLocation())) {
+ // If we can fix the conversion, suggest the FixIts.
+ for (const FixItHint &HI : Cand->Fix.Hints)
+ FDiag << HI;
+ }
+
S.Diag(Fn->getLocation(), FDiag);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
@@ -11483,6 +11629,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case Sema::TDK_Invalid:
@@ -12239,6 +12386,9 @@ private:
const auto *TA = FunDecl->getAttr<TargetAttr>();
if (TA && !TA->isDefaultVersion())
return false;
+ const auto *TVA = FunDecl->getAttr<TargetVersionAttr>();
+ if (TVA && !TVA->isDefaultVersion())
+ return false;
}
// If any candidate has a placeholder return type, trigger its deduction
@@ -12501,20 +12651,24 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
DeclAccessPair DAP;
SmallVector<FunctionDecl *, 2> AmbiguousDecls;
- auto CheckMoreConstrained =
- [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> {
- SmallVector<const Expr *, 1> AC1, AC2;
- FD1->getAssociatedConstraints(AC1);
- FD2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
- return None;
- if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
- return None;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return None;
- return AtLeastAsConstrained1;
- };
+ auto CheckMoreConstrained = [&](FunctionDecl *FD1,
+ FunctionDecl *FD2) -> std::optional<bool> {
+ if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
+ FD1 = MF;
+ if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
+ FD2 = MF;
+ SmallVector<const Expr *, 1> AC1, AC2;
+ FD1->getAssociatedConstraints(AC1);
+ FD2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
+ return std::nullopt;
+ if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
+ return std::nullopt;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return std::nullopt;
+ return AtLeastAsConstrained1;
+ };
// Don't use the AddressOfResolver because we're specifically looking for
// cases where we have one overload candidate that lacks
@@ -12530,8 +12684,8 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
// We have more than one result - see if it is more constrained than the
// previous one.
if (Result) {
- Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD,
- Result);
+ std::optional<bool> MoreConstrainedThanPrevious =
+ CheckMoreConstrained(FD, Result);
if (!MoreConstrainedThanPrevious) {
IsResultAmbiguous = true;
AmbiguousDecls.push_back(FD);
@@ -12569,7 +12723,7 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
/// Returns false if resolveAddressOfSingleOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
- ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
+ ExprResult &SrcExpr, bool DoFunctionPointerConversion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
@@ -12585,7 +12739,7 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
DiagnoseUseOfDecl(Found, E->getExprLoc());
CheckAddressOfMemberAccess(E, DAP);
Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
- if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType())
+ if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType())
SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
else
SrcExpr = Fixed;
@@ -12687,10 +12841,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// expression, regardless of whether or not it succeeded. Always
// returns true if 'complain' is set.
bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
- ExprResult &SrcExpr, bool doFunctionPointerConverion,
- bool complain, SourceRange OpRangeForComplaining,
- QualType DestTypeForComplaining,
- unsigned DiagIDForComplaining) {
+ ExprResult &SrcExpr, bool doFunctionPointerConversion, bool complain,
+ SourceRange OpRangeForComplaining, QualType DestTypeForComplaining,
+ unsigned DiagIDForComplaining) {
assert(SrcExpr.get()->getType() == Context.OverloadTy);
OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get());
@@ -12731,7 +12884,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
FixOverloadedFunctionReference(SrcExpr.get(), found, fn);
// If desired, do function-to-pointer decay.
- if (doFunctionPointerConverion) {
+ if (doFunctionPointerConversion) {
SingleFunctionExpression =
DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get());
if (SingleFunctionExpression.isInvalid()) {
@@ -13008,17 +13161,16 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
namespace {
class BuildRecoveryCallExprRAII {
Sema &SemaRef;
+ Sema::SatisfactionStackResetRAII SatStack;
+
public:
- BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) {
+ BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S), SatStack(S) {
assert(SemaRef.IsBuildingRecoveryCallExpr == false);
SemaRef.IsBuildingRecoveryCallExpr = true;
}
- ~BuildRecoveryCallExprRAII() {
- SemaRef.IsBuildingRecoveryCallExpr = false;
- }
+ ~BuildRecoveryCallExprRAII() { SemaRef.IsBuildingRecoveryCallExpr = false; }
};
-
}
/// Attempts to recover from a call where no functions were found.
@@ -13191,7 +13343,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// Guess at what the return type for an unresolvable overload should be.
static QualType chooseRecoveryType(OverloadCandidateSet &CS,
OverloadCandidateSet::iterator *Best) {
- llvm::Optional<QualType> Result;
+ std::optional<QualType> Result;
// Adjust Type after seeing a candidate.
auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
if (!Candidate.Function)
@@ -13594,14 +13746,14 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ if (CandidateSet.getRewriteInfo().allowsReversed(Op))
AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
OverloadCandidateParamOrder::Reversed);
// In C++20, also add any rewritten member candidates.
if (ExtraOp) {
AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
+ if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp))
AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
CandidateSet,
OverloadCandidateParamOrder::Reversed);
@@ -13732,9 +13884,9 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build the overload set.
- OverloadCandidateSet CandidateSet(
- OpLoc, OverloadCandidateSet::CSK_Operator,
- OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(
+ Op, OpLoc, AllowRewrittenCandidates));
if (DefaultedFn)
CandidateSet.exclude(DefaultedFn);
LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
@@ -13809,6 +13961,22 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (AmbiguousWithSelf) {
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&); };
+ // S()==S();
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl))
+ if (Op == OverloadedOperatorKind::OO_EqualEqual &&
+ !MD->isConst() &&
+ Context.hasSameUnqualifiedType(
+ MD->getThisObjectType(),
+ MD->getParamDecl(0)->getType().getNonReferenceType()) &&
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
+ Args[0]->getType()) &&
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
+ Args[1]->getType()))
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_eqeq_reversed_self_non_const);
} else {
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_oper_binary_selected_candidate);
@@ -13932,7 +14100,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
R = CreateOverloadedBinOp(
OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),
- IsReversed ? R.get() : ZeroLiteral, PerformADL,
+ IsReversed ? R.get() : ZeroLiteral, /*PerformADL=*/true,
/*AllowRewrittenCandidates=*/false);
popCodeSynthesisContext();
@@ -14206,7 +14374,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
MultiExprArg ArgExpr) {
SmallVector<Expr *, 2> Args;
Args.push_back(Base);
- for (auto e : ArgExpr) {
+ for (auto *e : ArgExpr) {
Args.push_back(e);
}
DeclarationName OpName =
@@ -14271,12 +14439,17 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
SmallVector<Expr *, 2> MethodArgs;
- ExprResult Arg0 = PerformObjectArgumentInitialization(
- Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
- if (Arg0.isInvalid())
- return ExprError();
- MethodArgs.push_back(Arg0.get());
+ // Handle 'this' parameter if the selected function is not static.
+ if (Method->isInstance()) {
+ ExprResult Arg0 = PerformObjectArgumentInitialization(
+ Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (Arg0.isInvalid())
+ return ExprError();
+
+ MethodArgs.push_back(Arg0.get());
+ }
+
bool IsError = PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, ArgExpr, LLoc);
if (IsError)
@@ -14296,9 +14469,16 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
- CurFPFeatureOverrides());
+ CallExpr *TheCall;
+ if (Method->isInstance())
+ TheCall = CXXOperatorCallExpr::Create(
+ Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK,
+ RLoc, CurFPFeatureOverrides());
+ else
+ TheCall =
+ CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK,
+ RLoc, CurFPFeatureOverrides());
+
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -14535,7 +14715,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Method = cast<CXXMethodDecl>(Best->Function);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
- if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
+ if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
break;
// If FoundDecl is different from Method (such as if one is a template
// and the other a specialization), make sure DiagnoseUseOfDecl is
@@ -14544,7 +14724,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
// being used.
if (Method != FoundDecl.getDecl() &&
- DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
+ DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc()))
break;
Succeeded = true;
break;
@@ -14874,15 +15054,18 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
bool IsError = false;
- // Initialize the implicit object parameter.
- ExprResult ObjRes =
- PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/nullptr,
- Best->FoundDecl, Method);
- if (ObjRes.isInvalid())
- IsError = true;
- else
- Object = ObjRes;
- MethodArgs.push_back(Object.get());
+ // Initialize the implicit object parameter if needed.
+ // Since C++2b, this could also be a call to a static call operator
+ // which we emit as a regular CallExpr.
+ if (Method->isInstance()) {
+ ExprResult ObjRes = PerformObjectArgumentInitialization(
+ Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (ObjRes.isInvalid())
+ IsError = true;
+ else
+ Object = ObjRes;
+ MethodArgs.push_back(Object.get());
+ }
IsError |= PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, Args, LParenLoc);
@@ -14908,9 +15091,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
- CurFPFeatureOverrides());
+ CallExpr *TheCall;
+ if (Method->isInstance())
+ TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(),
+ MethodArgs, ResultTy, VK, RParenLoc,
+ CurFPFeatureOverrides());
+ else
+ TheCall = CallExpr::Create(Context, NewFn.get(), MethodArgs, ResultTy, VK,
+ RParenLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
@@ -14956,7 +15144,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
- None, CandidateSet, /*SuppressUserConversion=*/false);
+ std::nullopt, CandidateSet,
+ /*SuppressUserConversion=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -15105,8 +15294,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL = UserDefinedLiteral::Create(
- Context, Fn.get(), llvm::makeArrayRef(ConvArgs, Args.size()), ResultTy,
- VK, LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides());
+ Context, Fn.get(), llvm::ArrayRef(ConvArgs, Args.size()), ResultTy, VK,
+ LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(FD->getReturnType(), UDSuffixLoc, UDL, FD))
return ExprError();
@@ -15146,7 +15335,8 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
- *CallExpr = BuildCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
+ *CallExpr =
+ BuildCallExpr(S, MemberRef.get(), Loc, std::nullopt, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 7fdb34905b61..abbdc12e7047 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -737,11 +737,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
assert(InstanceReceiver || RefExpr->isSuperReceiver());
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, Getter->getSelector(),
- Getter, None);
+ Getter, std::nullopt);
} else {
msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
- GenericLoc, Getter->getSelector(),
- Getter, None);
+ GenericLoc, Getter->getSelector(), Getter,
+ std::nullopt);
}
return msg;
}
@@ -1200,7 +1200,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
/*TInfo=*/nullptr,
SC_None,
nullptr);
- AtIndexGetter->setMethodParams(S.Context, Argument, None);
+ AtIndexGetter->setMethodParams(S.Context, Argument, std::nullopt);
}
if (!AtIndexGetter) {
@@ -1316,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
SC_None,
nullptr);
Params.push_back(key);
- AtIndexSetter->setMethodParams(S.Context, Params, None);
+ AtIndexSetter->setMethodParams(S.Context, Params, std::nullopt);
}
if (!AtIndexSetter) {
diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
index 50fd841c231b..7716dfb15458 100644
--- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp
+++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Support/RISCVVIntrinsicUtils.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
#include <string>
#include <vector>
@@ -66,7 +67,7 @@ static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
// Get subsequence of signature table.
static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index,
uint8_t Length) {
- return makeArrayRef(&RVVSignatureTable[Index], Length);
+ return ArrayRef(&RVVSignatureTable[Index], Length);
}
static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
@@ -115,7 +116,7 @@ static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
llvm_unreachable("Unhandled type.");
}
if (Type->isVector())
- QT = Context.getScalableVectorType(QT, Type->getScale().getValue());
+ QT = Context.getScalableVectorType(QT, *Type->getScale());
if (Type->isConstant())
QT = Context.getConstType(QT);
@@ -132,6 +133,7 @@ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
private:
Sema &S;
ASTContext &Context;
+ RVVTypeCache TypeCache;
// List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList;
@@ -146,7 +148,7 @@ private:
// Create RVVIntrinsicDef.
void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
StringRef OverloadedSuffixStr, bool IsMask,
- RVVTypes &Types);
+ RVVTypes &Types, bool HasPolicy, Policy PolicyAttrs);
// Create FunctionDecl for a vector intrinsic.
void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
@@ -185,15 +187,32 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
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);
+
llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false,
/*HasMaskedOffOperand=*/false,
- Record.HasVL, Record.NF);
+ Record.HasVL, Record.NF,
+ UnMaskedPolicyScheme, DefaultPolicy);
llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
- RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true,
- Record.HasMaskedOffOperand,
- Record.HasVL, Record.NF);
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
+ Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy);
+
+ bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone;
+ bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone;
+ SmallVector<Policy> SupportedUnMaskedPolicies =
+ RVVIntrinsic::getSupportedUnMaskedPolicies(Record.HasTailPolicy,
+ Record.HasMaskPolicy);
+ SmallVector<Policy> SupportedMaskedPolicies =
+ RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy,
+ Record.HasMaskPolicy);
for (unsigned int TypeRangeMaskShift = 0;
TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
@@ -229,46 +248,72 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
continue;
- Optional<RVVTypes> Types =
- RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
+ std::optional<RVVTypes> Types =
+ TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
// Ignored to create new intrinsic if there are any illegal types.
- if (!Types.hasValue())
+ if (!Types.has_value())
continue;
- std::string SuffixStr =
- RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto);
+ std::string SuffixStr = RVVIntrinsic::getSuffixStr(
+ TypeCache, BaseType, Log2LMUL, SuffixProto);
std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
- BaseType, Log2LMUL, OverloadedSuffixProto);
+ TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto);
// Create non-masked intrinsic.
- InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types);
-
- if (Record.HasMasked) {
- // Create masked intrinsic.
- Optional<RVVTypes> MaskTypes = RVVType::computeTypes(
- BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
-
- InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
- *MaskTypes);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types,
+ UnMaskedHasPolicy, DefaultPolicy);
+
+ // Create non-masked policy intrinsic.
+ if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) {
+ for (auto P : SupportedUnMaskedPolicies) {
+ llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/false,
+ /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF,
+ UnMaskedPolicyScheme, P);
+ std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
+ BaseType, Log2LMUL, Record.NF, PolicyPrototype);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
+ /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy,
+ P);
+ }
}
- }
- }
+ if (!Record.HasMasked)
+ continue;
+ // Create masked intrinsic.
+ std::optional<RVVTypes> MaskTypes =
+ TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
+ *MaskTypes, MaskedHasPolicy, DefaultPolicy);
+ if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone)
+ continue;
+ // Create masked policy intrinsic.
+ for (auto P : SupportedMaskedPolicies) {
+ llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
+ Record.HasVL, Record.NF, MaskedPolicyScheme, P);
+ 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
}
}
// Compute name and signatures for intrinsic with practical types.
void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
const RVVIntrinsicRecord &Record, StringRef SuffixStr,
- StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) {
+ StringRef OverloadedSuffixStr, bool IsMasked, RVVTypes &Signature,
+ bool HasPolicy, Policy PolicyAttrs) {
// Function name, e.g. vadd_vv_i32m1.
std::string Name = Record.Name;
if (!SuffixStr.empty())
Name += "_" + SuffixStr.str();
- if (IsMask)
- Name += "_m";
-
// Overloaded function name, e.g. vadd.
std::string OverloadedName;
if (!Record.OverloadedName)
@@ -280,8 +325,9 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
// clang built-in function name, e.g. __builtin_rvv_vadd.
std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
- if (IsMask)
- BuiltinName += "_m";
+
+ RVVIntrinsic::updateNamesAndPolicy(IsMasked, HasPolicy, Name, BuiltinName,
+ OverloadedName, PolicyAttrs);
// Put into IntrinsicList.
size_t Index = IntrinsicList.size();
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c6ca10c0342c..f15603fd0bd4 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -382,7 +382,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
// type of the left operand could be used for SFINAE, so technically it is
// *used*.
if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext())
- DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None,
+ DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : std::nullopt,
PDiag(DiagID) << R1 << R2);
}
@@ -1499,7 +1499,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond &&
ET && ET->getDecl()->isCompleteDefinition() &&
- !empty(ET->getDecl()->enumerators())) {
+ !ET->getDecl()->enumerators().empty()) {
const EnumDecl *ED = ET->getDecl();
EnumValsTy EnumVals;
@@ -2308,11 +2308,14 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
// If the type contained 'auto', deduce the 'auto' to 'id'.
if (FirstType->getContainedAutoType()) {
- OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(),
- VK_PRValue);
+ SourceLocation Loc = D->getLocation();
+ OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue);
Expr *DeducedInit = &OpaqueId;
- if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) ==
- DAR_Failed)
+ TemplateDeductionInfo Info(Loc);
+ FirstType = QualType();
+ TemplateDeductionResult Result = DeduceAutoType(
+ D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
DiagnoseAutoDeductionFailure(D, DeducedInit);
if (FirstType.isNull()) {
D->setInvalidDecl();
@@ -2376,10 +2379,16 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
QualType InitType;
- if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
- SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) ==
- Sema::DAR_Failed)
+ if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) {
SemaRef.Diag(Loc, DiagID) << Init->getType();
+ } else {
+ TemplateDeductionInfo Info(Init->getExprLoc());
+ Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType(
+ Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info);
+ if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed)
+ SemaRef.Diag(Loc, DiagID) << Init->getType();
+ }
+
if (InitType.isNull()) {
Decl->setInvalidDecl();
return true;
@@ -2660,7 +2669,7 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
SemaRef.PDiag(diag::err_for_range_invalid)
<< BeginRange->getType() << BEFFound),
SemaRef, OCD_AllCandidates, BeginRange);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::FRS_DiagnosticIssued:
for (NamedDecl *D : OldFound) {
@@ -3769,17 +3778,13 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
/// C++1y [dcl.spec.auto]p6.
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
- Expr *&RetExpr,
- const AutoType *AT) {
+ Expr *RetExpr, const AutoType *AT) {
// If this is the conversion function for a lambda, we choose to deduce its
// type from the corresponding call operator, not from the synthesized return
// statement within it. See Sema::DeduceReturnType.
if (isLambdaConversionOperator(FD))
return false;
- TypeLoc OrigResultType = getReturnTypeLoc(FD);
- QualType Deduced;
-
if (RetExpr && isa<InitListExpr>(RetExpr)) {
// If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed.
@@ -3799,87 +3804,74 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
return false;
}
- if (RetExpr) {
- // Otherwise, [...] deduce a value for U using the rules of template
- // argument deduction.
- DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
-
- if (DAR == DAR_Failed && !FD->isInvalidDecl())
- Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
- << OrigResultType.getType() << RetExpr->getType();
-
- if (DAR != DAR_Succeeded)
- return true;
-
- // If a local type is part of the returned type, mark its fields as
- // referenced.
- LocalTypedefNameReferencer Referencer(*this);
- Referencer.TraverseType(RetExpr->getType());
- } else {
- // For a function with a deduced result type to return void,
- // the result type as written must be 'auto' or 'decltype(auto)',
- // possibly cv-qualified or constrained, but not ref-qualified.
+ TypeLoc OrigResultType = getReturnTypeLoc(FD);
+ // In the case of a return with no operand, the initializer is considered
+ // to be void().
+ CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation());
+ if (!RetExpr) {
+ // For a function with a deduced result type to return with omitted
+ // expression, the result type as written must be 'auto' or
+ // 'decltype(auto)', possibly cv-qualified or constrained, but not
+ // ref-qualified.
if (!OrigResultType.getType()->getAs<AutoType>()) {
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
- << OrigResultType.getType();
+ << OrigResultType.getType();
return true;
}
- // In the case of a return with no operand, the initializer is considered
- // to be 'void()'.
- Expr *Dummy = new (Context) CXXScalarValueInitExpr(
- Context.VoidTy,
- Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc);
- DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced);
-
- if (DAR == DAR_Failed && !FD->isInvalidDecl())
- Diag(ReturnLoc, diag::err_auto_fn_deduction_failure)
- << OrigResultType.getType() << Dummy->getType();
-
- if (DAR != DAR_Succeeded)
- return true;
+ RetExpr = &VoidVal;
}
- // CUDA: Kernel function must have 'void' return type.
- if (getLangOpts().CUDA)
- if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) {
- Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
- << FD->getType() << FD->getSourceRange();
+ QualType Deduced = AT->getDeducedType();
+ {
+ // Otherwise, [...] deduce a value for U using the rules of template
+ // argument deduction.
+ TemplateDeductionInfo Info(RetExpr->getExprLoc());
+ TemplateDeductionResult Res =
+ DeduceAutoType(OrigResultType, RetExpr, Deduced, Info);
+ if (Res != TDK_Success && FD->isInvalidDecl())
return true;
- }
-
- // If a function with a declared return type that contains a placeholder type
- // has multiple return statements, the return type is deduced for each return
- // statement. [...] if the type deduced is not the same in each deduction,
- // the program is ill-formed.
- QualType DeducedT = AT->getDeducedType();
- if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
- AutoType *NewAT = Deduced->getContainedAutoType();
- // It is possible that NewAT->getDeducedType() is null. When that happens,
- // we should not crash, instead we ignore this deduction.
- if (NewAT->getDeducedType().isNull())
- return false;
-
- CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
- DeducedT);
- CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
- NewAT->getDeducedType());
- if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
+ switch (Res) {
+ case TDK_Success:
+ break;
+ case TDK_AlreadyDiagnosed:
+ return true;
+ case TDK_Inconsistent: {
+ // If a function with a declared return type that contains a placeholder
+ // type has multiple return statements, the return type is deduced for
+ // each return statement. [...] if the type deduced is not the same in
+ // each deduction, the program is ill-formed.
const LambdaScopeInfo *LambdaSI = getCurLambda();
- if (LambdaSI && LambdaSI->HasImplicitReturnType) {
+ if (LambdaSI && LambdaSI->HasImplicitReturnType)
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << NewAT->getDeducedType() << DeducedT
- << true /*IsLambda*/;
- } else {
+ << Info.SecondArg << Info.FirstArg << true /*IsLambda*/;
+ else
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << DeducedT;
- }
+ << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg
+ << Info.FirstArg;
return true;
}
- } else if (!FD->isInvalidDecl()) {
+ default:
+ Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
+ << OrigResultType.getType() << RetExpr->getType();
+ return true;
+ }
+ }
+
+ // If a local type is part of the returned type, mark its fields as
+ // referenced.
+ LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType());
+
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() &&
+ !Deduced->isVoidType()) {
+ Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
+ << FD->getType() << FD->getSourceRange();
+ return true;
+ }
+
+ if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced)
// Update all declarations of the function to have the deduced return type.
Context.adjustDeducedFunctionResultType(FD, Deduced);
- }
return false;
}
@@ -4695,11 +4687,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
- Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
- Cap.isReferenceCapture()
- ? CapturedStmt::VCK_ByRef
- : CapturedStmt::VCK_ByCopy,
- Cap.getVariable()));
+ Captures.push_back(CapturedStmt::Capture(
+ Cap.getLocation(),
+ Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
+ cast<VarDecl>(Cap.getVariable())));
}
CaptureInits.push_back(Init.get());
}
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 8dfcf9899e3f..97400483c63a 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -24,6 +24,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -330,7 +331,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return StmtError(Diag(OutputExpr->getBeginLoc(),
diag::err_asm_invalid_lvalue_in_output)
@@ -377,6 +378,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
Expr *InputExpr = Exprs[i];
+ if (InputExpr->getType()->isMemberPointerType())
+ return StmtError(Diag(InputExpr->getBeginLoc(),
+ diag::err_asm_pmf_through_constraint_not_permitted)
+ << InputExpr->getSourceRange());
+
// Referring to parameters is not allowed in naked functions.
if (CheckNakedParmReference(InputExpr, *this))
return StmtError();
@@ -454,7 +460,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
<< Info.getConstraintStr();
}
- Optional<SourceLocation> UnwindClobberLoc;
+ std::optional<SourceLocation> UnwindClobberLoc;
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
@@ -932,13 +938,24 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
setFunctionHasBranchProtectedScope();
+ bool InvalidOperand = false;
for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) {
- if (Exprs[I]->getType()->isBitIntType())
- return StmtError(
- Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type)
- << Exprs[I]->getType() << (I < NumOutputs)
- << Exprs[I]->getSourceRange());
+ Expr *E = Exprs[I];
+ if (E->getType()->isBitIntType()) {
+ InvalidOperand = true;
+ Diag(E->getBeginLoc(), diag::err_asm_invalid_type)
+ << E->getType() << (I < NumOutputs)
+ << E->getSourceRange();
+ } else if (E->refersToBitField()) {
+ InvalidOperand = true;
+ FieldDecl *BitField = E->getSourceBitField();
+ Diag(E->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported)
+ << E->getSourceRange();
+ Diag(BitField->getLocation(), diag::note_bitfield_decl);
+ }
}
+ if (InvalidOperand)
+ return StmtError();
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index b03c055a4f50..6d443837a4c5 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -306,21 +307,33 @@ CheckForIncompatibleAttributes(Sema &S,
if (!DiagnoseMutualExclusions(S, Attrs))
return;
- // There are 6 categories of loop hints attributes: vectorize, interleave,
- // unroll, unroll_and_jam, pipeline and distribute. Except for distribute they
- // come in two variants: a state form and a numeric form. The state form
- // selectively defaults/enables/disables the transformation for the loop
- // (for unroll, default indicates full unrolling rather than enabling the
- // transformation). The numeric form form provides an integer hint (for
- // example, unroll count) to the transformer. The following array accumulates
- // the hints encountered while iterating through the attributes to check for
- // compatibility.
+ enum CategoryType {
+ // For the following categories, they come in two variants: a state form and
+ // a numeric form. The state form may be one of default, enable, and
+ // disable. The numeric form provides an integer hint (for example, unroll
+ // count) to the transformer.
+ Vectorize,
+ Interleave,
+ UnrollAndJam,
+ Pipeline,
+ // For unroll, default indicates full unrolling rather than enabling the
+ // transformation.
+ Unroll,
+ // The loop distribution transformation only has a state form that is
+ // exposed by #pragma clang loop distribute (enable | disable).
+ Distribute,
+ // The vector predication only has a state form that is exposed by
+ // #pragma clang loop vectorize_predicate (enable | disable).
+ VectorizePredicate,
+ // This serves as a indicator to how many category are listed in this enum.
+ NumberOfCategories
+ };
+ // The following array accumulates the hints encountered while iterating
+ // through the attributes to check for compatibility.
struct {
const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
- } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}};
+ } HintAttrs[CategoryType::NumberOfCategories] = {};
for (const auto *I : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
@@ -329,16 +342,8 @@ CheckForIncompatibleAttributes(Sema &S,
if (!LH)
continue;
+ CategoryType Category = CategoryType::NumberOfCategories;
LoopHintAttr::OptionType Option = LH->getOption();
- enum {
- Vectorize,
- Interleave,
- Unroll,
- UnrollAndJam,
- Distribute,
- Pipeline,
- VectorizePredicate
- } Category;
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
@@ -369,7 +374,7 @@ CheckForIncompatibleAttributes(Sema &S,
break;
};
- assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0]));
+ assert(Category != NumberOfCategories && "Unhandled loop hint option");
auto &CategoryState = HintAttrs[Category];
const LoopHintAttr *PrevAttr;
if (Option == LoopHintAttr::Vectorize ||
@@ -420,7 +425,7 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
unsigned UnrollFactor = 0;
if (A.getNumArgs() == 1) {
Expr *E = A.getArgAsExpr(0);
- Optional<llvm::APSInt> ArgVal;
+ std::optional<llvm::APSInt> ArgVal;
if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) {
S.Diag(A.getLoc(), diag::err_attribute_argument_type)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1542a07713fb..4b144c239fa4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -39,6 +39,7 @@
#include "llvm/ADT/StringExtras.h"
#include <iterator>
+#include <optional>
using namespace clang;
using namespace sema;
@@ -109,7 +110,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
return D;
}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (const auto *Record = dyn_cast<CXXRecordDecl>(D)) {
// C++ [temp.local]p1:
// Like normal (non-template) classes, class templates have an
// injected-class-name (Clause 9). The injected-class-name
@@ -126,8 +127,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
if (Record->getDescribedClassTemplate())
return Record->getDescribedClassTemplate();
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record))
return Spec->getSpecializedTemplate();
}
@@ -399,6 +399,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
LookupCtx = computeDeclContext(ObjectType);
IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
+ !ObjectType->getAs<TagType>() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
@@ -816,7 +817,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
return true;
- llvm::Optional<unsigned> Note;
+ std::optional<unsigned> Note;
QualType InstantiationTy;
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
InstantiationTy = Context.getTypeDeclType(TD);
@@ -941,7 +942,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
TemplateName Template = Arg.getAsTemplate().get();
TemplateArgument TArg;
if (Arg.getEllipsisLoc().isValid())
- TArg = TemplateArgument(Template, Optional<unsigned int>());
+ TArg = TemplateArgument(Template, std::optional<unsigned int>());
else
TArg = Template;
return TemplateArgumentLoc(
@@ -1207,7 +1208,7 @@ static ExprResult formImmediatelyDeclaredConstraint(
ImmediatelyDeclaredConstraint.get(), BO_LAnd,
EllipsisLoc, /*RHS=*/nullptr,
/*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None);
+ /*NumExpansions=*/std::nullopt);
}
/// Attach a type-constraint to a template parameter.
@@ -1530,11 +1531,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
CheckValidDeclSpecifiers();
- if (TInfo->getType()->isUndeducedType()) {
- Diag(D.getIdentifierLoc(),
- diag::warn_cxx14_compat_template_nontype_parm_auto_type)
- << QualType(TInfo->getType()->getContainedAutoType(), 0);
- }
+ if (const auto *T = TInfo->getType()->getContainedDeducedType())
+ if (isa<AutoType>(T))
+ Diag(D.getIdentifierLoc(),
+ diag::warn_cxx14_compat_template_nontype_parm_auto_type)
+ << QualType(TInfo->getType()->getContainedAutoType(), 0);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -1591,9 +1592,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;
- TemplateArgument Converted;
- ExprResult DefaultRes =
- CheckTemplateArgument(Param, Param->getType(), Default, Converted);
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ ExprResult DefaultRes = CheckTemplateArgument(
+ Param, Param->getType(), Default, SugaredConverted, CanonicalConverted,
+ CTAK_Specified);
if (DefaultRes.isInvalid()) {
Param->setInvalidDecl();
return Param;
@@ -1686,6 +1688,99 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
return Param;
}
+namespace {
+class ConstraintRefersToContainingTemplateChecker
+ : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
+ bool Result = false;
+ const FunctionDecl *Friend = nullptr;
+ unsigned TemplateDepth = 0;
+
+ // Check a record-decl that we've seen to see if it is a lexical parent of the
+ // Friend, likely because it was referred to without its template arguments.
+ void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
+ CheckingRD = CheckingRD->getMostRecentDecl();
+
+ for (const DeclContext *DC = Friend->getLexicalDeclContext();
+ DC && !DC->isFileContext(); DC = DC->getParent())
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ if (CheckingRD == RD->getMostRecentDecl())
+ Result = true;
+ }
+
+ void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ assert(D->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (D->getDepth() != TemplateDepth)
+ Result = true;
+
+ // Necessary because the type of the NTTP might be what refers to the parent
+ // constriant.
+ TransformType(D->getType());
+ }
+
+public:
+ using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
+
+ ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
+ const FunctionDecl *Friend,
+ unsigned TemplateDepth)
+ : inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {}
+ bool getResult() const { return Result; }
+
+ // This should be the only template parm type that we have to deal with.
+ // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
+ // FunctionParmPackExpr are all partially substituted, which cannot happen
+ // with concepts at this point in translation.
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ assert(TL.getDecl()->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (TL.getDecl()->getDepth() != TemplateDepth)
+ Result = true;
+ return inherited::TransformTemplateTypeParmType(
+ TLB, TL,
+ /*SuppressObjCLifetime=*/false);
+ }
+
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+ if (!D)
+ return D;
+ // FIXME : This is possibly an incomplete list, but it is unclear what other
+ // Decl kinds could be used to refer to the template parameters. This is a
+ // best guess so far based on examples currently available, but the
+ // unreachable should catch future instances/cases.
+ if (auto *TD = dyn_cast<TypedefNameDecl>(D))
+ TransformType(TD->getUnderlyingType());
+ else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
+ CheckNonTypeTemplateParmDecl(NTTPD);
+ else if (auto *VD = dyn_cast<ValueDecl>(D))
+ TransformType(VD->getType());
+ else if (auto *TD = dyn_cast<TemplateDecl>(D))
+ TransformTemplateParameterList(TD->getTemplateParameters());
+ else if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ CheckIfContainingRecord(RD);
+ else if (isa<NamedDecl>(D)) {
+ // No direct types to visit here I believe.
+ } else
+ llvm_unreachable("Don't know how to handle this declaration type yet");
+ return D;
+ }
+};
+} // namespace
+
+bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
+ const FunctionDecl *Friend, unsigned TemplateDepth,
+ const Expr *Constraint) {
+ assert(Friend->getFriendObjectKind() && "Only works on a friend");
+ ConstraintRefersToContainingTemplateChecker Checker(*this, Friend,
+ TemplateDepth);
+ Checker.TransformExpr(const_cast<Expr *>(Constraint));
+ return Checker.getResult();
+}
+
/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
/// constrained by RequiresClause, that contains the template parameters in
/// Params.
@@ -1705,8 +1800,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
- llvm::makeArrayRef(Params.data(), Params.size()),
- RAngleLoc, RequiresClause);
+ llvm::ArrayRef(Params.data(), Params.size()), RAngleLoc, RequiresClause);
}
static void SetNestedNameSpecifier(Sema &S, TagDecl *T,
@@ -1985,8 +2079,8 @@ DeclResult Sema::CheckClassTemplate(
SetNestedNameSpecifier(*this, NewClass, SS);
if (NumOuterTemplateParamLists > 0)
NewClass->setTemplateParameterListsInfo(
- Context, llvm::makeArrayRef(OuterTemplateParamLists,
- NumOuterTemplateParamLists));
+ Context,
+ llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -2284,10 +2378,12 @@ private:
/*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(),
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
TTP->isParameterPack(), TTP->hasTypeConstraint(),
- TTP->isExpandedParameterPack() ?
- llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ TTP->isExpandedParameterPack()
+ ? std::optional<unsigned>(TTP->getNumExpansionParameters())
+ : std::nullopt);
if (const auto *TC = TTP->getTypeConstraint())
- SemaRef.SubstTypeConstraint(NewTTP, TC, Args);
+ SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
+ /*EvaluateConstraint*/ true);
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -2444,6 +2540,8 @@ 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);
@@ -2535,7 +2633,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
// additional function template derived as above from a hypothetical
// constructor C().
if (!AddedAny)
- Transform.buildSimpleDeductionGuide(None);
+ Transform.buildSimpleDeductionGuide(std::nullopt);
// -- An additional function template derived as above from a hypothetical
// constructor C(C), called the copy deduction candidate.
@@ -3411,7 +3509,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), None,
+ SourceLocation(), std::nullopt,
SourceLocation(), nullptr);
}
@@ -3496,45 +3594,54 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
static QualType
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
- const SmallVectorImpl<TemplateArgument> &Converted,
+ ArrayRef<TemplateArgument> Converted,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
+
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
+ QualType OrigType = Converted[1].getAsType();
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
- if (!Converted[1].getAsType()->isIntegralType(Context)) {
+ if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
SemaRef.Diag(TemplateArgs[1].getLocation(),
diag::err_integer_sequence_integral_element_type);
return QualType();
}
- // C++14 [inteseq.make]p1:
- // If N is negative the program is ill-formed.
TemplateArgument NumArgsArg = Converted[2];
- llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
- if (NumArgs < 0) {
+ if (NumArgsArg.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
+ TemplateArgumentListInfo SyntheticTemplateArgs;
+ // The type argument, wrapped in substitution sugar, gets reused as the
+ // first template argument in the synthetic template argument list.
+ SyntheticTemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(OrigType),
+ SemaRef.Context.getTrivialTypeSourceInfo(
+ OrigType, TemplateArgs[1].getLocation())));
+
+ if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) {
+ // Expand N into 0 ... N-1.
+ for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
+ I < NumArgs; ++I) {
+ TemplateArgument TA(Context, I, OrigType);
+ SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+ TA, OrigType, TemplateArgs[2].getLocation()));
+ }
+ } else {
+ // C++14 [inteseq.make]p1:
+ // If N is negative the program is ill-formed.
SemaRef.Diag(TemplateArgs[2].getLocation(),
diag::err_integer_sequence_negative_length);
return QualType();
}
- QualType ArgTy = NumArgsArg.getIntegralType();
- TemplateArgumentListInfo SyntheticTemplateArgs;
- // The type argument gets reused as the first template argument in the
- // synthetic template argument list.
- SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
- // Expand N into 0 ... N-1.
- for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
- I < NumArgs; ++I) {
- TemplateArgument TA(Context, I, ArgTy);
- SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
- TA, ArgTy, TemplateArgs[2].getLocation()));
- }
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
@@ -3548,11 +3655,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
assert(Converted.size() == 2 &&
"__type_pack_element should be given an index and a parameter pack");
- // If the Index is out of bounds, the program is ill-formed.
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+ if (IndexArg.isDependent() || Ts.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of "
"type std::size_t, and hence be non-negative");
+ // If the Index is out of bounds, the program is ill-formed.
if (Index >= Ts.pack_size()) {
SemaRef.Diag(TemplateArgs[0].getLocation(),
diag::err_type_pack_element_out_of_bounds);
@@ -3560,8 +3671,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
}
// We simply return the type at index `Index`.
- auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
- return Nth->getAsType();
+ int64_t N = Index.getExtValue();
+ return Ts.getPackAsArray()[N].getAsType();
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
@@ -3585,9 +3696,8 @@ static void collectConjunctionTerms(Expr *Clause,
if (BinOp->getOpcode() == BO_LAnd) {
collectConjunctionTerms(BinOp->getLHS(), Terms);
collectConjunctionTerms(BinOp->getRHS(), Terms);
+ return;
}
-
- return;
}
Terms.push_back(Clause);
@@ -3715,10 +3825,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// assume the template is a type template. Either our assumption is
// correct, or the code is ill-formed and will be diagnosed when the
// dependent name is substituted.
- return Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ return Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
if (Name.getAsAssumedTemplateName() &&
resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
@@ -3730,7 +3839,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
- return Context.getTemplateSpecializationType(Name, TemplateArgs);
+ return Context.getTemplateSpecializationType(Name,
+ TemplateArgs.arguments());
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
@@ -3740,9 +3850,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return QualType();
@@ -3756,12 +3866,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Pattern->isInvalidDecl())
return QualType();
- TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
+ TemplateArgLists.addOuterTemplateArguments(Template, CanonicalConverted,
+ /*Final=*/false);
TemplateArgLists.addOuterRetainedLevels(
AliasTemplate->getTemplateParameters()->getDepth());
@@ -3808,9 +3916,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
}
+ } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
+ CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted,
+ TemplateLoc, TemplateArgs);
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, Converted)) {
+ TemplateArgs, CanonicalConverted)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -3818,7 +3929,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// A<T, T> have identical types when A is declared as:
//
// template<typename T, typename U = T> struct A;
- CanonType = Context.getCanonicalTemplateSpecializationType(Name, Converted);
+ CanonType = Context.getCanonicalTemplateSpecializationType(
+ Name, CanonicalConverted);
// This might work out to be a current instantiation, in which
// case the canonical type needs to be the InjectedClassNameType.
@@ -3857,13 +3969,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
break;
}
}
- } else if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Template)) {
+ } else if (ClassTemplateDecl *ClassTemplate =
+ dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *Decl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *Decl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
if (!Decl) {
// This is the first time we have referenced this class template
// specialization. Create the canonical declaration and add it to
@@ -3872,7 +3984,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Context, ClassTemplate->getTemplatedDecl()->getTagKind(),
ClassTemplate->getDeclContext(),
ClassTemplate->getTemplatedDecl()->getBeginLoc(),
- ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr);
+ ClassTemplate->getLocation(), ClassTemplate, CanonicalConverted,
+ nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -3882,8 +3995,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getTemplatedDecl()->hasAttrs()) {
InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
if (!Inst.isInvalid()) {
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(Converted);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template,
+ CanonicalConverted,
+ /*Final=*/false);
InstantiateAttrsForDecl(TemplateArgLists,
ClassTemplate->getTemplatedDecl(), Decl);
}
@@ -3895,15 +4009,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
- } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
- CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
- TemplateArgs);
+ } else {
+ llvm_unreachable("Unhandled template kind");
}
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
+ CanonType);
}
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
@@ -3964,7 +4078,8 @@ TypeResult Sema::ActOnTemplateIdType(
TemplateTy TemplateD, IdentifierInfo *TemplateII,
SourceLocation TemplateIILoc, SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc,
- bool IsCtorOrDtorName, bool IsClassName) {
+ bool IsCtorOrDtorName, bool IsClassName,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -3978,9 +4093,18 @@ TypeResult Sema::ActOnTemplateIdType(
// qualified-id denotes a type, forming an
// elaborated-type-specifier (7.1.5.3).
if (!LookupCtx && isDependentScopeSpecifier(SS)) {
- Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
- << SS.getScopeRep() << TemplateII->getName();
- // Recover as if 'typename' were specified.
+ // C++2a relaxes some of those restrictions in [temp.res]p5.
+ if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
+ if (getLangOpts().CPlusPlus20)
+ Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
+ else
+ Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
+ << SS.getScopeRep() << TemplateII->getName()
+ << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
+ } else
+ Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
+ << SS.getScopeRep() << TemplateII->getName();
+
// FIXME: This is not quite correct recovery as we don't transform SS
// into the corresponding dependent form (and we don't diagnose missing
// 'template' keywords within SS as a result).
@@ -4014,11 +4138,10 @@ TypeResult Sema::ActOnTemplateIdType(
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T
- = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
@@ -4034,14 +4157,14 @@ TypeResult Sema::ActOnTemplateIdType(
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
- QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
- if (Result.isNull())
+ QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
+ if (SpecTy.isNull())
return true;
// Build type-source information.
TypeLocBuilder TLB;
- TemplateSpecializationTypeLoc SpecTL
- = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ TemplateSpecializationTypeLoc SpecTL =
+ TLB.push<TemplateSpecializationTypeLoc>(SpecTy);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
@@ -4049,18 +4172,14 @@ TypeResult Sema::ActOnTemplateIdType(
for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
- // NOTE: avoid constructing an ElaboratedTypeLoc if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Decl or Expr node).
- if (SS.isNotEmpty() && !IsCtorOrDtorName) {
- // Create an elaborated-type-specifier containing the nested-name-specifier.
- Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result);
- ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ // Create an elaborated-type-specifier containing the nested-name-specifier.
+ QualType ElTy = getElaboratedType(
+ ETK_None, !IsCtorOrDtorName ? SS : CXXScopeSpec(), SpecTy);
+ ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(ElTy);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ if (!ElabTL.isEmpty())
ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
- }
-
- return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
+ return CreateParsedType(ElTy, TLB.getTypeSourceInfo(Context, ElTy));
}
TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
@@ -4088,10 +4207,10 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
= TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T = Context.getDependentTemplateSpecializationType(Keyword,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ Keyword, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
@@ -4386,9 +4505,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -4396,21 +4515,22 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// corresponds to these arguments.
if (IsPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we
// also do them during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< VarTemplate->getDeclName();
IsPartialSpecialization = false;
}
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
- Converted) &&
+ CanonicalConverted) &&
(!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
@@ -4431,10 +4551,10 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
- PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
- InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = VarTemplate->findSpecialization(CanonicalConverted, InsertPos);
VarTemplateSpecializationDecl *Specialization = nullptr;
@@ -4461,7 +4581,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
- Converted, TemplateArgs);
+ CanonicalConverted, TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4478,7 +4598,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
- VarTemplate, DI->getType(), DI, SC, Converted);
+ VarTemplate, DI->getType(), DI, SC, CanonicalConverted);
Specialization->setTemplateArgsInfo(TemplateArgs);
if (!PrevDecl)
@@ -4556,24 +4676,25 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted, /*UpdateArgsWithConversions=*/true))
+ SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return true;
// Produce a placeholder value if the specialization is dependent.
if (Template->getDeclContext()->isDependentContext() ||
- TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted))
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted))
return DeclResult();
// Find the variable template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted, InsertPos)) {
+ if (VarTemplateSpecializationDecl *Spec =
+ Template->findSpecialization(CanonicalConverted, InsertPos)) {
checkSpecializationReachability(TemplateNameLoc, Spec);
// If we already have a variable template specialization, return it.
return Spec;
@@ -4585,7 +4706,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted);
+ CanonicalConverted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
@@ -4617,7 +4738,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
- Matched.back().Args = Info.take();
+ Matched.back().Args = Info.takeCanonical();
}
}
@@ -4673,7 +4794,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
- Converted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
+ CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
@@ -4744,29 +4865,41 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
- llvm::SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
- const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
- /*PartialTemplateArgs=*/false, Converted,
- /*UpdateArgsWithConversions=*/false))
+ llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(
+ NamedConcept, ConceptNameInfo.getLoc(),
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/false))
return ExprError();
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
+ CanonicalConverted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
- TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
- Converted);
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ *TemplateArgs, CanonicalConverted);
+ MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted,
+ /*Final=*/false);
+ LocalInstantiationScope Scope(*this);
+
+ EnterExpressionEvaluationContext EECtx{
+ *this, ExpressionEvaluationContext::ConstantEvaluated, CSD};
+
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
- NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
+ NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
TemplateArgs->getRAngleLoc()),
Satisfaction))
return ExprError();
- return ConceptSpecializationExpr::Create(Context,
+ return ConceptSpecializationExpr::Create(
+ Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
- ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD,
AreArgsDependent ? nullptr : &Satisfaction);
}
@@ -5008,9 +5141,10 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
return TNK_Non_template;
}
-bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
- TemplateArgumentLoc &AL,
- SmallVectorImpl<TemplateArgument> &Converted) {
+bool Sema::CheckTemplateTypeArgument(
+ TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted) {
const TemplateArgument &Arg = AL.getArgument();
QualType ArgType;
TypeSourceInfo *TSI = nullptr;
@@ -5087,7 +5221,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
// fallthrough
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
// We have a template type parameter but the template argument
@@ -5103,9 +5237,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
if (CheckTemplateArgument(TSI))
return true;
- // Add the converted template type argument.
- ArgType = Context.getCanonicalType(ArgType);
-
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
// with no lifetime qualifier, the __strong lifetime qualifier is inferred.
@@ -5117,7 +5248,9 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
ArgType = Context.getQualifiedType(ArgType, Qs);
}
- Converted.push_back(TemplateArgument(ArgType));
+ SugaredConverted.push_back(TemplateArgument(ArgType));
+ CanonicalConverted.push_back(
+ TemplateArgument(Context.getCanonicalType(ArgType)));
return false;
}
@@ -5142,31 +5275,27 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
/// \returns the substituted template argument, or NULL if an error occurred.
-static TypeSourceInfo *
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTypeParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
+static TypeSourceInfo *SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTypeParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isInstantiationDependentType()) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return nullptr;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
bool ForLambdaCallOperator = false;
if (const auto *Rec = dyn_cast<CXXRecordDecl>(Template->getDeclContext()))
@@ -5203,26 +5332,22 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static ExprResult
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- NonTypeTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+static ExprResult SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
@@ -5255,27 +5380,23 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// source-location information) that precedes the template name.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static TemplateName
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted,
- NestedNameSpecifierLoc &QualifierLoc) {
+static TemplateName SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted,
+ NestedNameSpecifierLoc &QualifierLoc) {
Sema::InstantiatingTemplate Inst(
- SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
+ SemaRef, TemplateLoc, TemplateParameter(Param), Template,
+ SugaredConverted, SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return TemplateName();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
// Substitute into the nested-name-specifier first,
@@ -5297,14 +5418,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// If the given template parameter has a default template
/// argument, substitute into that default template argument and
/// return the corresponding template argument.
-TemplateArgumentLoc
-Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- Decl *Param,
- SmallVectorImpl<TemplateArgument>
- &Converted,
- bool &HasDefaultArg) {
+TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(
+ TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, Decl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg) {
HasDefaultArg = false;
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
@@ -5312,11 +5430,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TypeParm,
- Converted);
+ TypeSourceInfo *DI = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted,
+ CanonicalConverted);
if (DI)
return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI);
@@ -5329,11 +5445,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NonTypeParm,
- Converted);
+ ExprResult Arg = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted,
+ CanonicalConverted);
if (Arg.isInvalid())
return TemplateArgumentLoc();
@@ -5348,12 +5462,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
HasDefaultArg = true;
NestedNameSpecifierLoc QualifierLoc;
- TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempTempParm,
- Converted,
- QualifierLoc);
+ TemplateName TName = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (TName.isNull())
return TemplateArgumentLoc();
@@ -5423,17 +5534,17 @@ convertTypeTemplateArgumentToTemplate(ASTContext &Context, TypeLoc TLoc) {
/// explicitly written, deduced, etc.
///
/// \returns true on error, false otherwise.
-bool Sema::CheckTemplateArgument(NamedDecl *Param,
- TemplateArgumentLoc &Arg,
- NamedDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- unsigned ArgumentPackIndex,
- SmallVectorImpl<TemplateArgument> &Converted,
- CheckTemplateArgumentKind CTAK) {
+bool Sema::CheckTemplateArgument(
+ NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template,
+ SourceLocation TemplateLoc, SourceLocation RAngleLoc,
+ unsigned ArgumentPackIndex,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- return CheckTemplateTypeArgument(TTP, Arg, Converted);
+ return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
+ CanonicalConverted);
// Check non-type template parameters.
if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -5448,27 +5559,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- NTTP, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
+ MultiLevelTemplateArgumentList MLTAL(Template, SugaredConverted,
+ /*Final=*/true);
// If the parameter is a pack expansion, expand this slice of the pack.
if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
ArgumentPackIndex);
- NTTPType = SubstType(PET->getPattern(),
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(PET->getPattern(), MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
} else {
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(NTTPType, MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
}
@@ -5486,11 +5592,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
llvm_unreachable("Should never see a NULL template argument here");
case TemplateArgument::Expression: {
- TemplateArgument Result;
+ Expr *E = Arg.getArgument().getAsExpr();
+ TemplateArgument SugaredResult, CanonicalResult;
unsigned CurSFINAEErrors = NumSFINAEErrors;
- ExprResult Res =
- CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(),
- Result, CTAK);
+ ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult,
+ CanonicalResult, CTAK);
if (Res.isInvalid())
return true;
// If the current template argument causes an error, give up now.
@@ -5499,12 +5605,13 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// If the resulting expression is new, then use it in place of the
// old expression in the template argument.
- if (Res.get() != Arg.getArgument().getAsExpr()) {
+ if (Res.get() != E) {
TemplateArgument TA(Res.get());
Arg = TemplateArgumentLoc(TA, Res.get());
}
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5513,7 +5620,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Template:
@@ -5549,12 +5658,14 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
}
- TemplateArgument Result;
- E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result);
+ TemplateArgument SugaredResult, CanonicalResult;
+ E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult,
+ CanonicalResult, CTAK_Specified);
if (E.isInvalid())
return true;
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5611,15 +5722,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
{
// Set up a template instantiation context.
LocalInstantiationScope Scope(*this);
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- TempParm, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
- Params = SubstTemplateParams(Params, CurContext,
- MultiLevelTemplateArgumentList(TemplateArgs));
+ Params =
+ SubstTemplateParams(Params, CurContext,
+ MultiLevelTemplateArgumentList(
+ Template, SugaredConverted, /*Final=*/true),
+ /*EvaluateConstraints=*/false);
if (!Params)
return true;
}
@@ -5644,7 +5757,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
return true;
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Expression:
@@ -5711,7 +5826,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
if (ConstraintsNotSatisfied)
@@ -5737,7 +5853,8 @@ bool Sema::CheckTemplateArgumentList(
// corresponding parameter declared by the template in its
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
- SmallVector<TemplateArgument, 2> ArgumentPack;
+ SmallVector<TemplateArgument, 2> SugaredArgumentPack;
+ SmallVector<TemplateArgument, 2> CanonicalArgumentPack;
unsigned ArgIdx = 0, NumArgs = NewArgs.size();
LocalInstantiationScope InstScope(*this, true);
for (TemplateParameterList::iterator Param = Params->begin(),
@@ -5745,13 +5862,17 @@ bool Sema::CheckTemplateArgumentList(
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
- if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
- if (*Expansions == ArgumentPack.size()) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (*Expansions == SugaredArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
// This argument is assigned to the next parameter.
++Param;
@@ -5770,9 +5891,10 @@ bool Sema::CheckTemplateArgumentList(
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
- if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template,
- TemplateLoc, RAngleLoc,
- ArgumentPack.size(), Converted))
+ if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+ RAngleLoc, SugaredArgumentPack.size(),
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
bool PackExpansionIntoNonPack =
@@ -5801,7 +5923,8 @@ bool Sema::CheckTemplateArgumentList(
// deduced argument and place it on the argument pack. Note that we
// stay on the same template parameter so that we can deduce more
// arguments.
- ArgumentPack.push_back(Converted.pop_back_val());
+ SugaredArgumentPack.push_back(SugaredConverted.pop_back_val());
+ CanonicalArgumentPack.push_back(CanonicalConverted.pop_back_val());
} else {
// Move to the next template parameter.
++Param;
@@ -5811,16 +5934,25 @@ bool Sema::CheckTemplateArgumentList(
// the remaining arguments, because we don't know what parameters they'll
// match up with.
if (PackExpansionIntoNonPack) {
- if (!ArgumentPack.empty()) {
+ if (!SugaredArgumentPack.empty()) {
// If we were part way through filling in an expanded parameter pack,
// fall back to just producing individual arguments.
- Converted.insert(Converted.end(),
- ArgumentPack.begin(), ArgumentPack.end());
- ArgumentPack.clear();
+ SugaredConverted.insert(SugaredConverted.end(),
+ SugaredArgumentPack.begin(),
+ SugaredArgumentPack.end());
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.insert(CanonicalConverted.end(),
+ CanonicalArgumentPack.begin(),
+ CanonicalArgumentPack.end());
+ CanonicalArgumentPack.clear();
}
while (ArgIdx < NumArgs) {
- Converted.push_back(NewArgs[ArgIdx].getArgument());
+ const TemplateArgument &Arg = NewArgs[ArgIdx].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg));
++ArgIdx;
}
@@ -5832,9 +5964,12 @@ bool Sema::CheckTemplateArgumentList(
// If we're checking a partial template argument list, we're done.
if (PartialTemplateArgs) {
- if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
+ if ((*Param)->isTemplateParameterPack() && !SugaredArgumentPack.empty()) {
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ }
return false;
}
@@ -5847,12 +5982,20 @@ bool Sema::CheckTemplateArgumentList(
// A non-expanded parameter pack before the end of the parameter list
// only occurs for an ill-formed template parameter list, unless we've
// got a partial argument list for a function template, so just bail out.
- if (Param + 1 != ParamEnd)
+ if (Param + 1 != ParamEnd) {
+ assert(
+ (Template->getMostRecentDecl()->getKind() != Decl::Kind::Concept) &&
+ "Concept templates must have parameter packs at the end.");
return true;
+ }
+
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
++Param;
continue;
@@ -5871,12 +6014,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
NewArgs);
- TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
- Template,
- TemplateLoc,
- RAngleLoc,
- TTP,
- Converted);
+ TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted,
+ CanonicalConverted);
if (!ArgType)
return true;
@@ -5888,11 +6028,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
NewArgs);
- ExprResult E = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NTTP,
- Converted);
+ ExprResult E = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted,
+ CanonicalConverted);
if (E.isInvalid())
return true;
@@ -5907,12 +6045,9 @@ bool Sema::CheckTemplateArgumentList(
NewArgs);
NestedNameSpecifierLoc QualifierLoc;
- TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempParm,
- Converted,
- QualifierLoc);
+ TemplateName Name = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (Name.isNull())
return true;
@@ -5925,14 +6060,16 @@ bool Sema::CheckTemplateArgumentList(
// the default template argument. We're not actually instantiating a
// template here, we just create this object to put a note into the
// context stack.
- InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted,
+ InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
// Check the default template argument.
- if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
- RAngleLoc, 0, Converted))
+ if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
// Core issue 150 (assumed resolution): if this is a template template
@@ -5952,8 +6089,12 @@ bool Sema::CheckTemplateArgumentList(
// still dependent).
if (ArgIdx < NumArgs && CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack()) {
- while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion())
- Converted.push_back(NewArgs[ArgIdx++].getArgument());
+ while (ArgIdx < NumArgs &&
+ NewArgs[ArgIdx].getArgument().isPackExpansion()) {
+ const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
+ }
}
// If we have any leftover arguments, then there were too many arguments.
@@ -5974,13 +6115,39 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- if (!PartialTemplateArgs &&
- EnsureTemplateArgumentListConstraints(
- Template, Converted, SourceRange(TemplateLoc,
- TemplateArgs.getRAngleLoc()))) {
- if (ConstraintsNotSatisfied)
- *ConstraintsNotSatisfied = true;
- return true;
+ if (!PartialTemplateArgs) {
+ TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+ CanonicalConverted);
+ // Setup the context/ThisScope for the case where we are needing to
+ // re-instantiate constraints outside of normal instantiation.
+ DeclContext *NewContext = Template->getDeclContext();
+
+ // If this template is in a template, make sure we extract the templated
+ // decl.
+ if (auto *TD = dyn_cast<TemplateDecl>(NewContext))
+ NewContext = Decl::castToDeclContext(TD->getTemplatedDecl());
+ auto *RD = dyn_cast<CXXRecordDecl>(NewContext);
+
+ Qualifiers ThisQuals;
+ if (const auto *Method =
+ dyn_cast_or_null<CXXMethodDecl>(Template->getTemplatedDecl()))
+ ThisQuals = Method->getMethodQualifiers();
+
+ ContextRAII Context(*this, NewContext);
+ CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
+
+ MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+ Template, /*Final=*/false, &StackTemplateArgs,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConceptInstantiation=*/true);
+ if (EnsureTemplateArgumentListConstraints(
+ Template, MLTAL,
+ SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
+ }
}
return false;
@@ -6125,7 +6292,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) {
}
bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) {
- return Visit(T->getUnderlyingType());
+ return Visit(T->getUnmodifiedType());
}
bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
@@ -6274,8 +6441,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
+ QualType CanonArg = Context.getCanonicalType(Arg);
- if (Arg->isVariablyModifiedType()) {
+ if (CanonArg->isVariablyModifiedType()) {
return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
@@ -6288,9 +6456,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
//
// C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (LangOpts.CPlusPlus11 || Arg->hasUnnamedOrLocalType()) {
+ if (LangOpts.CPlusPlus11 || CanonArg->hasUnnamedOrLocalType()) {
UnnamedLocalNoLinkageFinder Finder(*this, SR);
- (void)Finder.Visit(Context.getCanonicalType(Arg));
+ (void)Finder.Visit(CanonArg);
}
return false;
@@ -6362,7 +6530,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
// - a constant expression that evaluates to a null pointer value (4.10); or
// - a constant expression that evaluates to a null member pointer value
// (4.11); or
- if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+ if ((EvalResult.Val.isLValue() && EvalResult.Val.isNullPointer()) ||
(EvalResult.Val.isMemberPointer() &&
!EvalResult.Val.getMemberPointerDecl())) {
// If our expression has an appropriate type, we've succeeded.
@@ -6380,6 +6548,16 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
return NPV_NullPointer;
}
+ if (EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) {
+ // We found a pointer that isn't null, but doesn't refer to an object.
+ // We could just return NPV_NotNullPointer, but we can print a better
+ // message with the information we have here.
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid)
+ << EvalResult.Val.getAsString(S.Context, ParamType);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_Error;
+ }
+
// If we don't have a null pointer value, but we do have a NULL pointer
// constant, suggest a cast to the appropriate type.
if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
@@ -6457,12 +6635,9 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
/// Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-static bool
-CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *ArgIn,
- TemplateArgument &Converted) {
+static bool CheckTemplateArgumentAddressOfObjectOrFunction(
+ Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
+ TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ArgIn;
QualType ArgType = Arg->getType();
@@ -6566,8 +6741,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Entity)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr=*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted =
+ TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return false;
case NPV_Error:
@@ -6581,7 +6759,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
if (Arg->isValueDependent()) {
- Converted = TemplateArgument(ArgIn);
+ SugaredConverted = TemplateArgument(ArgIn);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
return false;
}
@@ -6711,19 +6891,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
// Create the template argument.
- Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
- S.Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Entity, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false);
return false;
}
/// Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-static bool CheckTemplateArgumentPointerToMember(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *&ResultArg,
- TemplateArgument &Converted) {
+static bool
+CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
+ QualType ParamType, Expr *&ResultArg,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ResultArg;
@@ -6771,10 +6953,14 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- Converted = TemplateArgument(VD, ParamType);
+ SugaredConverted = TemplateArgument(VD, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6792,8 +6978,10 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr*/ true);
+ CanonicalConverted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/ true);
return false;
case NPV_NotNullPointer:
break;
@@ -6830,10 +7018,15 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
- Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
+ ValueDecl *D = DRE->getDecl();
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(D->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6854,7 +7047,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
/// type of the non-type template parameter after it has been instantiated.
ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType ParamType, Expr *Arg,
- TemplateArgument &Converted,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted,
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getBeginLoc();
@@ -6869,7 +7063,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(DeducedT);
if (AT && AT->isDecltypeAuto()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
}
@@ -6877,7 +7073,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
- Optional<unsigned> Depth = Param->getDepth() + 1;
Expr *DeductionArg = Arg;
if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
DeductionArg = PE->getPattern();
@@ -6893,20 +7088,30 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits);
if (ParamType.isNull())
return ExprError();
- } else if (DeduceAutoType(
- TSI, DeductionArg, ParamType, Depth,
- // We do not check constraints right now because the
- // immediately-declared constraint of the auto type is also
- // an associated constraint, and will be checked along with
- // the other associated constraints after checking the
- // template argument list.
- /*IgnoreConstraints=*/true) == DAR_Failed) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
+ } else {
+ TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
+ Param->getDepth() + 1);
+ ParamType = QualType();
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
+ /*DependentDeduction=*/true,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is
+ // also an associated constraint, and will be checked
+ // along with the other associated constraints after
+ // checking the template argument list.
+ /*IgnoreConstraints=*/true);
+ if (Result == TDK_AlreadyDiagnosed) {
+ if (ParamType.isNull())
+ return ExprError();
+ } else if (Result != TDK_Success) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << Param->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
// an error. The error message normally references the parameter
@@ -6938,7 +7143,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// work. Similarly for CTAD, when comparing 'A<x>' against 'A'.
if ((ParamType->isDependentType() || Arg->isTypeDependent()) &&
!Arg->getType()->getContainedDeducedType()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
// FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770,
@@ -6953,11 +7160,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
// If either the parameter has a dependent type or the argument is
- // type-dependent, there's nothing we can check now. The argument only
- // contains an unexpanded pack during partial ordering, and there's
- // nothing more we can check in that case.
- if (ParamType->isDependentType() || Arg->isTypeDependent() ||
- Arg->containsUnexpandedParameterPack()) {
+ // type-dependent, there's nothing we can check now.
+ if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6975,7 +7179,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
PE->getNumExpansions());
}
- Converted = TemplateArgument(E.get());
+ SugaredConverted = TemplateArgument(E.get());
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return E;
}
@@ -7000,11 +7206,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) {
NamedDecl *ND = cast<DeclRefExpr>(InnerArg)->getDecl();
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
- Converted = TemplateArgument(TPO, CanonParamType);
+
+ SugaredConverted = TemplateArgument(TPO, ParamType);
+ CanonicalConverted =
+ TemplateArgument(TPO->getCanonicalDecl(), CanonParamType);
return Arg;
}
if (isa<NonTypeTemplateParmDecl>(ND)) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
}
@@ -7021,7 +7232,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// For a value-dependent argument, CheckConvertedConstantExpression is
// permitted (and expected) to be unable to determine a value.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7029,14 +7242,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
switch (Value.getKind()) {
case APValue::None:
assert(ParamType->isNullPtrType());
- Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
case APValue::Indeterminate:
llvm_unreachable("result of constant evaluation should be initialized");
break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
- Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
+ SugaredConverted = TemplateArgument(Context, Value.getInt(), ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value.getInt(), CanonParamType);
break;
case APValue::MemberPointer: {
assert(ParamType->isMemberPointerType());
@@ -7051,8 +7267,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::LValue: {
@@ -7092,17 +7312,25 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::Struct:
- case APValue::Union:
+ case APValue::Union: {
// Get or create the corresponding template parameter object.
- Converted = TemplateArgument(
- Context.getTemplateParamObjectDecl(CanonParamType, Value),
- CanonParamType);
+ TemplateParamObjectDecl *D =
+ Context.getTemplateParamObjectDecl(ParamType, Value);
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(D->getCanonicalDecl(), CanonParamType);
break;
+ }
case APValue::AddrLabelDiff:
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
case APValue::FixedPoint:
@@ -7152,7 +7380,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't check arbitrary value-dependent arguments.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7166,8 +7396,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
? Context.getIntWidth(IntegerType)
: Context.getTypeSize(IntegerType));
- Converted = TemplateArgument(Context, Value,
- Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Context, Value, ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(ParamType));
return ArgResult;
}
@@ -7237,13 +7468,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (Arg->isValueDependent()) {
// The argument is value-dependent. Create a new
// TemplateArgument with the converted expression.
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
- QualType IntegerType = Context.getCanonicalType(ParamType);
- if (const EnumType *Enum = IntegerType->getAs<EnumType>())
- IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
+ QualType IntegerType = ParamType;
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>()) {
+ IntegerType = Enum->getDecl()->getIntegerType();
+ }
if (ParamType->isBooleanType()) {
// Value must be zero or one.
@@ -7289,10 +7523,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- Converted = TemplateArgument(Context, Value,
- ParamType->isEnumeralType()
- ? Context.getCanonicalType(ParamType)
- : IntegerType);
+ QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType;
+ SugaredConverted = TemplateArgument(Context, Value, T);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(T));
return Arg;
}
@@ -7337,15 +7571,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
if (!ParamType->isMemberPointerType()) {
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted,
+ CanonicalConverted))
return ExprError();
return Arg;
}
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7358,9 +7592,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getPointeeType()->isIncompleteOrObjectType() &&
"Only object pointers allowed here");
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7389,9 +7622,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7399,7 +7631,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Deal with parameters of type std::nullptr_t.
if (ParamType->isNullPtrType()) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
@@ -7415,8 +7649,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return Arg;
}
}
@@ -7425,8 +7661,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7499,10 +7735,10 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
Arg.getLocation())) {
- // C++2a[temp.func.order]p2
+ // P2113
+ // C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
- // more constrained template as described by the rules in
- // [temp.constr.order].
+ // more constrained template (if one exists) as determined below.
SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
// C++2a[temp.arg.template]p3
@@ -7510,7 +7746,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// are not considered.
if (ParamsAC.empty())
return false;
+
Template->getAssociatedConstraints(TemplateAC);
+
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
IsParamAtLeastAsConstrained))
@@ -7685,8 +7923,8 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc);
} else if (T->isBooleanType()) {
- E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
- T, Loc);
+ E = CXXBoolLiteralExpr::Create(Context, Arg.getAsIntegral().getBoolValue(),
+ T, Loc);
} else if (T->isNullPtrType()) {
E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
} else {
@@ -7706,10 +7944,11 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
}
/// Match two template parameters within template parameter lists.
-static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
- bool Complain,
- Sema::TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+static bool MatchTemplateParameterKind(
+ Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old,
+ const NamedDecl *OldInstFrom, bool Complain,
+ Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
if (Complain) {
@@ -7791,20 +8030,34 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
- (Kind == Sema::TPL_TemplateMatch
- ? Sema::TPL_TemplateTemplateParmMatch
- : Kind),
- TemplateArgLoc))
+ if (!S.TemplateParameterListsAreEqual(
+ NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+ OldTTP->getTemplateParameters(), Complain,
+ (Kind == Sema::TPL_TemplateMatch
+ ? Sema::TPL_TemplateTemplateParmMatch
+ : Kind),
+ TemplateArgLoc, PartialOrdering))
return false;
- } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ }
+
+ if (!PartialOrdering && Kind != Sema::TPL_TemplateTemplateArgumentMatch &&
+ !isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
- if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
- NewC = TC->getImmediatelyDeclaredConstraint();
- if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
- OldC = TC->getImmediatelyDeclaredConstraint();
+
+ if (isa<TemplateTypeParmDecl>(New)) {
+ if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
+ NewC = TC->getImmediatelyDeclaredConstraint();
+ if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
+ OldC = TC->getImmediatelyDeclaredConstraint();
+ } else if (isa<NonTypeTemplateParmDecl>(New)) {
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(New)
+ ->getPlaceholderTypeConstraint())
+ NewC = E;
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(Old)
+ ->getPlaceholderTypeConstraint())
+ OldC = E;
+ } else
+ llvm_unreachable("unexpected template parameter type");
auto Diagnose = [&] {
S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
@@ -7820,10 +8073,8 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
}
if (NewC) {
- llvm::FoldingSetNodeID OldCID, NewCID;
- OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
- NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
- if (OldCID != NewCID) {
+ if (!S.AreConstraintExpressionsEqual(OldInstFrom, OldC, NewInstFrom,
+ NewC)) {
if (Complain)
Diagnose();
return false;
@@ -7879,12 +8130,11 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
-bool
-Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
- TemplateParameterList *Old,
- bool Complain,
- TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+bool Sema::TemplateParameterListsAreEqual(
+ const NamedDecl *NewInstFrom, TemplateParameterList *New,
+ const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
if (Complain)
DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
@@ -7914,8 +8164,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
++NewParm;
@@ -7930,8 +8181,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// template parameter pack in P (ignoring whether those template
// parameters are template parameter packs).
for (; NewParm != NewParmEnd; ++NewParm) {
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
}
}
@@ -7945,7 +8197,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) {
const Expr *NewRC = New->getRequiresClause();
const Expr *OldRC = Old->getRequiresClause();
@@ -7963,10 +8215,8 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
}
if (NewRC) {
- llvm::FoldingSetNodeID OldRCID, NewRCID;
- OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
- NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
- if (OldRCID != NewRCID) {
+ if (!AreConstraintExpressionsEqual(OldInstFrom, OldRC, NewInstFrom,
+ NewRC)) {
if (Complain)
Diagnose();
return false;
@@ -8413,9 +8663,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -8423,14 +8673,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// corresponds to these arguments.
if (isPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move this to CheckTemplatePartialSpecializationArgs so we
// also do it during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -8441,11 +8692,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
- PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
- TemplateParams,
- InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8464,7 +8714,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- Converted);
+ CanonicalConverted);
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization()) &&
@@ -8494,16 +8744,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- TemplateParams,
- ClassTemplate,
- Converted,
- TemplateArgs,
- CanonType,
- PrevPartial);
+ ClassTemplatePartialSpecializationDecl *Partial =
+ ClassTemplatePartialSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
+ TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
+ TemplateArgs, CanonType, PrevPartial);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(
@@ -8523,13 +8768,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
} else {
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
@@ -8541,8 +8782,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (CurContext->isDependentContext()) {
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(
- CanonTemplate, Converted);
+ CanonType = Context.getTemplateSpecializationType(CanonTemplate,
+ CanonicalConverted);
} else {
CanonType = Context.getTypeDeclType(Specialization);
}
@@ -8686,17 +8927,33 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
return nullptr;
}
- if (TemplateParameterLists.front()->size() == 0) {
+ TemplateParameterList *Params = TemplateParameterLists.front();
+
+ if (Params->size() == 0) {
Diag(NameLoc, diag::err_concept_no_parameters);
return nullptr;
}
+ // Ensure that the parameter pack, if present, is the last parameter in the
+ // template.
+ for (TemplateParameterList::const_iterator ParamIt = Params->begin(),
+ ParamEnd = Params->end();
+ ParamIt != ParamEnd; ++ParamIt) {
+ Decl const *Param = *ParamIt;
+ if (Param->isParameterPack()) {
+ if (++ParamIt == ParamEnd)
+ break;
+ Diag(Param->getLocation(),
+ diag::err_template_param_pack_must_be_last_template_parameter);
+ return nullptr;
+ }
+ }
+
if (DiagnoseUnexpandedParameterPack(ConstraintExpr))
return nullptr;
- ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
- TemplateParameterLists.front(),
- ConstraintExpr);
+ ConceptDecl *NewDecl =
+ ConceptDecl::Create(Context, DC, NameLoc, Name, Params, ConstraintExpr);
if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
@@ -8728,7 +8985,7 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
if (Previous.empty())
return;
- auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
+ auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl()->getUnderlyingDecl());
if (!OldConcept) {
auto *Old = Previous.getRepresentativeDecl();
Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
@@ -8746,7 +9003,8 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
AddToScope = false;
return;
}
- if (hasReachableDefinition(OldConcept)) {
+ if (hasReachableDefinition(OldConcept) &&
+ IsRedefinitionInModule(NewDecl, OldConcept)) {
Diag(NewDecl->getLocation(), diag::err_redefinition)
<< NewDecl->getDeclName();
notePreviousDefinition(OldConcept, NewDecl->getLocation());
@@ -8758,14 +9016,18 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
// Other decls (e.g. namespaces) also have this shortcoming.
return;
}
- Context.setPrimaryMergedDecl(NewDecl, OldConcept);
+ // We unwrap canonical decl late to check for module visibility.
+ Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
-static void StripImplicitInstantiation(NamedDecl *D) {
- D->dropAttr<DLLImportAttr>();
- D->dropAttr<DLLExportAttr>();
+static void StripImplicitInstantiation(NamedDecl *D, bool MinGW) {
+ if (MinGW || (isa<FunctionDecl>(D) &&
+ cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())) {
+ D->dropAttr<DLLImportAttr>();
+ D->dropAttr<DLLExportAttr>();
+ }
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
FD->setInlineSpecified(false);
@@ -8840,11 +9102,13 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
// still okay to specialize it.
- StripImplicitInstantiation(PrevDecl);
+ StripImplicitInstantiation(
+ PrevDecl,
+ Context.getTargetInfo().getTriple().isWindowsGNUEnvironment());
return false;
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -9701,17 +9965,17 @@ DeclResult Sema::ActOnExplicitInstantiation(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *PrevDecl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
@@ -9768,13 +10032,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
if (!Specialization) {
// Create a new class template specialization declaration node for
// this explicit specialization.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (!HasNoEffect && !PrevDecl) {
@@ -9921,13 +10181,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,
bool Owned = false;
bool IsDependent = false;
- 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);
+ UsingShadowDecl* FoundUsing = nullptr;
+ 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();
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -10469,10 +10730,11 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
-TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, const IdentifierInfo &II,
- SourceLocation IdLoc) {
+TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ ImplicitTypenameContext IsImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -10485,9 +10747,13 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
TypeSourceInfo *TSI = nullptr;
- QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
- TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
- /*DeducedTSTContext=*/true);
+ QualType T =
+ CheckTypenameType((TypenameLoc.isValid() ||
+ IsImplicitTypename == ImplicitTypenameContext::Yes)
+ ? ETK_Typename
+ : ETK_None,
+ TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
+ /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
return CreateParsedType(T, TSI);
@@ -10533,10 +10799,9 @@ Sema::ActOnTypenameType(Scope *S,
// Construct a dependent template specialization type.
assert(DTN && "dependent template has non-dependent name?");
assert(DTN->getQualifier() == SS.getScopeRep());
- QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;
@@ -10745,7 +11010,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
// Fall through to create a dependent typename type, from which we can recover
// better.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9ec33e898198..9e48a2a35a34 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -45,7 +45,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,7 +53,9 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
+#include <optional>
#include <tuple>
+#include <type_traits>
#include <utility>
namespace clang {
@@ -235,11 +236,13 @@ checkDeducedTemplateArguments(ASTContext &Context,
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
- case TemplateArgument::Type:
+ case TemplateArgument::Type: {
// If two template type arguments have the same type, they're compatible.
- if (Y.getKind() == TemplateArgument::Type &&
- Context.hasSameType(X.getAsType(), Y.getAsType()))
- return X;
+ QualType TX = X.getAsType(), TY = Y.getAsType();
+ if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY))
+ return DeducedTemplateArgument(Context.getCommonSugaredType(TX, TY),
+ X.wasDeducedFromArrayBound() ||
+ Y.wasDeducedFromArrayBound());
// If one of the two arguments was deduced from an array bound, the other
// supersedes it.
@@ -248,6 +251,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
// The arguments are not compatible.
return DeducedTemplateArgument();
+ }
case TemplateArgument::Integral:
// If we deduced a constant in one case and either a dependent expression or
@@ -325,7 +329,9 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced a null pointer and a dependent expression, keep the
// null pointer.
if (Y.getKind() == TemplateArgument::Expression)
- return X;
+ return TemplateArgument(Context.getCommonSugaredType(
+ X.getNullPtrType(), Y.getAsExpr()->getType()),
+ true);
// If we deduced a null pointer and an integral constant, keep the
// integral constant.
@@ -334,7 +340,9 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced two null pointers, they are the same.
if (Y.getKind() == TemplateArgument::NullPtr)
- return X;
+ return TemplateArgument(
+ Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
+ true);
// All other combinations are incompatible.
return DeducedTemplateArgument();
@@ -555,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Try to preserve type sugar here, which is hard
// because of the unresolved template arguments.
const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
+ TemplateName TNP = TP->getTemplateName();
+
+ // If the parameter is an alias template, there is nothing to deduce.
+ if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
+ return Sema::TDK_Success;
+
ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
QualType UA = A;
@@ -566,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Should not lose sugar here.
if (const auto *SA =
dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
+ TemplateName TNA = SA->getTemplateName();
+
+ // If the argument is an alias template, there is nothing to deduce.
+ if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
+ return Sema::TDK_Success;
+
// Perform template argument deduction for the template name.
if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
- SA->getTemplateName(), Info, Deduced))
+ DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced))
return Result;
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be
@@ -700,7 +719,7 @@ private:
// FIXME: What if we encounter multiple packs with different numbers of
// pre-expanded expansions? (This should already have been diagnosed
// during substitution.)
- if (Optional<unsigned> ExpandedPackExpansions =
+ if (std::optional<unsigned> ExpandedPackExpansions =
getExpandedPackSize(TemplateParams->getParam(Index)))
FixedNumExpansions = ExpandedPackExpansions;
@@ -737,8 +756,11 @@ private:
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ UnexpandedParameterPack U = Unexpanded[I];
+ if (U.first.is<const SubstTemplateTypeParmPackType *>() ||
+ U.first.is<const SubstNonTypeTemplateParmPackExpr *>())
+ continue;
+ auto [Depth, Index] = getDepthAndIndex(U);
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}
@@ -894,7 +916,7 @@ public:
new (S.Context) TemplateArgument[Pack.New.size()];
std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
NewPack = DeducedTemplateArgument(
- TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())),
+ TemplateArgument(llvm::ArrayRef(ArgumentPack, Pack.New.size())),
// FIXME: This is wrong, it's possible that some pack elements are
// deduced from an array bound and others are not:
// template<typename ...T, T ...V> void g(const T (&...p)[V]);
@@ -939,7 +961,7 @@ public:
// If we have a pre-expanded pack and we didn't deduce enough elements
// for it, fail deduction.
- if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(Param)) {
if (*Expansions != PackElements) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Result;
@@ -961,7 +983,7 @@ private:
unsigned PackElements = 0;
bool IsPartiallyExpanded = false;
/// The number of expansions, if we have a fully-expanded pack in this scope.
- Optional<unsigned> FixedNumExpansions;
+ std::optional<unsigned> FixedNumExpansions;
SmallVector<DeducedPack, 2> Packs;
};
@@ -1086,7 +1108,7 @@ DeduceTemplateArguments(Sema &S,
// If the parameter type contains an explicitly-specified pack that we
// could not expand, skip the number of parameters notionally created
// by the expansion.
- Optional<unsigned> NumExpansions = Expansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = Expansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs;
++I, ++ArgIdx)
@@ -1100,6 +1122,16 @@ DeduceTemplateArguments(Sema &S,
return Result;
}
+ // DR692, DR1395
+ // C++0x [temp.deduct.type]p10:
+ // If the parameter-declaration corresponding to P_i ...
+ // During partial ordering, if Ai was originally a function parameter pack:
+ // - if P does not contain a function parameter type corresponding to Ai then
+ // Ai is ignored;
+ if (PartialOrdering && ArgIdx + 1 == NumArgs &&
+ isa<PackExpansionType>(Args[ArgIdx]))
+ return Sema::TDK_Success;
+
// Make sure we don't have any extra arguments.
if (ArgIdx < NumArgs)
return Sema::TDK_MiscellaneousDeductionFailure;
@@ -1587,7 +1619,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// FIXME: Implement deduction in dependent case.
if (P->isDependentType())
return Sema::TDK_Success;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::Builtin:
case Type::VariableArray:
case Type::Vector:
@@ -1755,7 +1787,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
- TDF & TDF_TopLevelParameterTypeList))
+ TDF & TDF_TopLevelParameterTypeList, PartialOrdering))
return Result;
if (TDF & TDF_AllowCompatibleFunctionType)
@@ -1775,7 +1807,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
switch (FPA->canThrow()) {
case CT_Cannot:
Noexcept = 1;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CT_Can:
// We give E in noexcept(E) the "deduced from array bound" treatment.
@@ -2049,7 +2081,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
const auto *ACM = dyn_cast<ConstantMatrixType>(A);
const auto *ADM = dyn_cast<DependentSizedMatrixType>(A);
if (!ParamExpr->isValueDependent()) {
- Optional<llvm::APSInt> ParamConst =
+ std::optional<llvm::APSInt> ParamConst =
ParamExpr->getIntegerConstantExpr(S.Context);
if (!ParamConst)
return Sema::TDK_NonDeducedMismatch;
@@ -2061,7 +2093,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
}
Expr *ArgExpr = (ADM->*GetArgDimensionExpr)();
- if (Optional<llvm::APSInt> ArgConst =
+ if (std::optional<llvm::APSInt> ArgConst =
ArgExpr->getIntegerConstantExpr(S.Context))
if (*ArgConst == *ParamConst)
return Sema::TDK_Success;
@@ -2422,6 +2454,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
static bool isSameTemplateArg(ASTContext &Context,
TemplateArgument X,
const TemplateArgument &Y,
+ bool PartialOrdering,
bool PackExpansionMatchesPack = false) {
// If we're checking deduced arguments (X) against original arguments (Y),
// we will have flattened packs to non-expansions in X.
@@ -2462,18 +2495,33 @@ static bool isSameTemplateArg(ASTContext &Context,
return XID == YID;
}
- case TemplateArgument::Pack:
- if (X.pack_size() != Y.pack_size())
- return false;
+ case TemplateArgument::Pack: {
+ unsigned PackIterationSize = X.pack_size();
+ if (X.pack_size() != Y.pack_size()) {
+ if (!PartialOrdering)
+ return false;
- for (TemplateArgument::pack_iterator XP = X.pack_begin(),
- XPEnd = X.pack_end(),
- YP = Y.pack_begin();
- XP != XPEnd; ++XP, ++YP)
- if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack))
+ // C++0x [temp.deduct.type]p9:
+ // During partial ordering, if Ai was originally a pack expansion:
+ // - if P does not contain a template argument corresponding to Ai
+ // then Ai is ignored;
+ bool XHasMoreArg = X.pack_size() > Y.pack_size();
+ if (!(XHasMoreArg && X.pack_elements().back().isPackExpansion()) &&
+ !(!XHasMoreArg && Y.pack_elements().back().isPackExpansion()))
return false;
+ if (XHasMoreArg)
+ PackIterationSize = Y.pack_size();
+ }
+
+ ArrayRef<TemplateArgument> XP = X.pack_elements();
+ ArrayRef<TemplateArgument> YP = Y.pack_elements();
+ for (unsigned i = 0; i < PackIterationSize; ++i)
+ if (!isSameTemplateArg(Context, XP[i], YP[i], PartialOrdering,
+ PackExpansionMatchesPack))
+ return false;
return true;
+ }
}
llvm_unreachable("Invalid TemplateArgument Kind!");
@@ -2563,13 +2611,11 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
/// Convert the given deduced template argument and add it to the set of
/// fully-converted template arguments.
-static bool
-ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
- DeducedTemplateArgument Arg,
- NamedDecl *Template,
- TemplateDeductionInfo &Info,
- bool IsDeduced,
- SmallVectorImpl<TemplateArgument> &Output) {
+static bool ConvertDeducedTemplateArgument(
+ Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template,
+ TemplateDeductionInfo &Info, bool IsDeduced,
+ SmallVectorImpl<TemplateArgument> &SugaredOutput,
+ SmallVectorImpl<TemplateArgument> &CanonicalOutput) {
auto ConvertArg = [&](DeducedTemplateArgument Arg,
unsigned ArgumentPackIndex) {
// Convert the deduced template argument into a template
@@ -2581,7 +2627,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// Check the template argument, converting it as necessary.
return S.CheckTemplateArgument(
Param, ArgLoc, Template, Template->getLocation(),
- Template->getSourceRange().getEnd(), ArgumentPackIndex, Output,
+ Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
+ CanonicalOutput,
IsDeduced
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
@@ -2591,7 +2638,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
- SmallVector<TemplateArgument, 2> PackedArgsBuilder;
+ SmallVector<TemplateArgument, 2> SugaredPackedArgsBuilder,
+ CanonicalPackedArgsBuilder;
for (const auto &P : Arg.pack_elements()) {
// When converting the deduced template argument, append it to the
// general output list. We need to do this so that the template argument
@@ -2610,23 +2658,24 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
<< Arg << Param;
return true;
}
- if (ConvertArg(InnerArg, PackedArgsBuilder.size()))
+ if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size()))
return true;
// Move the converted template argument into our argument pack.
- PackedArgsBuilder.push_back(Output.pop_back_val());
+ SugaredPackedArgsBuilder.push_back(SugaredOutput.pop_back_val());
+ CanonicalPackedArgsBuilder.push_back(CanonicalOutput.pop_back_val());
}
// If the pack is empty, we still need to substitute into the parameter
// itself, in case that substitution fails.
- if (PackedArgsBuilder.empty()) {
+ if (SugaredPackedArgsBuilder.empty()) {
LocalInstantiationScope Scope(S);
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
- MultiLevelTemplateArgumentList Args(TemplateArgs);
+ MultiLevelTemplateArgumentList Args(Template, SugaredOutput,
+ /*Final=*/true);
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
- NTTP, Output,
+ NTTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() ||
S.SubstType(NTTP->getType(), Args, NTTP->getLocation(),
@@ -2634,7 +2683,7 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
return true;
} else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
- TTP, Output,
+ TTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args))
return true;
@@ -2643,8 +2692,10 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
}
// Create the resulting argument pack.
- Output.push_back(
- TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder));
+ SugaredOutput.push_back(
+ TemplateArgument::CreatePackCopy(S.Context, SugaredPackedArgsBuilder));
+ CanonicalOutput.push_back(TemplateArgument::CreatePackCopy(
+ S.Context, CanonicalPackedArgsBuilder));
return false;
}
@@ -2654,11 +2705,13 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// FIXME: This should not be a template, but
// ClassTemplatePartialSpecializationDecl sadly does not derive from
// TemplateDecl.
-template<typename TemplateDeclT>
+template <typename TemplateDeclT>
static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
Sema &S, TemplateDeclT *Template, bool IsDeduced,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<TemplateArgument> &SugaredBuilder,
+ SmallVectorImpl<TemplateArgument> &CanonicalBuilder,
LocalInstantiationScope *CurrentInstantiationScope = nullptr,
unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
@@ -2692,7 +2745,9 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// We have already fully type-checked and converted this
// argument, because it was explicitly-specified. Just record the
// presence of this argument.
- Builder.push_back(Deduced[I]);
+ SugaredBuilder.push_back(Deduced[I]);
+ CanonicalBuilder.push_back(
+ S.Context.getCanonicalTemplateArgument(Deduced[I]));
continue;
}
}
@@ -2700,10 +2755,13 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// We may have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
- IsDeduced, Builder)) {
+ IsDeduced, SugaredBuilder,
+ CanonicalBuilder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(
+ TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
return Sema::TDK_SubstitutionFailure;
}
@@ -2734,15 +2792,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
S.getLangOpts().CPlusPlus17);
DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
- TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
- HasDefaultArg);
+ TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param,
+ SugaredBuilder, CanonicalBuilder, HasDefaultArg);
}
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
if (PartialOverloading) break;
return HasDefaultArg ? Sema::TDK_SubstitutionFailure
@@ -2750,13 +2809,14 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
}
// Check whether we can actually use the default argument.
- if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
- TD->getSourceRange().getEnd(), 0, Builder,
- Sema::CTAK_Specified)) {
+ if (S.CheckTemplateArgument(
+ Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
+ 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
return Sema::TDK_SubstitutionFailure;
}
@@ -2783,19 +2843,54 @@ template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
+template <typename TemplateDeclT>
+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
+ return false;
+}
+template <>
+bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
+ VarTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
+template <>
+bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
+ ClassTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
-template<typename TemplateDeclT>
+template <typename TemplateDeclT>
static Sema::TemplateDeductionResult
-CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
- ArrayRef<TemplateArgument> DeducedArgs,
- TemplateDeductionInfo& Info) {
+CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
+ ArrayRef<TemplateArgument> SugaredDeducedArgs,
+ ArrayRef<TemplateArgument> CanonicalDeducedArgs,
+ TemplateDeductionInfo &Info) {
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
- if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
- DeducedArgs, Info.getLocation(),
+
+ bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
+ TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack,
+ CanonicalDeducedArgs};
+
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ Template, /*Final=*/false,
+ /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL,
+ /*RelativeToPrimary=*/true, /*Pattern=*/
+ nullptr, /*ForConstraintInstantiation=*/true);
+
+ // getTemplateInstantiationArgs picks up the non-deduced version of the
+ // template args when this is a variable template partial specialization and
+ // not class-scope explicit specialization, so replace with Deduced Args
+ // instead of adding to inner-most.
+ if (NeedsReplacement)
+ MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs);
+
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
+ Info.getLocation(),
Info.AssociatedConstraintsSatisfaction) ||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+ Info.reset(
+ TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs));
return Sema::TDK_ConstraintsNotSatisfied;
}
return Sema::TDK_Success;
@@ -2820,16 +2915,19 @@ FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- S, Partial, IsPartialOrdering, Deduced, Info, Builder))
+ S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder,
+ CanonicalBuilder))
return Result;
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(S.Context, Builder);
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder);
- Info.reset(DeducedArgumentList);
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
// Substitute the deduced template arguments into the template
// arguments of the class template partial specialization, and
@@ -2844,9 +2942,11 @@ FinishTemplateArgumentDeduction(
TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
PartialTemplArgInfo->RAngleLoc);
- if (S.SubstTemplateArguments(
- PartialTemplArgInfo->arguments(),
- MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) {
+ if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(),
+ MultiLevelTemplateArgumentList(Partial,
+ SugaredBuilder,
+ /*Final=*/true),
+ InstArgs)) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= Partial->getTemplateParameters()->size())
ParamIdx = Partial->getTemplateParameters()->size() - 1;
@@ -2859,18 +2959,20 @@ FinishTemplateArgumentDeduction(
}
bool ConstraintsNotSatisfied;
- SmallVector<TemplateArgument, 4> ConvertedInstArgs;
- if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs,
- false, ConvertedInstArgs,
- /*UpdateArgsWithConversions=*/true,
- &ConstraintsNotSatisfied))
- return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied :
- Sema::TDK_SubstitutionFailure;
+ SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
+ CanonicalConvertedInstArgs;
+ if (S.CheckTemplateArgumentList(
+ Template, Partial->getLocation(), InstArgs, false,
+ SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
+ /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
+ return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied
+ : Sema::TDK_SubstitutionFailure;
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
- TemplateArgument InstArg = ConvertedInstArgs.data()[I];
- if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
+ TemplateArgument InstArg = SugaredConvertedInstArgs.data()[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
+ IsPartialOrdering)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
@@ -2881,7 +2983,8 @@ FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
+ if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder,
+ CanonicalBuilder, Info))
return Result;
return Sema::TDK_Success;
@@ -2905,17 +3008,20 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder))
+ S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder,
+ /*CurrentInstantiationScope=*/nullptr,
+ /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false))
return Result;
// Check that we produced the correct argument list.
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
- TemplateArgument InstArg = Builder[I];
- if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
- /*PackExpansionMatchesPack*/true)) {
+ TemplateArgument InstArg = CanonicalBuilder[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering,
+ /*PackExpansionMatchesPack=*/true)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
@@ -2926,8 +3032,8 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
- Info))
+ if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder,
+ CanonicalBuilder, Info))
return Result;
return Sema::TDK_Success;
@@ -3079,14 +3185,12 @@ static bool isSimpleTemplateIdType(QualType T) {
///
/// \returns TDK_Success if substitution was successful, or some failure
/// condition.
-Sema::TemplateDeductionResult
-Sema::SubstituteExplicitTemplateArguments(
- FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo &ExplicitTemplateArgs,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- SmallVectorImpl<QualType> &ParamTypes,
- QualType *FunctionType,
- TemplateDeductionInfo &Info) {
+Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo &ExplicitTemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType,
+ TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -3094,7 +3198,7 @@ Sema::SubstituteExplicitTemplateArguments(
if (ExplicitTemplateArgs.size() == 0) {
// No arguments to substitute; just copy over the parameter types and
// fill in the function type.
- for (auto P : Function->parameters())
+ for (auto *P : Function->parameters())
ParamTypes.push_back(P->getType());
if (FunctionType)
@@ -3112,7 +3216,7 @@ Sema::SubstituteExplicitTemplateArguments(
// declaration order of their corresponding template-parameters. The
// template argument list shall not specify more template-arguments than
// there are corresponding template-parameters.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
@@ -3125,9 +3229,11 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(),
- ExplicitTemplateArgs, true, Builder, false) ||
+ ExplicitTemplateArgs, true, SugaredBuilder,
+ CanonicalBuilder,
+ /*UpdateArgsWithConversions=*/false) ||
Trap.hasErrorOccurred()) {
- unsigned Index = Builder.size();
+ unsigned Index = SugaredBuilder.size();
if (Index >= TemplateParams->size())
return TDK_SubstitutionFailure;
Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
@@ -3136,9 +3242,12 @@ Sema::SubstituteExplicitTemplateArguments(
// Form the template argument list from the explicitly-specified
// template arguments.
- TemplateArgumentList *ExplicitArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder);
- Info.setExplicitArgs(ExplicitArgumentList);
+ TemplateArgumentList *SugaredExplicitArgumentList =
+ TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalExplicitArgumentList =
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder);
+ Info.setExplicitArgs(SugaredExplicitArgumentList,
+ CanonicalExplicitArgumentList);
// Template argument deduction and the final substitution should be
// done in the context of the templated declaration. Explicit
@@ -3151,15 +3260,15 @@ Sema::SubstituteExplicitTemplateArguments(
// the explicit template arguments. They'll be used as part of deduction
// for this template parameter pack.
unsigned PartiallySubstitutedPackIndex = -1u;
- if (!Builder.empty()) {
- const TemplateArgument &Arg = Builder.back();
+ if (!CanonicalBuilder.empty()) {
+ const TemplateArgument &Arg = CanonicalBuilder.back();
if (Arg.getKind() == TemplateArgument::Pack) {
- auto *Param = TemplateParams->getParam(Builder.size() - 1);
+ auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1);
// If this is a fully-saturated fixed-size pack, it should be
// fully-substituted, not partially-substituted.
- Optional<unsigned> Expansions = getExpandedPackSize(Param);
+ std::optional<unsigned> Expansions = getExpandedPackSize(Param);
if (!Expansions || Arg.pack_size() < *Expansions) {
- PartiallySubstitutedPackIndex = Builder.size() - 1;
+ PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1;
CurrentInstantiationScope->SetPartiallySubstitutedPack(
Param, Arg.pack_begin(), Arg.pack_size());
}
@@ -3175,15 +3284,18 @@ Sema::SubstituteExplicitTemplateArguments(
ExtParameterInfoBuilder ExtParamInfos;
+ MultiLevelTemplateArgumentList MLTAL(FunctionTemplate,
+ SugaredExplicitArgumentList->asArray(),
+ /*Final=*/true);
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments. If the function has a trailing
// return type, substitute it after the arguments to ensure we substitute
// in lexical order.
if (Proto->hasTrailingReturn()) {
if (SubstParmTypes(Function->getLocation(), Function->parameters(),
- Proto->getExtParameterInfosOrNull(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes, /*params*/ nullptr, ExtParamInfos))
+ Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes,
+ /*params=*/nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
}
@@ -3207,8 +3319,7 @@ Sema::SubstituteExplicitTemplateArguments(
getLangOpts().CPlusPlus11);
ResultType =
- SubstType(Proto->getReturnType(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ SubstType(Proto->getReturnType(), MLTAL,
Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
@@ -3225,9 +3336,8 @@ Sema::SubstituteExplicitTemplateArguments(
// explicitly-specified template arguments if we didn't do so earlier.
if (!Proto->hasTrailingReturn() &&
SubstParmTypes(Function->getLocation(), Function->parameters(),
- Proto->getExtParameterInfosOrNull(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes, /*params*/ nullptr, ExtParamInfos))
+ Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes,
+ /*params*/ nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
if (FunctionType) {
@@ -3239,9 +3349,8 @@ Sema::SubstituteExplicitTemplateArguments(
// specification.
SmallVector<QualType, 4> ExceptionStorage;
if (getLangOpts().CPlusPlus17 &&
- SubstExceptionSpec(
- Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
- MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
+ SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec,
+ ExceptionStorage, MLTAL))
return TDK_SubstitutionFailure;
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
@@ -3263,8 +3372,8 @@ Sema::SubstituteExplicitTemplateArguments(
// parameter pack, however, will be set to NULL since the deduction
// mechanism handles the partially-substituted argument pack directly.
Deduced.reserve(TemplateParams->size());
- for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
- const TemplateArgument &Arg = ExplicitArgumentList->get(I);
+ for (unsigned I = 0, N = SugaredExplicitArgumentList->size(); I != N; ++I) {
+ const TemplateArgument &Arg = SugaredExplicitArgumentList->get(I);
if (I == PartiallySubstitutedPackIndex)
Deduced.push_back(DeducedTemplateArgument());
else
@@ -3452,11 +3561,11 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder,
- CurrentInstantiationScope, NumExplicitlySpecified,
- PartialOverloading))
+ *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope,
+ NumExplicitlySpecified, PartialOverloading))
return Result;
// C++ [temp.deduct.call]p10: [DR1391]
@@ -3472,16 +3581,20 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TDK_NonDependentConversionFailure;
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder);
- Info.reset(DeducedArgumentList);
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder);
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
DeclContext *Owner = FunctionTemplate->getDeclContext();
if (FunctionTemplate->getFriendObjectKind())
Owner = FunctionTemplate->getLexicalDeclContext();
- MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
+ MultiLevelTemplateArgumentList SubstArgs(
+ FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
+ /*Final=*/false);
Specialization = cast_or_null<FunctionDecl>(
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
if (!Specialization || Specialization->isInvalidDecl())
@@ -3492,9 +3605,10 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// If the template argument list is owned by the function template
// specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList &&
+ if (Specialization->getTemplateSpecializationArgs() ==
+ CanonicalDeducedArgumentList &&
!Trap.hasErrorOccurred())
- Info.take();
+ Info.takeCanonical();
// There may have been an error that did not prevent us from constructing a
// declaration. Mark the declaration invalid and return with a substitution
@@ -3513,13 +3627,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
if (!PartialOverloading ||
- (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) {
- if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
- Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ (CanonicalBuilder.size() ==
+ FunctionTemplate->getTemplateParameters()->size())) {
+ if (CheckInstantiatedFunctionTemplateConstraints(
+ Info.getLocation(), Specialization, CanonicalBuilder,
+ Info.AssociatedConstraintsSatisfaction))
return TDK_MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ Info.reset(Info.takeSugared(),
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
return TDK_ConstraintsNotSatisfied;
}
}
@@ -3765,13 +3882,11 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(
// - If A is an array type, the pointer type produced by the
// array-to-pointer standard conversion (4.2) is used in place of
// A for type deduction; otherwise,
- if (ArgType->isArrayType())
- ArgType = S.Context.getArrayDecayedType(ArgType);
// - If A is a function type, the pointer type produced by the
// function-to-pointer standard conversion (4.3) is used in place
// of A for type deduction; otherwise,
- else if (ArgType->isFunctionType())
- ArgType = S.Context.getPointerType(ArgType);
+ if (ArgType->canDecayToPointerType())
+ ArgType = S.Context.getDecayedType(ArgType);
else {
// - If A is a cv-qualified type, the top level cv-qualifiers of A's
// type are ignored for type deduction.
@@ -4068,7 +4183,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// If the parameter type contains an explicitly-specified pack that we
// could not expand, skip the number of parameters notionally created
// by the expansion.
- Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions =
+ ParamExpansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
++I, ++ArgIdx) {
@@ -4521,42 +4637,9 @@ namespace {
} // namespace
-Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
- return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth, IgnoreConstraints);
-}
-
-/// Attempt to produce an informative diagostic explaining why auto deduction
-/// failed.
-/// \return \c true if diagnosed, \c false if not.
-static bool diagnoseAutoDeductionFailure(Sema &S,
- Sema::TemplateDeductionResult TDK,
- TemplateDeductionInfo &Info,
- ArrayRef<SourceRange> Ranges) {
- switch (TDK) {
- case Sema::TDK_Inconsistent: {
- // Inconsistent deduction means we were deducing from an initializer list.
- auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
- D << Info.FirstArg << Info.SecondArg;
- for (auto R : Ranges)
- D << R;
- return true;
- }
-
- // FIXME: Are there other cases for which a custom diagnostic is more useful
- // than the basic "types don't match" diagnostic?
-
- default:
- return false;
- }
-}
-
-static Sema::DeduceAutoResult
-CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
- AutoTypeLoc TypeLoc, QualType Deduced) {
+static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc,
+ QualType Deduced) {
ConstraintSatisfaction Satisfaction;
ConceptDecl *Concept = Type.getTypeConstraintConcept();
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
@@ -4568,14 +4651,17 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
- llvm::SmallVector<TemplateArgument, 4> Converted;
+ llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
- /*PartialTemplateArgs=*/false, Converted))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ /*PartialTemplateArgs=*/false,
+ SugaredConverted, CanonicalConverted))
+ return true;
+ MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
+ /*Final=*/false);
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
- Converted, TypeLoc.getLocalSourceRange(),
+ MLTAL, TypeLoc.getLocalSourceRange(),
Satisfaction))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
if (!Satisfaction.IsSatisfied) {
std::string Buf;
llvm::raw_string_ostream OS(Buf);
@@ -4589,11 +4675,11 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
OS.flush();
S.Diag(TypeLoc.getConceptNameLoc(),
diag::err_placeholder_constraints_not_satisfied)
- << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
}
- return Sema::DAR_Succeeded;
+ return false;
}
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
@@ -4606,184 +4692,165 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
/// \param Init the initializer for the variable whose type is to be deduced.
/// \param Result if type deduction was successful, this will be set to the
/// deduced type.
-/// \param DependentDeductionDepth Set if we should permit deduction in
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+/// \param DependentDeduction Set if we should permit deduction in
/// dependent cases. This is necessary for template partial ordering with
-/// 'auto' template parameters. The value specified is the template
-/// parameter depth at which we should perform 'auto' deduction.
+/// 'auto' template parameters. The template parameter depth to be used
+/// 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::DeduceAutoResult
-Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
+Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init,
+ QualType &Result,
+ TemplateDeductionInfo &Info,
+ bool DependentDeduction,
+ bool IgnoreConstraints) {
+ assert(DependentDeduction || Info.getDeducedDepth() == 0);
if (Init->containsErrors())
- return DAR_FailedAlreadyDiagnosed;
- if (Init->getType()->isNonOverloadPlaceholderType()) {
+ return TDK_AlreadyDiagnosed;
+
+ const AutoType *AT = Type.getType()->getContainedAutoType();
+ assert(AT);
+
+ if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_AlreadyDiagnosed;
Init = NonPlaceholder.get();
}
DependentAuto DependentResult = {
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
- if (!DependentDeductionDepth &&
+ if (!DependentDeduction &&
(Type.getType()->isDependentType() || Init->isTypeDependent() ||
Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- // Find the depth of template parameter to synthesize.
- unsigned Depth = DependentDeductionDepth.value_or(0);
-
- // If this is a 'decltype(auto)' specifier, do the decltype dance.
- // Since 'decltype(auto)' can only occur at the top of the type, we
- // don't need to go digging for it.
- if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
- if (AT->isDecltypeAuto()) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
- return DAR_FailedAlreadyDiagnosed;
- }
-
- ExprResult ER = CheckPlaceholderExpr(Init);
- if (ER.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
- QualType Deduced = getDecltypeForExpr(ER.get());
- assert(!Deduced.isNull());
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult =
- CheckDeducedPlaceholderConstraints(*this, *AT,
- Type.getContainedAutoTypeLoc(),
- Deduced);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
- }
- Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
- if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Succeeded;
- } else if (!getLangOpts().CPlusPlus) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
- return DAR_FailedAlreadyDiagnosed;
- }
- }
+ auto *InitList = dyn_cast<InitListExpr>(Init);
+ if (!getLangOpts().CPlusPlus && InitList) {
+ Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
+ return TDK_AlreadyDiagnosed;
}
- SourceLocation Loc = Init->getExprLoc();
-
- LocalInstantiationScope InstScope(*this);
-
- // Build template<class TemplParam> void Func(FuncParam);
- TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
- Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
- false);
- QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
- NamedDecl *TemplParamPtr = TemplParam;
- FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
-
- QualType FuncParam =
- SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
- .Apply(Type);
- assert(!FuncParam.isNull() &&
- "substituting template parameter for 'auto' failed");
-
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
- TemplateDeductionInfo Info(Loc, Depth);
-
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&](TemplateDeductionResult TDK,
- ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK) {
if (Init->isTypeDependent()) {
Result =
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Failed;
+ return TDK;
};
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
- InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
- if (InitList) {
- // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce
- // against that. Such deduction only succeeds if removing cv-qualifiers and
- // references results in std::initializer_list<T>.
- if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
- return DAR_Failed;
-
- // Resolving a core issue: a braced-init-list containing any designators is
- // a non-deduced context.
- for (Expr *E : InitList->inits())
- if (isa<DesignatedInitExpr>(E))
- return DAR_Failed;
+ QualType DeducedType;
+ // If this is a 'decltype(auto)' specifier, do the decltype dance.
+ if (AT->isDecltypeAuto()) {
+ if (InitList) {
+ Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
+ return TDK_AlreadyDiagnosed;
+ }
- SourceRange DeducedFromInitRange;
- for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- Expr *Init = InitList->getInit(i);
+ DeducedType = getDecltypeForExpr(Init);
+ assert(!DeducedType.isNull());
+ } else {
+ LocalInstantiationScope InstScope(*this);
+
+ // Build template<class TemplParam> void Func(FuncParam);
+ SourceLocation Loc = Init->getExprLoc();
+ TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
+ Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0,
+ nullptr, false, false, false);
+ QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
+ NamedDecl *TemplParamPtr = TemplParam;
+ FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
+
+ if (InitList) {
+ // Notionally, we substitute std::initializer_list<T> for 'auto' and
+ // deduce against that. Such deduction only succeeds if removing
+ // cv-qualifiers and references results in std::initializer_list<T>.
+ if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
+ return TDK_Invalid;
+
+ SourceRange DeducedFromInitRange;
+ for (Expr *Init : InitList->inits()) {
+ // Resolving a core issue: a braced-init-list containing any designators
+ // is a non-deduced context.
+ if (isa<DesignatedInitExpr>(Init))
+ return TDK_Invalid;
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/true,
+ /*ArgIdx=*/0, /*TDF=*/0)) {
+ if (TDK == TDK_Inconsistent) {
+ Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
+ << Info.FirstArg << Info.SecondArg << DeducedFromInitRange
+ << Init->getSourceRange();
+ return DeductionFailed(TDK_AlreadyDiagnosed);
+ }
+ return DeductionFailed(TDK);
+ }
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
+ }
+ } else {
+ if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
+ Diag(Loc, diag::err_auto_bitfield);
+ return TDK_AlreadyDiagnosed;
+ }
+ QualType FuncParam =
+ SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type);
+ assert(!FuncParam.isNull() &&
+ "substituting template parameter for 'auto' failed");
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, Init,
- Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
- /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {DeducedFromInitRange,
- Init->getSourceRange()});
-
- if (DeducedFromInitRange.isInvalid() &&
- Deduced[0].getKind() != TemplateArgument::Null)
- DeducedFromInitRange = Init->getSourceRange();
- }
- } else {
- if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
- Diag(Loc, diag::err_auto_bitfield);
- return DAR_FailedAlreadyDiagnosed;
+ *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0))
+ return DeductionFailed(TDK);
}
- if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
- OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {});
- }
-
- // Could be null if somehow 'auto' appears in a non-deduced context.
- if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed(TDK_Incomplete, {});
-
- QualType DeducedType = Deduced[0].getAsType();
+ // Could be null if somehow 'auto' appears in a non-deduced context.
+ if (Deduced[0].getKind() != TemplateArgument::Type)
+ return DeductionFailed(TDK_Incomplete);
+ DeducedType = Deduced[0].getAsType();
- if (InitList) {
- DeducedType = BuildStdInitializerList(DeducedType, Loc);
- if (DeducedType.isNull())
- return DAR_FailedAlreadyDiagnosed;
+ if (InitList) {
+ DeducedType = BuildStdInitializerList(DeducedType, Loc);
+ if (DeducedType.isNull())
+ return TDK_AlreadyDiagnosed;
+ }
}
- QualType MaybeAuto = Type.getType().getNonReferenceType();
- while (MaybeAuto->isPointerType())
- MaybeAuto = MaybeAuto->getPointeeType();
- if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
- *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
+ if (!Result.isNull()) {
+ if (!Context.hasSameType(DeducedType, Result)) {
+ Info.FirstArg = Result;
+ Info.SecondArg = DeducedType;
+ return DeductionFailed(TDK_Inconsistent);
}
+ DeducedType = Context.getCommonSugaredType(Result, DeducedType);
}
+ if (AT->isConstrained() && !IgnoreConstraints &&
+ CheckDeducedPlaceholderConstraints(
+ *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType))
+ return TDK_AlreadyDiagnosed;
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_AlreadyDiagnosed;
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
@@ -4794,11 +4861,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (auto TDK =
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed(TDK, {});
+ return DeductionFailed(TDK);
}
}
- return DAR_Succeeded;
+ return TDK_Success;
}
QualType Sema::SubstAutoType(QualType TypeWithAuto,
@@ -5102,27 +5169,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
return true;
}
-/// Determine whether this a function template whose parameter-type-list
-/// ends with a function parameter pack.
-static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
- FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- unsigned NumParams = Function->getNumParams();
- if (NumParams == 0)
- return false;
-
- ParmVarDecl *Last = Function->getParamDecl(NumParams - 1);
- if (!Last->isParameterPack())
- return false;
-
- // Make sure that no previous parameter is a parameter pack.
- while (--NumParams > 0) {
- if (Function->getParamDecl(NumParams - 1)->isParameterPack())
- return false;
- }
-
- return true;
-}
-
/// Returns the more specialized function template according
/// to the rules of function template partial ordering (C++ [temp.func.order]).
///
@@ -5143,53 +5189,128 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// candidate with a reversed parameter order. In this case, the corresponding
/// P/A pairs between FT1 and FT2 are reversed.
///
-/// \param AllowOrderingByConstraints If \c is false, don't check whether one
-/// of the templates is more constrained than the other. Default is true.
-///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
- unsigned NumCallArguments2, bool Reversed,
- bool AllowOrderingByConstraints) {
-
- auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * {
- if (!AllowOrderingByConstraints)
- return nullptr;
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- FT1->getAssociatedConstraints(AC1);
- FT2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? FT1 : FT2;
- };
+ unsigned NumCallArguments2, bool Reversed) {
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments1, Reversed);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
NumCallArguments2, Reversed);
+ // C++ [temp.deduct.partial]p10:
+ // F is more specialized than G if F is at least as specialized as G and G
+ // is not at least as specialized as F.
if (Better1 != Better2) // We have a clear winner
return Better1 ? FT1 : FT2;
if (!Better1 && !Better2) // Neither is better than the other
- return JudgeByConstraints();
+ return nullptr;
- // FIXME: This mimics what GCC implements, but doesn't match up with the
- // proposed resolution for core issue 692. This area needs to be sorted out,
- // but for now we attempt to maintain compatibility.
- bool Variadic1 = isVariadicFunctionTemplate(FT1);
- bool Variadic2 = isVariadicFunctionTemplate(FT2);
- if (Variadic1 != Variadic2)
- return Variadic1? FT2 : FT1;
+ // C++ [temp.deduct.partial]p11:
+ // ... and if G has a trailing function parameter pack for which F does not
+ // have a corresponding parameter, and if F does not have a trailing
+ // function parameter pack, then F is more specialized than G.
+ FunctionDecl *FD1 = FT1->getTemplatedDecl();
+ FunctionDecl *FD2 = FT2->getTemplatedDecl();
+ unsigned NumParams1 = FD1->getNumParams();
+ unsigned NumParams2 = FD2->getNumParams();
+ bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack();
+ bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack();
+ if (Variadic1 != Variadic2) {
+ if (Variadic1 && NumParams1 > NumParams2)
+ return FT2;
+ if (Variadic2 && NumParams2 > NumParams1)
+ return FT1;
+ }
+
+ // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+ // there is no wording or even resolution for this issue.
+ for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) {
+ QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType();
+ QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType();
+ auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
+ auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
+ if (!TST1 || !TST2)
+ continue;
+ const TemplateArgument &TA1 = TST1->template_arguments().back();
+ if (TA1.getKind() == TemplateArgument::Pack) {
+ assert(TST1->template_arguments().size() ==
+ TST2->template_arguments().size());
+ const TemplateArgument &TA2 = TST2->template_arguments().back();
+ assert(TA2.getKind() == TemplateArgument::Pack);
+ unsigned PackSize1 = TA1.pack_size();
+ unsigned PackSize2 = TA2.pack_size();
+ bool IsPackExpansion1 =
+ PackSize1 && TA1.pack_elements().back().isPackExpansion();
+ bool IsPackExpansion2 =
+ PackSize2 && TA2.pack_elements().back().isPackExpansion();
+ if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
+ if (PackSize1 > PackSize2 && IsPackExpansion1)
+ return FT2;
+ if (PackSize1 < PackSize2 && IsPackExpansion2)
+ return FT1;
+ }
+ }
+ }
+
+ if (!Context.getLangOpts().CPlusPlus20)
+ return nullptr;
+
+ // Match GCC on not implementing [temp.func.order]p6.2.1.
+
+ // C++20 [temp.func.order]p6:
+ // If deduction against the other template succeeds for both transformed
+ // templates, constraints can be considered as follows:
+
+ // C++20 [temp.func.order]p6.1:
+ // If their template-parameter-lists (possibly including template-parameters
+ // invented for an abbreviated function template ([dcl.fct])) or function
+ // parameter lists differ in length, neither template is more specialized
+ // than the other.
+ TemplateParameterList *TPL1 = FT1->getTemplateParameters();
+ TemplateParameterList *TPL2 = FT2->getTemplateParameters();
+ if (TPL1->size() != TPL2->size() || NumParams1 != NumParams2)
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.2.2:
+ // Otherwise, if the corresponding template-parameters of the
+ // template-parameter-lists are not equivalent ([temp.over.link]) or if the
+ // 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))
+ return nullptr;
+
+ for (unsigned i = 0; i < NumParams1; ++i)
+ if (!Context.hasSameType(FD1->getParamDecl(i)->getType(),
+ FD2->getParamDecl(i)->getType()))
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.3:
+ // Otherwise, if the context in which the partial ordering is done is
+ // that of a call to a conversion function and the return types of the
+ // templates are not the same, then neither template is more specialized
+ // than the other.
+ if (TPOC == TPOC_Conversion &&
+ !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType()))
+ return nullptr;
- return JudgeByConstraints();
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ FT1->getAssociatedConstraints(AC1);
+ FT2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
+ return nullptr;
+ if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? FT1 : FT2;
}
/// Determine if the two templates are equivalent.
@@ -5354,7 +5475,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
if (Inst.isInvalid())
return false;
- auto *TST1 = T1->castAs<TemplateSpecializationType>();
+ const auto *TST1 = cast<TemplateSpecializationType>(T1);
bool AtLeastAsSpecialized;
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
AtLeastAsSpecialized = !FinishTemplateArgumentDeduction(
@@ -5366,6 +5487,180 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
return AtLeastAsSpecialized;
}
+namespace {
+// A dummy class to return nullptr instead of P2 when performing "more
+// specialized than primary" check.
+struct GetP2 {
+ template <typename T1, typename T2,
+ std::enable_if_t<std::is_same_v<T1, T2>, bool> = true>
+ T2 *operator()(T1 *, T2 *P2) {
+ return P2;
+ }
+ template <typename T1, typename T2,
+ std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true>
+ T1 *operator()(T1 *, T2 *) {
+ return nullptr;
+ }
+};
+
+// The assumption is that two template argument lists have the same size.
+struct TemplateArgumentListAreEqual {
+ ASTContext &Ctx;
+ TemplateArgumentListAreEqual(ASTContext &Ctx) : Ctx(Ctx) {}
+
+ template <typename T1, typename T2,
+ std::enable_if_t<std::is_same_v<T1, T2>, bool> = true>
+ bool operator()(T1 *PS1, T2 *PS2) {
+ ArrayRef<TemplateArgument> Args1 = PS1->getTemplateArgs().asArray(),
+ Args2 = PS2->getTemplateArgs().asArray();
+
+ for (unsigned I = 0, E = Args1.size(); I < E; ++I) {
+ // We use profile, instead of structural comparison of the arguments,
+ // because canonicalization can't do the right thing for dependent
+ // expressions.
+ llvm::FoldingSetNodeID IDA, IDB;
+ Args1[I].Profile(IDA, Ctx);
+ Args2[I].Profile(IDB, Ctx);
+ if (IDA != IDB)
+ return false;
+ }
+ return true;
+ }
+
+ template <typename T1, typename T2,
+ std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true>
+ bool operator()(T1 *Spec, T2 *Primary) {
+ ArrayRef<TemplateArgument> Args1 = Spec->getTemplateArgs().asArray(),
+ Args2 = Primary->getInjectedTemplateArgs();
+
+ for (unsigned I = 0, E = Args1.size(); I < E; ++I) {
+ // We use profile, instead of structural comparison of the arguments,
+ // because canonicalization can't do the right thing for dependent
+ // expressions.
+ llvm::FoldingSetNodeID IDA, IDB;
+ Args1[I].Profile(IDA, Ctx);
+ // Unlike the specialization arguments, the injected arguments are not
+ // always canonical.
+ Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx);
+ if (IDA != IDB)
+ return false;
+ }
+ return true;
+ }
+};
+} // namespace
+
+/// Returns the more specialized template specialization between T1/P1 and
+/// T2/P2.
+/// - If IsMoreSpecialThanPrimaryCheck is true, T1/P1 is the partial
+/// specialization and T2/P2 is the primary template.
+/// - otherwise, both T1/P1 and T2/P2 are the partial specialization.
+///
+/// \param T1 the type of the first template partial specialization
+///
+/// \param T2 if IsMoreSpecialThanPrimaryCheck is true, the type of the second
+/// template partial specialization; otherwise, the type of the
+/// primary template.
+///
+/// \param P1 the first template partial specialization
+///
+/// \param P2 if IsMoreSpecialThanPrimaryCheck is true, the second template
+/// partial specialization; otherwise, the primary template.
+///
+/// \returns - If IsMoreSpecialThanPrimaryCheck is true, returns P1 if P1 is
+/// more specialized, returns nullptr if P1 is not more specialized.
+/// - otherwise, returns the more specialized template partial
+/// specialization. If neither partial specialization is more
+/// specialized, returns NULL.
+template <typename TemplateLikeDecl, typename PrimaryDel>
+static TemplateLikeDecl *
+getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
+ PrimaryDel *P2, TemplateDeductionInfo &Info) {
+ constexpr bool IsMoreSpecialThanPrimaryCheck =
+ !std::is_same_v<TemplateLikeDecl, PrimaryDel>;
+
+ bool Better1 = isAtLeastAsSpecializedAs(S, T1, T2, P2, Info);
+ if (IsMoreSpecialThanPrimaryCheck && !Better1)
+ return nullptr;
+
+ bool Better2 = isAtLeastAsSpecializedAs(S, T2, T1, P1, Info);
+ if (IsMoreSpecialThanPrimaryCheck && !Better2)
+ return P1;
+
+ // C++ [temp.deduct.partial]p10:
+ // F is more specialized than G if F is at least as specialized as G and G
+ // is not at least as specialized as F.
+ if (Better1 != Better2) // We have a clear winner
+ return Better1 ? P1 : GetP2()(P1, P2);
+
+ if (!Better1 && !Better2)
+ return nullptr;
+
+ // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+ // there is no wording or even resolution for this issue.
+ auto *TST1 = cast<TemplateSpecializationType>(T1);
+ auto *TST2 = cast<TemplateSpecializationType>(T2);
+ const TemplateArgument &TA1 = TST1->template_arguments().back();
+ if (TA1.getKind() == TemplateArgument::Pack) {
+ assert(TST1->template_arguments().size() ==
+ TST2->template_arguments().size());
+ const TemplateArgument &TA2 = TST2->template_arguments().back();
+ assert(TA2.getKind() == TemplateArgument::Pack);
+ unsigned PackSize1 = TA1.pack_size();
+ unsigned PackSize2 = TA2.pack_size();
+ bool IsPackExpansion1 =
+ PackSize1 && TA1.pack_elements().back().isPackExpansion();
+ bool IsPackExpansion2 =
+ PackSize2 && TA2.pack_elements().back().isPackExpansion();
+ if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
+ if (PackSize1 > PackSize2 && IsPackExpansion1)
+ return GetP2()(P1, P2);
+ if (PackSize1 < PackSize2 && IsPackExpansion2)
+ return P1;
+ }
+ }
+
+ if (!S.Context.getLangOpts().CPlusPlus20)
+ return nullptr;
+
+ // Match GCC on not implementing [temp.func.order]p6.2.1.
+
+ // C++20 [temp.func.order]p6:
+ // If deduction against the other template succeeds for both transformed
+ // templates, constraints can be considered as follows:
+
+ TemplateParameterList *TPL1 = P1->getTemplateParameters();
+ TemplateParameterList *TPL2 = P2->getTemplateParameters();
+ if (TPL1->size() != TPL2->size())
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.2.2:
+ // Otherwise, if the corresponding template-parameters of the
+ // template-parameter-lists are not equivalent ([temp.over.link]) or if the
+ // 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))
+ return nullptr;
+
+ if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2))
+ return nullptr;
+
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ P1->getAssociatedConstraints(AC1);
+ P2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (S.IsAtLeastAsConstrained(P1, AC1, P2, AC2, AtLeastAsConstrained1) ||
+ (IsMoreSpecialThanPrimaryCheck && !AtLeastAsConstrained1))
+ return nullptr;
+ if (S.IsAtLeastAsConstrained(P2, AC2, P1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? P1 : GetP2()(P1, P2);
+}
+
/// Returns the more specialized class template partial specialization
/// according to the rules of partial ordering of class template partial
/// specializations (C++ [temp.class.order]).
@@ -5385,26 +5680,7 @@ Sema::getMoreSpecializedPartialSpecialization(
QualType PT2 = PS2->getInjectedSpecializationType();
TemplateDeductionInfo Info(Loc);
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
-
- if (!Better1 && !Better2)
- return nullptr;
- if (Better1 && Better2) {
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- PS1->getAssociatedConstraints(AC1);
- PS2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? PS1 : PS2;
- }
-
- return Better1 ? PS1 : PS2;
+ return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
}
bool Sema::isMoreSpecializedThanPrimary(
@@ -5412,24 +5688,12 @@ bool Sema::isMoreSpecializedThanPrimary(
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
QualType PartialT = Spec->getInjectedSpecializationType();
- if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
- return false;
- if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
- return true;
- Info.clearSFINAEDiagnostic();
- llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
- Primary->getAssociatedConstraints(PrimaryAC);
- Spec->getAssociatedConstraints(SpecAC);
- bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
- if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
- AtLeastAsConstrainedSpec))
- return false;
- if (!AtLeastAsConstrainedSpec)
- return false;
- if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
- AtLeastAsConstrainedPrimary))
- return false;
- return !AtLeastAsConstrainedPrimary;
+
+ ClassTemplatePartialSpecializationDecl *MaybeSpec =
+ getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
+ if (MaybeSpec)
+ Info.clearSFINAEDiagnostic();
+ return MaybeSpec;
}
VarTemplatePartialSpecializationDecl *
@@ -5449,62 +5713,24 @@ Sema::getMoreSpecializedPartialSpecialization(
CanonTemplate, PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc);
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
-
- if (!Better1 && !Better2)
- return nullptr;
- if (Better1 && Better2) {
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- PS1->getAssociatedConstraints(AC1);
- PS2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? PS1 : PS2;
- }
-
- return Better1 ? PS1 : PS2;
+ return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
}
bool Sema::isMoreSpecializedThanPrimary(
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
- TemplateDecl *Primary = Spec->getSpecializedTemplate();
- // FIXME: Cache the injected template arguments rather than recomputing
- // them for each partial specialization.
- SmallVector<TemplateArgument, 8> PrimaryArgs;
- Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
- PrimaryArgs);
-
+ VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName CanonTemplate =
Context.getCanonicalTemplateName(TemplateName(Primary));
QualType PrimaryT = Context.getTemplateSpecializationType(
- CanonTemplate, PrimaryArgs);
+ CanonTemplate, Primary->getInjectedTemplateArgs());
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
- if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
- return false;
- if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
- return true;
- Info.clearSFINAEDiagnostic();
- llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
- Primary->getAssociatedConstraints(PrimaryAC);
- Spec->getAssociatedConstraints(SpecAC);
- bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
- if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
- AtLeastAsConstrainedSpec))
- return false;
- if (!AtLeastAsConstrainedSpec)
- return false;
- if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
- AtLeastAsConstrainedPrimary))
- return false;
- return !AtLeastAsConstrainedPrimary;
+ VarTemplatePartialSpecializationDecl *MaybeSpec =
+ getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
+ if (MaybeSpec)
+ Info.clearSFINAEDiagnostic();
+ return MaybeSpec;
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
@@ -5556,13 +5782,15 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// C++1z [temp.arg.template]p3:
// If the rewrite produces an invalid type, then P is not at least as
// specialized as A.
- if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) ||
+ SmallVector<TemplateArgument, 4> SugaredPArgs;
+ if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs,
+ PArgs) ||
Trap.hasErrorOccurred())
return false;
}
- QualType AType = Context.getTemplateSpecializationType(X, AArgs);
- QualType PType = Context.getTemplateSpecializationType(X, PArgs);
+ QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs);
+ QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs);
// ... the function template corresponding to P is at least as specialized
// as the function template corresponding to A according to the partial
@@ -5588,8 +5816,8 @@ struct MarkUsedTemplateParameterVisitor :
}
bool TraverseTemplateName(TemplateName Template) {
- if (auto *TTP =
- dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl()))
+ if (auto *TTP = llvm::dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Template.getAsTemplateDecl()))
if (TTP->getDepth() == Depth)
Used[TTP->getIndex()] = true;
RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
@@ -5734,7 +5962,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -5834,9 +6062,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::SubstTemplateTypeParmPack: {
const SubstTemplateTypeParmPackType *Subst
= cast<SubstTemplateTypeParmPackType>(T);
- MarkUsedTemplateParameters(Ctx,
- QualType(Subst->getReplacedParameter(), 0),
- OnlyDeduced, Depth, Used);
+ if (Subst->getReplacedParameter()->getDepth() == Depth)
+ Used[Subst->getIndex()] = true;
MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
OnlyDeduced, Depth, Used);
break;
@@ -5844,7 +6071,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::InjectedClassName:
T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
@@ -5860,9 +6087,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
hasPackExpansionBeforeEnd(Spec->template_arguments()))
break;
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
- Used);
+ for (const auto &Arg : Spec->template_arguments())
+ MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break;
}
@@ -5906,16 +6132,14 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
OnlyDeduced, Depth, Used);
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
- Used);
+ for (const auto &Arg : Spec->template_arguments())
+ MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break;
}
case Type::TypeOf:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(Ctx,
- cast<TypeOfType>(T)->getUnderlyingType(),
+ MarkUsedTemplateParameters(Ctx, cast<TypeOfType>(T)->getUnmodifiedType(),
OnlyDeduced, Depth, Used);
break;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f09b3473c074..2790e78aa53a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,10 +15,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
@@ -26,12 +28,15 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -40,13 +45,231 @@ using namespace sema;
// Template Instantiation Support
//===----------------------------------------------------------------------===/
+namespace {
+namespace TemplateInstArgsHelpers {
+struct Response {
+ const Decl *NextDecl = nullptr;
+ bool IsDone = false;
+ bool ClearRelativeToPrimary = true;
+ static Response Done() {
+ Response R;
+ R.IsDone = true;
+ return R;
+ }
+ static Response ChangeDecl(const Decl *ND) {
+ Response R;
+ R.NextDecl = ND;
+ return R;
+ }
+ static Response ChangeDecl(const DeclContext *Ctx) {
+ Response R;
+ R.NextDecl = Decl::castFromDeclContext(Ctx);
+ return R;
+ }
+
+ static Response UseNextDecl(const Decl *CurDecl) {
+ return ChangeDecl(CurDecl->getDeclContext());
+ }
+
+ static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
+ Response R = Response::UseNextDecl(CurDecl);
+ R.ClearRelativeToPrimary = false;
+ return R;
+ }
+};
+// Add template arguments from a variable template instantiation.
+Response
+HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ // For a class-scope explicit specialization, there are no template arguments
+ // at this level, but there may be enclosing template arguments.
+ if (VarTemplSpec->isClassScopeExplicitSpecialization())
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+
+ // We're done when we hit an explicit specialization.
+ if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
+ return Response::Done();
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Partial->isMemberSpecialization())
+ return Response::Done();
+ } else {
+ VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Tmpl->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
+
+// If we have a template template parameter with translation unit context,
+// then we're performing substitution into a default template argument of
+// this template template parameter before we've constructed the template
+// that will own this template template parameter. In this case, we
+// use empty template parameter lists for all of the outer templates
+// to avoid performing any substitutions.
+Response
+HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
+ MultiLevelTemplateArgumentList &Result) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(std::nullopt);
+ return Response::Done();
+}
+
+// Add template arguments from a class template instantiation.
+Response
+HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
+ // We're done when we hit an explicit specialization.
+ if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
+ return Response::Done();
+
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
+ ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
+ if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::UseNextDecl(ClassTemplSpec);
+}
+
+Response HandleFunction(const FunctionDecl *Function,
+ MultiLevelTemplateArgumentList &Result,
+ const FunctionDecl *Pattern, bool RelativeToPrimary,
+ bool ForConstraintInstantiation) {
+ // Add template arguments from a function template specialization.
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
+ return Response::Done();
+
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ // This is an implicit instantiation of an explicit specialization. We
+ // don't get any template arguments from this function but might get
+ // some from an enclosing template.
+ return Response::UseNextDecl(Function);
+ } else if (const TemplateArgumentList *TemplateArgs =
+ Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
+ TemplateArgs->asArray(),
+ /*Final=*/false);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ return Response::Done();
+
+ // If this function is a generic lambda specialization, we are done.
+ if (!ForConstraintInstantiation &&
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+ return Response::Done();
+
+ } else if (Function->getDescribedFunctionTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ }
+ // If this is a friend or local declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
+ if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
+ Function->getNonTransparentDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
+ }
+ return Response::UseNextDecl(Function);
+}
+
+Response HandleRecordDecl(const CXXRecordDecl *Rec,
+ MultiLevelTemplateArgumentList &Result,
+ ASTContext &Context,
+ bool ForConstraintInstantiation) {
+ if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "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);
+ Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
+ InjectedType->template_arguments(),
+ /*Final=*/false);
+ }
+ }
+
+ bool IsFriend = Rec->getFriendObjectKind() ||
+ (Rec->getDescribedClassTemplate() &&
+ Rec->getDescribedClassTemplate()->getFriendObjectKind());
+ if (ForConstraintInstantiation && IsFriend &&
+ Rec->getNonTransparentDeclContext()->isFileContext()) {
+ return Response::ChangeDecl(Rec->getLexicalDeclContext());
+ }
+
+ // This is to make sure we pick up the VarTemplateSpecializationDecl that this
+ // lambda is defined inside of.
+ if (Rec->isLambda())
+ if (const Decl *LCD = Rec->getLambdaContextDecl())
+ return Response::ChangeDecl(LCD);
+
+ return Response::UseNextDecl(Rec);
+}
+
+Response HandleImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD,
+ MultiLevelTemplateArgumentList &Result) {
+ Result.addOuterTemplateArguments(
+ const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+ CSD->getTemplateArguments(),
+ /*Final=*/false);
+ return Response::UseNextDecl(CSD);
+}
+
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+ return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
+} // namespace
+
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
-/// \param D the declaration for which we are computing template instantiation
+/// \param ND the declaration for which we are computing template instantiation
/// arguments.
///
-/// \param Innermost if non-NULL, the innermost template argument list.
+/// \param Innermost if non-NULL, specifies a template argument list for the
+/// template declaration passed as ND.
///
/// \param RelativeToPrimary true if we should get the template
/// arguments relative to the primary template, even when we're
@@ -54,137 +277,64 @@ using namespace sema;
/// template specializations.
///
/// \param Pattern If non-NULL, indicates the pattern from which we will be
-/// instantiating the definition of the given declaration, \p D. This is
+/// instantiating the definition of the given declaration, \p ND. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
+///
+/// \param ForConstraintInstantiation when collecting arguments,
+/// ForConstraintInstantiation indicates we should continue looking when
+/// encountering a lambda generic call operator, and continue looking for
+/// arguments on an enclosing class template.
+
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
- const NamedDecl *D, const TemplateArgumentList *Innermost,
- bool RelativeToPrimary, const FunctionDecl *Pattern) {
+ const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary, const FunctionDecl *Pattern,
+ bool ForConstraintInstantiation, bool SkipForSpecialization) {
+ assert(ND && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
if (Innermost)
- Result.addOuterTemplateArguments(Innermost);
-
- const auto *Ctx = dyn_cast<DeclContext>(D);
- if (!Ctx) {
- Ctx = D->getDeclContext();
-
- // Add template arguments from a variable template instantiation. For a
- // class-scope explicit specialization, there are no template arguments
- // at this level, but there may be enclosing template arguments.
- const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<VarTemplatePartialSpecializationDecl>(Spec))
- return Result;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this variable template specialization was instantiated from a
- // specialized member that is a variable template, we're done.
- assert(Spec->getSpecializedTemplate() && "No variable template?");
- llvm::PointerUnion<VarTemplateDecl*,
- VarTemplatePartialSpecializationDecl*> Specialized
- = Spec->getSpecializedTemplateOrPartial();
- if (VarTemplatePartialSpecializationDecl *Partial =
- Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- if (Partial->isMemberSpecialization())
- return Result;
- } else {
- VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
- if (Tmpl->isMemberSpecialization())
- return Result;
- }
- }
-
- // If we have a template template parameter with translation unit context,
- // then we're performing substitution into a default template argument of
- // this template template parameter before we've constructed the template
- // that will own this template template parameter. In this case, we
- // use empty template parameter lists for all of the outer templates
- // to avoid performing any substitutions.
- if (Ctx->isTranslationUnit()) {
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
- for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
- Result.addOuterTemplateArguments(None);
- return Result;
- }
- }
- }
-
- while (!Ctx->isFileContext()) {
- // Add template arguments from a class template instantiation.
- const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<ClassTemplatePartialSpecializationDecl>(Spec))
- break;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this class template specialization was instantiated from a
- // specialized member that is a class template, we're done.
- assert(Spec->getSpecializedTemplate() && "No class template?");
- if (Spec->getSpecializedTemplate()->isMemberSpecialization())
- break;
- }
- // Add template arguments from a function template specialization.
- else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) {
- if (!RelativeToPrimary &&
- Function->getTemplateSpecializationKindForInstantiation() ==
- TSK_ExplicitSpecialization)
- break;
-
- if (!RelativeToPrimary && Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization) {
- // This is an implicit instantiation of an explicit specialization. We
- // don't get any template arguments from this function but might get
- // some from an enclosing template.
- } else if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs()) {
- // Add the template arguments for this specialization.
- Result.addOuterTemplateArguments(TemplateArgs);
-
- // If this function was instantiated from a specialized member that is
- // a function template, we're done.
- assert(Function->getPrimaryTemplate() && "No function template?");
- if (Function->getPrimaryTemplate()->isMemberSpecialization())
- break;
-
- // If this function is a generic lambda specialization, we are done.
- if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
- break;
-
- } else if (Function->getDescribedFunctionTemplate()) {
- assert(Result.getNumSubstitutedLevels() == 0 &&
- "Outer template not instantiated?");
- }
-
- // If this is a friend declaration and it declares an entity at
- // namespace scope, take arguments from its lexical parent
- // instead of its semantic parent, unless of course the pattern we're
- // instantiating actually comes from the file's context!
- if (Function->getFriendObjectKind() &&
- Function->getDeclContext()->isFileContext() &&
- (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
- Ctx = Function->getLexicalDeclContext();
- RelativeToPrimary = false;
- continue;
- }
- } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
- if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
- assert(Result.getNumSubstitutedLevels() == 0 &&
- "Outer template not instantiated?");
- if (ClassTemplate->isMemberSpecialization())
- break;
+ Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
+ Innermost->asArray(), Final);
+
+ const Decl *CurDecl = ND;
+
+ 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 *ClassTemplSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleClassTemplateSpec(ClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
+ R = HandleFunction(Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation);
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
+ R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation);
+ } else if (const auto *CSD =
+ dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
+ R = HandleImplicitConceptSpecializationDecl(CSD, Result);
+ } else if (!isa<DeclContext>(CurDecl)) {
+ R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
+ if (CurDecl->getDeclContext()->isTranslationUnit()) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+ R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+ }
}
+ } else {
+ R = HandleGenericDeclContext(CurDecl);
}
- Ctx = Ctx->getParent();
- RelativeToPrimary = false;
+ if (R.IsDone)
+ return Result;
+ if (R.ClearRelativeToPrimary)
+ RelativeToPrimary = false;
+ assert(R.NextDecl);
+ CurDecl = R.NextDecl;
}
return Result;
@@ -204,6 +354,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
return true;
case RequirementInstantiation:
+ case RequirementParameterInstantiation:
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DeclaringImplicitEqualityComparison:
@@ -377,8 +528,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::RequirementInstantiation,
PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
- /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {}
-
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) {
+}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -387,8 +538,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck,
PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
- /*Template=*/nullptr, /*TemplateArgs=*/None) {}
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::RequirementParameterInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) {
+}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -424,6 +583,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ParameterMappingSubstitution,
PointOfInstantiation, InstantiationRange, Template) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -593,7 +753,7 @@ void Sema::PrintInstantiationStack() {
TemplateDecl *Template = cast<TemplateDecl>(Active->Template);
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- Template->printName(OS);
+ Template->printName(OS, getPrintingPolicy());
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
@@ -659,7 +819,7 @@ void Sema::PrintInstantiationStack() {
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- FD->printName(OS);
+ FD->printName(OS, getPrintingPolicy());
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
@@ -729,6 +889,11 @@ void Sema::PrintInstantiationStack() {
diag::note_template_requirement_instantiation_here)
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::RequirementParameterInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_requirement_params_instantiation_here)
+ << Active->InstantiationRange;
+ break;
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
Diags.Report(Active->PointOfInstantiation,
@@ -790,8 +955,7 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation,
diag::note_building_builtin_dump_struct_call)
<< convertCallArgsToString(
- *this,
- llvm::makeArrayRef(Active->CallArgs, Active->NumCallArgs));
+ *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
break;
case CodeSynthesisContext::Memoization:
@@ -819,7 +983,7 @@ void Sema::PrintInstantiationStack() {
}
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- cast<NamedDecl>(Active->Entity)->printName(OS);
+ cast<NamedDecl>(Active->Entity)->printName(OS, getPrintingPolicy());
if (!isa<FunctionDecl>(Active->Entity)) {
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
@@ -848,9 +1012,9 @@ void Sema::PrintInstantiationStack() {
}
}
-Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
+std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
- return Optional<TemplateDeductionInfo *>(nullptr);
+ return std::optional<TemplateDeductionInfo *>(nullptr);
for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
Active = CodeSynthesisContexts.rbegin(),
@@ -864,7 +1028,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// context, depending on what else is on the stack.
if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
case CodeSynthesisContext::ConstraintsCheck:
@@ -872,7 +1036,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ConstraintNormalization:
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
- return None;
+ return std::nullopt;
case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
@@ -887,6 +1051,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
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.
@@ -901,7 +1066,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
- return None;
+ return std::nullopt;
case CodeSynthesisContext::ExceptionSpecEvaluation:
// FIXME: This should not be treated as a SFINAE context, because
@@ -916,10 +1081,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// The inner context was transparent for SFINAE. If it occurred within a
// non-instantiation SFINAE context, then SFINAE applies.
if (Active->SavedInNonInstantiationSFINAEContext)
- return Optional<TemplateDeductionInfo *>(nullptr);
+ return std::optional<TemplateDeductionInfo *>(nullptr);
}
- return None;
+ return std::nullopt;
}
//===----------------------------------------------------------------------===/
@@ -930,16 +1095,23 @@ namespace {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
+ bool EvaluateConstraints = true;
public:
typedef TreeTransform<TemplateInstantiator> inherited;
TemplateInstantiator(Sema &SemaRef,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- Entity(Entity) { }
+ SourceLocation Loc, DeclarationName Entity)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity) {}
+
+ void setEvaluateConstraints(bool B) {
+ EvaluateConstraints = B;
+ }
+ bool getEvaluateConstraints() {
+ return EvaluateConstraints;
+ }
/// Determine whether the given type \p T has already been
/// transformed.
@@ -965,11 +1137,18 @@ namespace {
return TemplateArgs.getNewDepth(Depth);
}
+ std::optional<unsigned> getPackIndex(TemplateArgument Pack) {
+ int Index = getSema().ArgumentPackSubstitutionIndex;
+ if (Index == -1)
+ return std::nullopt;
+ return Pack.pack_size() - 1 - Index;
+ }
+
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand, bool &RetainExpansion,
- Optional<unsigned> &NumExpansions) {
+ std::optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
TemplateArgs,
@@ -1052,7 +1231,7 @@ 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))
+ if (auto *DC = dyn_cast<DeclContext>(Old); DC && DC->isDependentContext())
SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
}
@@ -1128,30 +1307,79 @@ namespace {
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec);
- ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack);
+ ParmVarDecl *
+ TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
+ using inherited::TransformTemplateTypeParmType;
/// Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL);
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime);
+
+ QualType BuildSubstTemplateTypeParmType(
+ TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
+ Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex,
+ TemplateArgument Arg, SourceLocation NameLoc);
/// Transforms an already-substituted template type parameter pack
/// into either itself (if we aren't substituting into its pack expansion)
/// or the appropriate substituted argument.
- QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
- SubstTemplateTypeParmPackTypeLoc TL);
+ using inherited::TransformSubstTemplateTypeParmPackType;
+ QualType
+ TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+ SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime);
ExprResult TransformLambdaExpr(LambdaExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformLambdaExpr(E);
+ Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+ ExprResult Result = inherited::TransformLambdaExpr(E);
+ if (Result.isInvalid())
+ return Result;
+
+ CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator();
+ for (ParmVarDecl *PVD : MD->parameters()) {
+ if (!PVD->hasDefaultArg())
+ continue;
+ Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+ // FIXME: Obtain the source location for the '=' token.
+ SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+ if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ PVD->setDefaultArg(ErrorResult.get());
+ }
+ }
+
+ return Result;
}
ExprResult TransformRequiresExpr(RequiresExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformRequiresExpr(E);
+ ExprResult TransReq = inherited::TransformRequiresExpr(E);
+ if (TransReq.isInvalid())
+ return TransReq;
+ assert(TransReq.get() != E &&
+ "Do not change value of isSatisfied for the existing expression. "
+ "Create a new expression instead.");
+ if (E->getBody()->isDependentContext()) {
+ Sema::SFINAETrap Trap(SemaRef);
+ // We recreate the RequiresExpr body, but not by instantiating it.
+ // Produce pending diagnostics for dependent access check.
+ SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+ // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
+ if (Trap.hasErrorOccurred())
+ TransReq.getAs<RequiresExpr>()->setSatisfied(false);
+ }
+ return TransReq;
}
bool TransformRequiresExprRequirements(
@@ -1191,6 +1419,7 @@ namespace {
DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
TemplateDeclInstantiator DeclInstantiator(getSema(),
/* DeclContext *Owner */ Owner, TemplateArgs);
+ DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
@@ -1200,11 +1429,19 @@ namespace {
TransformExprRequirement(concepts::ExprRequirement *Req);
concepts::NestedRequirement *
TransformNestedRequirement(concepts::NestedRequirement *Req);
+ ExprResult TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos);
private:
- ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
- SourceLocation loc,
- TemplateArgument arg);
+ ExprResult
+ transformNonTypeTemplateParmRef(Decl *AssociatedDecl,
+ const NonTypeTemplateParmDecl *parm,
+ SourceLocation loc, TemplateArgument arg,
+ std::optional<unsigned> PackIndex);
};
}
@@ -1394,6 +1631,9 @@ TemplateName TemplateInstantiator::TransformTemplateName(
return Arg.getAsTemplate();
}
+ auto [AssociatedDecl, Final] =
+ TemplateArgs.getAssociatedDecl(TTP->getDepth());
+ std::optional<unsigned> PackIndex;
if (TTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1402,9 +1642,11 @@ TemplateName TemplateInstantiator::TransformTemplateName(
// We have the template argument pack to substitute, but we're not
// actually expanding the enclosing pack expansion yet. So, just
// keep the entire argument pack.
- return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg);
+ return getSema().Context.getSubstTemplateTemplateParmPack(
+ Arg, AssociatedDecl, TTP->getIndex(), Final);
}
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
@@ -1413,8 +1655,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
assert(!Template.getAsQualifiedTemplateName() &&
"template decl to substitute is qualified?");
- Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
- return Template;
+ if (Final)
+ return Template;
+ return getSema().Context.getSubstTemplateTemplateParm(
+ Template, AssociatedDecl, TTP->getIndex(), PackIndex);
}
}
@@ -1423,9 +1667,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(
if (getSema().ArgumentPackSubstitutionIndex == -1)
return Name;
- TemplateArgument Arg = SubstPack->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return Arg.getAsTemplate().getNameToSubstitute();
+ TemplateArgument Pack = SubstPack->getArgumentPack();
+ TemplateName Template =
+ getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate();
+ if (SubstPack->getFinal())
+ return Template;
+ return getSema().Context.getSubstTemplateTemplateParm(
+ Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(),
+ SubstPack->getIndex(), getPackIndex(Pack));
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -1469,6 +1718,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return Arg.getAsExpr();
}
+ auto [AssociatedDecl, _] = TemplateArgs.getAssociatedDecl(NTTP->getDepth());
+ std::optional<unsigned> PackIndex;
if (NTTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1486,16 +1737,17 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
QualType ExprType = TargetType.getNonLValueExprType(SemaRef.Context);
if (TargetType->isRecordType())
ExprType.addConst();
-
+ // FIXME: Pass in Final.
return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr(
ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue,
- NTTP, E->getLocation(), Arg);
+ E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition());
}
-
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
-
- return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
+ // FIXME: Don't put subst node on Final replacement.
+ return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(),
+ Arg, PackIndex);
}
const LoopHintAttr *
@@ -1516,9 +1768,9 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
- NonTypeTemplateParmDecl *parm,
- SourceLocation loc,
- TemplateArgument arg) {
+ Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm,
+ SourceLocation loc, TemplateArgument arg,
+ std::optional<unsigned> PackIndex) {
ExprResult result;
// Determine the substituted parameter type. We can usually infer this from
@@ -1586,9 +1838,10 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
return ExprError();
Expr *resultExpr = result.get();
+ // FIXME: Don't put subst node on final replacement.
return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
- resultExpr->getType(), resultExpr->getValueKind(), loc, parm, refParam,
- resultExpr);
+ resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr,
+ AssociatedDecl, parm->getIndex(), PackIndex, refParam);
}
ExprResult
@@ -1599,11 +1852,12 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
return E;
}
- TemplateArgument Arg = E->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return transformNonTypeTemplateParmRef(E->getParameterPack(),
- E->getParameterPackLocation(),
- Arg);
+ TemplateArgument Pack = E->getArgumentPack();
+ TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ // FIXME: Don't put subst node on final replacement.
+ return transformNonTypeTemplateParmRef(
+ E->getAssociatedDecl(), E->getParameterPack(),
+ E->getParameterPackLocation(), Arg, getPackIndex(Pack));
}
ExprResult
@@ -1637,13 +1891,16 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
// Type=char)),
// Type=decltype(2)))
// The call to CheckTemplateArgument here produces the ImpCast.
- TemplateArgument Converted;
- if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType,
- SubstReplacement.get(),
- Converted).isInvalid())
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ if (SemaRef
+ .CheckTemplateArgument(E->getParameter(), SubstType,
+ SubstReplacement.get(), SugaredConverted,
+ CanonicalConverted, Sema::CTAK_Specified)
+ .isInvalid())
return true;
- return transformNonTypeTemplateParmRef(E->getParameter(),
- E->getExprLoc(), Converted);
+ return transformNonTypeTemplateParmRef(E->getAssociatedDecl(),
+ E->getParameter(), E->getExprLoc(),
+ SugaredConverted, E->getPackIndex());
}
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
@@ -1744,9 +2001,9 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
- return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(),
- cast<FunctionDecl>(E->getParam()->getDeclContext()),
- E->getParam());
+ return SemaRef.BuildCXXDefaultArgExpr(
+ E->getUsedLocation(), cast<FunctionDecl>(E->getParam()->getDeclContext()),
+ E->getParam());
}
template<typename Fn>
@@ -1761,22 +2018,50 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
}
-ParmVarDecl *
-TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
- auto NewParm =
- SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
- NumExpansions, ExpectParameterPack);
+ParmVarDecl *TemplateInstantiator::TransformFunctionTypeParam(
+ ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions, bool ExpectParameterPack) {
+ auto NewParm = SemaRef.SubstParmVarDecl(
+ OldParm, TemplateArgs, indexAdjustment, NumExpansions,
+ ExpectParameterPack, EvaluateConstraints);
if (NewParm && SemaRef.getLangOpts().OpenCL)
SemaRef.deduceOpenCLAddressSpace(NewParm);
return NewParm;
}
+QualType TemplateInstantiator::BuildSubstTemplateTypeParmType(
+ TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
+ Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex,
+ TemplateArgument Arg, SourceLocation NameLoc) {
+ QualType Replacement = Arg.getAsType();
+
+ // If the template parameter had ObjC lifetime qualifiers,
+ // then any such qualifiers on the replacement type are ignored.
+ if (SuppressObjCLifetime) {
+ Qualifiers RQs;
+ RQs = Replacement.getQualifiers();
+ RQs.removeObjCLifetime();
+ Replacement =
+ SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), RQs);
+ }
+
+ if (Final) {
+ TLB.pushTrivial(SemaRef.Context, Replacement, NameLoc);
+ return Replacement;
+ }
+ // TODO: only do this uniquing once, at the start of instantiation.
+ QualType Result = getSema().Context.getSubstTemplateTypeParmType(
+ Replacement, AssociatedDecl, Index, PackIndex);
+ SubstTemplateTypeParmTypeLoc NewTL =
+ TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(NameLoc);
+ return Result;
+}
+
QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL) {
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime) {
const TemplateTypeParmType *T = TL.getTypePtr();
if (T->getDepth() < TemplateArgs.getNumLevels()) {
// Replace the template type parameter with its corresponding
@@ -1813,6 +2098,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return NewT;
}
+ auto [AssociatedDecl, Final] =
+ TemplateArgs.getAssociatedDecl(T->getDepth());
+ std::optional<unsigned> PackIndex;
if (T->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1821,29 +2109,25 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// We have the template argument pack, but we're not expanding the
// enclosing pack expansion yet. Just save the template argument
// pack for later substitution.
- QualType Result
- = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg);
+ QualType Result = getSema().Context.getSubstTemplateTypeParmPackType(
+ AssociatedDecl, T->getIndex(), Final, Arg);
SubstTemplateTypeParmPackTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
+ // PackIndex starts from last element.
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
assert(Arg.getKind() == TemplateArgument::Type &&
"Template argument kind mismatch");
- QualType Replacement = Arg.getAsType();
-
- // TODO: only do this uniquing once, at the start of instantiation.
- QualType Result
- = getSema().Context.getSubstTemplateTypeParmType(T, Replacement);
- SubstTemplateTypeParmTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
+ return BuildSubstTemplateTypeParmType(TLB, SuppressObjCLifetime, Final,
+ AssociatedDecl, T->getIndex(),
+ PackIndex, Arg, TL.getNameLoc());
}
// The template type parameter comes from an inner template (e.g.,
@@ -1853,8 +2137,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmDecl *NewTTPDecl = nullptr;
if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
- TransformDecl(TL.getNameLoc(), OldTTPDecl));
-
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
QualType Result = getSema().Context.getTemplateTypeParmType(
T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
T->isParameterPack(), NewTTPDecl);
@@ -1863,29 +2146,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
-QualType
-TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
- TypeLocBuilder &TLB,
- SubstTemplateTypeParmPackTypeLoc TL) {
+QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
+ TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime) {
+ const SubstTemplateTypeParmPackType *T = TL.getTypePtr();
+
+ Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getAssociatedDecl());
+
if (getSema().ArgumentPackSubstitutionIndex == -1) {
// We aren't expanding the parameter pack, so just return ourselves.
- SubstTemplateTypeParmPackTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType());
+ QualType Result = TL.getType();
+ if (NewReplaced != T->getAssociatedDecl())
+ Result = getSema().Context.getSubstTemplateTypeParmPackType(
+ NewReplaced, T->getIndex(), T->getFinal(), T->getArgumentPack());
+ SubstTemplateTypeParmPackTypeLoc NewTL =
+ TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
- return TL.getType();
+ return Result;
}
- TemplateArgument Arg = TL.getTypePtr()->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- QualType Result = Arg.getAsType();
-
- Result = getSema().Context.getSubstTemplateTypeParmType(
- TL.getTypePtr()->getReplacedParameter(),
- Result);
- SubstTemplateTypeParmTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
+ TemplateArgument Pack = T->getArgumentPack();
+ TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ return BuildSubstTemplateTypeParmType(
+ TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(),
+ getPackIndex(Pack), Arg, TL.getNameLoc());
}
template<typename EntityPrinter>
@@ -1914,6 +2198,37 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
StringRef(MessageBuf, Message.size())};
}
+ExprResult TemplateInstantiator::TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+
+ TemplateDeductionInfo Info(KWLoc);
+ Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc,
+ RE, Info,
+ SourceRange{KWLoc, RBraceLoc});
+ Sema::SFINAETrap Trap(SemaRef);
+
+ unsigned ErrorIdx;
+ if (getDerived().TransformFunctionTypeParams(
+ KWLoc, Params, /*ParamTypes=*/nullptr, /*ParamInfos=*/nullptr, PTypes,
+ &TransParams, PInfos, &ErrorIdx) ||
+ Trap.hasErrorOccurred()) {
+ SmallVector<concepts::Requirement *, 4> TransReqs;
+ ParmVarDecl *FailedDecl = Params[ErrorIdx];
+ // Add a 'failed' Requirement to contain the error that caused the failure
+ // here.
+ TransReqs.push_back(RebuildTypeRequirement(createSubstDiag(
+ SemaRef, Info, [&](llvm::raw_ostream &OS) { OS << *FailedDecl; })));
+ return getDerived().RebuildRequiresExpr(KWLoc, Body, TransParams, TransReqs,
+ RBraceLoc);
+ }
+
+ return ExprResult{};
+}
+
concepts::TypeRequirement *
TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) {
if (!Req->isDependent() && !AlwaysRebuild())
@@ -1971,7 +2286,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
TransExpr = TransExprRes.get();
}
- llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
const auto &RetReq = Req->getReturnTypeRequirement();
if (RetReq.isEmpty())
TransRetReq.emplace();
@@ -1985,8 +2300,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
Req, Info, OrigTPL->getSourceRange());
if (TPLInst.isInvalid())
return nullptr;
- TemplateParameterList *TPL =
- TransformTemplateParameterList(OrigTPL);
+ TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
if (!TPL)
TransRetReq.emplace(createSubstDiag(SemaRef, Info,
[&] (llvm::raw_ostream& OS) {
@@ -2012,10 +2326,10 @@ TemplateInstantiator::TransformNestedRequirement(
concepts::NestedRequirement *Req) {
if (!Req->isDependent() && !AlwaysRebuild())
return Req;
- if (Req->isSubstitutionFailure()) {
+ if (Req->hasInvalidConstraint()) {
if (AlwaysRebuild())
- return RebuildNestedRequirement(
- Req->getSubstitutionDiagnostic());
+ return RebuildNestedRequirement(Req->getInvalidConstraintEntity(),
+ Req->getConstraintSatisfaction());
return Req;
}
Sema::InstantiatingTemplate ReqInst(SemaRef,
@@ -2035,36 +2349,30 @@ TemplateInstantiator::TransformNestedRequirement(
Req->getConstraintExpr()->getSourceRange());
if (ConstrInst.isInvalid())
return nullptr;
- TransConstraint = TransformExpr(Req->getConstraintExpr());
- if (!TransConstraint.isInvalid()) {
- bool CheckSucceeded =
- SemaRef.CheckConstraintExpression(TransConstraint.get());
- (void)CheckSucceeded;
- assert((CheckSucceeded || Trap.hasErrorOccurred()) &&
- "CheckConstraintExpression failed, but "
- "did not produce a SFINAE error");
- }
- // Use version of CheckConstraintSatisfaction that does no substitutions.
- if (!TransConstraint.isInvalid() &&
- !TransConstraint.get()->isInstantiationDependent() &&
- !Trap.hasErrorOccurred()) {
- bool CheckFailed = SemaRef.CheckConstraintSatisfaction(
- TransConstraint.get(), Satisfaction);
- (void)CheckFailed;
- assert((!CheckFailed || Trap.hasErrorOccurred()) &&
- "CheckConstraintSatisfaction failed, "
- "but did not produce a SFINAE error");
- }
- if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
- return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
- [&] (llvm::raw_ostream& OS) {
- Req->getConstraintExpr()->printPretty(OS, nullptr,
- SemaRef.getPrintingPolicy());
- }));
+ llvm::SmallVector<Expr *> Result;
+ if (!SemaRef.CheckConstraintSatisfaction(
+ nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs,
+ Req->getConstraintExpr()->getSourceRange(), Satisfaction) &&
+ !Result.empty())
+ TransConstraint = Result[0];
+ assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
+ "by CheckConstraintSatisfaction.");
}
- if (TransConstraint.get()->isInstantiationDependent())
+ if (TransConstraint.isUsable() &&
+ TransConstraint.get()->isInstantiationDependent())
return new (SemaRef.Context)
concepts::NestedRequirement(TransConstraint.get());
+ if (TransConstraint.isInvalid() || !TransConstraint.get() ||
+ Satisfaction.HasSubstitutionFailure()) {
+ SmallString<128> Entity;
+ llvm::raw_svector_ostream OS(Entity);
+ Req->getConstraintExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ char *EntityBuf = new (SemaRef.Context) char[Entity.size()];
+ std::copy(Entity.begin(), Entity.end(), EntityBuf);
+ return new (SemaRef.Context) concepts::NestedRequirement(
+ SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction);
+ }
return new (SemaRef.Context) concepts::NestedRequirement(
SemaRef.Context, TransConstraint.get(), Satisfaction);
}
@@ -2196,7 +2504,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
SourceLocation Loc,
DeclarationName Entity,
CXXRecordDecl *ThisContext,
- Qualifiers ThisTypeQuals) {
+ Qualifiers ThisTypeQuals,
+ bool EvaluateConstraints) {
assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -2205,6 +2514,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+ Instantiator.setEvaluateConstraints(EvaluateConstraints);
TypeLocBuilder TLB;
@@ -2349,9 +2659,19 @@ namespace {
bool Sema::SubstTypeConstraint(
TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool EvaluateConstraints) {
const ASTTemplateArgumentListInfo *TemplArgInfo =
TC->getTemplateArgsAsWritten();
+
+ if (!EvaluateConstraints) {
+ Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
+ TC->getConceptNameInfo(), TC->getNamedConcept(),
+ TC->getNamedConcept(), TemplArgInfo,
+ TC->getImmediatelyDeclaredConstraint());
+ return false;
+ }
+
TemplateArgumentListInfo InstArgs;
if (TemplArgInfo) {
@@ -2370,11 +2690,10 @@ bool Sema::SubstTypeConstraint(
: SourceLocation());
}
-ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+ParmVarDecl *Sema::SubstParmVarDecl(
+ ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment, std::optional<unsigned> NumExpansions,
+ bool ExpectParameterPack, bool EvaluateConstraint) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = nullptr;
@@ -2432,9 +2751,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// template's described function, but we might also get here later.
// Make sure we do not instantiate the TypeConstraint more than once.
if (Inst && !Inst->getTypeConstraint()) {
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- if (SubstTypeConstraint(Inst, TC, TemplateArgs))
+ if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint))
return nullptr;
}
}
@@ -2457,29 +2774,17 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setUnparsedDefaultArg();
UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
} else if (Expr *Arg = OldParm->getDefaultArg()) {
- FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
- if (OwningFunc->isInLocalScopeForInstantiation()) {
- // Instantiate default arguments for methods of local classes (DR1484)
- // and non-defining declarations.
- Sema::ContextRAII SavedContext(*this, OwningFunc);
- LocalInstantiationScope Local(*this, true);
- ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
- if (NewArg.isUsable()) {
- // It would be nice if we still had this.
- SourceLocation EqualLoc = NewArg.get()->getBeginLoc();
- ExprResult Result =
- ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc);
- if (Result.isInvalid())
- return nullptr;
-
- SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc);
- }
- } else {
- // FIXME: if we non-lazily instantiated non-dependent default args for
- // non-dependent parameter types we could remove a bunch of duplicate
- // conversion warnings for such arguments.
- NewParm->setUninstantiatedDefaultArg(Arg);
- }
+ // Default arguments cannot be substituted until the declaration context
+ // for the associated function or lambda capture class is available.
+ // This is necessary for cases like the following where construction of
+ // the lambda capture class for the outer lambda is dependent on the
+ // parameter types but where the default argument is dependent on the
+ // outer lambda's declaration context.
+ // template <typename T>
+ // auto f() {
+ // return [](T = []{ return T{}; }()) { return 0; };
+ // }
+ NewParm->setUninstantiatedDefaultArg(Arg);
}
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
@@ -2524,6 +2829,88 @@ bool Sema::SubstParmTypes(
Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos);
}
+/// Substitute the given template arguments into the default argument.
+bool Sema::SubstDefaultArgument(
+ SourceLocation Loc,
+ ParmVarDecl *Param,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool ForCallExpr) {
+ FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
+ Expr *PatternExpr = Param->getUninstantiatedDefaultArg();
+
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+
+ InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost());
+ if (Inst.isInvalid())
+ return true;
+ if (Inst.isAlreadyInstantiating()) {
+ Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+ Param->setInvalidDecl();
+ return true;
+ }
+
+ ExprResult Result;
+ {
+ // C++ [dcl.fct.default]p5:
+ // The names in the [default argument] expression are bound, and
+ // the semantic constraints are checked, at the point where the
+ // default argument expression appears.
+ ContextRAII SavedContext(*this, FD);
+ std::unique_ptr<LocalInstantiationScope> LIS;
+
+ if (ForCallExpr) {
+ // When instantiating a default argument due to use in a call expression,
+ // an instantiation scope that includes the parameters of the callee is
+ // required to satisfy references from the default argument. For example:
+ // template<typename T> void f(T a, int = decltype(a)());
+ // void g() { f(0); }
+ LIS = std::make_unique<LocalInstantiationScope>(*this);
+ FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern(
+ /*ForDefinition*/ false);
+ if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
+ return true;
+ }
+
+ runWithSufficientStackSpace(Loc, [&] {
+ Result = SubstInitializer(PatternExpr, TemplateArgs,
+ /*DirectInit*/false);
+ });
+ }
+ if (Result.isInvalid())
+ return true;
+
+ if (ForCallExpr) {
+ // Check the expression as an initializer for the parameter.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context, Param);
+ InitializationKind Kind = InitializationKind::CreateCopy(
+ Param->getLocation(),
+ /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc());
+ Expr *ResultE = Result.getAs<Expr>();
+
+ InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
+ Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
+ if (Result.isInvalid())
+ return true;
+
+ Result =
+ ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
+ /*DiscardedValue*/ false);
+ } else {
+ // FIXME: Obtain the source location for the '=' token.
+ SourceLocation EqualLoc = PatternExpr->getBeginLoc();
+ Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc);
+ }
+ if (Result.isInvalid())
+ return true;
+
+ // Remember the instantiated default argument.
+ Param->setDefaultArg(Result.getAs<Expr>());
+
+ return false;
+}
+
/// Perform substitution on the base class specifiers of the
/// given class template specialization.
///
@@ -2556,7 +2943,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(),
Base.getSourceRange(),
Unexpanded,
@@ -2743,6 +3130,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiation->setInvalidDecl();
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
+ Instantiator.setEvaluateConstraints(false);
SmallVector<Decl*, 4> Fields;
// Delay instantiation of late parsed attributes.
LateInstantiatedAttrVec LateAttrs;
@@ -3033,6 +3421,8 @@ bool Sema::InstantiateInClassInitializer(
ContextRAII SavedContext(*this, Instantiation->getParent());
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprEvalContexts.back().DelayedDefaultInitializationContext = {
+ PointOfInstantiation, Instantiation, CurContext};
LocalInstantiationScope Scope(*this, true);
@@ -3130,7 +3520,7 @@ getPatternForClassTemplateSpecialization(
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
- Matched.back().Args = Info.take();
+ Matched.back().Args = Info.takeCanonical();
}
}
@@ -3521,11 +3911,9 @@ bool Sema::SubstTemplateArguments(
ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Out) {
- TemplateInstantiator Instantiator(*this, TemplateArgs,
- SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
DeclarationName());
- return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
- Out);
+ return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
}
ExprResult
@@ -3539,11 +3927,23 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
+ExprResult
+Sema::SubstConstraintExpr(Expr *E,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!E)
+ return E;
+
+ // This is where we need to make sure we 'know' constraint checking needs to
+ // happen.
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformExpr(E);
+}
+
ExprResult Sema::SubstInitializer(Expr *Init,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool CXXDirectInit) {
- TemplateInstantiator Instantiator(*this, TemplateArgs,
- SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
DeclarationName());
return Instantiator.TransformInitializer(Init, CXXDirectInit);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9bf6ca1f8084..7a0da8d08333 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
@@ -120,7 +121,7 @@ static void instantiateDependentAlignedAttr(
// Determine whether we can expand this attribute pack yet.
bool Expand = true, RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
// FIXME: Use the actual location of the ellipsis.
SourceLocation EllipsisLoc = Aligned->getLocation();
if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
@@ -461,7 +462,7 @@ static void instantiateOMPDeclareVariantAttr(
// Check function/variant ref for `omp declare variant` but not for `omp
// begin declare variant` (which use implicit attributes).
- Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI,
Attr.appendArgs_size(),
Attr.getRange());
@@ -469,8 +470,8 @@ static void instantiateOMPDeclareVariantAttr(
if (!DeclVarData)
return;
- E = DeclVarData.value().second;
- FD = DeclVarData.value().first;
+ E = DeclVarData->second;
+ FD = DeclVarData->first;
if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) {
@@ -506,7 +507,7 @@ static void instantiateOMPDeclareVariantAttr(
SmallVector<Expr *, 8> NothingExprs;
SmallVector<Expr *, 8> NeedDevicePtrExprs;
- SmallVector<OMPDeclareVariantAttr::InteropType, 8> AppendArgs;
+ SmallVector<OMPInteropInfo, 4> AppendArgs;
for (Expr *E : Attr.adjustArgsNothing()) {
ExprResult ER = Subst(E);
@@ -520,7 +521,10 @@ static void instantiateOMPDeclareVariantAttr(
continue;
NeedDevicePtrExprs.push_back(ER.get());
}
- llvm::append_range(AppendArgs, Attr.appendArgs());
+ for (OMPInteropInfo &II : Attr.appendArgs()) {
+ // When prefer_type is implemented for append_args handle them here too.
+ AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync);
+ }
S.ActOnOpenMPDeclareVariantDirective(
FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(),
@@ -633,7 +637,7 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
FD->getReturnType()->isLValueReferenceType()) {
return false;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
// HACK: Super-old versions of libc++ (3.1 and earlier) provide
@@ -873,6 +877,10 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units cannot be instantiated");
}
+Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) {
+ llvm_unreachable("HLSL buffer declarations cannot be instantiated");
+}
+
Decl *
TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
llvm_unreachable("pragma comment cannot be instantiated");
@@ -1172,6 +1180,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
if (Var->isStaticLocal())
SemaRef.CheckStaticLocalForDllExport(Var);
+ if (Var->getTLSKind())
+ SemaRef.CheckThreadLocalForLargeAlignment(Var);
+
return Var;
}
@@ -1628,12 +1639,16 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
if (PrevClassTemplate) {
- TemplateParameterList *PrevParams
- = PrevClassTemplate->getMostRecentDecl()->getTemplateParameters();
+ const ClassTemplateDecl *MostRecentPrevCT =
+ PrevClassTemplate->getMostRecentDecl();
+ TemplateParameterList *PrevParams =
+ MostRecentPrevCT->getTemplateParameters();
// Make sure the parameter lists match.
- if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, true,
- Sema::TPL_TemplateMatch))
+ if (!SemaRef.TemplateParameterListsAreEqual(
+ D->getTemplatedDecl(), InstParams,
+ MostRecentPrevCT->getTemplatedDecl(), PrevParams, true,
+ Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
@@ -1823,6 +1838,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// merged with the local instantiation scope for the function template
// itself.
LocalInstantiationScope Scope(SemaRef);
+ Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -1991,7 +2007,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves three purposes:
/// 1) instantiating function templates
-/// 2) substituting friend declarations
+/// 2) substituting friend and local function declarations
/// 3) substituting deduction guide declarations for nested class templates
Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionDecl *D, TemplateParameterList *TemplateParams,
@@ -2062,19 +2078,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
}
- // FIXME: Concepts: Do not substitute into constraint expressions
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
- if (TrailingRequiresClause) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
- TemplateArgs);
- if (SubstRC.isInvalid())
- return nullptr;
- TrailingRequiresClause = SubstRC.get();
- if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
- return nullptr;
- }
// If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated
@@ -2114,6 +2118,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
TrailingRequiresClause);
+ Function->setFriendConstraintRefersToEnclosingTemplate(
+ D->FriendConstraintRefersToEnclosingTemplate());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -2131,6 +2137,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
assert(D->getDeclContext()->isFileContext());
LexicalDC = D->getDeclContext();
}
+ else if (D->isLocalExternDecl()) {
+ LexicalDC = SemaRef.CurContext;
+ }
Function->setLexicalDeclContext(LexicalDC);
@@ -2260,7 +2269,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
+ // tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
@@ -2268,9 +2277,42 @@ 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.
- SemaRef.FilterLookupForScope(Previous, DC, /*Scope*/ nullptr,
- /*ConsiderLinkage*/ true,
- QualifierLoc.hasQualifier());
+ if (isFriend && !QualifierLoc && !FunctionTemplate) {
+ SemaRef.FilterLookupForScope(Previous, DC, /*Scope=*/ nullptr,
+ /*ConsiderLinkage=*/ true,
+ QualifierLoc.hasQualifier());
+ }
+ }
+
+ // Per [temp.inst], default arguments in function declarations at local scope
+ // are instantiated along with the enclosing declaration. For example:
+ //
+ // template<typename T>
+ // void ft() {
+ // void f(int = []{ return T::value; }());
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::' because it has no members
+ //
+ // The error is issued during instantiation of ft<int>() because substitution
+ // into the default argument fails; the default argument is instantiated even
+ // though it is never used.
+ if (Function->isLocalExternDecl()) {
+ for (ParmVarDecl *PVD : Function->parameters()) {
+ if (!PVD->hasDefaultArg())
+ continue;
+ if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ PVD->setDefaultArg(ErrorResult.get());
+ }
+ }
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
@@ -2331,7 +2373,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
- Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs,
+ std::optional<const ASTTemplateArgumentListInfo *>
+ ClassScopeSpecializationArgs,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
@@ -2425,23 +2468,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
- // FIXME: Concepts: Do not substitute into constraint expressions
- Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
- if (TrailingRequiresClause) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
- Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
- D->getMethodQualifiers(), ThisContext);
- ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
- TemplateArgs);
- if (SubstRC.isInvalid())
- return nullptr;
- TrailingRequiresClause = SubstRC.get();
- if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
- return nullptr;
- }
-
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
@@ -2459,6 +2485,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
@@ -2466,7 +2495,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
// Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
@@ -2478,6 +2506,9 @@ 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,
@@ -2500,6 +2531,8 @@ 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())
@@ -2551,7 +2584,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (NumTempParamLists)
Method->setTemplateParameterListsInfo(
SemaRef.Context,
- llvm::makeArrayRef(TempParamLists.data(), NumTempParamLists));
+ llvm::ArrayRef(TempParamLists.data(), NumTempParamLists));
Method->setLexicalDeclContext(Owner);
Method->setObjectOfFriendDecl();
@@ -2630,12 +2663,45 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
+ // tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
}
+ // Per [temp.inst], default arguments in member functions of local classes
+ // are instantiated along with the member function declaration. For example:
+ //
+ // template<typename T>
+ // void ft() {
+ // struct lc {
+ // int operator()(int p = []{ return T::value; }());
+ // };
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::'because it has no members
+ //
+ // The error is issued during instantiation of ft<int>()::lc::operator()
+ // because substitution into the default argument fails; the default argument
+ // is instantiated even though it is never used.
+ if (D->isInLocalScopeForInstantiation()) {
+ for (unsigned P = 0; P < Params.size(); ++P) {
+ if (!Params[P]->hasDefaultArg())
+ continue;
+ if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg();
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ Params[P]->setDefaultArg(ErrorResult.get());
+ }
+ }
+ }
+
SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
IsExplicitSpecialization,
Method->isThisDeclarationADefinition());
@@ -2723,15 +2789,16 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None,
- /*ExpectParameterPack=*/ false);
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
+ std::nullopt,
+ /*ExpectParameterPack=*/false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
TemplateTypeParmDecl *D) {
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- Optional<unsigned> NumExpanded;
+ std::optional<unsigned> NumExpanded;
if (const TypeConstraint *TC = D->getTypeConstraint()) {
if (D->isPackExpansion() && !D->isExpandedParameterPack()) {
@@ -2771,13 +2838,11 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
if (!D->isImplicit()) {
- // Invented template parameter type constraints will be instantiated with
- // the corresponding auto-typed parameter as it might reference other
- // parameters.
-
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
+ // Invented template parameter type constraints will be instantiated
+ // with the corresponding auto-typed parameter as it might reference
+ // other parameters.
+ if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs,
+ EvaluateConstraints))
return nullptr;
}
}
@@ -2844,9 +2909,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions
- = Expansion.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions =
+ Expansion.getTypePtr()->getNumExpansions();
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded,
@@ -3009,7 +3074,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
@@ -3235,9 +3300,11 @@ Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) {
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
return nullptr;
+ TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
UsingEnumDecl *NewUD =
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
- D->getEnumLoc(), D->getLocation(), EnumD);
+ D->getEnumLoc(), D->getLocation(), TSI);
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
@@ -3278,7 +3345,7 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
Expand, RetainExpansion, NumExpansions))
@@ -3617,9 +3684,10 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(),
OldC->getEndLoc());
OMPClause *NewC = SemaRef.ActOnOpenMPMapClause(
- OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS,
- NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(),
- OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs);
+ OldC->getIteratorModifier(), OldC->getMapTypeModifiers(),
+ OldC->getMapTypeModifiersLoc(), SS, NewNameInfo, OldC->getMapType(),
+ OldC->isImplicitMapType(), OldC->getMapLoc(), OldC->getColonLoc(),
+ NewVars, Locs);
Clauses.push_back(NewC);
}
SemaRef.EndOpenMPDSABlock(nullptr);
@@ -3691,12 +3759,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(InstClassTemplate,
- D->getLocation(),
- InstTemplateArgs,
- false,
- Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(),
+ InstTemplateArgs, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return nullptr;
@@ -3704,7 +3770,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// in the member template's set of class template explicit specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl =
- InstClassTemplate->findSpecialization(Converted, InsertPos);
+ InstClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
@@ -3742,7 +3808,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *InstD =
ClassTemplateSpecializationDecl::Create(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
- D->getLocation(), InstClassTemplate, Converted, PrevDecl);
+ D->getLocation(), InstClassTemplate, CanonicalConverted, PrevDecl);
// Add this partial specialization to the set of class template partial
// specializations.
@@ -3756,7 +3822,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Build the canonical type that describes the converted template
// arguments of the class template explicit specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(InstClassTemplate), Converted,
+ TemplateName(InstClassTemplate), CanonicalConverted,
SemaRef.Context.getRecordType(InstD));
// Build the fully-sugared type for this class template
@@ -3818,16 +3884,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
}
// Check that the template argument list is well-formed for this template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
- VarTemplateArgsInfo, false, Converted,
+ VarTemplateArgsInfo, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- InstVarTemplate->findSpecialization(Converted, InsertPos);
+ InstVarTemplate->findSpecialization(CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
@@ -3839,7 +3906,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
return nullptr;
return VisitVarTemplateSpecializationDecl(
- InstVarTemplate, D, VarTemplateArgsInfo, Converted, PrevDecl);
+ InstVarTemplate, D, VarTemplateArgsInfo, CanonicalConverted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
@@ -3904,6 +3971,11 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
+Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ llvm_unreachable("Concept specializations cannot reside inside a template");
+}
+
Decl *
TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
@@ -3975,7 +4047,7 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
Decl *R;
if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
R = Instantiator.VisitCXXMethodDecl(
- MD, nullptr, None,
+ MD, nullptr, std::nullopt,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
} else {
assert(Spaceship->getFriendObjectKind() &&
@@ -4021,18 +4093,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- // FIXME: Concepts: Substitution into requires clause should only happen when
- // checking satisfaction.
- Expr *InstRequiresClause = nullptr;
- if (Expr *E = L->getRequiresClause()) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
- if (Res.isInvalid() || !Res.isUsable()) {
- return nullptr;
- }
- InstRequiresClause = Res.get();
- }
+ Expr *InstRequiresClause = L->getRequiresClause();
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
@@ -4043,8 +4104,10 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
TemplateParameterList *
Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool EvaluateConstraints) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
+ Instantiator.setEvaluateConstraints(EvaluateConstraints);
return Instantiator.SubstTemplateParams(Params);
}
@@ -4087,32 +4150,29 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
- PartialSpec->getLocation(),
- InstTemplateArgs,
- false,
- Converted))
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(
+ ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs,
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(),
- Converted))
+ CanonicalConverted))
return nullptr;
// Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted, InstParams,
+ ClassTemplateSpecializationDecl *PrevDecl =
+ ClassTemplate->findPartialSpecialization(CanonicalConverted, InstParams,
InsertPos);
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
- QualType CanonType
- = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
- Converted);
+ QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(ClassTemplate), CanonicalConverted);
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
@@ -4157,7 +4217,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
- ClassTemplate, Converted, InstTemplateArgs, CanonType, nullptr);
+ ClassTemplate, CanonicalConverted, InstTemplateArgs, CanonType,
+ nullptr);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
@@ -4214,27 +4275,29 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
- InstTemplateArgs, false, Converted))
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(
+ VarTemplate, PartialSpec->getLocation(), InstTemplateArgs,
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(),
- Converted))
+ CanonicalConverted))
return nullptr;
// Figure out where to insert this variable template partial specialization
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos);
+ VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams,
+ InsertPos);
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(VarTemplate), Converted);
+ TemplateName(VarTemplate), CanonicalConverted);
// Build the fully-sugared type for this variable template
// specialization as the user wrote in the specialization
@@ -4290,7 +4353,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
- DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs);
+ DI, PartialSpec->getStorageClass(), CanonicalConverted,
+ InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -4326,11 +4390,9 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
ThisTypeQuals = Method->getMethodQualifiers();
}
- TypeSourceInfo *NewTInfo
- = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName(),
- ThisContext, ThisTypeQuals);
+ TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(
+ OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(),
+ ThisContext, ThisTypeQuals, EvaluateConstraints);
if (!NewTInfo)
return nullptr;
@@ -4349,7 +4411,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
- Optional<unsigned> NumArgumentsInExpansion;
+ std::optional<unsigned> NumArgumentsInExpansion;
if (OldParam->isParameterPack())
NumArgumentsInExpansion =
SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
@@ -4451,7 +4513,7 @@ bool Sema::addInstantiatedParametersToScope(
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- Optional<unsigned> NumArgumentsInExpansion =
+ std::optional<unsigned> NumArgumentsInExpansion =
getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
if (NumArgumentsInExpansion) {
QualType PatternType =
@@ -4481,10 +4543,6 @@ bool Sema::addInstantiatedParametersToScope(
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());
- Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
-
- EnterExpressionEvaluationContext EvalContext(
- *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
// Instantiate the expression.
//
@@ -4503,62 +4561,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs
- = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, /*Final=*/false, nullptr, /*RelativeToPrimary=*/true);
- InstantiatingTemplate Inst(*this, CallLoc, Param,
- TemplateArgs.getInnermost());
- if (Inst.isInvalid())
+ if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
- if (Inst.isAlreadyInstantiating()) {
- Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
- Param->setInvalidDecl();
- return true;
- }
- ExprResult Result;
- {
- // C++ [dcl.fct.default]p5:
- // The names in the [default argument] expression are bound, and
- // the semantic constraints are checked, at the point where the
- // default argument expression appears.
- ContextRAII SavedContext(*this, FD);
- LocalInstantiationScope Local(*this);
-
- FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
- /*ForDefinition*/ false);
- if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs))
- return true;
-
- runWithSufficientStackSpace(CallLoc, [&] {
- Result = SubstInitializer(UninstExpr, TemplateArgs,
- /*DirectInit*/false);
- });
- }
- if (Result.isInvalid())
- return true;
-
- // Check the expression as an initializer for the parameter.
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(Context, Param);
- InitializationKind Kind = InitializationKind::CreateCopy(
- Param->getLocation(),
- /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc());
- Expr *ResultE = Result.getAs<Expr>();
-
- InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
- Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
- if (Result.isInvalid())
- return true;
-
- Result =
- ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
- /*DiscardedValue*/ false);
- if (Result.isInvalid())
- return true;
-
- // Remember the instantiated default argument.
- Param->setDefaultArg(Result.getAs<Expr>());
if (ASTMutationListener *L = getASTMutationListener())
L->DefaultArgumentInstantiated(Param);
@@ -4592,8 +4600,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ Decl, /*Final=*/false, nullptr, /*RelativeToPrimary*/ true);
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
@@ -4767,7 +4775,8 @@ Sema::InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
return nullptr;
ContextRAII SavedContext(*this, FD);
- MultiLevelTemplateArgumentList MArgs(*Args);
+ MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
+ /*Final=*/false);
return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
}
@@ -5033,8 +5042,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ Function, /*Final=*/false, nullptr, false, PatternDecl);
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
@@ -5103,8 +5112,7 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
const TemplateArgumentList &TemplateArgList,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
- SourceLocation PointOfInstantiation,
- LateInstantiatedAttrVec *LateAttrs,
+ SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
if (FromVar->isInvalidDecl())
return nullptr;
@@ -5113,9 +5121,6 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
if (Inst.isInvalid())
return nullptr;
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
-
// Instantiate the first declaration of the variable template: for a partial
// specialization of a static data member template, the first declaration may
// or may not be the declaration in the class; if it's in the class, we want
@@ -5126,15 +5131,21 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
// partial specialization, don't do this. The member specialization completely
// replaces the original declaration in this case.
bool IsMemberSpec = false;
- if (VarTemplatePartialSpecializationDecl *PartialSpec =
- dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar))
+ MultiLevelTemplateArgumentList MultiLevelList;
+ if (auto *PartialSpec =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) {
IsMemberSpec = PartialSpec->isMemberSpecialization();
- else if (VarTemplateDecl *FromTemplate = FromVar->getDescribedVarTemplate())
- IsMemberSpec = FromTemplate->isMemberSpecialization();
+ MultiLevelList.addOuterTemplateArguments(
+ PartialSpec, TemplateArgList.asArray(), /*Final=*/false);
+ } else {
+ assert(VarTemplate == FromVar->getDescribedVarTemplate());
+ IsMemberSpec = VarTemplate->isMemberSpecialization();
+ MultiLevelList.addOuterTemplateArguments(
+ VarTemplate, TemplateArgList.asArray(), /*Final=*/false);
+ }
if (!IsMemberSpec)
FromVar = FromVar->getFirstDecl();
- MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList);
TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
MultiLevelList);
@@ -5633,7 +5644,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
collectUnexpandedParameterPacks(Init->getInit(), Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded,
@@ -6147,7 +6158,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// Move to the outer template scope.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
- if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
+ if (FD->getFriendObjectKind() &&
+ FD->getNonTransparentDeclContext()->isFileContext()) {
DC = FD->getLexicalDeclContext();
continue;
}
@@ -6388,7 +6400,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- for (auto DD : Pattern->ddiags()) {
+ for (auto *DD : Pattern->ddiags()) {
switch (DD->getKind()) {
case DependentDiagnostic::Access:
HandleDependentAccessCheck(*DD, TemplateArgs);
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 790792f77b24..01a435668d88 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include <optional>
using namespace clang;
@@ -88,6 +89,23 @@ 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) {
@@ -306,7 +324,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
return TTPD && TTPD->getTypeForDecl() == TTPT;
}
- return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ return declaresSameEntity(Pack.first.get<const NamedDecl *>(),
+ LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
@@ -358,7 +377,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
else
- Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
+ Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier();
if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
@@ -421,7 +440,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<NamedDecl*>()))
+ if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>()))
UnexpandedParms.push_back(Parm);
if (UnexpandedParms.empty())
return false;
@@ -594,7 +613,8 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
if (!TSInfo)
return true;
- TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None);
+ TypeSourceInfo *TSResult =
+ CheckPackExpansion(TSInfo, EllipsisLoc, std::nullopt);
if (!TSResult)
return true;
@@ -603,7 +623,7 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
TypeSourceInfo *
Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
// Create the pack expansion type and source-location information.
QualType Result = CheckPackExpansion(Pattern->getType(),
Pattern->getTypeLoc().getSourceRange(),
@@ -621,7 +641,7 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
// C++11 [temp.variadic]p5:
// The pattern of a pack expansion shall name one or more
// parameter packs that are not expanded by a nested pack
@@ -641,11 +661,11 @@ QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
}
ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
- return CheckPackExpansion(Pattern, EllipsisLoc, None);
+ return CheckPackExpansion(Pattern, EllipsisLoc, std::nullopt);
}
ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
if (!Pattern)
return ExprError();
@@ -669,112 +689,98 @@ bool Sema::CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
- bool &RetainExpansion, Optional<unsigned> &NumExpansions) {
+ bool &RetainExpansion, std::optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
- std::pair<IdentifierInfo *, SourceLocation> FirstPack;
- bool HaveFirstPack = false;
- Optional<unsigned> NumPartialExpansions;
- SourceLocation PartiallySubstitutedPackLoc;
+ std::pair<const IdentifierInfo *, SourceLocation> FirstPack;
+ std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion;
+ std::optional<unsigned> CurNumExpansions;
- for (UnexpandedParameterPack ParmPack : Unexpanded) {
+ for (auto [P, Loc] : Unexpanded) {
// Compute the depth and index for this parameter pack.
- 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.
+ std::optional<std::pair<unsigned, unsigned>> Pos;
unsigned NewPackSize;
- 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 {
+ 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) {
// 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 (Depth >= TemplateArgs.getNumLevels() ||
- !TemplateArgs.hasTemplateArgument(Depth, Index)) {
+ if (Pos->first >= TemplateArgs.getNumLevels() ||
+ !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) {
ShouldExpand = false;
continue;
}
-
// Determine the size of the argument pack.
- 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) {
+ 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) {
RetainExpansion = true;
// We don't actually know the new pack size yet.
- NumPartialExpansions = NewPackSize;
- PartiallySubstitutedPackLoc = ParmPack.second;
+ PartialExpansion = {NewPackSize, Loc};
continue;
}
- }
}
- if (!NumExpansions) {
+ // FIXME: Workaround for Canonical TTP.
+ const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr;
+ if (!CurNumExpansions) {
// The is the first pack we've seen for which we have an argument.
// Record it.
- NumExpansions = NewPackSize;
- FirstPack.first = Name;
- FirstPack.second = ParmPack.second;
- HaveFirstPack = true;
- continue;
- }
-
- if (NewPackSize != *NumExpansions) {
+ CurNumExpansions = NewPackSize;
+ FirstPack = {Name, Loc};
+ } else if (NewPackSize != *CurNumExpansions) {
// C++0x [temp.variadic]p5:
// All of the parameter packs expanded by a pack expansion shall have
// the same number of arguments specified.
- 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);
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
+ << FirstPack.first << Name << *CurNumExpansions << NewPackSize
+ << SourceRange(FirstPack.second) << SourceRange(Loc);
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:
//
@@ -784,70 +790,72 @@ bool Sema::CheckParameterPacksForExpansion(
//
// ... a call to 'A<int, int>().f<int>' should expand the pack once and
// retain an expansion.
- if (NumPartialExpansions) {
- if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
+ if (PartialExpansion) {
+ if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) {
NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack();
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
- << PartialPack << *NumPartialExpansions << *NumExpansions
- << SourceRange(PartiallySubstitutedPackLoc);
+ << PartialPack << PartialExpansion->first << *CurNumExpansions
+ << SourceRange(PartialExpansion->second);
return true;
}
-
- NumExpansions = NumPartialExpansions;
+ NumExpansions = PartialExpansion->first;
+ } else {
+ NumExpansions = CurNumExpansions;
}
return false;
}
-Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+std::optional<unsigned> Sema::getNumArgumentsInExpansion(
+ QualType T, const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
- Optional<unsigned> Result;
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- // Compute the depth and index for this parameter pack.
- unsigned Depth;
- unsigned Index;
+ 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;
+ };
- if (const TemplateTypeParmType *TTP
- = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
+ 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());
} else {
- NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
+ const auto *ND = I.get<const NamedDecl *>();
+ // Function parameter pack or init-capture pack.
if (isa<VarDecl>(ND)) {
- // 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*>())
+ const auto *DAP =
+ CurrentInstantiationScope->findInstantiationOf(ND)
+ ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>();
+ if (!DAP)
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
- return None;
-
- unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
- assert((!Result || *Result == Size) && "inconsistent pack sizes");
- Result = Size;
- continue;
+ return std::nullopt;
+ setResultSz(DAP->size());
+ } else if (setResultPos(getDepthAndIndex(ND))) {
+ return std::nullopt;
}
-
- 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 None;
-
- // 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;
@@ -857,8 +865,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
case TST_typename:
+ case TST_typeof_unqualType:
case TST_typeofType:
- case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case TST_atomic: {
QualType T = DS.getRepAsType().get();
if (!T.isNull() && T->containsUnexpandedParameterPack())
@@ -866,6 +876,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
break;
}
+ case TST_typeof_unqualExpr:
case TST_typeofExpr:
case TST_decltype:
case TST_bitint:
@@ -1049,10 +1060,9 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
RParenLoc);
}
-TemplateArgumentLoc
-Sema::getTemplateArgumentPackExpansionPattern(
- TemplateArgumentLoc OrigLoc,
- SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions) const {
+TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
+ TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis,
+ std::optional<unsigned> &NumExpansions) const {
const TemplateArgument &Argument = OrigLoc.getArgument();
assert(Argument.isPackExpansion());
switch (Argument.getKind()) {
@@ -1109,7 +1119,7 @@ Sema::getTemplateArgumentPackExpansionPattern(
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
+std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
assert(Arg.containsUnexpandedParameterPack());
// If this is a substituted pack, grab that pack. If not, we don't know
@@ -1123,7 +1133,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>())
Pack = Subst->getArgumentPack();
else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Expression:
@@ -1133,10 +1143,10 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
for (VarDecl *PD : *Subst)
if (PD->isParameterPack())
- return None;
+ return std::nullopt;
return Subst->getNumExpansions();
} else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Template:
@@ -1144,7 +1154,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack())
Pack = Subst->getArgumentPack();
else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Declaration:
@@ -1153,7 +1163,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
- return None;
+ return std::nullopt;
}
// Check that no argument in the pack is itself a pack expansion.
@@ -1161,7 +1171,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
// There's no point recursing in this case; we would have already
// expanded this pack expansion into the enclosing pack if we could.
if (Elem.isPackExpansion())
- return None;
+ return std::nullopt;
}
return Pack.pack_size();
}
@@ -1242,7 +1252,7 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
}
return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
- None);
+ std::nullopt);
}
ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
@@ -1250,7 +1260,7 @@ ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return new (Context)
CXXFoldExpr(Context.DependentTy, Callee, LParenLoc, LHS, Operator,
EllipsisLoc, RHS, RParenLoc, NumExpansions);
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3ab5d26a9a75..89d819a77dcb 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -19,9 +19,11 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -33,12 +35,13 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include <bitset>
+#include <optional>
using namespace clang;
@@ -430,7 +433,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
if (onlyBlockPointers)
continue;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::BlockPointer:
result = &ptrChunk;
@@ -759,7 +762,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
- /*DeclsInPrototype=*/None, loc, loc, declarator));
+ /*DeclsInPrototype=*/std::nullopt, loc, loc, declarator));
// For consistency, make sure the state still has us as processing
// the decl spec.
@@ -827,8 +830,8 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator,
/// Apply Objective-C type arguments to the given type.
static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
ArrayRef<TypeSourceInfo *> typeArgs,
- SourceRange typeArgsRange,
- bool failOnError = false) {
+ SourceRange typeArgsRange, bool failOnError,
+ bool rebuilding) {
// We can only apply type arguments to an Objective-C class type.
const auto *objcObjectType = type->getAs<ObjCObjectType>();
if (!objcObjectType || !objcObjectType->getInterface()) {
@@ -892,7 +895,9 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
}
}
- if (!diagnosed) {
+ // When rebuilding, qualifiers might have gotten here through a
+ // final substitution.
+ if (!rebuilding && !diagnosed) {
S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified)
<< typeArg << typeArg.getQualifiers().getAsString()
<< FixItHint::CreateRemoval(rangeToRemove);
@@ -1054,22 +1059,18 @@ QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
return Result;
}
-QualType Sema::BuildObjCObjectType(QualType BaseType,
- SourceLocation Loc,
- SourceLocation TypeArgsLAngleLoc,
- ArrayRef<TypeSourceInfo *> TypeArgs,
- SourceLocation TypeArgsRAngleLoc,
- SourceLocation ProtocolLAngleLoc,
- ArrayRef<ObjCProtocolDecl *> Protocols,
- ArrayRef<SourceLocation> ProtocolLocs,
- SourceLocation ProtocolRAngleLoc,
- bool FailOnError) {
+QualType Sema::BuildObjCObjectType(
+ QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc,
+ bool FailOnError, bool Rebuilding) {
QualType Result = BaseType;
if (!TypeArgs.empty()) {
- Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
- SourceRange(TypeArgsLAngleLoc,
- TypeArgsRAngleLoc),
- FailOnError);
+ Result =
+ applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
+ SourceRange(TypeArgsLAngleLoc, TypeArgsRAngleLoc),
+ FailOnError, Rebuilding);
if (FailOnError && Result.isNull())
return QualType();
}
@@ -1097,11 +1098,10 @@ TypeResult Sema::actOnObjCProtocolQualifierType(
SourceLocation rAngleLoc) {
// Form id<protocol-list>.
QualType Result = Context.getObjCObjectType(
- Context.ObjCBuiltinIdTy, { },
- llvm::makeArrayRef(
- (ObjCProtocolDecl * const *)protocols.data(),
- protocols.size()),
- false);
+ Context.ObjCBuiltinIdTy, {},
+ llvm::ArrayRef((ObjCProtocolDecl *const *)protocols.data(),
+ protocols.size()),
+ false);
Result = Context.getObjCObjectPointerType(Result);
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
@@ -1168,10 +1168,11 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(),
TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc,
ProtocolLAngleLoc,
- llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(),
- Protocols.size()),
+ llvm::ArrayRef((ObjCProtocolDecl *const *)Protocols.data(),
+ Protocols.size()),
ProtocolLocs, ProtocolRAngleLoc,
- /*FailOnError=*/false);
+ /*FailOnError=*/false,
+ /*Rebuilding=*/false);
if (Result == T)
return BaseType;
@@ -1247,6 +1248,18 @@ getImageAccess(const ParsedAttributesView &Attrs) {
return OpenCLAccessAttr::Keyword_read_only;
}
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+ switch (SwitchTST) {
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case TST_##Trait: \
+ return UnaryTransformType::Enum;
+#include "clang/Basic/TransformTypeTraits.def"
+ default:
+ llvm_unreachable("attempted to parse a non-unary transform builtin");
+ }
+}
+
/// Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1369,7 +1382,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclSpec::TST_int: {
if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) {
switch (DS.getTypeSpecWidth()) {
@@ -1575,6 +1588,9 @@ 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
@@ -1596,6 +1612,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// TypeQuals handled by caller.
break;
}
+ case DeclSpec::TST_typeof_unqualType:
case DeclSpec::TST_typeofType:
// FIXME: Preserve type source info.
Result = S.GetTypeFromParser(DS.getRepAsType());
@@ -1604,13 +1621,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (const TagType *TT = Result->getAs<TagType>())
S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc());
// TypeQuals handled by caller.
- Result = Context.getTypeOfType(Result);
+ Result = Context.getTypeOfType(
+ Result, DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType
+ ? TypeOfKind::Unqualified
+ : TypeOfKind::Qualified);
break;
+ case DeclSpec::TST_typeof_unqualExpr:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
assert(E && "Didn't get an expression for typeof?");
// TypeQuals handled by caller.
- Result = S.BuildTypeofExprType(E);
+ Result = S.BuildTypeofExprType(E, DS.getTypeSpecType() ==
+ DeclSpec::TST_typeof_unqualExpr
+ ? TypeOfKind::Unqualified
+ : TypeOfKind::Qualified);
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1628,12 +1652,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
- case DeclSpec::TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
Result = S.GetTypeFromParser(DS.getRepAsType());
- assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
- Result = S.BuildUnaryTransformType(Result,
- UnaryTransformType::EnumUnderlyingType,
- DS.getTypeSpecTypeLoc());
+ assert(!Result.isNull() && "Didn't get a type for the transformation?");
+ Result = S.BuildUnaryTransformType(
+ Result, TSTToUnaryTransformType(DS.getTypeSpecType()),
+ DS.getTypeSpecTypeLoc());
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -2158,7 +2183,7 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
return QualType();
}
@@ -2228,7 +2253,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1;
return QualType();
}
@@ -2379,6 +2404,23 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
return R;
}
+bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) {
+ EltTy = Context.getBaseElementType(EltTy);
+ if (EltTy->isIncompleteType() || EltTy->isDependentType() ||
+ EltTy->isUndeducedType())
+ return true;
+
+ CharUnits Size = Context.getTypeSizeInChars(EltTy);
+ CharUnits Alignment = Context.getTypeAlignInChars(EltTy);
+
+ if (Size.isMultipleOf(Alignment))
+ return true;
+
+ Diag(Loc, diag::err_array_element_alignment)
+ << EltTy << Size.getQuantity() << Alignment.getQuantity();
+ return false;
+}
+
/// Build an array type.
///
/// \param T The type of each element in the array.
@@ -2462,6 +2504,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
+ if (!checkArrayElementAlignment(T, Loc))
+ return QualType();
+
// Do placeholder conversions on the array size expression.
if (ArraySize && ArraySize->hasPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(ArraySize);
@@ -2584,12 +2629,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) {
// CUDA device code and some other targets don't support VLAs.
- targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
- ? diag::err_cuda_vla
- : diag::err_vla_unsupported)
- << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
- ? CurrentCUDATarget()
- : CFT_InvalidTarget);
+ bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice);
+ targetDiag(Loc,
+ IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported)
+ << (IsCUDADevice ? CurrentCUDATarget() : 0);
}
// If this is not C99, diagnose array size modifiers on non-VLAs.
@@ -2621,17 +2664,28 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr,
// can't already be a vector.
if ((!CurType->isDependentType() &&
(!CurType->isBuiltinType() || CurType->isBooleanType() ||
- (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) ||
+ (!CurType->isIntegerType() && !CurType->isRealFloatingType())) &&
+ !CurType->isBitIntType()) ||
CurType->isArrayType()) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType;
return QualType();
}
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ if (CurType->isBitIntType()) {
+ unsigned NumBits = CurType->getAs<BitIntType>()->getNumBits();
+ if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) {
+ Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type)
+ << (NumBits < 8);
+ return QualType();
+ }
+ }
if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent())
return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc,
VectorType::GenericVector);
- Optional<llvm::APSInt> VecSize = SizeExpr->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> VecSize =
+ SizeExpr->getIntegerConstantExpr(Context);
if (!VecSize) {
Diag(AttrLoc, diag::err_attribute_argument_type)
<< "vector_size" << AANT_ArgumentIntegerConstant
@@ -2697,8 +2751,19 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ if (T->isBitIntType()) {
+ unsigned NumBits = T->getAs<BitIntType>()->getNumBits();
+ if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) {
+ Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type)
+ << (NumBits < 8);
+ return QualType();
+ }
+ }
+
if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) {
- Optional<llvm::APSInt> vecSize = ArraySize->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> vecSize =
+ ArraySize->getIntegerConstantExpr(Context);
if (!vecSize) {
Diag(AttrLoc, diag::err_attribute_argument_type)
<< "ext_vector_type" << AANT_ArgumentIntegerConstant
@@ -2744,8 +2809,9 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols,
return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols,
AttrLoc);
- Optional<llvm::APSInt> ValueRows = NumRows->getIntegerConstantExpr(Context);
- Optional<llvm::APSInt> ValueColumns =
+ std::optional<llvm::APSInt> ValueRows =
+ NumRows->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> ValueColumns =
NumCols->getIntegerConstantExpr(Context);
auto const RowRange = NumRows->getSourceRange();
@@ -2810,7 +2876,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
}
// Functions cannot return half FP.
- if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
+ if (T->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns &&
+ !Context.getTargetInfo().allowHalfArgsAndReturns()) {
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 <<
FixItHint::CreateInsertion(Loc, "*");
return true;
@@ -2834,6 +2901,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
if (T.isVolatileQualified() && getLangOpts().CPlusPlus20)
Diag(Loc, diag::warn_deprecated_volatile_return) << T;
+ if (T.getAddressSpace() != LangAS::Default && getLangOpts().HLSL)
+ return true;
return false;
}
@@ -2916,7 +2985,8 @@ QualType Sema::BuildFunctionType(QualType T,
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
- } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
+ } else if (ParamType->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns &&
+ !Context.getTargetInfo().allowHalfArgsAndReturns()) {
// Disallow half FP arguments.
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
FixItHint::CreateInsertion(Loc, "*");
@@ -2992,7 +3062,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
return QualType();
}
@@ -3540,7 +3610,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
!D.getNumTypeObjects() &&
D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::TemplateTypeArg:
Error = 10; // Template type argument
break;
@@ -3565,7 +3635,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
!Auto->isDecltypeAuto())
break; // auto(x)
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::TypeName:
case DeclaratorContext::Association:
Error = 15; // Generic
@@ -3834,7 +3904,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) {
case DeclaratorChunk::Paren:
if (&C == &Paren)
continue;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::Pointer:
StartsWithDeclaratorId = false;
continue;
@@ -4604,7 +4674,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
// Determine whether we should infer _Nonnull on pointer types.
- Optional<NullabilityKind> inferNullability;
+ std::optional<NullabilityKind> inferNullability;
bool inferNullabilityCS = false;
bool inferNullabilityInnerOnly = false;
bool inferNullabilityInnerOnlyComplete = false;
@@ -4637,8 +4707,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
- if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
- !T->getNullability(S.Context)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
+ !T->getNullability()) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@@ -4674,7 +4744,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TrailingReturn:
case DeclaratorContext::TrailingReturnVar:
isFunctionOrMethod = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::Member:
if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) {
@@ -4683,12 +4753,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
// Weak properties are inferred to be nullable.
- if (state.getDeclarator().isObjCWeakProperty() && inAssumeNonNullRegion) {
- inferNullability = NullabilityKind::Nullable;
+ if (state.getDeclarator().isObjCWeakProperty()) {
+ // Weak properties cannot be nonnull, and should not complain about
+ // missing nullable attributes during completeness checks.
+ complainAboutMissingNullability = CAMN_No;
+ if (inAssumeNonNullRegion) {
+ inferNullability = NullabilityKind::Nullable;
+ }
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::File:
case DeclaratorContext::KNRTypeList: {
@@ -4843,7 +4918,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case CAMN_InnerPointers:
if (NumPointersRemaining == 0)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CAMN_Yes:
checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc);
@@ -4854,8 +4929,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
if (S.CodeSynthesisContexts.empty()) {
- if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
- !T->getNullability(S.Context)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
+ !T->getNullability()) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)
@@ -4878,9 +4953,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
- if (complainAboutMissingNullability == CAMN_Yes &&
- T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) &&
- D.isPrototypeContext() &&
+ if (complainAboutMissingNullability == CAMN_Yes && T->isArrayType() &&
+ !T->getNullability() && !isVaList(T) && D.isPrototypeContext() &&
!hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) {
checkNullabilityConsistency(S, SimplePointerKind::Array,
D.getDeclSpec().getTypeSpecTypeLoc());
@@ -5152,7 +5226,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << 0 /*pointer hint*/;
D.setInvalidType(true);
}
- } else if (!S.getLangOpts().HalfArgsAndReturns) {
+ } else if (!S.getLangOpts().NativeHalfArgsAndReturns &&
+ !S.Context.getTargetInfo().allowHalfArgsAndReturns()) {
S.Diag(D.getIdentifierLoc(),
diag::err_parameters_retval_cannot_have_fp16_type) << 1;
D.setInvalidType(true);
@@ -5301,14 +5376,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
- // for this attribute now.
- if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus)
- if (!D.getDeclarationAttributes().hasAttribute(
- ParsedAttr::AT_Overloadable) &&
- !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
- !D.getDeclSpec().getAttributes().hasAttribute(
- ParsedAttr::AT_Overloadable))
+ // for this attribute now. We also allow it in C2x per WG14 N2975.
+ if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) {
+ if (LangOpts.C2x)
+ S.Diag(FTI.getEllipsisLoc(),
+ diag::warn_c17_compat_ellipsis_only_parameter);
+ else if (!D.getDeclarationAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable) &&
+ !D.getAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable) &&
+ !D.getDeclSpec().getAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable))
S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
+ }
if (FTI.NumParams && FTI.Params[0].Param == nullptr) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function
@@ -5384,16 +5464,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType();
Param->setInvalidDecl();
}
- } else if (!S.getLangOpts().HalfArgsAndReturns) {
+ } else if (!S.getLangOpts().NativeHalfArgsAndReturns &&
+ !S.Context.getTargetInfo().allowHalfArgsAndReturns()) {
S.Diag(Param->getLocation(),
diag::err_parameters_retval_cannot_have_fp16_type) << 0;
D.setInvalidType();
}
} else if (!FTI.hasPrototype) {
- if (ParamTy->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(ParamTy)) {
ParamTy = Context.getPromotedIntegerType(ParamTy);
Param->setKNRPromoted(true);
- } else if (const BuiltinType* BTy = ParamTy->getAs<BuiltinType>()) {
+ } else if (const BuiltinType *BTy = ParamTy->getAs<BuiltinType>()) {
if (BTy->getKind() == BuiltinType::Float) {
ParamTy = Context.DoubleTy;
Param->setKNRPromoted(true);
@@ -5538,7 +5619,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// in ClsType; hence we wrap ClsType into an ElaboratedType.
// NOTE: in particular, no wrap occurs if ClsType already is an
// Elaborated, DependentName, or DependentTemplateSpecialization.
- if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType()))
+ if (isa<TemplateSpecializationType>(NNS->getAsType()))
ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
break;
}
@@ -5775,7 +5856,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
} else {
- T = Context.getPackExpansionType(T, None, /*ExpectPackInType=*/false);
+ T = Context.getPackExpansionType(T, std::nullopt,
+ /*ExpectPackInType=*/false);
}
break;
case DeclaratorContext::TemplateParam:
@@ -5788,7 +5870,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// parameter packs in the type of the non-type template parameter, then
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
- T = Context.getPackExpansionType(T, None);
+ T = Context.getPackExpansionType(T, std::nullopt);
else
S.Diag(D.getEllipsisLoc(),
LangOpts.CPlusPlus11
@@ -5974,6 +6056,21 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr()));
}
+static void fillMatrixTypeLoc(MatrixTypeLoc MTL,
+ const ParsedAttributesView &Attrs) {
+ for (const ParsedAttr &AL : Attrs) {
+ if (AL.getKind() == ParsedAttr::AT_MatrixType) {
+ MTL.setAttrNameLoc(AL.getLoc());
+ MTL.setAttrRowOperand(AL.getArgAsExpr(0));
+ MTL.setAttrColumnOperand(AL.getArgAsExpr(1));
+ MTL.setAttrOperandParensRange(SourceRange());
+ return;
+ }
+ }
+
+ llvm_unreachable("no matrix_type attribute found at the expected location!");
+}
+
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
Sema &SemaRef;
@@ -6048,18 +6145,20 @@ namespace {
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualExpr);
TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
}
void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType);
TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- TL.setUnderlyingTInfo(TInfo);
+ TL.setUnmodifiedTInfo(TInfo);
}
void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
@@ -6067,8 +6166,7 @@ namespace {
TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
}
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
- // FIXME: This holds only because we only have one unary transform.
- assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+ assert(DS.isTransformTypeTrait(DS.getTypeSpecType()));
TL.setKWLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
@@ -6090,19 +6188,19 @@ namespace {
}
}
void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- ElaboratedTypeKeyword Keyword
- = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
if (DS.getTypeSpecType() == TST_typename) {
TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- if (TInfo) {
- TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>());
- return;
- }
+ if (TInfo)
+ if (auto ETL = TInfo->getTypeLoc().getAs<ElaboratedTypeLoc>()) {
+ TL.copy(ETL);
+ return;
+ }
}
- TL.setElaboratedKeywordLoc(Keyword != ETK_None
- ? DS.getTypeSpecTypeLoc()
- : SourceLocation());
+ const ElaboratedType *T = TL.getTypePtr();
+ TL.setElaboratedKeywordLoc(T->getKeyword() != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
TL.setQualifierLoc(SS.getWithLocInContext(Context));
Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
@@ -6158,6 +6256,9 @@ 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.
@@ -6339,6 +6440,9 @@ namespace {
VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) {
TL.setNameLoc(Chunk.Loc);
}
+ void VisitMatrixTypeLoc(MatrixTypeLoc TL) {
+ fillMatrixTypeLoc(TL, Chunk.getAttrs());
+ }
void VisitTypeLoc(TypeLoc TL) {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
@@ -6386,21 +6490,6 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
"no address_space attribute found at the expected location!");
}
-static void fillMatrixTypeLoc(MatrixTypeLoc MTL,
- const ParsedAttributesView &Attrs) {
- for (const ParsedAttr &AL : Attrs) {
- if (AL.getKind() == ParsedAttr::AT_MatrixType) {
- MTL.setAttrNameLoc(AL.getLoc());
- MTL.setAttrRowOperand(AL.getArgAsExpr(0));
- MTL.setAttrColumnOperand(AL.getArgAsExpr(1));
- MTL.setAttrOperandParensRange(SourceRange());
- return;
- }
- }
-
- llvm_unreachable("no matrix_type attribute found at the expected location!");
-}
-
/// Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -6432,29 +6521,42 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
}
- while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>()) {
- TL.setExpansionLoc(
- State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- }
+ bool HasDesugaredTypeLoc = true;
+ while (HasDesugaredTypeLoc) {
+ switch (CurrTL.getTypeLocClass()) {
+ case TypeLoc::MacroQualified: {
+ auto TL = CurrTL.castAs<MacroQualifiedTypeLoc>();
+ TL.setExpansionLoc(
+ State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
- fillAttributedTypeLoc(TL, State);
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- }
+ case TypeLoc::Attributed: {
+ auto TL = CurrTL.castAs<AttributedTypeLoc>();
+ fillAttributedTypeLoc(TL, State);
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- while (DependentAddressSpaceTypeLoc TL =
- CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
- fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs());
- CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc();
- }
+ case TypeLoc::Adjusted:
+ case TypeLoc::BTFTagAttributed: {
+ CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>())
- fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs());
+ case TypeLoc::DependentAddressSpace: {
+ auto TL = CurrTL.castAs<DependentAddressSpaceTypeLoc>();
+ fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs());
+ CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- // FIXME: Ordering here?
- while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ default:
+ HasDesugaredTypeLoc = false;
+ break;
+ }
+ }
DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
@@ -6539,7 +6641,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx,
const Expr *AddrSpace,
SourceLocation AttrLoc) {
if (!AddrSpace->isValueDependent()) {
- Optional<llvm::APSInt> OptAddrSpace =
+ std::optional<llvm::APSInt> OptAddrSpace =
AddrSpace->getIntegerConstantExpr(S.Context);
if (!OptAddrSpace) {
S.Diag(AttrLoc, diag::err_attribute_argument_type)
@@ -6707,6 +6809,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
// The keyword-based type attributes imply which address space to use.
ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS()
: Attr.asOpenCLLangAS();
+ if (S.getLangOpts().HLSL)
+ ASIdx = Attr.asHLSLLangAS();
if (ASIdx == LangAS::Default)
llvm_unreachable("Invalid address space");
@@ -7158,17 +7262,25 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
}
std::bitset<attr::LastAttr> Attrs;
- attr::Kind NewAttrKind = A->getKind();
QualType Desugared = Type;
- const AttributedType *AT = dyn_cast<AttributedType>(Type);
- while (AT) {
+ for (;;) {
+ if (const TypedefType *TT = dyn_cast<TypedefType>(Desugared)) {
+ Desugared = TT->desugar();
+ continue;
+ } else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Desugared)) {
+ Desugared = ET->desugar();
+ continue;
+ }
+ const AttributedType *AT = dyn_cast<AttributedType>(Desugared);
+ if (!AT)
+ break;
Attrs[AT->getAttrKind()] = true;
Desugared = AT->getModifiedType();
- AT = dyn_cast<AttributedType>(Desugared);
}
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
+ attr::Kind NewAttrKind = A->getKind();
if (Attrs[NewAttrKind]) {
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
return true;
@@ -7189,14 +7301,11 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
return true;
}
- // Pointer type qualifiers can only operate on pointer types, but not
- // pointer-to-member types.
- //
- // FIXME: Should we really be disallowing this attribute if there is any
- // type sugar between it and the pointer (other than attributes)? Eg, this
- // disallows the attribute on a parenthesized pointer.
- // And if so, should we really allow *any* type attribute?
+ // Check the raw (i.e., desugared) Canonical type to see if it
+ // is a pointer type.
if (!isa<PointerType>(Desugared)) {
+ // Pointer type qualifiers can only operate on pointer types, but not
+ // pointer-to-member types.
if (Type->isMemberPointerType())
S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr;
else
@@ -7206,7 +7315,8 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// Add address space to type based on its attributes.
LangAS ASIdx = LangAS::Default;
- uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ uint64_t PtrWidth =
+ S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
if (PtrWidth == 32) {
if (Attrs[attr::Ptr64])
ASIdx = LangAS::ptr64;
@@ -7300,7 +7410,7 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
// This (unlike the code above) looks through typedefs that might
// have nullability specifiers on them, which means we cannot
// provide a useful Fix-It.
- if (auto existingNullability = desugared->getNullability(S.Context)) {
+ if (auto existingNullability = desugared->getNullability()) {
if (nullability != *existingNullability) {
S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
@@ -7399,7 +7509,7 @@ static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type,
// If we started with an object pointer type, rebuild it.
if (ptrType) {
equivType = S.Context.getObjCObjectPointerType(equivType);
- if (auto nullability = type->getNullability(S.Context)) {
+ if (auto nullability = type->getNullability()) {
// We create a nullability attribute from the __kindof attribute.
// Make sure that will make sense.
assert(attr.getAttributeSpellingListIndex() == 0 &&
@@ -7714,7 +7824,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
case EST_NoexceptTrue:
case EST_NoThrow:
// Exception spec doesn't conflict with nothrow, so don't warn.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_Unparsed:
case EST_Uninstantiated:
case EST_DependentNoexcept:
@@ -7853,7 +7963,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
CallingConv DefaultCC =
Context.getDefaultCallingConvention(IsVariadic, IsStatic);
- if (CurCC != DefaultCC || DefaultCC == ToCC)
+ if (CurCC != DefaultCC)
return;
if (hasExplicitCallingConv(T))
@@ -7960,7 +8070,7 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr,
llvm::APSInt &Result) {
const auto *AttrExpr = Attr.getArgAsExpr(0);
if (!AttrExpr->isTypeDependent()) {
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
AttrExpr->getIntegerConstantExpr(S.Context)) {
Result = *Res;
return true;
@@ -8315,6 +8425,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case ParsedAttr::AT_OpenCLLocalAddressSpace:
case ParsedAttr::AT_OpenCLConstantAddressSpace:
case ParsedAttr::AT_OpenCLGenericAddressSpace:
+ case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
case ParsedAttr::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state);
attr.setUsedAsTypeAttr();
@@ -8443,7 +8554,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// clang, so revert to attribute-based handling for C.
if (!state.getSema().getLangOpts().CPlusPlus)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
@@ -9100,29 +9211,23 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
TagDecl *OwnedTagDecl) {
if (T.isNull())
return T;
- NestedNameSpecifier *NNS;
- if (SS.isValid())
- NNS = SS.getScopeRep();
- else {
- if (Keyword == ETK_None)
- return T;
- NNS = nullptr;
- }
- return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
+ return Context.getElaboratedType(
+ Keyword, SS.isValid() ? SS.getScopeRep() : nullptr, T, OwnedTagDecl);
}
-QualType Sema::BuildTypeofExprType(Expr *E) {
+QualType Sema::BuildTypeofExprType(Expr *E, TypeOfKind Kind) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (!getLangOpts().CPlusPlus && E->refersToBitField())
- Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2;
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield)
+ << (Kind == TypeOfKind::Unqualified ? 3 : 2);
if (!E->isTypeDependent()) {
QualType T = E->getType();
if (const TagType *TT = T->getAs<TagType>())
DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc());
}
- return Context.getTypeOfExprType(E);
+ return Context.getTypeOfExprType(E, Kind);
}
/// getDecltypeForExpr - Given an expr, will return the decltype for
@@ -9207,39 +9312,257 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
return Context.getDecltypeType(E, getDecltypeForExpr(E));
}
-QualType Sema::BuildUnaryTransformType(QualType BaseType,
- UnaryTransformType::UTTKind UKind,
- SourceLocation Loc) {
- switch (UKind) {
- case UnaryTransformType::EnumUnderlyingType:
- if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) {
- Diag(Loc, diag::err_only_enums_have_underlying_types);
- return QualType();
- } else {
- QualType Underlying = BaseType;
- if (!BaseType->isDependentType()) {
- // The enum could be incomplete if we're parsing its definition or
- // recovering from an error.
- NamedDecl *FwdDecl = nullptr;
- if (BaseType->isIncompleteType(&FwdDecl)) {
- Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
- Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
- return QualType();
- }
+static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType,
+ SourceLocation Loc) {
+ assert(BaseType->isEnumeralType());
+ EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
+ assert(ED && "EnumType has no EnumDecl");
- EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
- assert(ED && "EnumType has no EnumDecl");
+ S.DiagnoseUseOfDecl(ED, Loc);
- DiagnoseUseOfDecl(ED, Loc);
+ QualType Underlying = ED->getIntegerType();
+ assert(!Underlying.isNull());
- Underlying = ED->getIntegerType();
- assert(!Underlying.isNull());
- }
- return Context.getUnaryTransformType(BaseType, Underlying,
- UnaryTransformType::EnumUnderlyingType);
+ return Underlying;
+}
+
+QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType,
+ SourceLocation Loc) {
+ if (!BaseType->isEnumeralType()) {
+ Diag(Loc, diag::err_only_enums_have_underlying_types);
+ return QualType();
+ }
+
+ // The enum could be incomplete if we're parsing its definition or
+ // recovering from an error.
+ NamedDecl *FwdDecl = nullptr;
+ if (BaseType->isIncompleteType(&FwdDecl)) {
+ Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
+ Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
+ return QualType();
+ }
+
+ return GetEnumUnderlyingType(*this, BaseType, Loc);
+}
+
+QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) {
+ QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType()
+ ? BuildPointerType(BaseType.getNonReferenceType(), Loc,
+ DeclarationName())
+ : BaseType;
+
+ return Pointer.isNull() ? QualType() : Pointer;
+}
+
+QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) {
+ // We don't want block pointers or ObjectiveC's id type.
+ if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType())
+ return BaseType;
+
+ return BaseType->getPointeeType();
+}
+
+QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) {
+ QualType Underlying = BaseType.getNonReferenceType();
+ if (Underlying->isArrayType())
+ return Context.getDecayedType(Underlying);
+
+ if (Underlying->isFunctionType())
+ return BuiltinAddPointer(BaseType, Loc);
+
+ SplitQualType Split = Underlying.getSplitUnqualifiedType();
+ // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is
+ // in the same group of qualifiers as 'const' and 'volatile', we're extending
+ // '__decay(T)' so that it removes all qualifiers.
+ Split.Quals.removeCVRQualifiers();
+ return Context.getQualifiedType(Split);
+}
+
+QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ assert(LangOpts.CPlusPlus);
+ QualType Reference =
+ BaseType.isReferenceable()
+ ? BuildReferenceType(BaseType,
+ UKind == UnaryTransformType::AddLvalueReference,
+ Loc, DeclarationName())
+ : BaseType;
+ return Reference.isNull() ? QualType() : Reference;
+}
+
+QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if (UKind == UnaryTransformType::RemoveAllExtents)
+ return Context.getBaseElementType(BaseType);
+
+ if (const auto *AT = Context.getAsArrayType(BaseType))
+ return AT->getElementType();
+
+ return BaseType;
+}
+
+QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ assert(LangOpts.CPlusPlus);
+ QualType T = BaseType.getNonReferenceType();
+ if (UKind == UTTKind::RemoveCVRef &&
+ (T.isConstQualified() || T.isVolatileQualified())) {
+ Qualifiers Quals;
+ QualType Unqual = Context.getUnqualifiedArrayType(T, Quals);
+ Quals.removeConst();
+ Quals.removeVolatile();
+ T = Context.getQualifiedType(Unqual, Quals);
+ }
+ return T;
+}
+
+QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) ||
+ BaseType->isFunctionType())
+ return BaseType;
+
+ Qualifiers Quals;
+ QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals);
+
+ if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV)
+ Quals.removeConst();
+ if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV)
+ Quals.removeVolatile();
+ if (UKind == UTTKind::RemoveRestrict)
+ Quals.removeRestrict();
+
+ return Context.getQualifiedType(Unqual, Quals);
+}
+
+static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType,
+ bool IsMakeSigned,
+ SourceLocation Loc) {
+ if (BaseType->isEnumeralType()) {
+ QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc);
+ if (auto *BitInt = dyn_cast<BitIntType>(Underlying)) {
+ unsigned int Bits = BitInt->getNumBits();
+ if (Bits > 1)
+ return S.Context.getBitIntType(!IsMakeSigned, Bits);
+
+ S.Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying;
+ return QualType();
+ }
+ if (Underlying->isBooleanType()) {
+ S.Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1
+ << Underlying;
+ return QualType();
}
}
- llvm_unreachable("unknown unary transform type");
+
+ bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type();
+ std::array<CanQualType *, 6> AllSignedIntegers = {
+ &S.Context.SignedCharTy, &S.Context.ShortTy, &S.Context.IntTy,
+ &S.Context.LongTy, &S.Context.LongLongTy, &S.Context.Int128Ty};
+ ArrayRef<CanQualType *> AvailableSignedIntegers(
+ AllSignedIntegers.data(), AllSignedIntegers.size() - Int128Unsupported);
+ std::array<CanQualType *, 6> AllUnsignedIntegers = {
+ &S.Context.UnsignedCharTy, &S.Context.UnsignedShortTy,
+ &S.Context.UnsignedIntTy, &S.Context.UnsignedLongTy,
+ &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty};
+ ArrayRef<CanQualType *> AvailableUnsignedIntegers(AllUnsignedIntegers.data(),
+ AllUnsignedIntegers.size() -
+ Int128Unsupported);
+ ArrayRef<CanQualType *> *Consider =
+ IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers;
+
+ uint64_t BaseSize = S.Context.getTypeSize(BaseType);
+ auto *Result =
+ llvm::find_if(*Consider, [&S, BaseSize](const CanQual<Type> *T) {
+ return BaseSize == S.Context.getTypeSize(T->getTypePtr());
+ });
+
+ assert(Result != Consider->end());
+ return QualType((*Result)->getTypePtr(), 0);
+}
+
+QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned;
+ if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) ||
+ BaseType->isBooleanType() ||
+ (BaseType->isBitIntType() &&
+ BaseType->getAs<BitIntType>()->getNumBits() < 2)) {
+ Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0;
+ return QualType();
+ }
+
+ bool IsNonIntIntegral =
+ BaseType->isChar16Type() || BaseType->isChar32Type() ||
+ BaseType->isWideCharType() || BaseType->isEnumeralType();
+
+ QualType Underlying =
+ IsNonIntIntegral
+ ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc)
+ : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType)
+ : Context.getCorrespondingUnsignedType(BaseType);
+ if (Underlying.isNull())
+ return Underlying;
+ return Context.getQualifiedType(Underlying, BaseType.getQualifiers());
+}
+
+QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if (BaseType->isDependentType())
+ return Context.getUnaryTransformType(BaseType, BaseType, UKind);
+ QualType Result;
+ switch (UKind) {
+ case UnaryTransformType::EnumUnderlyingType: {
+ Result = BuiltinEnumUnderlyingType(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::AddPointer: {
+ Result = BuiltinAddPointer(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::RemovePointer: {
+ Result = BuiltinRemovePointer(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::Decay: {
+ Result = BuiltinDecay(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::AddLvalueReference:
+ case UnaryTransformType::AddRvalueReference: {
+ Result = BuiltinAddReference(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveAllExtents:
+ case UnaryTransformType::RemoveExtent: {
+ Result = BuiltinRemoveExtent(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveCVRef:
+ case UnaryTransformType::RemoveReference: {
+ Result = BuiltinRemoveReference(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveConst:
+ case UnaryTransformType::RemoveCV:
+ case UnaryTransformType::RemoveRestrict:
+ case UnaryTransformType::RemoveVolatile: {
+ Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::MakeSigned:
+ case UnaryTransformType::MakeUnsigned: {
+ Result = BuiltinChangeSignedness(BaseType, UKind, Loc);
+ break;
+ }
+ }
+
+ return !Result.isNull()
+ ? Context.getUnaryTransformType(BaseType, Result, UKind)
+ : Result;
}
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a8589191fc91..6a05ecc5370f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -40,6 +40,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+#include <optional>
using namespace llvm::omp;
@@ -279,9 +280,8 @@ public:
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
- bool &ShouldExpand,
- bool &RetainExpansion,
- Optional<unsigned> &NumExpansions) {
+ bool &ShouldExpand, bool &RetainExpansion,
+ std::optional<unsigned> &NumExpansions) {
ShouldExpand = false;
return false;
}
@@ -636,6 +636,14 @@ public:
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
#include "clang/AST/TypeLocNodes.def"
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime);
+ QualType
+ TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+ SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime);
+
template<typename Fn>
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
@@ -671,13 +679,49 @@ public:
/// The result vectors should be kept in sync; null entries in the
/// variables vector are acceptable.
///
+ /// LastParamTransformed, if non-null, will be set to the index of the last
+ /// parameter on which transfromation was started. In the event of an error,
+ /// this will contain the parameter which failed to instantiate.
+ ///
/// Return true on error.
bool TransformFunctionTypeParams(
SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
const QualType *ParamTypes,
const FunctionProtoType::ExtParameterInfo *ParamInfos,
SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars,
- Sema::ExtParameterInfoBuilder &PInfos);
+ Sema::ExtParameterInfoBuilder &PInfos, unsigned *LastParamTransformed);
+
+ bool TransformFunctionTypeParams(
+ SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
+ const QualType *ParamTypes,
+ const FunctionProtoType::ExtParameterInfo *ParamInfos,
+ SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+ return getDerived().TransformFunctionTypeParams(
+ Loc, Params, ParamTypes, ParamInfos, PTypes, PVars, PInfos, nullptr);
+ }
+
+ /// Transforms the parameters of a requires expresison into the given vectors.
+ ///
+ /// The result vectors should be kept in sync; null entries in the
+ /// variables vector are acceptable.
+ ///
+ /// Returns an unset ExprResult on success. Returns an ExprResult the 'not
+ /// satisfied' RequiresExpr if subsitution failed, OR an ExprError, both of
+ /// which are cases where transformation shouldn't continue.
+ ExprResult TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+ if (getDerived().TransformFunctionTypeParams(
+ KWLoc, Params, /*ParamTypes=*/nullptr,
+ /*ParamInfos=*/nullptr, PTypes, &TransParams, PInfos))
+ return ExprError();
+
+ return ExprResult{};
+ }
/// Transforms a single function-type parameter. Return null
/// on error.
@@ -686,7 +730,7 @@ public:
/// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- Optional<unsigned> NumExpansions,
+ std::optional<unsigned> NumExpansions,
bool ExpectParameterPack);
/// Transform the body of a lambda-expression.
@@ -963,12 +1007,13 @@ public:
///
/// By default, performs semantic analysis when building the typeof type.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc);
+ QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc,
+ TypeOfKind Kind);
/// Build a new typeof(type) type.
///
/// By default, builds a new TypeOfType with the given underlying type.
- QualType RebuildTypeOfType(QualType Underlying);
+ QualType RebuildTypeOfType(QualType Underlying, TypeOfKind Kind);
/// Build a new unary transform type.
QualType RebuildUnaryTransformType(QualType BaseType,
@@ -1061,23 +1106,18 @@ public:
// If it's still dependent, make a dependent specialization.
if (InstName.getAsDependentTemplateName())
- return SemaRef.Context.getDependentTemplateSpecializationType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- Name,
- Args);
+ return SemaRef.Context.getDependentTemplateSpecializationType(
+ Keyword, QualifierLoc.getNestedNameSpecifier(), Name,
+ Args.arguments());
// Otherwise, make an elaborated type wrapping a non-dependent
// specialization.
QualType T =
- getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
- if (T.isNull()) return QualType();
-
- if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr)
- return T;
-
- return SemaRef.Context.getElaboratedType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- T);
+ getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
+ if (T.isNull())
+ return QualType();
+ return SemaRef.Context.getElaboratedType(
+ Keyword, QualifierLoc.getNestedNameSpecifier(), T);
}
/// Build a new typename type that refers to an identifier.
@@ -1182,10 +1222,9 @@ public:
///
/// By default, builds a new PackExpansionType type from the given pattern.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildPackExpansionType(QualType Pattern,
- SourceRange PatternRange,
+ QualType RebuildPackExpansionType(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc,
NumExpansions);
}
@@ -1252,9 +1291,11 @@ public:
/// be resolved to a specific template, then builds the appropriate kind of
/// template name. Subclasses may override this routine to provide different
/// behavior.
- TemplateName RebuildTemplateName(TemplateTemplateParmDecl *Param,
- const TemplateArgument &ArgPack) {
- return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
+ TemplateName RebuildTemplateName(const TemplateArgument &ArgPack,
+ Decl *AssociatedDecl, unsigned Index,
+ bool Final) {
+ return getSema().Context.getSubstTemplateTemplateParmPack(
+ ArgPack, AssociatedDecl, Index, Final);
}
/// Build a new compound statement.
@@ -1946,15 +1987,16 @@ public:
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPMapClause(
- ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
return getSema().ActOnOpenMPMapClause(
- MapTypeModifiers, MapTypeModifiersLoc, MapperIdScopeSpec, MapperId,
- MapType, IsMapTypeImplicit, MapLoc, ColonLoc, VarList, Locs,
+ IteratorModifier, MapTypeModifiers, MapTypeModifiersLoc,
+ MapperIdScopeSpec, MapperId, MapType, IsMapTypeImplicit, MapLoc,
+ ColonLoc, VarList, Locs,
/*NoDiagnose=*/false, UnresolvedMappers);
}
@@ -2009,22 +2051,26 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc,
+ OMPClause *RebuildOMPGrainsizeClause(OpenMPGrainsizeClauseModifier Modifier,
+ Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPGrainsizeClause(Grainsize, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPGrainsizeClause(Modifier, Device, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
/// Build a new OpenMP 'num_tasks' clause.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc,
+ OMPClause *RebuildOMPNumTasksClause(OpenMPNumTasksClauseModifier Modifier,
+ Expr *NumTasks, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPNumTasksClause(NumTasks, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPNumTasksClause(Modifier, NumTasks, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
/// Build a new OpenMP 'hint' clause.
@@ -2207,28 +2253,25 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPOrderClause(OpenMPOrderClauseKind Kind,
- SourceLocation KindKwLoc,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- return getSema().ActOnOpenMPOrderClause(Kind, KindKwLoc, StartLoc,
- LParenLoc, EndLoc);
+ OMPClause *RebuildOMPOrderClause(
+ OpenMPOrderClauseKind Kind, SourceLocation KindKwLoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
+ OpenMPOrderClauseModifier Modifier, SourceLocation ModifierKwLoc) {
+ return getSema().ActOnOpenMPOrderClause(Modifier, Kind, StartLoc, LParenLoc,
+ ModifierKwLoc, KindKwLoc, EndLoc);
}
/// Build a new OpenMP 'init' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
- bool IsTarget, bool IsTargetSync,
+ OMPClause *RebuildOMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation VarLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPInitClause(InteropVar, PrefExprs, IsTarget,
- IsTargetSync, StartLoc, LParenLoc,
- VarLoc, EndLoc);
+ return getSema().ActOnOpenMPInitClause(InteropVar, InteropInfo, StartLoc,
+ LParenLoc, VarLoc, EndLoc);
}
/// Build a new OpenMP 'use' clause.
@@ -2301,6 +2344,17 @@ public:
EndLoc);
}
+ /// Build a new OpenMP 'ompx_dyn_cgroup_mem' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPXDynCGroupMemClause(Expr *Size, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPXDynCGroupMemClause(Size, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Build a new OpenMP 'align' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2311,6 +2365,41 @@ public:
return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'at' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAtClause(OpenMPAtClauseKind Kind, SourceLocation KwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPAtClause(Kind, KwLoc, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'severity' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPSeverityClause(OpenMPSeverityClauseKind Kind,
+ SourceLocation KwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPSeverityClause(Kind, KwLoc, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'message' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPMessageClause(Expr *MS, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -2783,20 +2872,18 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildExtVectorElementExpr(Expr *Base,
- SourceLocation OpLoc,
- SourceLocation AccessorLoc,
- IdentifierInfo &Accessor) {
+ ExprResult RebuildExtVectorElementExpr(Expr *Base, SourceLocation OpLoc,
+ bool IsArrow,
+ SourceLocation AccessorLoc,
+ IdentifierInfo &Accessor) {
CXXScopeSpec SS;
DeclarationNameInfo NameInfo(&Accessor, AccessorLoc);
- return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, /*IsArrow*/ false,
- SS, SourceLocation(),
- /*FirstQualifierInScope*/ nullptr,
- NameInfo,
- /* TemplateArgs */ nullptr,
- /*S*/ nullptr);
+ return getSema().BuildMemberReferenceExpr(
+ Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(),
+ /*FirstQualifierInScope*/ nullptr, NameInfo,
+ /* TemplateArgs */ nullptr,
+ /*S*/ nullptr);
}
/// Build a new initializer list expression.
@@ -3134,9 +3221,10 @@ public:
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) {
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param,
+ Expr *RewrittenExpr) {
return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param,
- getSema().CurContext);
+ RewrittenExpr, getSema().CurContext);
}
/// Build a new C++11 default-initialization expression.
@@ -3146,8 +3234,7 @@ public:
/// routine to provide different behavior.
ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
FieldDecl *Field) {
- return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field,
- getSema().CurContext);
+ return getSema().BuildCXXDefaultInitExpr(Loc, Field);
}
/// Build a new C++ zero-initialization expression.
@@ -3157,25 +3244,23 @@ public:
ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- return getSema().BuildCXXTypeConstructExpr(
- TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false);
+ return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, std::nullopt,
+ RParenLoc,
+ /*ListInitialization=*/false);
}
/// Build a new C++ "new" expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXNewExpr(SourceLocation StartLoc,
- bool UseGlobal,
+ ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- SourceRange TypeIdParens,
- QualType AllocatedType,
+ SourceRange TypeIdParens, QualType AllocatedType,
TypeSourceInfo *AllocatedTypeInfo,
- Optional<Expr *> ArraySize,
- SourceRange DirectInitRange,
- Expr *Initializer) {
+ std::optional<Expr *> ArraySize,
+ SourceRange DirectInitRange, Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
PlacementArgs,
@@ -3397,11 +3482,10 @@ public:
}
/// Build a new expression to compute the length of a parameter pack.
- ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
- NamedDecl *Pack,
+ ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc,
SourceLocation RParenLoc,
- Optional<unsigned> Length,
+ std::optional<unsigned> Length,
ArrayRef<TemplateArgument> PartialArgs) {
return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc,
RParenLoc, Length, PartialArgs);
@@ -3479,9 +3563,10 @@ public:
}
concepts::NestedRequirement *
- RebuildNestedRequirement(
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
- return SemaRef.BuildNestedRequirement(SubstDiag);
+ RebuildNestedRequirement(StringRef InvalidConstraintEntity,
+ const ASTConstraintSatisfaction &Satisfaction) {
+ return SemaRef.BuildNestedRequirement(InvalidConstraintEntity,
+ Satisfaction);
}
concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) {
@@ -3704,9 +3789,9 @@ public:
/// By default, performs semantic analysis to build a new pack expansion
/// for a template argument. Subclasses may override this routine to provide
/// different behavior.
- TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
- SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ TemplateArgumentLoc
+ RebuildPackExpansion(TemplateArgumentLoc Pattern, SourceLocation EllipsisLoc,
+ std::optional<unsigned> NumExpansions) {
switch (Pattern.getArgument().getKind()) {
case TemplateArgument::Expression: {
ExprResult Result
@@ -3753,7 +3838,7 @@ public:
/// for an expression. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
@@ -3766,7 +3851,7 @@ public:
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().BuildCXXFoldExpr(ULE, LParenLoc, LHS, Operator,
EllipsisLoc, RHS, RParenLoc,
NumExpansions);
@@ -3781,6 +3866,16 @@ 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.
@@ -3931,13 +4026,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
// Revert value-initialization back to empty parens.
if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) {
SourceRange Parens = VIE->getSourceRange();
- return getDerived().RebuildParenListExpr(Parens.getBegin(), None,
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), std::nullopt,
Parens.getEnd());
}
// FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization.
if (isa<ImplicitValueInitExpr>(Init))
- return getDerived().RebuildParenListExpr(SourceLocation(), None,
+ return getDerived().RebuildParenListExpr(SourceLocation(), std::nullopt,
SourceLocation());
// Revert initialization by constructor back to a parenthesized or braced list
@@ -4005,8 +4100,8 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -4123,9 +4218,13 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS, QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
- for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
- Qualifier = Qualifier.getPrefix())
- Qualifiers.push_back(Qualifier);
+
+ auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) {
+ for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
+ Qualifier = Qualifier.getPrefix())
+ Qualifiers.push_back(Qualifier);
+ };
+ insertNNS(NNS);
CXXScopeSpec SS;
while (!Qualifiers.empty()) {
@@ -4182,24 +4281,27 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
if (!TL)
return NestedNameSpecifierLoc();
- if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOpts().CPlusPlus11 &&
- TL.getType()->isEnumeralType())) {
- assert(!TL.getType().hasLocalQualifiers() &&
- "Can't get cv-qualifiers here");
- if (TL.getType()->isEnumeralType())
+ QualType T = TL.getType();
+ if (T->isDependentType() || T->isRecordType() ||
+ (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) {
+ if (T->isEnumeralType())
SemaRef.Diag(TL.getBeginLoc(),
diag::warn_cxx98_compat_enum_nested_name_spec);
+
+ if (const auto ETL = TL.getAs<ElaboratedTypeLoc>()) {
+ SS.Adopt(ETL.getQualifierLoc());
+ TL = ETL.getNamedTypeLoc();
+ }
SS.Extend(SemaRef.Context, /*FIXME:*/ SourceLocation(), TL,
Q.getLocalEndLoc());
break;
}
// If the nested-name-specifier is an invalid type def, don't emit an
// error because a previous error should have already been emitted.
- TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>();
+ TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>();
if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) {
SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
- << TL.getType() << SS.getRange();
+ << T << SS.getRange();
}
return NestedNameSpecifierLoc();
}
@@ -4362,18 +4464,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
if (SubstTemplateTemplateParmPackStorage *SubstPack
= Name.getAsSubstTemplateTemplateParmPack()) {
- TemplateTemplateParmDecl *TransParam
- = cast_or_null<TemplateTemplateParmDecl>(
- getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack()));
- if (!TransParam)
- return TemplateName();
-
- if (!getDerived().AlwaysRebuild() &&
- TransParam == SubstPack->getParameterPack())
- return Name;
-
- return getDerived().RebuildTemplateName(TransParam,
- SubstPack->getArgumentPack());
+ return getDerived().RebuildTemplateName(
+ SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(),
+ SubstPack->getIndex(), SubstPack->getFinal());
}
// These should be getting filtered out before they reach the AST.
@@ -4587,7 +4680,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
// We have a pack expansion, for which we will be substituting into
// the pattern.
SourceLocation Ellipsis;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
= getSema().getTemplateArgumentPackExpansionPattern(
In, Ellipsis, OrigNumExpansions);
@@ -4600,7 +4693,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded,
@@ -4787,7 +4880,20 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
QualifiedTypeLoc T) {
- QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc());
+ QualType Result;
+ TypeLoc UnqualTL = T.getUnqualifiedLoc();
+ auto SuppressObjCLifetime =
+ T.getType().getLocalQualifiers().hasObjCLifetime();
+ if (auto TTP = UnqualTL.getAs<TemplateTypeParmTypeLoc>()) {
+ Result = getDerived().TransformTemplateTypeParmType(TLB, TTP,
+ SuppressObjCLifetime);
+ } else if (auto STTP = UnqualTL.getAs<SubstTemplateTypeParmPackTypeLoc>()) {
+ Result = getDerived().TransformSubstTemplateTypeParmPackType(
+ TLB, STTP, SuppressObjCLifetime);
+ } else {
+ Result = getDerived().TransformType(TLB, UnqualTL);
+ }
+
if (Result.isNull())
return QualType();
@@ -4850,16 +4956,7 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
const AutoType *AutoTy;
- if (const SubstTemplateTypeParmType *SubstTypeParam
- = dyn_cast<SubstTemplateTypeParmType>(T)) {
- QualType Replacement = SubstTypeParam->getReplacementType();
- Qualifiers Qs = Replacement.getQualifiers();
- Qs.removeObjCLifetime();
- Replacement = SemaRef.Context.getQualifiedType(
- Replacement.getUnqualifiedType(), Qs);
- T = SemaRef.Context.getSubstTemplateTypeParmType(
- SubstTypeParam->getReplacedParameter(), Replacement);
- } else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
+ if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
// 'auto' types behave the same way as template parameters.
QualType Deduced = AutoTy->getDeducedType();
Qualifiers Qs = Deduced.getQualifiers();
@@ -5604,8 +5701,8 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
template <typename Derived>
ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
- ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+ ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions, bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = nullptr;
@@ -5665,15 +5762,18 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
const FunctionProtoType::ExtParameterInfo *ParamInfos,
SmallVectorImpl<QualType> &OutParamTypes,
SmallVectorImpl<ParmVarDecl *> *PVars,
- Sema::ExtParameterInfoBuilder &PInfos) {
+ Sema::ExtParameterInfoBuilder &PInfos,
+ unsigned *LastParamTransformed) {
int indexAdjustment = 0;
unsigned NumParams = Params.size();
for (unsigned i = 0; i != NumParams; ++i) {
+ if (LastParamTransformed)
+ *LastParamTransformed = i;
if (ParmVarDecl *OldParm = Params[i]) {
assert(OldParm->getFunctionScopeIndex() == i);
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
ParmVarDecl *NewParm = nullptr;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
@@ -5688,7 +5788,7 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
if (Unexpanded.size() > 0) {
OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
NumExpansions = OrigNumExpansions;
@@ -5771,7 +5871,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
"transformation.");
} else {
NewParm = getDerived().TransformFunctionTypeParam(
- OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
+ OldParm, indexAdjustment, std::nullopt,
+ /*ExpectParameterPack=*/false);
}
if (!NewParm)
@@ -5787,14 +5888,16 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
// Deal with the possibility that we don't have a parameter
// declaration for this parameter.
+ assert(ParamTypes);
QualType OldType = ParamTypes[i];
bool IsPackExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
QualType NewType;
if (const PackExpansionType *Expansion
= 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);
@@ -5819,8 +5922,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
return true;
if (NewType->containsUnexpandedParameterPack()) {
- NewType =
- getSema().getASTContext().getPackExpansionType(NewType, None);
+ NewType = getSema().getASTContext().getPackExpansionType(
+ NewType, std::nullopt);
if (NewType.isNull())
return true;
@@ -5965,8 +6068,8 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
if (auto NewExtParamInfos =
ExtParamInfos.getPointerOrNull(ParamTypes.size())) {
if (!EPI.ExtParameterInfos ||
- llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams())
- != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) {
+ llvm::ArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) !=
+ llvm::ArrayRef(NewExtParamInfos, ParamTypes.size())) {
EPIChanged = true;
}
EPI.ExtParameterInfos = NewExtParamInfos;
@@ -5977,7 +6080,7 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
- T->getParamTypes() != llvm::makeArrayRef(ParamTypes) || EPIChanged) {
+ T->getParamTypes() != llvm::ArrayRef(ParamTypes) || EPIChanged) {
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI);
if (Result.isNull())
return QualType();
@@ -6041,7 +6144,7 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
// be expanded.
bool Expand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
// FIXME: Track the location of the ellipsis (and track source location
// information for the types in the exception specification in general).
if (getDerived().TryExpandParameterPacks(
@@ -6203,13 +6306,13 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
return QualType();
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- E.get() != TL.getUnderlyingExpr()) {
- Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc());
+ TypeOfKind Kind = Result->getAs<TypeOfExprType>()->getKind();
+ if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) {
+ Result =
+ getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc(), Kind);
if (Result.isNull())
return QualType();
}
- else E.get();
TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result);
NewTL.setTypeofLoc(TL.getTypeofLoc());
@@ -6222,14 +6325,15 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
TypeOfTypeLoc TL) {
- TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
+ TypeSourceInfo* Old_Under_TI = TL.getUnmodifiedTInfo();
TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
if (!New_Under_TI)
return QualType();
QualType Result = TL.getType();
+ TypeOfKind Kind = Result->getAs<TypeOfType>()->getKind();
if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) {
- Result = getDerived().RebuildTypeOfType(New_Under_TI->getType());
+ Result = getDerived().RebuildTypeOfType(New_Under_TI->getType(), Kind);
if (Result.isNull())
return QualType();
}
@@ -6238,7 +6342,7 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
NewTL.setTypeofLoc(TL.getTypeofLoc());
NewTL.setLParenLoc(TL.getLParenLoc());
NewTL.setRParenLoc(TL.getRParenLoc());
- NewTL.setUnderlyingTInfo(New_Under_TI);
+ NewTL.setUnmodifiedTInfo(New_Under_TI);
return Result;
}
@@ -6395,6 +6499,14 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL) {
+ return getDerived().TransformTemplateTypeParmType(
+ TLB, TL,
+ /*SuppressObjCLifetime=*/false);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
+ TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, bool) {
return TransformTypeSpecType(TLB, TL);
}
@@ -6404,6 +6516,9 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
SubstTemplateTypeParmTypeLoc TL) {
const SubstTemplateTypeParmType *T = TL.getTypePtr();
+ Decl *NewReplaced =
+ getDerived().TransformDecl(TL.getNameLoc(), T->getAssociatedDecl());
+
// Substitute into the replacement type, which itself might involve something
// that needs to be transformed. This only tends to occur with default
// template arguments of template template parameters.
@@ -6412,11 +6527,8 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
if (Replacement.isNull())
return QualType();
- // Always canonicalize the replacement type.
- Replacement = SemaRef.Context.getCanonicalType(Replacement);
- QualType Result
- = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- Replacement);
+ QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
+ Replacement, NewReplaced, T->getIndex(), T->getPackIndex());
// Propagate type-source information.
SubstTemplateTypeParmTypeLoc NewTL
@@ -6430,6 +6542,13 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmPackTypeLoc TL) {
+ return getDerived().TransformSubstTemplateTypeParmPackType(
+ TLB, TL, /*SuppressObjCLifetime=*/false);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
+ TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, bool) {
return TransformTypeSpecType(TLB, TL);
}
@@ -6750,12 +6869,9 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
// FIXME: maybe don't rebuild if all the template arguments are the same.
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType Result
- = getSema().Context.getDependentTemplateSpecializationType(
- TL.getTypePtr()->getKeyword(),
- DTN->getQualifier(),
- DTN->getIdentifier(),
- NewTemplateArgs);
+ QualType Result = getSema().Context.getDependentTemplateSpecializationType(
+ TL.getTypePtr()->getKeyword(), DTN->getQualifier(),
+ DTN->getIdentifier(), NewTemplateArgs.arguments());
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
@@ -7113,12 +7229,10 @@ TreeTransform<Derived>::TransformObjCTypeParamType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
OTP != T->getDecl()) {
- Result = getDerived().RebuildObjCTypeParamType(OTP,
- TL.getProtocolLAngleLoc(),
- llvm::makeArrayRef(TL.getTypePtr()->qual_begin(),
- TL.getNumProtocols()),
- TL.getProtocolLocs(),
- TL.getProtocolRAngleLoc());
+ Result = getDerived().RebuildObjCTypeParamType(
+ OTP, TL.getProtocolLAngleLoc(),
+ llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
+ TL.getProtocolLocs(), TL.getProtocolRAngleLoc());
if (Result.isNull())
return QualType();
}
@@ -7166,7 +7280,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
bool Expand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
if (getDerived().TryExpandParameterPacks(
PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
Unexpanded, Expand, RetainExpansion, NumExpansions))
@@ -7216,7 +7330,8 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
TypeLocBuilder TypeArgBuilder;
TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
- QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
+ QualType NewTypeArg =
+ getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
if (NewTypeArg.isNull())
return QualType();
@@ -7237,7 +7352,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
Result = getDerived().RebuildObjCObjectType(
BaseType, TL.getBeginLoc(), TL.getTypeArgsLAngleLoc(), NewTypeArgInfos,
TL.getTypeArgsRAngleLoc(), TL.getProtocolLAngleLoc(),
- llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
+ llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
TL.getProtocolLocs(), TL.getProtocolRAngleLoc());
if (Result.isNull())
@@ -7483,7 +7598,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
}
// If this is a constexpr if, determine which arm we should instantiate.
- llvm::Optional<bool> ConstexprConditionValue;
+ std::optional<bool> ConstexprConditionValue;
if (S->isConstexpr())
ConstexprConditionValue = Cond.getKnownValue();
@@ -7800,8 +7915,7 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
- ArrayRef<Token> AsmToks =
- llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks());
+ ArrayRef<Token> AsmToks = llvm::ArrayRef(S->getAsmToks(), S->getNumAsmToks());
bool HadError = false, HadChange = false;
@@ -8839,6 +8953,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
}
template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_error, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPTaskgroupDirective(
OMPTaskgroupDirective *D) {
DeclarationNameInfo DirName;
@@ -9676,17 +9801,17 @@ OMPClause *TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) {
if (IVR.isInvalid())
return nullptr;
- llvm::SmallVector<Expr *, 8> PrefExprs;
- PrefExprs.reserve(C->varlist_size() - 1);
+ OMPInteropInfo InteropInfo(C->getIsTarget(), C->getIsTargetSync());
+ InteropInfo.PreferTypes.reserve(C->varlist_size() - 1);
for (Expr *E : llvm::drop_begin(C->varlists())) {
ExprResult ER = getDerived().TransformExpr(cast<Expr>(E));
if (ER.isInvalid())
return nullptr;
- PrefExprs.push_back(ER.get());
+ InteropInfo.PreferTypes.push_back(ER.get());
}
- return getDerived().RebuildOMPInitClause(
- IVR.get(), PrefExprs, C->getIsTarget(), C->getIsTargetSync(),
- C->getBeginLoc(), C->getLParenLoc(), C->getVarLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPInitClause(IVR.get(), InteropInfo,
+ C->getBeginLoc(), C->getLParenLoc(),
+ C->getVarLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -9786,6 +9911,32 @@ OMPClause *TreeTransform<Derived>::TransformOMPAtomicDefaultMemOrderClause(
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPAtClause(OMPAtClause *C) {
+ return getDerived().RebuildOMPAtClause(C->getAtKind(), C->getAtKindKwLoc(),
+ C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPSeverityClause(OMPSeverityClause *C) {
+ return getDerived().RebuildOMPSeverityClause(
+ C->getSeverityKind(), C->getSeverityKindKwLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPMessageClause(OMPMessageClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getMessageString());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPMessageClause(
+ C->getMessageString(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -10168,6 +10319,13 @@ template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
llvm::SmallVector<Expr *, 16> Vars;
+ Expr *IteratorModifier = C->getIteratorModifier();
+ if (IteratorModifier) {
+ ExprResult MapModRes = getDerived().TransformExpr(IteratorModifier);
+ if (MapModRes.isInvalid())
+ return nullptr;
+ IteratorModifier = MapModRes.get();
+ }
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperIdInfo;
llvm::SmallVector<Expr *, 16> UnresolvedMappers;
@@ -10175,9 +10333,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
*this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers))
return nullptr;
return getDerived().RebuildOMPMapClause(
- C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec,
- MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(),
- C->getColonLoc(), Vars, Locs, UnresolvedMappers);
+ IteratorModifier, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
+ MapperIdScopeSpec, MapperIdInfo, C->getMapType(), C->isImplicitMapType(),
+ C->getMapLoc(), C->getColonLoc(), Vars, Locs, UnresolvedMappers);
}
template <typename Derived>
@@ -10240,7 +10398,8 @@ TreeTransform<Derived>::TransformOMPGrainsizeClause(OMPGrainsizeClause *C) {
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPGrainsizeClause(
- E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -10250,7 +10409,8 @@ TreeTransform<Derived>::TransformOMPNumTasksClause(OMPNumTasksClause *C) {
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPNumTasksClause(
- E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -10472,9 +10632,9 @@ TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) {
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
- return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(),
- C->getBeginLoc(), C->getLParenLoc(),
- C->getEndLoc());
+ return getDerived().RebuildOMPOrderClause(
+ C->getKind(), C->getKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc(), C->getModifier(), C->getModifierKwLoc());
}
template <typename Derived>
@@ -10484,6 +10644,16 @@ OMPClause *TreeTransform<Derived>::TransformOMPBindClause(OMPBindClause *C) {
C->getLParenLoc(), C->getEndLoc());
}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause(
+ OMPXDynCGroupMemClause *C) {
+ ExprResult Size = getDerived().TransformExpr(C->getSize());
+ if (Size.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPXDynCGroupMemClause(
+ Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -11190,7 +11360,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
return getDerived().RebuildBinaryOperator(
E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get());
Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
- FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ FPOptionsOverride NewOverrides(E->getFPFeatures());
getSema().CurFPFeatures =
NewOverrides.applyOverrides(getSema().getLangOpts());
getSema().FpPragmaStack.CurrentValue = NewOverrides;
@@ -11257,7 +11427,7 @@ ExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
CompoundAssignOperator *E) {
Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
- FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ FPOptionsOverride NewOverrides(E->getFPFeatures());
getSema().CurFPFeatures =
NewOverrides.applyOverrides(getSema().getLangOpts());
getSema().FpPragmaStack.CurrentValue = NewOverrides;
@@ -11389,9 +11559,9 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
// FIXME: Bad source location
SourceLocation FakeOperatorLoc =
SemaRef.getLocForEndOfToken(E->getBase()->getEndLoc());
- return getDerived().RebuildExtVectorElementExpr(Base.get(), FakeOperatorLoc,
- E->getAccessorLoc(),
- E->getAccessor());
+ return getDerived().RebuildExtVectorElementExpr(
+ Base.get(), FakeOperatorLoc, E->isArrow(), E->getAccessorLoc(),
+ E->getAccessor());
}
template<typename Derived>
@@ -12024,11 +12194,20 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return ExprError();
+ ExprResult InitRes;
+ if (E->hasRewrittenInit()) {
+ InitRes = getDerived().TransformExpr(E->getRewrittenExpr());
+ if (InitRes.isInvalid())
+ return ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() && Param == E->getParam() &&
- E->getUsedContext() == SemaRef.CurContext)
+ E->getUsedContext() == SemaRef.CurContext &&
+ InitRes.get() == E->getRewrittenExpr())
return E;
- return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
+ return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param,
+ InitRes.get());
}
template<typename Derived>
@@ -12073,10 +12252,10 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return ExprError();
// Transform the size of the array we're allocating (if any).
- Optional<Expr *> ArraySize;
+ std::optional<Expr *> ArraySize;
if (E->isArray()) {
ExprResult NewArraySize;
- if (Optional<Expr *> OldArraySize = E->getArraySize()) {
+ if (std::optional<Expr *> OldArraySize = E->getArraySize()) {
NewArraySize = getDerived().TransformExpr(*OldArraySize);
if (NewArraySize.isInvalid())
return ExprError();
@@ -12455,9 +12634,9 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
+ std::optional<unsigned> OrigNumExpansions =
ExpansionTL.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
PatternTL.getSourceRange(),
Unexpanded,
@@ -12578,7 +12757,8 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
// C++2a [expr.prim.req]p2
// Expressions appearing within a requirement-body are unevaluated operands.
EnterExpressionEvaluationContext Ctx(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(
getSema().Context, getSema().CurContext,
@@ -12586,16 +12766,20 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false);
- if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(),
- E->getLocalParameters(),
- /*ParamTypes=*/nullptr,
- /*ParamInfos=*/nullptr,
- TransParamTypes, &TransParams,
- ExtParamInfos))
- return ExprError();
+ ExprResult TypeParamResult = getDerived().TransformRequiresTypeParams(
+ E->getRequiresKWLoc(), E->getRBraceLoc(), E, Body,
+ E->getLocalParameters(), TransParamTypes, TransParams, ExtParamInfos);
for (ParmVarDecl *Param : TransParams)
- Param->setDeclContext(Body);
+ if (Param)
+ Param->setDeclContext(Body);
+
+ // On failure to transform, TransformRequiresTypeParams returns an expression
+ // in the event that the transformation of the type params failed in some way.
+ // It is expected that this will result in a 'not satisfied' Requires clause
+ // when instantiating.
+ if (!TypeParamResult.isUnset())
+ return TypeParamResult;
SmallVector<concepts::Requirement *, 4> TransReqs;
if (getDerived().TransformRequiresExprRequirements(E->getRequirements(),
@@ -12668,7 +12852,7 @@ TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req)
TransExpr = TransExprRes.get();
}
- llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
const auto &RetReq = Req->getReturnTypeRequirement();
if (RetReq.isEmpty())
TransRetReq.emplace();
@@ -12697,10 +12881,10 @@ template<typename Derived>
concepts::NestedRequirement *
TreeTransform<Derived>::TransformNestedRequirement(
concepts::NestedRequirement *Req) {
- if (Req->isSubstitutionFailure()) {
+ if (Req->hasInvalidConstraint()) {
if (getDerived().AlwaysRebuild())
return getDerived().RebuildNestedRequirement(
- Req->getSubstitutionDiagnostic());
+ Req->getInvalidConstraintEntity(), Req->getConstraintSatisfaction());
return Req;
}
ExprResult TransConstraint =
@@ -12990,10 +13174,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
continue;
TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
- VarDecl *OldVD = C->getCapturedVar();
+ auto *OldVD = cast<VarDecl>(C->getCapturedVar());
auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
ExprResult NewExprInitResult = getDerived().TransformInitializer(
OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit);
@@ -13005,9 +13189,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
QualType NewInitCaptureType =
getSema().buildLambdaInitCaptureInitialization(
- C->getLocation(), OldVD->getType()->isReferenceType(),
+ C->getLocation(), C->getCaptureKind() == LCK_ByRef,
EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
- C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
+ cast<VarDecl>(C->getCapturedVar())->getInitStyle() !=
+ VarDecl::CInit,
NewExprInit);
Result.Expansions.push_back(
InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
@@ -13025,9 +13210,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
+ std::optional<unsigned> OrigNumExpansions =
ExpansionTL.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(
ExpansionTL.getEllipsisLoc(),
OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
@@ -13036,7 +13221,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
- SubstInitCapture(SourceLocation(), None);
+ SubstInitCapture(SourceLocation(), std::nullopt);
}
}
if (!Expand || RetainExpansion) {
@@ -13045,7 +13230,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Result.EllipsisLoc = ExpansionTL.getEllipsisLoc();
}
} else {
- SubstInitCapture(SourceLocation(), None);
+ SubstInitCapture(SourceLocation(), std::nullopt);
}
}
@@ -13083,23 +13268,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
- // Transform the trailing requires clause
- ExprResult NewTrailingRequiresClause;
- if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
- // FIXME: Concepts: Substitution into requires clause should only happen
- // when checking satisfaction.
- NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
-
// Create the local class that will describe the lambda.
// FIXME: DependencyKind below is wrong when substituting inside a templated
// context that isn't a DeclContext (such as a variable template), or when
// substituting an unevaluated lambda inside of a function's parameter's type
// - as parameter types are not instantiated from within a function's DC. We
- // use isUnevaluatedContext() to distinguish the function parameter case.
+ // use evaluation contexts to distinguish the function parameter case.
CXXRecordDecl::LambdaDependencyKind DependencyKind =
CXXRecordDecl::LDK_Unknown;
- if (getSema().isUnevaluatedContext() &&
+ if ((getSema().isUnevaluatedContext() ||
+ getSema().isConstantEvaluatedContext()) &&
(getSema().CurContext->isFileContext() ||
!getSema().CurContext->getParent()->isDependentContext()))
DependencyKind = CXXRecordDecl::LDK_NeverDependent;
@@ -13111,7 +13290,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformedLocalDecl(OldClass, {Class});
- Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
+ std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
if (getDerived().ReplacingOriginal())
Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(),
OldClass->getLambdaManglingNumber(),
@@ -13124,7 +13303,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
E->getCallOperator()->getConstexprKind(),
- NewTrailingRequiresClause.get());
+ E->getCallOperator()->getStorageClass(),
+ E->getCallOperator()->getTrailingRequiresClause());
LSI->CallOperator = NewCallOperator;
@@ -13174,7 +13354,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (E->isInitCapture(C)) {
TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
- VarDecl *OldVD = C->getCapturedVar();
+ auto *OldVD = cast<VarDecl>(C->getCapturedVar());
llvm::SmallVector<Decl*, 4> NewVDs;
for (InitCaptureInfoTy &Info : NewC.Expansions) {
@@ -13192,7 +13372,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
break;
}
NewVDs.push_back(NewVD);
- getSema().addInitCapture(LSI, NewVD);
+ getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef);
}
if (Invalid)
@@ -13215,7 +13395,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
C->getLocation(),
Unexpanded,
@@ -13229,7 +13409,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// The transform has determined that we should perform an expansion;
// transform and capture each of the arguments.
// expansion of the pattern. Do so.
- VarDecl *Pack = C->getCapturedVar();
+ auto *Pack = cast<VarDecl>(C->getCapturedVar());
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
VarDecl *CapturedVar
@@ -13253,9 +13433,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
// Transform the captured variable.
- VarDecl *CapturedVar
- = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
- C->getCapturedVar()));
+ auto *CapturedVar = cast_or_null<ValueDecl>(
+ getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()));
if (!CapturedVar || CapturedVar->isInvalidDecl()) {
Invalid = true;
continue;
@@ -13592,7 +13771,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
Unexpanded,
ShouldExpand, RetainExpansion,
@@ -13605,9 +13784,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
auto *Pack = E->getPack();
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Pack)) {
ArgStorage = getSema().Context.getPackExpansionType(
- getSema().Context.getTypeDeclType(TTPD), None);
+ getSema().Context.getTypeDeclType(TTPD), std::nullopt);
} else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Pack)) {
- ArgStorage = TemplateArgument(TemplateName(TTPD), None);
+ ArgStorage = TemplateArgument(TemplateName(TTPD), std::nullopt);
} else {
auto *VD = cast<ValueDecl>(Pack);
ExprResult DRE = getSema().BuildDeclRefExpr(
@@ -13616,8 +13795,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
E->getPackLoc());
if (DRE.isInvalid())
return ExprError();
- ArgStorage = new (getSema().Context) PackExpansionExpr(
- getSema().Context.DependentTy, DRE.get(), E->getPackLoc(), None);
+ ArgStorage = new (getSema().Context)
+ PackExpansionExpr(getSema().Context.DependentTy, DRE.get(),
+ E->getPackLoc(), std::nullopt);
}
PackArgs = ArgStorage;
}
@@ -13629,13 +13809,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
getDerived().TransformDecl(E->getPackLoc(), E->getPack()));
if (!Pack)
return ExprError();
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
- E->getPackLoc(),
- E->getRParenLoc(), None, None);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(),
+ std::nullopt, std::nullopt);
}
// Try to compute the result without performing a partial substitution.
- Optional<unsigned> Result = 0;
+ std::optional<unsigned> Result = 0;
for (const TemplateArgument &Arg : PackArgs) {
if (!Arg.isPackExpansion()) {
Result = *Result + 1;
@@ -13647,7 +13827,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// Find the pattern of the pack expansion.
SourceLocation Ellipsis;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern =
getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis,
OrigNumExpansions);
@@ -13660,12 +13840,12 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
return true;
// See if we can determine the number of arguments from the result.
- Optional<unsigned> NumExpansions =
+ std::optional<unsigned> NumExpansions =
getSema().getFullyPackExpandedSize(OutPattern.getArgument());
if (!NumExpansions) {
// No: we must be in an alias template expansion, and we're going to need
// to actually expand the packs.
- Result = None;
+ Result = std::nullopt;
break;
}
@@ -13675,9 +13855,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// Common case: we could determine the number of expansions without
// substituting.
if (Result)
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
- E->getPackLoc(),
- E->getRParenLoc(), *Result, None);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+ *Result, std::nullopt);
TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
E->getPackLoc());
@@ -13702,13 +13882,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
}
if (PartialSubstitution)
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
- E->getPackLoc(),
- E->getRParenLoc(), None, Args);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+ std::nullopt, Args);
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
E->getPackLoc(), E->getRParenLoc(),
- Args.size(), None);
+ Args.size(), std::nullopt);
}
template<typename Derived>
@@ -13762,8 +13942,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
- NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
+ NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -13887,6 +14067,20 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
return Result;
}
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ SmallVector<Expr *, 4> TransformedInits;
+ ArrayRef<Expr *> InitExprs = E->getInitExprs();
+ if (TransformExprs(InitExprs.data(), InitExprs.size(), true,
+ TransformedInits))
+ return ExprError();
+
+ return getDerived().RebuildCXXParenListInitExpr(
+ TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
+ E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
@@ -13959,8 +14153,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// and should be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
SourceRange PatternRange(OrigElement.Key->getBeginLoc(),
OrigElement.Value->getEndLoc());
if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
@@ -14047,9 +14241,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
if (Value.get() != OrigElement.Value)
ArgChanged = true;
- ObjCDictionaryElement Element = {
- Key.get(), Value.get(), SourceLocation(), None
- };
+ ObjCDictionaryElement Element = {Key.get(), Value.get(), SourceLocation(),
+ std::nullopt};
Elements.push_back(Element);
}
@@ -14506,11 +14699,11 @@ QualType TreeTransform<Derived>::RebuildObjCObjectType(
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc) {
- return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc,
- TypeArgs, TypeArgsRAngleLoc,
- ProtocolLAngleLoc, Protocols, ProtocolLocs,
- ProtocolRAngleLoc,
- /*FailOnError=*/true);
+ return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, TypeArgs,
+ TypeArgsRAngleLoc, ProtocolLAngleLoc,
+ Protocols, ProtocolLocs, ProtocolRAngleLoc,
+ /*FailOnError=*/true,
+ /*Rebuilding=*/true);
}
template<typename Derived>
@@ -14538,11 +14731,10 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
};
- const unsigned NumTypes = llvm::array_lengthof(Types);
QualType SizeType;
- for (unsigned I = 0; I != NumTypes; ++I)
- if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
- SizeType = Types[I];
+ for (const auto &T : Types)
+ if (Size->getBitWidth() == SemaRef.Context.getIntWidth(T)) {
+ SizeType = T;
break;
}
@@ -14733,14 +14925,15 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
}
template <typename Derived>
-QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E,
- SourceLocation) {
- return SemaRef.BuildTypeofExprType(E);
+QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, SourceLocation,
+ TypeOfKind Kind) {
+ return SemaRef.BuildTypeofExprType(E, Kind);
}
template<typename Derived>
-QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
- return SemaRef.Context.getTypeOfType(Underlying);
+QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying,
+ TypeOfKind Kind) {
+ return SemaRef.Context.getTypeOfType(Underlying, Kind);
}
template <typename Derived>
diff --git a/clang/lib/Sema/TypeLocBuilder.cpp b/clang/lib/Sema/TypeLocBuilder.cpp
index 2dcbbd83c691..fcd090ff2020 100644
--- a/clang/lib/Sema/TypeLocBuilder.cpp
+++ b/clang/lib/Sema/TypeLocBuilder.cpp
@@ -41,6 +41,29 @@ void TypeLocBuilder::pushFullCopy(TypeLoc L) {
}
}
+void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T,
+ SourceLocation Loc) {
+ auto L = TypeLoc(T, nullptr);
+ reserve(L.getFullDataSize());
+
+ SmallVector<TypeLoc, 4> TypeLocs;
+ for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc())
+ TypeLocs.push_back(CurTL);
+
+ for (const auto &CurTL : llvm::reverse(TypeLocs)) {
+ switch (CurTL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ case TypeLoc::CLASS: { \
+ auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
+ NewTL.initializeLocal(Context, Loc); \
+ break; \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ }
+ }
+}
+
void TypeLocBuilder::grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
@@ -85,7 +108,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
// FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
// hardcode them.
if (LocalAlignment == 4) {
- if (NumBytesAtAlign8 == 0) {
+ if (!AtAlign8) {
NumBytesAtAlign4 += LocalSize;
} else {
unsigned Padding = NumBytesAtAlign4 % 8;
@@ -114,7 +137,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
NumBytesAtAlign4 += LocalSize;
}
} else if (LocalAlignment == 8) {
- if (NumBytesAtAlign8 == 0) {
+ if (!AtAlign8) {
// We have not seen any 8-byte aligned element yet. We insert a padding
// only if the new Index is not 8-byte-aligned.
if ((Index - LocalSize) % 8 != 0) {
@@ -149,7 +172,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
// Forget about any padding.
NumBytesAtAlign4 = 0;
- NumBytesAtAlign8 += LocalSize;
+ AtAlign8 = true;
} else {
assert(LocalSize == 0);
}
diff --git a/clang/lib/Sema/TypeLocBuilder.h b/clang/lib/Sema/TypeLocBuilder.h
index 738f731c9fe2..d413d74b74ff 100644
--- a/clang/lib/Sema/TypeLocBuilder.h
+++ b/clang/lib/Sema/TypeLocBuilder.h
@@ -40,12 +40,13 @@ class TypeLocBuilder {
/// The inline buffer.
enum { BufferMaxAlignment = alignof(void *) };
alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
- unsigned NumBytesAtAlign4, NumBytesAtAlign8;
+ unsigned NumBytesAtAlign4;
+ bool AtAlign8;
public:
TypeLocBuilder()
: Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
- NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
+ NumBytesAtAlign4(0), AtAlign8(false) {}
~TypeLocBuilder() {
if (Buffer != InlineBuffer)
@@ -63,6 +64,10 @@ public:
/// must be empty for this to work.
void pushFullCopy(TypeLoc L);
+ /// Pushes 'T' with all locations pointing to 'Loc'.
+ /// The builder must be empty for this to work.
+ void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc);
+
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
@@ -77,7 +82,8 @@ public:
LastTy = QualType();
#endif
Index = Capacity;
- NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
+ NumBytesAtAlign4 = 0;
+ AtAlign8 = false;
}
/// Tell the TypeLocBuilder that the type it is storing has been
diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h
index 24b7342b3fb4..580d702f96fe 100644
--- a/clang/lib/Sema/UsedDeclVisitor.h
+++ b/clang/lib/Sema/UsedDeclVisitor.h
@@ -82,11 +82,28 @@ public:
void VisitCXXConstructExpr(CXXConstructExpr *E) {
asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor());
+ CXXConstructorDecl *D = E->getConstructor();
+ for (const CXXCtorInitializer *Init : D->inits()) {
+ if (Init->isInClassMemberInitializer())
+ asImpl().Visit(Init->getInit());
+ }
Inherited::VisitCXXConstructExpr(E);
}
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
asImpl().Visit(E->getExpr());
+ Inherited::VisitCXXDefaultArgExpr(E);
+ }
+
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ asImpl().Visit(E->getExpr());
+ Inherited::VisitCXXDefaultInitExpr(E);
+ }
+
+ void VisitInitListExpr(InitListExpr *ILE) {
+ if (ILE->hasArrayFiller())
+ asImpl().Visit(ILE->getArrayFiller());
+ Inherited::VisitInitListExpr(ILE);
}
void visitUsedDecl(SourceLocation Loc, Decl *D) {