aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.cpp2
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp6
-rw-r--r--clang/lib/Sema/SemaConcept.cpp3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp11
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp10
-rw-r--r--clang/lib/Sema/SemaModule.cpp472
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp18
-rw-r--r--clang/lib/Sema/SemaOpenACCAtomic.cpp16
-rw-r--r--clang/lib/Sema/SemaOpenACCClause.cpp16
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp37
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp21
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp2
-rw-r--r--clang/lib/Sema/SemaWasm.cpp49
13 files changed, 638 insertions, 25 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 56608e9..d50eeff 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1616,6 +1616,8 @@ void Sema::ActOnEndOfTranslationUnit() {
if (!PP.isIncrementalProcessingEnabled())
TUScope = nullptr;
+
+ checkExposure(Context.getTranslationUnitDecl());
}
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 8c6a173..68a698f 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -547,6 +547,12 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
return;
}
case AR_Deprecated:
+ // Suppress -Wdeprecated-declarations in implicit
+ // functions.
+ if (const auto *FD = dyn_cast_or_null<FunctionDecl>(S.getCurFunctionDecl());
+ FD && FD->isImplicit())
+ return;
+
if (ObjCPropertyAccess)
diag = diag::warn_property_method_deprecated;
else if (S.currentEvaluationContext().IsCaseExpr)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 5205ca0b..044cf5c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -588,6 +588,9 @@ static bool CheckConstraintSatisfaction(
return true;
for (const AssociatedConstraint &AC : AssociatedConstraints) {
+ if (AC.isNull())
+ return true;
+
Sema::ArgPackSubstIndexRAII _(S, AC.ArgPackSubstIndex);
ExprResult Res = calculateConstraintSatisfaction(
S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fd22e01..d7420bd 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3267,6 +3267,14 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
if (isa<UsedAttr>(I) || isa<RetainAttr>(I))
continue;
+ if (isa<InferredNoReturnAttr>(I)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(New)) {
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue; // Don't propagate inferred noreturn attributes to explicit
+ // specializations.
+ }
+ }
+
if (mergeDeclAttribute(*this, New, I, LocalAMK))
foundAny = true;
}
@@ -20573,7 +20581,8 @@ TopLevelStmtDecl *Sema::ActOnStartTopLevelStmtDecl(Scope *S) {
}
void Sema::ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement) {
- D->setStmt(Statement);
+ if (Statement)
+ D->setStmt(Statement);
PopCompoundScope();
PopFunctionScopeInfo();
PopDeclContext();
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 9a2950c..a4e8de4 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1970,6 +1970,13 @@ void clang::inferNoReturnAttr(Sema &S, const Decl *D) {
if (!FD)
return;
+ // Skip explicit specializations here as they may have
+ // a user-provided definition that may deliberately differ from the primary
+ // template. If an explicit specialization truly never returns, the user
+ // should explicitly mark it with [[noreturn]].
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
auto *NonConstFD = const_cast<FunctionDecl *>(FD);
DiagnosticsEngine &Diags = S.getDiagnostics();
if (Diags.isIgnored(diag::warn_falloff_nonvoid, FD->getLocation()) &&
@@ -2034,7 +2041,8 @@ bool Sema::CheckAttrTarget(const ParsedAttr &AL) {
// Check whether the attribute is valid on the current target.
if (!AL.existsInTarget(Context.getTargetInfo())) {
if (AL.isRegularKeywordAttribute())
- Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target);
+ Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target)
+ << AL << AL.getRange();
else
DiagnoseUnknownAttribute(AL);
AL.setInvalid();
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 7c982bc..98ebd70 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/ParsedAttr.h"
@@ -485,6 +486,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// implementation unit importing its interface). Make this module visible
// and return the import decl to be added to the current TU.
if (Interface) {
+ HadImportedNamedModules = true;
makeTransitiveImportsVisible(getASTContext(), VisibleModules, Interface,
Mod, ModuleLoc,
@@ -728,6 +730,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
getCurrentModule()->Imports.insert(Mod);
}
+ HadImportedNamedModules = true;
+
return Import;
}
@@ -1102,3 +1106,471 @@ bool Sema::isCurrentModulePurview() const {
return false;
}
}
+
+//===----------------------------------------------------------------------===//
+// Checking Exposure in modules //
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ExposureChecker {
+public:
+ ExposureChecker(Sema &S) : SemaRef(S) {}
+
+ bool checkExposure(const VarDecl *D, bool Diag);
+ bool checkExposure(const CXXRecordDecl *D, bool Diag);
+ bool checkExposure(const Stmt *S, bool Diag);
+ bool checkExposure(const FunctionDecl *D, bool Diag);
+ bool checkExposure(const NamedDecl *D, bool Diag);
+ void checkExposureInContext(const DeclContext *DC);
+ bool isExposureCandidate(const NamedDecl *D);
+
+ bool isTULocal(QualType Ty);
+ bool isTULocal(const NamedDecl *ND);
+ bool isTULocal(const Expr *E);
+
+ Sema &SemaRef;
+
+private:
+ llvm::DenseSet<const NamedDecl *> ExposureSet;
+ llvm::DenseSet<const NamedDecl *> KnownNonExposureSet;
+};
+
+bool ExposureChecker::isTULocal(QualType Ty) {
+ // [basic.link]p15:
+ // An entity is TU-local if it is
+ // - a type, type alias, namespace, namespace alias, function, variable, or
+ // template that
+ // -- has internal linkage, or
+ return Ty->getLinkage() == Linkage::Internal;
+
+ // TODO:
+ // [basic.link]p15.2:
+ // a type with no name that is defined outside a class-specifier, function
+ // body, or initializer or is introduced by a defining-type-specifier that
+ // is used to declare only TU-local entities,
+}
+
+bool ExposureChecker::isTULocal(const NamedDecl *D) {
+ if (!D)
+ return false;
+
+ // [basic.link]p15:
+ // An entity is TU-local if it is
+ // - a type, type alias, namespace, namespace alias, function, variable, or
+ // template that
+ // -- has internal linkage, or
+ if (D->getLinkageInternal() == Linkage::Internal)
+ return true;
+
+ if (D->isInAnonymousNamespace())
+ return true;
+
+ // [basic.link]p15.1.2:
+ // does not have a name with linkage and is declared, or introduced by a
+ // lambda-expression, within the definition of a TU-local entity,
+ if (D->getLinkageInternal() == Linkage::None)
+ if (auto *ND = dyn_cast<NamedDecl>(D->getDeclContext());
+ ND && isTULocal(ND))
+ return true;
+
+ // [basic.link]p15.3, p15.4:
+ // - a specialization of a TU-local template,
+ // - a specialization of a template with any TU-local template argument, or
+ ArrayRef<TemplateArgument> TemplateArgs;
+ NamedDecl *PrimaryTemplate = nullptr;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ TemplateArgs = CTSD->getTemplateArgs().asArray();
+ PrimaryTemplate = CTSD->getSpecializedTemplate();
+ if (isTULocal(PrimaryTemplate))
+ return true;
+ } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ TemplateArgs = VTSD->getTemplateArgs().asArray();
+ PrimaryTemplate = VTSD->getSpecializedTemplate();
+ if (isTULocal(PrimaryTemplate))
+ return true;
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *TAList = FD->getTemplateSpecializationArgs())
+ TemplateArgs = TAList->asArray();
+
+ PrimaryTemplate = FD->getPrimaryTemplate();
+ if (isTULocal(PrimaryTemplate))
+ return true;
+ }
+
+ if (!PrimaryTemplate)
+ // Following off, we only check for specializations.
+ return false;
+
+ if (KnownNonExposureSet.count(D))
+ return false;
+
+ for (auto &TA : TemplateArgs) {
+ switch (TA.getKind()) {
+ case TemplateArgument::Type:
+ if (isTULocal(TA.getAsType()))
+ return true;
+ break;
+ case TemplateArgument::Declaration:
+ if (isTULocal(TA.getAsDecl()))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // [basic.link]p15.5
+ // - a specialization of a template whose (possibly instantiated) declaration
+ // is an exposure.
+ if (checkExposure(PrimaryTemplate, /*Diag=*/false))
+ return true;
+
+ // Avoid calling checkExposure again since it is expensive.
+ KnownNonExposureSet.insert(D);
+ return false;
+}
+
+bool ExposureChecker::isTULocal(const Expr *E) {
+ if (!E)
+ return false;
+
+ // [basic.link]p16:
+ // A value or object is TU-local if either
+ // - it is of TU-local type,
+ if (isTULocal(E->getType()))
+ return true;
+
+ E = E->IgnoreParenImpCasts();
+ // [basic.link]p16.2:
+ // - it is, or is a pointer to, a TU-local function or the object associated
+ // with a TU-local variable,
+ // - it is an object of class or array type and any of its subobjects or any
+ // of the objects or functions to which its non-static data members of
+ // reference type refer is TU-local and is usable in constant expressions, or
+ // FIXME: But how can we know the value of pointers or arrays at compile time?
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(DRE->getFoundDecl()))
+ return isTULocal(FD);
+ else if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getFoundDecl()))
+ return isTULocal(VD);
+ else if (auto *RD = dyn_cast_or_null<CXXRecordDecl>(DRE->getFoundDecl()))
+ return isTULocal(RD);
+ }
+
+ // TODO:
+ // [basic.link]p16.4:
+ // it is a reflection value that represents...
+
+ return false;
+}
+
+bool ExposureChecker::isExposureCandidate(const NamedDecl *D) {
+ if (!D)
+ return false;
+
+ // [basic.link]p17:
+ // If a (possibly instantiated) declaration of, or a deduction guide for,
+ // a non-TU-local entity in a module interface unit
+ // (outside the private-module-fragment, if any) or
+ // module partition is an exposure, the program is ill-formed.
+ Module *M = D->getOwningModule();
+ if (!M || !M->isInterfaceOrPartition())
+ return false;
+
+ if (D->isImplicit())
+ return false;
+
+ // [basic.link]p14:
+ // A declaration is an exposure if it either names a TU-local entity
+ // (defined below), ignoring:
+ // ...
+ // - friend declarations in a class definition
+ if (D->getFriendObjectKind() &&
+ isa<CXXRecordDecl>(D->getLexicalDeclContext()))
+ return false;
+
+ return true;
+}
+
+bool ExposureChecker::checkExposure(const NamedDecl *D, bool Diag) {
+ if (!isExposureCandidate(D))
+ return false;
+
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return checkExposure(FD, Diag);
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ return checkExposure(FTD->getTemplatedDecl(), Diag);
+
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return checkExposure(VD, Diag);
+ if (auto *VTD = dyn_cast<VarTemplateDecl>(D))
+ return checkExposure(VTD->getTemplatedDecl(), Diag);
+
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return checkExposure(RD, Diag);
+
+ if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
+ return checkExposure(CTD->getTemplatedDecl(), Diag);
+
+ return false;
+}
+
+bool ExposureChecker::checkExposure(const FunctionDecl *FD, bool Diag) {
+ bool IsExposure = false;
+ if (isTULocal(FD->getReturnType())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(FD->getReturnTypeSourceRange().getBegin(),
+ diag::warn_exposure)
+ << FD->getReturnType();
+ }
+
+ for (ParmVarDecl *Parms : FD->parameters())
+ if (isTULocal(Parms->getType())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(Parms->getLocation(), diag::warn_exposure)
+ << Parms->getType();
+ }
+
+ bool IsImplicitInstantiation =
+ FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+
+ // [basic.link]p14:
+ // A declaration is an exposure if it either names a TU-local entity
+ // (defined below), ignoring:
+ // - the function-body for a non-inline function or function template
+ // (but not the deduced return
+ // type for a (possibly instantiated) definition of a function with a
+ // declared return type that uses a placeholder type
+ // ([dcl.spec.auto])),
+ Diag &=
+ (FD->isInlined() || IsImplicitInstantiation) && !FD->isDependentContext();
+
+ IsExposure |= checkExposure(FD->getBody(), Diag);
+ if (IsExposure)
+ ExposureSet.insert(FD);
+
+ return IsExposure;
+}
+
+bool ExposureChecker::checkExposure(const VarDecl *VD, bool Diag) {
+ bool IsExposure = false;
+ // [basic.link]p14:
+ // A declaration is an exposure if it either names a TU-local entity (defined
+ // below), ignoring:
+ // ...
+ // or defines a constexpr variable initialized to a TU-local value (defined
+ // below).
+ if (VD->isConstexpr() && isTULocal(VD->getInit())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(VD->getInit()->getExprLoc(), diag::warn_exposure)
+ << VD->getInit();
+ }
+
+ if (isTULocal(VD->getType())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(VD->getLocation(), diag::warn_exposure) << VD->getType();
+ }
+
+ // [basic.link]p14:
+ // ..., ignoring:
+ // - the initializer for a variable or variable template (but not the
+ // variable's type),
+ //
+ // Note: although the spec says to ignore the initializer for all variable,
+ // for the code we generated now for inline variables, it is dangerous if the
+ // initializer of an inline variable is TULocal.
+ Diag &= !VD->getDeclContext()->isDependentContext() && VD->isInline();
+ IsExposure |= checkExposure(VD->getInit(), Diag);
+ if (IsExposure)
+ ExposureSet.insert(VD);
+
+ return IsExposure;
+}
+
+bool ExposureChecker::checkExposure(const CXXRecordDecl *RD, bool Diag) {
+ if (!RD->hasDefinition())
+ return false;
+
+ bool IsExposure = false;
+ for (CXXMethodDecl *Method : RD->methods())
+ IsExposure |= checkExposure(Method, Diag);
+
+ for (FieldDecl *FD : RD->fields()) {
+ if (isTULocal(FD->getType())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(FD->getLocation(), diag::warn_exposure) << FD->getType();
+ }
+ }
+
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (isTULocal(Base.getType())) {
+ IsExposure = true;
+ if (Diag)
+ SemaRef.Diag(Base.getBaseTypeLoc(), diag::warn_exposure)
+ << Base.getType();
+ }
+ }
+
+ if (IsExposure)
+ ExposureSet.insert(RD);
+
+ return IsExposure;
+}
+
+template <typename CallbackTy>
+class ReferenceTULocalChecker
+ : public clang::RecursiveASTVisitor<ReferenceTULocalChecker<CallbackTy>> {
+public:
+ ReferenceTULocalChecker(ExposureChecker &C, CallbackTy &&Callback)
+ : Checker(C), Callback(std::move(Callback)) {}
+
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ ValueDecl *Referenced = DRE->getDecl();
+ if (!Referenced)
+ return true;
+
+ if (!Checker.isTULocal(Referenced))
+ // We don't care if the referenced declaration is not TU-local.
+ return true;
+
+ Qualifiers Qual = DRE->getType().getQualifiers();
+ // [basic.link]p14:
+ // A declaration is an exposure if it either names a TU-local entity
+ // (defined below), ignoring:
+ // ...
+ // - any reference to a non-volatile const object ...
+ if (Qual.hasConst() && !Qual.hasVolatile())
+ return true;
+
+ // [basic.link]p14:
+ // ..., ignoring:
+ // ...
+ // (p14.4) - ... or reference with internal or no linkage initialized with
+ // a constant expression that is not an odr-use
+ ASTContext &Context = Referenced->getASTContext();
+ Linkage L = Referenced->getLinkageInternal();
+ if (DRE->isNonOdrUse() && (L == Linkage::Internal || L == Linkage::None))
+ if (auto *VD = dyn_cast<VarDecl>(Referenced);
+ VD && VD->getInit() && !VD->getInit()->isValueDependent() &&
+ VD->getInit()->isConstantInitializer(Context, /*IsForRef=*/false))
+ return true;
+
+ Callback(DRE, Referenced);
+ return true;
+ }
+
+ ExposureChecker &Checker;
+ CallbackTy Callback;
+};
+
+template <typename CallbackTy>
+ReferenceTULocalChecker(ExposureChecker &, CallbackTy &&)
+ -> ReferenceTULocalChecker<CallbackTy>;
+
+bool ExposureChecker::checkExposure(const Stmt *S, bool Diag) {
+ if (!S)
+ return false;
+
+ bool HasReferencedTULocals = false;
+ ReferenceTULocalChecker Checker(
+ *this, [this, &HasReferencedTULocals, Diag](DeclRefExpr *DRE,
+ ValueDecl *Referenced) {
+ if (Diag) {
+ SemaRef.Diag(DRE->getExprLoc(), diag::warn_exposure) << Referenced;
+ }
+ HasReferencedTULocals = true;
+ });
+ Checker.TraverseStmt(const_cast<Stmt *>(S));
+ return HasReferencedTULocals;
+}
+
+void ExposureChecker::checkExposureInContext(const DeclContext *DC) {
+ for (auto *TopD : DC->noload_decls()) {
+ auto *TopND = dyn_cast<NamedDecl>(TopD);
+ if (!TopND)
+ continue;
+
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(TopND)) {
+ checkExposureInContext(Namespace);
+ continue;
+ }
+
+ // [basic.link]p17:
+ // If a (possibly instantiated) declaration of, or a deduction guide for,
+ // a non-TU-local entity in a module interface unit
+ // (outside the private-module-fragment, if any) or
+ // module partition is an exposure, the program is ill-formed.
+ if (!TopND->isFromASTFile() && isExposureCandidate(TopND) &&
+ !isTULocal(TopND))
+ checkExposure(TopND, /*Diag=*/true);
+ }
+}
+
+} // namespace
+
+void Sema::checkExposure(const TranslationUnitDecl *TU) {
+ if (!TU)
+ return;
+
+ ExposureChecker Checker(*this);
+
+ Module *M = TU->getOwningModule();
+ if (M && M->isInterfaceOrPartition())
+ Checker.checkExposureInContext(TU);
+
+ // [basic.link]p18:
+ // If a declaration that appears in one translation unit names a TU-local
+ // entity declared in another translation unit that is not a header unit,
+ // the program is ill-formed.
+ for (auto FDAndInstantiationLocPair : PendingCheckReferenceForTULocal) {
+ FunctionDecl *FD = FDAndInstantiationLocPair.first;
+ SourceLocation PointOfInstantiation = FDAndInstantiationLocPair.second;
+
+ if (!FD->hasBody())
+ continue;
+
+ ReferenceTULocalChecker(Checker, [&, this](DeclRefExpr *DRE,
+ ValueDecl *Referenced) {
+ // A "defect" in current implementation. Now an implicit instantiation of
+ // a template, the instantiation is considered to be in the same module
+ // unit as the template instead of the module unit where the instantiation
+ // happens.
+ //
+ // See test/Modules/Exposre-2.cppm for example.
+ if (!Referenced->isFromASTFile())
+ return;
+
+ if (!Referenced->isInAnotherModuleUnit())
+ return;
+
+ // This is not standard conforming. But given there are too many static
+ // (inline) functions in headers in existing code, it is more user
+ // friendly to ignore them temporarily now. maybe we can have another flag
+ // for this.
+ if (Referenced->getOwningModule()->isExplicitGlobalModule() &&
+ isa<FunctionDecl>(Referenced))
+ return;
+
+ Diag(PointOfInstantiation,
+ diag::warn_reference_tu_local_entity_in_other_tu)
+ << FD << Referenced
+ << Referenced->getOwningModule()->getTopLevelModuleName();
+ }).TraverseStmt(FD->getBody());
+ }
+}
+
+void Sema::checkReferenceToTULocalFromOtherTU(
+ FunctionDecl *FD, SourceLocation PointOfInstantiation) {
+ // Checking if a declaration have any reference to TU-local entities in other
+ // TU is expensive. Try to avoid it as much as possible.
+ if (!FD || !HadImportedNamedModules)
+ return;
+
+ PendingCheckReferenceForTULocal.push_back(
+ std::make_pair(FD, PointOfInstantiation));
+}
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 128a5db..8bfea62 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -699,11 +699,19 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
// OpenACC3.3 2.13:
// A 'var' in a 'declare' directive must be a variable or array name.
if ((CK == OpenACCClauseKind::UseDevice ||
- DK == OpenACCDirectiveKind::Declare) &&
- isa<ArraySectionExpr, ArraySubscriptExpr>(CurVarExpr)) {
- Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref_use_device_declare)
- << (DK == OpenACCDirectiveKind::Declare);
- return ExprError();
+ DK == OpenACCDirectiveKind::Declare)) {
+ if (isa<ArraySubscriptExpr>(CurVarExpr)) {
+ Diag(VarExpr->getExprLoc(),
+ diag::err_acc_not_a_var_ref_use_device_declare)
+ << (DK == OpenACCDirectiveKind::Declare);
+ return ExprError();
+ }
+ // As an extension, we allow 'array sections'/'sub-arrays' here, as that is
+ // effectively defining an array, and are in common use.
+ if (isa<ArraySectionExpr>(CurVarExpr))
+ Diag(VarExpr->getExprLoc(),
+ diag::ext_acc_array_section_use_device_declare)
+ << (DK == OpenACCDirectiveKind::Declare);
}
// Sub-arrays/subscript-exprs are fine as long as the base is a
diff --git a/clang/lib/Sema/SemaOpenACCAtomic.cpp b/clang/lib/Sema/SemaOpenACCAtomic.cpp
index 9c8c8d1..a9319dc 100644
--- a/clang/lib/Sema/SemaOpenACCAtomic.cpp
+++ b/clang/lib/Sema/SemaOpenACCAtomic.cpp
@@ -576,6 +576,11 @@ class AtomicOperandChecker {
return AssocStmt;
}
+ const Expr *IgnoreBeforeCompare(const Expr *E) {
+ return E->IgnoreParenImpCasts()->IgnoreParenNoopCasts(
+ SemaRef.getASTContext());
+ }
+
bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind, const Expr *FirstX,
IDACInfo::ExprKindTy SecondKind, const Expr *SecondX) {
llvm::FoldingSetNodeID First_ID, Second_ID;
@@ -648,8 +653,10 @@ class AtomicOperandChecker {
if (CheckOperandVariable(AssignRes->RHS, PD))
return getRecoveryExpr();
- if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var,
- IDACInfo::SimpleAssign, AssignRes->RHS))
+ if (CheckVarRefsSame(FirstExprResults.ExprKind,
+ IgnoreBeforeCompare(FirstExprResults.X_Var),
+ IDACInfo::SimpleAssign,
+ IgnoreBeforeCompare(AssignRes->RHS)))
return getRecoveryExpr();
break;
}
@@ -660,9 +667,10 @@ class AtomicOperandChecker {
if (SecondExprResults.Failed)
return getRecoveryExpr();
- if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var,
+ if (CheckVarRefsSame(FirstExprResults.ExprKind,
+ IgnoreBeforeCompare(FirstExprResults.X_Var),
SecondExprResults.ExprKind,
- SecondExprResults.X_Var))
+ IgnoreBeforeCompare(SecondExprResults.X_Var)))
return getRecoveryExpr();
break;
}
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index 3f90fe8..b54a012 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -1919,6 +1919,14 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind,
<< EltTy << /*Sub array base type*/ 1;
return ExprError();
}
+ } else if (VarExpr->getType()->isArrayType()) {
+ // Arrays are considered an 'aggregate variable' explicitly, so are OK, no
+ // additional checking required.
+ //
+ // Glossary: Aggregate variables – a variable of any non-scalar datatype,
+ // including array or composite variables.
+ //
+ // The next branch (record decl) checks for composite variables.
} else if (auto *RD = VarExpr->getType()->getAsRecordDecl()) {
if (!RD->isStruct() && !RD->isClass()) {
Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_composite_type)
@@ -2246,7 +2254,13 @@ bool SemaOpenACC::CheckDeclareClause(SemaOpenACC::OpenACCParsedClause &Clause,
continue;
}
} else {
- const auto *DRE = cast<DeclRefExpr>(VarExpr);
+
+ const Expr *VarExprTemp = VarExpr;
+
+ while (const auto *ASE = dyn_cast<ArraySectionExpr>(VarExprTemp))
+ VarExprTemp = ASE->getBase()->IgnoreParenImpCasts();
+
+ const auto *DRE = cast<DeclRefExpr>(VarExprTemp);
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
CurDecl = Var->getCanonicalDecl();
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 4ecc9b0..2c5d97c 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2829,7 +2829,7 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
continue;
}
for (Expr *Ref : RC->varlist()) {
- assert(Ref && "NULL expr in OpenMP nontemporal clause.");
+ assert(Ref && "NULL expr in OpenMP reduction clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = Ref;
@@ -7612,6 +7612,23 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective(
return;
}
+ // OpenMP 6.0 [9.6.2 (page 332, line 31-33, adjust_args clause, Restrictions]
+ // If the `need_device_addr` adjust-op modifier is present, each list item
+ // that appears in the clause must refer to an argument in the declaration of
+ // the function variant that has a reference type
+ if (getLangOpts().OpenMP >= 60) {
+ for (Expr *E : AdjustArgsNeedDeviceAddr) {
+ E = E->IgnoreParenImpCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (!VD->getType()->isReferenceType())
+ Diag(E->getExprLoc(),
+ diag::err_omp_non_by_ref_need_device_addr_modifier_argument);
+ }
+ }
+ }
+ }
+
auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
getASTContext(), VariantRef, &TI,
const_cast<Expr **>(AdjustArgsNothing.data()), AdjustArgsNothing.size(),
@@ -18344,7 +18361,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
+ assert(RefExpr && "NULL expr in OpenMP shared clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -19991,7 +20008,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAlignedClause(
SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP linear clause.");
+ assert(RefExpr && "NULL expr in OpenMP aligned clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -20167,7 +20184,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP linear clause.");
+ assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -20526,7 +20543,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDependClause(
TotalDepCount = VarOffset.TotalDepCount;
} else {
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ assert(RefExpr && "NULL expr in OpenMP depend clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
@@ -23737,7 +23754,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAllocateClause(
// Analyze and build list of variables.
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP private clause.");
+ assert(RefExpr && "NULL expr in OpenMP allocate clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -23829,7 +23846,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ assert(RefExpr && "NULL expr in OpenMP inclusive clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -23870,7 +23887,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ assert(RefExpr && "NULL expr in OpenMP exclusive clause.");
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -24063,7 +24080,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAffinityClause(
SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) {
SmallVector<Expr *, 8> Vars;
for (Expr *RefExpr : Locators) {
- assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ assert(RefExpr && "NULL expr in OpenMP affinity clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) {
// It will be analyzed later.
Vars.push_back(RefExpr);
@@ -24375,7 +24392,7 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr(
return ExprError();
}
}
- } else if (ColonLocFirst.isValid() &&
+ } else if (SemaRef.getLangOpts().OpenMP < 60 && ColonLocFirst.isValid() &&
(OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() &&
!OriginalTy->isVariableArrayType()))) {
// OpenMP 5.0, [2.1.5 Array Sections]
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index e1a975b..9e56e697 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5523,6 +5523,15 @@ static TemplateDeductionResult CheckDeductionConsistency(
// FIXME: A substitution can be incomplete on a non-structural part of the
// type. Use the canonical type for now, until the TemplateInstantiator can
// deal with that.
+
+ // Workaround: Implicit deduction guides use InjectedClassNameTypes, whereas
+ // the explicit guides don't. The substitution doesn't transform these types,
+ // so let it transform their specializations instead.
+ bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
+ if (IsDeductionGuide) {
+ if (auto *Injected = P->getAs<InjectedClassNameType>())
+ P = Injected->getInjectedSpecializationType();
+ }
QualType InstP = S.SubstType(P.getCanonicalType(), MLTAL, FTD->getLocation(),
FTD->getDeclName(), &IsIncompleteSubstitution);
if (InstP.isNull() && !IsIncompleteSubstitution)
@@ -5537,9 +5546,15 @@ static TemplateDeductionResult CheckDeductionConsistency(
if (auto *PA = dyn_cast<PackExpansionType>(A);
PA && !isa<PackExpansionType>(InstP))
A = PA->getPattern();
- if (!S.Context.hasSameType(
- S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()),
- S.Context.getUnqualifiedArrayType(A.getNonReferenceType())))
+ auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType());
+ auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType());
+ if (IsDeductionGuide) {
+ if (auto *Injected = T1->getAs<InjectedClassNameType>())
+ T1 = Injected->getInjectedSpecializationType();
+ if (auto *Injected = T2->getAs<InjectedClassNameType>())
+ T2 = Injected->getInjectedSpecializationType();
+ }
+ if (!S.Context.hasSameType(T1, T2))
return TemplateDeductionResult::NonDeducedMismatch;
return TemplateDeductionResult::Success;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e2c3cdc..233bb65 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5853,6 +5853,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// context seems wrong. Investigate more.
ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true);
+ checkReferenceToTULocalFromOtherTU(Function, PointOfInstantiation);
+
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
if (auto *Listener = getASTMutationListener())
diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp
index 6faea24..8998492 100644
--- a/clang/lib/Sema/SemaWasm.cpp
+++ b/clang/lib/Sema/SemaWasm.cpp
@@ -227,6 +227,53 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) {
return false;
}
+bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) {
+ if (SemaRef.checkArgCount(TheCall, 1))
+ return true;
+
+ Expr *FuncPtrArg = TheCall->getArg(0);
+ QualType ArgType = FuncPtrArg->getType();
+
+ // Check that the argument is a function pointer
+ const PointerType *PtrTy = ArgType->getAs<PointerType>();
+ if (!PtrTy) {
+ return Diag(FuncPtrArg->getBeginLoc(),
+ diag::err_typecheck_expect_function_pointer)
+ << ArgType << FuncPtrArg->getSourceRange();
+ }
+
+ const FunctionProtoType *FuncTy =
+ PtrTy->getPointeeType()->getAs<FunctionProtoType>();
+ if (!FuncTy) {
+ return Diag(FuncPtrArg->getBeginLoc(),
+ diag::err_typecheck_expect_function_pointer)
+ << ArgType << FuncPtrArg->getSourceRange();
+ }
+
+ // Check that the function pointer doesn't use reference types
+ if (FuncTy->getReturnType().isWebAssemblyReferenceType()) {
+ return Diag(
+ FuncPtrArg->getBeginLoc(),
+ diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
+ << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange();
+ }
+ auto NParams = FuncTy->getNumParams();
+ for (unsigned I = 0; I < NParams; I++) {
+ if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) {
+ return Diag(
+ FuncPtrArg->getBeginLoc(),
+ diag::
+ err_wasm_builtin_test_fp_sig_cannot_include_reference_type)
+ << 1 << FuncPtrArg->getSourceRange();
+ }
+ }
+
+ // Set return type to int (the result of the test)
+ TheCall->setType(getASTContext().IntTy);
+
+ return false;
+}
+
bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall) {
@@ -249,6 +296,8 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
return BuiltinWasmTableFill(TheCall);
case WebAssembly::BI__builtin_wasm_table_copy:
return BuiltinWasmTableCopy(TheCall);
+ case WebAssembly::BI__builtin_wasm_test_function_pointer_signature:
+ return BuiltinWasmTestFunctionPointerSignature(TheCall);
}
return false;