aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp67
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp44
-rw-r--r--clang/lib/Sema/DeclSpec.cpp65
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp25
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp6
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td331
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp86
-rw-r--r--clang/lib/Sema/Sema.cpp372
-rw-r--r--clang/lib/Sema/SemaAttr.cpp250
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp964
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp120
-rw-r--r--clang/lib/Sema/SemaCast.cpp196
-rw-r--r--clang/lib/Sema/SemaChecking.cpp2536
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp782
-rw-r--r--clang/lib/Sema/SemaConcept.cpp433
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp140
-rw-r--r--clang/lib/Sema/SemaDecl.cpp845
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp1408
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp1221
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp117
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp27
-rw-r--r--clang/lib/Sema/SemaExpr.cpp1845
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp979
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp236
-rw-r--r--clang/lib/Sema/SemaInit.cpp156
-rw-r--r--clang/lib/Sema/SemaLambda.cpp27
-rw-r--r--clang/lib/Sema/SemaLookup.cpp225
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp617
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp3883
-rw-r--r--clang/lib/Sema/SemaOverload.cpp625
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp107
-rw-r--r--clang/lib/Sema/SemaSYCL.cpp49
-rw-r--r--clang/lib/Sema/SemaStmt.cpp127
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp27
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp41
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp888
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp444
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp565
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp357
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp4
-rw-r--r--clang/lib/Sema/SemaType.cpp717
-rw-r--r--clang/lib/Sema/TreeTransform.h1322
-rw-r--r--clang/lib/Sema/UsedDeclVisitor.h102
43 files changed, 16405 insertions, 6973 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 04611dadde66..3b7356893833 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -974,6 +974,14 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
<< Use.getUser()->getSourceRange();
}
+/// Diagnose uninitialized const reference usages.
+static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD,
+ const UninitUse &Use) {
+ S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference)
+ << VD->getDeclName() << Use.getUser()->getSourceRange();
+ return true;
+}
+
/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an
/// uninitialized variable. This manages the different forms of diagnostic
/// emitted for particular types of uses. Returns true if the use was diagnosed
@@ -1506,13 +1514,14 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
// order of diagnostics when calling flushDiagnostics().
typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
UsesMap uses;
+ UsesMap constRefUses;
public:
UninitValsDiagReporter(Sema &S) : S(S) {}
~UninitValsDiagReporter() override { flushDiagnostics(); }
- MappedType &getUses(const VarDecl *vd) {
- MappedType &V = uses[vd];
+ MappedType &getUses(UsesMap &um, const VarDecl *vd) {
+ MappedType &V = um[vd];
if (!V.getPointer())
V.setPointer(new UsesVec());
return V;
@@ -1520,11 +1529,17 @@ public:
void handleUseOfUninitVariable(const VarDecl *vd,
const UninitUse &use) override {
- getUses(vd).getPointer()->push_back(use);
+ getUses(uses, vd).getPointer()->push_back(use);
+ }
+
+ void handleConstRefUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) override {
+ getUses(constRefUses, vd).getPointer()->push_back(use);
}
void handleSelfInit(const VarDecl *vd) override {
- getUses(vd).setInt(true);
+ getUses(uses, vd).setInt(true);
+ getUses(constRefUses, vd).setInt(true);
}
void flushDiagnostics() {
@@ -1571,6 +1586,32 @@ public:
}
uses.clear();
+
+ // Flush all const reference uses diags.
+ for (const auto &P : constRefUses) {
+ const VarDecl *vd = P.first;
+ const MappedType &V = P.second;
+
+ UsesVec *vec = V.getPointer();
+ bool hasSelfInit = V.getInt();
+
+ if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec))
+ DiagnoseUninitializedUse(S, vd,
+ UninitUse(vd->getInit()->IgnoreParenCasts(),
+ /* isAlwaysUninit */ true),
+ /* alwaysReportSelfInit */ true);
+ else {
+ for (const auto &U : *vec) {
+ if (DiagnoseUninitializedConstRefUse(S, vd, U))
+ break;
+ }
+ }
+
+ // Release the uses vector.
+ delete vec;
+ }
+
+ constRefUses.clear();
}
private:
@@ -1659,6 +1700,14 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
: getNotes();
}
+ OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked,
+ StringRef Kind) {
+ return LocUnlocked.isValid()
+ ? getNotes(PartialDiagnosticAt(
+ LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind))
+ : getNotes();
+ }
+
public:
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
: S(S), FunLocation(FL), FunEndLocation(FEL),
@@ -1685,13 +1734,14 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes());
}
- void handleUnmatchedUnlock(StringRef Kind, Name LockName,
- SourceLocation Loc) override {
+ void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc,
+ SourceLocation LocPreviousUnlock) override {
if (Loc.isInvalid())
Loc = FunLocation;
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)
<< Kind << LockName);
- Warnings.emplace_back(std::move(Warning), getNotes());
+ Warnings.emplace_back(std::move(Warning),
+ makeUnlockedHereNote(LocPreviousUnlock, Kind));
}
void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
@@ -2184,7 +2234,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
!Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
- !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc())) {
+ !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
+ !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
UninitVariablesAnalysisStats stats;
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index b88ff9dd64cd..f1ad8aeaacbb 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -23,6 +23,7 @@
#include "clang/Sema/Sema.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Casting.h"
@@ -570,29 +571,10 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(
if (const char *BriefComment = CCS->getBriefComment())
OS << " : " << BriefComment;
}
- for (const FixItHint &FixIt : Results[I].FixIts) {
- const SourceLocation BLoc = FixIt.RemoveRange.getBegin();
- const SourceLocation ELoc = FixIt.RemoveRange.getEnd();
-
- SourceManager &SM = SemaRef.SourceMgr;
- std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
- std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
- // Adjust for token ranges.
- if (FixIt.RemoveRange.isTokenRange())
- EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts);
-
- OS << " (requires fix-it:"
- << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
- << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
- << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
- << SM.getColumnNumber(EInfo.first, EInfo.second) << "}"
- << " to \"" << FixIt.CodeToInsert << "\")";
- }
- OS << '\n';
break;
case CodeCompletionResult::RK_Keyword:
- OS << Results[I].Keyword << '\n';
+ OS << Results[I].Keyword;
break;
case CodeCompletionResult::RK_Macro:
@@ -602,13 +584,31 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(
includeBriefComments())) {
OS << " : " << CCS->getAsString();
}
- OS << '\n';
break;
case CodeCompletionResult::RK_Pattern:
- OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n';
+ OS << "Pattern : " << Results[I].Pattern->getAsString();
break;
}
+ for (const FixItHint &FixIt : Results[I].FixIts) {
+ const SourceLocation BLoc = FixIt.RemoveRange.getBegin();
+ const SourceLocation ELoc = FixIt.RemoveRange.getEnd();
+
+ SourceManager &SM = SemaRef.SourceMgr;
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
+ // Adjust for token ranges.
+ if (FixIt.RemoveRange.isTokenRange())
+ EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts);
+
+ OS << " (requires fix-it:"
+ << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
+ << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
+ << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
+ << SM.getColumnNumber(EInfo.first, EInfo.second) << "}"
+ << " to \"" << FixIt.CodeToInsert << "\")";
+ }
+ OS << '\n';
}
}
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 639231c87232..f4c30c90ad27 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/LocInfoType.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
@@ -29,6 +30,9 @@ using namespace clang;
void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
assert(TemplateId && "NULL template-id annotation?");
+ assert(!TemplateId->isInvalid() &&
+ "should not convert invalid template-ids to unqualified-ids");
+
Kind = UnqualifiedIdKind::IK_TemplateId;
this->TemplateId = TemplateId;
StartLocation = TemplateId->TemplateNameLoc;
@@ -37,6 +41,9 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) {
void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) {
assert(TemplateId && "NULL template-id annotation?");
+ assert(!TemplateId->isInvalid() &&
+ "should not convert invalid template-ids to unqualified-ids");
+
Kind = UnqualifiedIdKind::IK_ConstructorTemplateId;
this->TemplateId = TemplateId;
StartLocation = TemplateId->TemplateNameLoc;
@@ -130,6 +137,8 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
Range = Other.getSourceRange();
Builder.Adopt(Other);
+ assert(Range == Builder.getSourceRange() &&
+ "NestedNameSpecifierLoc range computation incorrect");
}
SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const {
@@ -351,6 +360,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_half:
case TST_int:
case TST_int128:
+ case TST_extint:
case TST_struct:
case TST_interface:
case TST_union:
@@ -358,6 +368,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_unspecified:
case TST_void:
case TST_wchar:
+ case TST_BFloat16:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
return false;
@@ -529,6 +540,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_char32: return "char32_t";
case DeclSpec::TST_int: return "int";
case DeclSpec::TST_int128: return "__int128";
+ case DeclSpec::TST_extint: return "_ExtInt";
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
@@ -555,6 +567,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
+ case DeclSpec::TST_BFloat16: return "__bf16";
#define GENERIC_IMAGE_TYPE(ImgType, Id) \
case DeclSpec::TST_##ImgType##_t: \
return #ImgType "_t";
@@ -784,6 +797,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
return false;
}
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, TemplateIdAnnotation *Rep,
+ const PrintingPolicy &Policy) {
+ assert(T == TST_auto || T == TST_decltype_auto);
+ ConstrainedAuto = true;
+ TemplateIdRep = Rep;
+ return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy);
+}
+
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
@@ -895,6 +917,27 @@ bool DeclSpec::SetTypeSpecError() {
return false;
}
+bool DeclSpec::SetExtIntType(SourceLocation KWLoc, Expr *BitsExpr,
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
+ assert(BitsExpr && "no expression provided!");
+ if (TypeSpecType == TST_error)
+ return false;
+
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
+ DiagID = diag::err_invalid_decl_spec_combination;
+ return true;
+ }
+
+ TypeSpecType = TST_extint;
+ ExprRep = BitsExpr;
+ TSTLoc = KWLoc;
+ TSTNameLoc = KWLoc;
+ TypeSpecOwned = false;
+ return false;
+}
+
bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, const LangOptions &Lang) {
// Duplicates are permitted in C99 onwards, but are not permitted in C89 or
@@ -1107,14 +1150,20 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
S.Diag(TSSLoc, diag::err_invalid_vector_bool_decl_spec)
<< getSpecifierName((TSS)TypeSpecSign);
}
-
- // Only char/int are valid with vector bool. (PIM 2.1)
+ // Only char/int are valid with vector bool prior to Power10.
+ // Power10 adds instructions that produce vector bool data
+ // for quadwords as well so allow vector bool __int128.
if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) &&
- (TypeSpecType != TST_int)) || TypeAltiVecPixel) {
+ (TypeSpecType != TST_int) && (TypeSpecType != TST_int128)) ||
+ TypeAltiVecPixel) {
S.Diag(TSTLoc, diag::err_invalid_vector_bool_decl_spec)
<< (TypeAltiVecPixel ? "__pixel" :
getSpecifierName((TST)TypeSpecType, Policy));
}
+ // vector bool __int128 requires Power10.
+ if ((TypeSpecType == TST_int128) &&
+ (!S.Context.getTargetInfo().hasFeature("power10-vector")))
+ S.Diag(TSTLoc, diag::err_invalid_vector_bool_int128_decl_spec);
// Only 'short' and 'long long' are valid with vector bool. (PIM 2.1)
if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) &&
@@ -1131,7 +1180,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// Elements of vector bool are interpreted as unsigned. (PIM 2.1)
if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) ||
- (TypeSpecWidth != TSW_unspecified))
+ (TypeSpecType == TST_int128) || (TypeSpecWidth != TSW_unspecified))
TypeSpecSign = TSS_unsigned;
} else if (TypeSpecType == TST_double) {
// vector long double and vector long long double are never allowed.
@@ -1176,7 +1225,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int.
else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 &&
TypeSpecType != TST_char && TypeSpecType != TST_wchar &&
- !IsFixedPointType) {
+ !IsFixedPointType && TypeSpecType != TST_extint) {
S.Diag(TSSLoc, diag::err_invalid_sign_spec)
<< getSpecifierName((TST)TypeSpecType, Policy);
// signed double -> double.
@@ -1223,11 +1272,13 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
S.getLocForEndOfToken(getTypeSpecComplexLoc()),
" double");
TypeSpecType = TST_double; // _Complex -> _Complex double.
- } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) {
+ } else if (TypeSpecType == TST_int || TypeSpecType == TST_char ||
+ TypeSpecType == TST_extint) {
// Note that this intentionally doesn't include _Complex _Bool.
if (!S.getLangOpts().CPlusPlus)
S.Diag(TSTLoc, diag::ext_integer_complex);
- } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
+ } else if (TypeSpecType != TST_float && TypeSpecType != TST_double &&
+ TypeSpecType != TST_float128) {
S.Diag(TSCLoc, diag::err_invalid_complex_spec)
<< getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecComplex = TSC_unspecified;
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index 960e62d4a2db..b34243edea35 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -75,6 +75,7 @@ private:
void BuildScopeInformation(Decl *D, unsigned &ParentScope);
void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl,
unsigned &ParentScope);
+ void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope);
void BuildScopeInformation(Stmt *S, unsigned &origParentScope);
void VerifyJumps();
@@ -276,6 +277,16 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
}
}
+/// Build scope information for compound literals of C struct types that are
+/// non-trivial to destruct.
+void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE,
+ unsigned &ParentScope) {
+ unsigned InDiag = diag::note_enters_compound_literal_scope;
+ unsigned OutDiag = diag::note_exits_compound_literal_scope;
+ Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc()));
+ ParentScope = Scopes.size() - 1;
+}
+
/// BuildScopeInformation - The statements from CI to CE are known to form a
/// coherent VLA scope with a specified parent node. Walk through the
/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
@@ -529,11 +540,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
// implementable but a lot of work which we haven't felt up to doing.
ExprWithCleanups *EWC = cast<ExprWithCleanups>(S);
for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
- const BlockDecl *BDecl = EWC->getObject(i);
- for (const auto &CI : BDecl->captures()) {
- VarDecl *variable = CI.getVariable();
- BuildScopeInformation(variable, BDecl, origParentScope);
- }
+ if (auto *BDecl = EWC->getObject(i).dyn_cast<BlockDecl *>())
+ for (const auto &CI : BDecl->captures()) {
+ VarDecl *variable = CI.getVariable();
+ BuildScopeInformation(variable, BDecl, origParentScope);
+ }
+ else if (auto *CLE = EWC->getObject(i).dyn_cast<CompoundLiteralExpr *>())
+ BuildScopeInformation(CLE, origParentScope);
+ else
+ llvm_unreachable("unexpected cleanup object type");
}
break;
}
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 2b0cd6b8c4fc..80333e63127e 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -275,6 +275,12 @@ void MultiplexExternalSemaSource::ReadExtVectorDecls(
Sources[i]->ReadExtVectorDecls(Decls);
}
+void MultiplexExternalSemaSource::ReadDeclsToCheckForDeferredDiags(
+ llvm::SmallVector<Decl *, 4> &Decls) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadDeclsToCheckForDeferredDiags(Decls);
+}
+
void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates(
llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) {
for(size_t i = 0; i < Sources.size(); ++i)
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index 9d6bb411eff8..745363a6b43f 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -60,10 +60,17 @@ def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32
def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">;
def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">;
def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">;
+def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">;
def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">;
// Multiple extensions
-def FuncExtKhrMipmapAndWrite3d : FunctionExtension<"cl_khr_mipmap_image cl_khr_3d_image_writes">;
+def FuncExtKhrMipmapWritesAndWrite3d : FunctionExtension<"cl_khr_mipmap_image_writes cl_khr_3d_image_writes">;
+
+// Arm extensions.
+def ArmIntegerDotProductInt8 : FunctionExtension<"cl_arm_integer_dot_product_int8">;
+def ArmIntegerDotProductAccumulateInt8 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_int8">;
+def ArmIntegerDotProductAccumulateInt16 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_int16">;
+def ArmIntegerDotProductAccumulateSaturateInt8 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_saturate_int8">;
// Qualified Type. These map to ASTContext::QualType.
class QualType<string _Name, bit _IsAbstract=0> {
@@ -120,7 +127,7 @@ class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
// OpenCL pointer types (e.g. int*, float*, ...).
class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> :
- Type<_Ty.Name, _Ty.QTName> {
+ Type<_Ty.Name, _Ty.QTName> {
let AddrSpace = _AS.Name;
// Inherited fields
let VecWidth = _Ty.VecWidth;
@@ -154,7 +161,7 @@ class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
// OpenCL image types (e.g. image2d).
class ImageType<Type _Ty, string _AccessQualifier> :
- Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
+ Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
let VecWidth = 0;
let AccessQualifier = _AccessQualifier;
// Inherited fields
@@ -165,8 +172,7 @@ class ImageType<Type _Ty, string _AccessQualifier> :
}
// List of Types.
-class TypeList<string _Name, list<Type> _Type> {
- string Name = _Name;
+class TypeList<list<Type> _Type> {
list<Type> List = _Type;
}
@@ -195,7 +201,7 @@ class TypeList<string _Name, list<Type> _Type> {
// A declaration f(GenT, SGenT) results in the combinations
// f(half, half), f(half2, half), f(int, int), f(int2, int) .
class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
- Type<_Ty, QualType<"null", 1>> {
+ Type<_Ty, QualType<"null", 1>> {
// Possible element types of the generic type.
TypeList TypeList = _TypeList;
// Possible vector sizes of the types in the TypeList.
@@ -259,8 +265,8 @@ def Half : Type<"half", QualType<"HalfTy">>;
def Size : Type<"size_t", QualType<"getSizeType()">>;
def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>;
-def UIntPtr : Type<"uintPtr_t", QualType<"getUIntPtrType()">>;
-def Void : Type<"void_t", QualType<"VoidTy">>;
+def UIntPtr : Type<"uintptr_t", QualType<"getUIntPtrType()">>;
+def Void : Type<"void", QualType<"VoidTy">>;
// OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types.
// Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter.
@@ -268,21 +274,36 @@ def Void : Type<"void_t", QualType<"VoidTy">>;
// OpenCL v1.0/1.2/2.0 s6.1.3: Other Built-in Data Types.
// The image definitions are "abstract". They should not be used without
// specifying an access qualifier (RO/WO/RW).
-def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>;
-def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>;
-def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>;
-def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>;
-def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>;
-def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>;
-def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>;
-def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>;
-def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>;
-def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>;
-def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>;
-def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>;
-
-def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>;
-def Event : Type<"Event", QualType<"OCLEventTy">>;
+def Image1d : Type<"image1d_t", QualType<"OCLImage1d", 1>>;
+def Image2d : Type<"image2d_t", QualType<"OCLImage2d", 1>>;
+def Image3d : Type<"image3d_t", QualType<"OCLImage3d", 1>>;
+def Image1dArray : Type<"image1d_array_t", QualType<"OCLImage1dArray", 1>>;
+def Image1dBuffer : Type<"image1d_buffer_t", QualType<"OCLImage1dBuffer", 1>>;
+def Image2dArray : Type<"image2d_array_t", QualType<"OCLImage2dArray", 1>>;
+def Image2dDepth : Type<"image2d_depth_t", QualType<"OCLImage2dDepth", 1>>;
+def Image2dArrayDepth : Type<"image2d_array_depth_t", QualType<"OCLImage2dArrayDepth", 1>>;
+def Image2dMsaa : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>;
+def Image2dArrayMsaa : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>;
+def Image2dMsaaDepth : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>;
+def Image2dArrayMsaaDepth : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>;
+
+def Sampler : Type<"sampler_t", QualType<"OCLSamplerTy">>;
+def ClkEvent : Type<"clk_event_t", QualType<"OCLClkEventTy">>;
+def Event : Type<"event_t", QualType<"OCLEventTy">>;
+def Queue : Type<"queue_t", QualType<"OCLQueueTy">>;
+def ReserveId : Type<"reserve_id_t", QualType<"OCLReserveIDTy">>;
+
+// OpenCL v2.0 s6.13.11: Atomic integer and floating-point types.
+def AtomicInt : Type<"atomic_int", QualType<"getAtomicType(Context.IntTy)">>;
+def AtomicUInt : Type<"atomic_uint", QualType<"getAtomicType(Context.UnsignedIntTy)">>;
+def AtomicLong : Type<"atomic_long", QualType<"getAtomicType(Context.LongTy)">>;
+def AtomicULong : Type<"atomic_ulong", QualType<"getAtomicType(Context.UnsignedLongTy)">>;
+def AtomicFloat : Type<"atomic_float", QualType<"getAtomicType(Context.FloatTy)">>;
+def AtomicDouble : Type<"atomic_double", QualType<"getAtomicType(Context.DoubleTy)">>;
+def AtomicIntPtr : Type<"atomic_intptr_t", QualType<"getAtomicType(Context.getIntPtrType())">>;
+def AtomicUIntPtr : Type<"atomic_uintptr_t", QualType<"getAtomicType(Context.getUIntPtrType())">>;
+def AtomicSize : Type<"atomic_size_t", QualType<"getAtomicType(Context.getSizeType())">>;
+def AtomicPtrDiff : Type<"atomic_ptrdiff_t", QualType<"getAtomicType(Context.getPointerDiffType())">>;
//===----------------------------------------------------------------------===//
// Definitions of OpenCL gentype variants
@@ -305,20 +326,20 @@ def Vec16 : IntList<"Vec16", [16]>;
def Vec1234 : IntList<"Vec1234", [1, 2, 3, 4]>;
// Type lists.
-def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
-def TLAllUnsigned : TypeList<"TLAllUnsigned", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>;
-def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
-def TLSignedInts : TypeList<"TLSignedInts", [Char, Short, Int, Long]>;
-def TLUnsignedInts : TypeList<"TLUnsignedInts", [UChar, UShort, UInt, ULong]>;
+def TLAll : TypeList<[Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLAllUnsigned : TypeList<[UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>;
+def TLFloat : TypeList<[Float, Double, Half]>;
+def TLSignedInts : TypeList<[Char, Short, Int, Long]>;
+def TLUnsignedInts : TypeList<[UChar, UShort, UInt, ULong]>;
-def TLIntLongFloats : TypeList<"TLIntLongFloats", [Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLIntLongFloats : TypeList<[Int, UInt, Long, ULong, Float, Double, Half]>;
// All unsigned integer types twice, to facilitate unsigned return types for e.g.
// uchar abs(char) and
// uchar abs(uchar).
-def TLAllUIntsTwice : TypeList<"TLAllUIntsTwice", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>;
+def TLAllUIntsTwice : TypeList<[UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>;
-def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
+def TLAllInts : TypeList<[Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
// GenType definitions for multiple base types (e.g. all floating point types,
// or all integer types).
@@ -348,8 +369,7 @@ foreach Type = [Char, UChar, Short, UShort,
foreach VecSizes = [VecAndScalar, VecNoScalar] in {
def "GenType" # Type # VecSizes :
GenericType<"GenType" # Type # VecSizes,
- TypeList<"GL" # Type.Name, [Type]>,
- VecSizes>;
+ TypeList<[Type]>, VecSizes>;
}
}
@@ -357,8 +377,7 @@ foreach Type = [Char, UChar, Short, UShort,
foreach Type = [Float, Double, Half] in {
def "GenType" # Type # Vec1234 :
GenericType<"GenType" # Type # Vec1234,
- TypeList<"GL" # Type.Name, [Type]>,
- Vec1234>;
+ TypeList<[Type]>, Vec1234>;
}
@@ -374,7 +393,11 @@ foreach RType = [Float, Double, Half, Char, UChar, Short,
UShort, Int, UInt, Long, ULong] in {
foreach IType = [Float, Double, Half, Char, UChar, Short,
UShort, Int, UInt, Long, ULong] in {
- foreach sat = ["", "_sat"] in {
+ // Conversions to integer type have a sat and non-sat variant.
+ foreach sat = !cond(!eq(RType.Name, "float") : [""],
+ !eq(RType.Name, "double") : [""],
+ !eq(RType.Name, "half") : [""],
+ 1 : ["", "_sat"]) in {
foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in {
def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType],
Attr.Const>;
@@ -667,7 +690,7 @@ foreach name = ["isfinite", "isinf", "isnan", "isnormal", "signbit"] in {
def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>;
}
foreach name = ["any", "all"] in {
- def : Builtin<name, [Int, AIGenTypeN], Attr.Const>;
+ def : Builtin<name, [Int, SGenTypeN], Attr.Const>;
}
// --- 2 arguments ---
@@ -722,17 +745,17 @@ let MaxVersion = CL20 in {
def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
}
foreach name = ["vstore" # VSize] in {
- def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>;
- def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>;
- def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>;
- def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>;
- def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>;
- def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>;
- def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>;
- def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>;
- def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>;
- def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>;
- def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<Char, AS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<UChar, AS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<Short, AS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<UShort, AS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<Int, AS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<UInt, AS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<Long, AS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ULong, AS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Float, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Double, AS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<Half, AS>]>;
}
foreach name = ["vloada_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
@@ -764,17 +787,17 @@ let MinVersion = CL20 in {
def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
}
foreach name = ["vstore" # VSize] in {
- def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>;
- def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<Char, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<UChar, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<Short, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<UShort, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<Int, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<UInt, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<Long, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ULong, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Float, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Double, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<Half, GenericAS>]>;
}
foreach name = ["vloada_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
@@ -805,24 +828,21 @@ foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vloada_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>;
}
- foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
- foreach name = ["vstorea_half" # VSize # rnd] in {
- def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, ConstantAS>]>;
- def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, ConstantAS>]>;
- }
- }
}
let MaxVersion = CL20 in {
foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vload_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
}
}
foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
- def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
- def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in {
+ def : Builtin<name, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, Double, Size, PointerType<Half, AS>]>;
+ }
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vstore_half" # VSize # rnd] in {
def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
@@ -835,14 +855,17 @@ let MaxVersion = CL20 in {
let MinVersion = CL20 in {
foreach AS = [GenericAS] in {
def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vload_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
}
}
foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
- def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
- def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in {
+ def : Builtin<name, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, Double, Size, PointerType<Half, AS>]>;
+ }
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vstore_half" # VSize # rnd] in {
def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
@@ -855,6 +878,7 @@ let MinVersion = CL20 in {
foreach AS = [ConstantAS] in {
def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vload_half" # VSize] in {
def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
@@ -976,6 +1000,45 @@ foreach AS = [GlobalAS, LocalAS] in {
}
}
}
+// OpenCL v2.0 s6.13.11 - Atomic Functions.
+let MinVersion = CL20 in {
+ foreach TypePair = [[AtomicInt, Int], [AtomicUInt, UInt],
+ [AtomicLong, Long], [AtomicULong, ULong],
+ [AtomicFloat, Float], [AtomicDouble, Double]] in {
+ def : Builtin<"atomic_init",
+ [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
+ def : Builtin<"atomic_store",
+ [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
+ def : Builtin<"atomic_load",
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>]>;
+ def : Builtin<"atomic_exchange",
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
+ foreach Variant = ["weak", "strong"] in {
+ def : Builtin<"atomic_compare_exchange_" # Variant,
+ [Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
+ PointerType<TypePair[1], GenericAS>, TypePair[1]]>;
+ }
+ }
+
+ foreach TypePair = [[AtomicInt, Int, Int], [AtomicUInt, UInt, UInt],
+ [AtomicLong, Long, Long], [AtomicULong, ULong, ULong],
+ [AtomicIntPtr, IntPtr, PtrDiff],
+ [AtomicUIntPtr, UIntPtr, PtrDiff]] in {
+ foreach ModOp = ["add", "sub"] in {
+ def : Builtin<"atomic_fetch_" # ModOp,
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>;
+ }
+ }
+ foreach TypePair = [[AtomicInt, Int, Int], [AtomicUInt, UInt, UInt],
+ [AtomicLong, Long, Long], [AtomicULong, ULong, ULong],
+ [AtomicIntPtr, IntPtr, IntPtr],
+ [AtomicUIntPtr, UIntPtr, UIntPtr]] in {
+ foreach ModOp = ["or", "xor", "and", "min", "max"] in {
+ def : Builtin<"atomic_fetch_" # ModOp,
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>;
+ }
+ }
+}
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions
@@ -1172,14 +1235,43 @@ let MinVersion = CL20 in {
}
-// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
-let MinVersion = CL20 in {
- let Extension = FuncExtKhrSubgroups in {
- def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>;
- def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>;
- def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>;
- }
-}
+//--------------------------------------------------------------------
+// OpenCL2.0 : 6.13.16 : Pipe Functions
+// --- Table 27 ---
+// Defined in Builtins.def
+
+// --- Table 28 ---
+// Builtins taking pipe arguments are defined in Builtins.def
+def : Builtin<"is_valid_reserve_id", [Bool, ReserveId]>;
+
+// --- Table 29 ---
+// Defined in Builtins.def
+
+
+//--------------------------------------------------------------------
+// OpenCL2.0 : 6.13.17 : Enqueuing Kernels
+// --- Table 30 ---
+// Defined in Builtins.def
+
+// --- Table 32 ---
+// Defined in Builtins.def
+
+// --- Table 33 ---
+def : Builtin<"enqueue_marker",
+ [Int, Queue, UInt, PointerType<ConstType<ClkEvent>, GenericAS>, PointerType<ClkEvent, GenericAS>]>;
+
+// --- Table 34 ---
+def : Builtin<"retain_event", [Void, ClkEvent]>;
+def : Builtin<"release_event", [Void, ClkEvent]>;
+def : Builtin<"create_user_event", [ClkEvent]>;
+def : Builtin<"is_valid_event", [Bool, ClkEvent]>;
+def : Builtin<"set_user_event_status", [Void, ClkEvent, Int]>;
+// TODO: capture_event_profiling_info
+
+// --- Table 35 ---
+def : Builtin<"get_default_queue", [Queue]>;
+// TODO: ndrange functions
+
//--------------------------------------------------------------------
// End of the builtin functions defined in the OpenCL C specification.
@@ -1274,6 +1366,16 @@ let Extension = FuncExtKhrMipmapImage in {
}
}
}
+ // Added to section 6.13.14.5
+ foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in {
+ def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>;
+ }
+ }
+}
+
+// Write functions are enabled using a separate extension.
+let Extension = FuncExtKhrMipmapImageWrites in {
// Added to section 6.13.14.4.
foreach aQual = ["WO"] in {
foreach imgTy = [Image2d] in {
@@ -1298,7 +1400,7 @@ let Extension = FuncExtKhrMipmapImage in {
def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
}
def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>;
- let Extension = FuncExtKhrMipmapAndWrite3d in {
+ let Extension = FuncExtKhrMipmapWritesAndWrite3d in {
foreach imgTy = [Image3d] in {
def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>;
def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>;
@@ -1306,15 +1408,8 @@ let Extension = FuncExtKhrMipmapImage in {
}
}
}
- // Added to section 6.13.14.5
- foreach aQual = ["RO", "WO", "RW"] in {
- foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in {
- def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>;
- }
- }
}
-
//--------------------------------------------------------------------
// OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures
let Extension = FuncExtKhrGlMsaaSharing in {
@@ -1346,6 +1441,70 @@ let Extension = FuncExtKhrGlMsaaSharing in {
}
def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>;
}
- def : Builtin<"get_image_array_size", [Size, ImageType<Image2dArrayMsaaDepth, aQual>], Attr.Const>;
+ foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in {
+ def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>;
+ }
+ }
+}
+
+//--------------------------------------------------------------------
+// OpenCL Extension v2.0 s28 - Subgroups
+// --- Table 28.2.1 ---
+let Extension = FuncExtKhrSubgroups in {
+ foreach name = ["get_sub_group_size", "get_max_sub_group_size",
+ "get_num_sub_groups", "get_sub_group_id",
+ "get_sub_group_local_id"] in {
+ def : Builtin<name, [UInt]>;
+ }
+ let MinVersion = CL20 in {
+ foreach name = ["get_enqueued_num_sub_groups"] in {
+ def : Builtin<name, [UInt]>;
+ }
+ }
+}
+
+// --- Table 28.2.2 ---
+// TODO: sub_group_barrier
+
+// --- Table 28.2.4 ---
+let Extension = FuncExtKhrSubgroups in {
+ foreach name = ["sub_group_all", "sub_group_any"] in {
+ def : Builtin<name, [Int, Int], Attr.Convergent>;
+ }
+ foreach name = ["sub_group_broadcast"] in {
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, UInt], Attr.Convergent>;
+ }
+ foreach name = ["sub_group_reduce_", "sub_group_scan_exclusive_",
+ "sub_group_scan_inclusive_"] in {
+ foreach op = ["add", "min", "max"] in {
+ def : Builtin<name # op, [IntLongFloatGenType1, IntLongFloatGenType1], Attr.Convergent>;
+ }
+ }
+}
+
+//--------------------------------------------------------------------
+// Arm extensions.
+let Extension = ArmIntegerDotProductInt8 in {
+ foreach name = ["arm_dot"] in {
+ def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>]>;
+ def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>]>;
+ }
+}
+let Extension = ArmIntegerDotProductAccumulateInt8 in {
+ foreach name = ["arm_dot_acc"] in {
+ def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>, UInt]>;
+ def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>, Int]>;
+ }
+}
+let Extension = ArmIntegerDotProductAccumulateInt16 in {
+ foreach name = ["arm_dot_acc"] in {
+ def : Builtin<name, [UInt, VectorType<UShort, 2>, VectorType<UShort, 2>, UInt]>;
+ def : Builtin<name, [Int, VectorType<Short, 2>, VectorType<Short, 2>, Int]>;
+ }
+}
+let Extension = ArmIntegerDotProductAccumulateSaturateInt8 in {
+ foreach name = ["arm_dot_acc_sat"] in {
+ def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>, UInt]>;
+ def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>, Int]>;
}
}
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 5d0a734f237a..3ef8498baffd 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -19,12 +19,15 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ManagedStatic.h"
#include <cassert>
#include <cstddef>
#include <utility>
using namespace clang;
+LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
+
IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
IdentifierInfo *Ident) {
IdentifierLoc *Result = new (Ctx) IdentifierLoc;
@@ -100,47 +103,60 @@ void AttributePool::takePool(AttributePool &pool) {
pool.Attrs.clear();
}
-struct ParsedAttrInfo {
- unsigned NumArgs : 4;
- unsigned OptArgs : 4;
- unsigned HasCustomParsing : 1;
- unsigned IsTargetSpecific : 1;
- unsigned IsType : 1;
- unsigned IsStmt : 1;
- unsigned IsKnownToGCC : 1;
- unsigned IsSupportedByPragmaAttribute : 1;
-
- bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *);
- bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr);
- bool (*ExistsInTarget)(const TargetInfo &Target);
- unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr);
- void (*GetPragmaAttributeMatchRules)(
- llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
- const LangOptions &LangOpts);
-};
-
namespace {
#include "clang/Sema/AttrParsedAttrImpl.inc"
} // namespace
-static const ParsedAttrInfo &getInfo(const ParsedAttr &A) {
- return AttrInfoMap[A.getKind()];
+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))
+ return *AttrInfoMap[A.getParsedKind()];
+
+ // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
+ static const ParsedAttrInfo IgnoredParsedAttrInfo(
+ AttributeCommonInfo::IgnoredAttribute);
+ if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
+ return IgnoredParsedAttrInfo;
+
+ // Otherwise this may be an attribute defined by a plugin. First instantiate
+ // all plugin attributes if we haven't already done so.
+ static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>>
+ PluginAttrInstances;
+ if (PluginAttrInstances->empty())
+ for (auto It : ParsedAttrInfoRegistry::entries())
+ PluginAttrInstances->emplace_back(It.instantiate());
+
+ // Search for a ParsedAttrInfo whose name and syntax match.
+ std::string FullName = A.getNormalizedFullName();
+ AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
+ if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
+ SyntaxUsed = AttributeCommonInfo::AS_Keyword;
+
+ for (auto &Ptr : *PluginAttrInstances)
+ for (auto &S : Ptr->Spellings)
+ if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName)
+ return *Ptr;
+
+ // If we failed to find a match then return a default ParsedAttrInfo.
+ static const ParsedAttrInfo DefaultParsedAttrInfo(
+ AttributeCommonInfo::UnknownAttribute);
+ return DefaultParsedAttrInfo;
}
-unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
+unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
unsigned ParsedAttr::getMaxArgs() const {
- return getMinArgs() + getInfo(*this).OptArgs;
+ return getMinArgs() + getInfo().OptArgs;
}
bool ParsedAttr::hasCustomParsing() const {
- return getInfo(*this).HasCustomParsing;
+ return getInfo().HasCustomParsing;
}
bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
- return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
+ return getInfo().diagAppertainsToDecl(S, *this, D);
}
bool ParsedAttr::appliesToDecl(const Decl *D,
@@ -152,33 +168,33 @@ void ParsedAttr::getMatchRules(
const LangOptions &LangOpts,
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
const {
- return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
+ return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
}
bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
- return getInfo(*this).DiagLangOpts(S, *this);
+ return getInfo().diagLangOpts(S, *this);
}
bool ParsedAttr::isTargetSpecificAttr() const {
- return getInfo(*this).IsTargetSpecific;
+ return getInfo().IsTargetSpecific;
}
-bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; }
+bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
-bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; }
+bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
- return getInfo(*this).ExistsInTarget(Target);
+ return getInfo().existsInTarget(Target);
}
-bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; }
+bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
bool ParsedAttr::isSupportedByPragmaAttribute() const {
- return getInfo(*this).IsSupportedByPragmaAttribute;
+ return getInfo().IsSupportedByPragmaAttribute;
}
unsigned ParsedAttr::getSemanticSpelling() const {
- return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
+ return getInfo().spellingIndexToSemanticSpelling(*this);
}
bool ParsedAttr::hasVariadicArg() const {
@@ -186,5 +202,5 @@ bool ParsedAttr::hasVariadicArg() const {
// claim that as being variadic. If we someday get an attribute that
// legitimately bumps up against that maximum, we can use another bit to track
// whether it's truly variadic or not.
- return getInfo(*this).OptArgs == 15;
+ return getInfo().OptArgs == 15;
}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2cd158a8b43c..2f2b52106f3d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "UsedDeclVisitor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -22,6 +23,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/HeaderSearch.h"
@@ -52,6 +54,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
+IdentifierInfo *
+Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned int Index) {
+ std::string InventedName;
+ llvm::raw_string_ostream OS(InventedName);
+
+ if (!ParamName)
+ OS << "auto:" << Index + 1;
+ else
+ OS << ParamName->getName() << ":auto";
+
+ OS.flush();
+ return &Context.Idents.get(OS.str());
+}
+
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -127,10 +144,13 @@ public:
} // end namespace sema
} // end namespace clang
+const unsigned Sema::MaxAlignmentExponent;
+const unsigned Sema::MaximumAlignment;
+
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
: ExternalSource(nullptr), isMultiplexExternalSource(false),
- FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
+ CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
SourceMgr(PP.getSourceManager()), CollectStats(false),
CodeCompleter(CodeCompleter), CurContext(nullptr),
@@ -139,8 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
- PragmaAttributeCurrentTargetDecl(nullptr),
+ CodeSegStack(nullptr), FpPragmaStack(0xffffffff), CurInitSeg(nullptr),
+ VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
@@ -153,10 +173,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TUKind(TUKind), NumSFINAEErrors(0),
FullyCheckedComparisonCategories(
static_cast<unsigned>(ComparisonCategoryType::Last) + 1),
- AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
- NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
- TyposCorrected(0), AnalysisWarnings(*this),
+ SatisfactionCache(Context), AccessCheckingSFINAE(false),
+ InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
+ ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
+ DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
TUScope = nullptr;
@@ -379,6 +399,14 @@ Sema::~Sema() {
if (isMultiplexExternalSource)
delete ExternalSource;
+ // Delete cached satisfactions.
+ std::vector<ConstraintSatisfaction *> Satisfactions;
+ Satisfactions.reserve(Satisfactions.size());
+ for (auto &Node : SatisfactionCache)
+ Satisfactions.push_back(&Node);
+ for (auto *Node : Satisfactions)
+ delete Node;
+
threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache);
// Destroys data sharing attributes stack for OpenMP
@@ -928,9 +956,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
PerformPendingInstantiations();
}
- // Finalize analysis of OpenMP-specific constructs.
- if (LangOpts.OpenMP)
- finalizeOpenMPDelayedAnalysis();
+ emitDeferredDiags();
assert(LateParsedInstantiations.empty() &&
"end of TU template instantiation should not create more "
@@ -983,6 +1009,11 @@ void Sema::ActOnEndOfTranslationUnit() {
LateParsedInstantiations.begin(),
LateParsedInstantiations.end());
LateParsedInstantiations.clear();
+
+ if (LangOpts.PCHInstantiateTemplates) {
+ llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
+ PerformPendingInstantiations();
+ }
}
DiagnoseUnterminatedPragmaPack();
@@ -1261,7 +1292,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
while (true) {
- if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) ||
+ isa<RequiresExprBodyDecl>(DC)) {
DC = DC->getParent();
} else if (isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
@@ -1413,38 +1445,184 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
auto FnIt = S.DeviceKnownEmittedFns.find(FD);
while (FnIt != S.DeviceKnownEmittedFns.end()) {
+ // Respect error limit.
+ if (S.Diags.hasFatalErrorOccurred())
+ return;
DiagnosticBuilder Builder(
S.Diags.Report(FnIt->second.Loc, diag::note_called_by));
Builder << FnIt->second.FD;
- Builder.setForceEmit();
-
FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD);
}
}
-// Emit any deferred diagnostics for FD and erase them from the map in which
-// they're stored.
-static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) {
- auto It = S.DeviceDeferredDiags.find(FD);
- if (It == S.DeviceDeferredDiags.end())
- return;
- bool HasWarningOrError = false;
- for (PartialDiagnosticAt &PDAt : It->second) {
- const SourceLocation &Loc = PDAt.first;
- const PartialDiagnostic &PD = PDAt.second;
- HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel(
- PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning;
- DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID()));
- Builder.setForceEmit();
- PD.Emit(Builder);
+namespace {
+
+/// Helper class that emits deferred diagnostic messages if an entity directly
+/// or indirectly using the function that causes the deferred diagnostic
+/// messages is known to be emitted.
+///
+/// During parsing of AST, certain diagnostic messages are recorded as deferred
+/// diagnostics since it is unknown whether the functions containing such
+/// diagnostics will be emitted. A list of potentially emitted functions and
+/// variables that may potentially trigger emission of functions are also
+/// recorded. DeferredDiagnosticsEmitter recursively visits used functions
+/// by each function to emit deferred diagnostics.
+///
+/// During the visit, certain OpenMP directives or initializer of variables
+/// with certain OpenMP attributes will cause subsequent visiting of any
+/// functions enter a state which is called OpenMP device context in this
+/// implementation. The state is exited when the directive or initializer is
+/// exited. This state can change the emission states of subsequent uses
+/// of functions.
+///
+/// Conceptually the functions or variables to be visited form a use graph
+/// where the parent node uses the child node. At any point of the visit,
+/// the tree nodes traversed from the tree root to the current node form a use
+/// stack. The emission state of the current node depends on two factors:
+/// 1. the emission state of the root node
+/// 2. whether the current node is in OpenMP device context
+/// If the function is decided to be emitted, its contained deferred diagnostics
+/// are emitted, together with the information about the use stack.
+///
+class DeferredDiagnosticsEmitter
+ : public UsedDeclVisitor<DeferredDiagnosticsEmitter> {
+public:
+ typedef UsedDeclVisitor<DeferredDiagnosticsEmitter> Inherited;
+
+ // Whether the function is already in the current use-path.
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> InUsePath;
+
+ // The current use-path.
+ llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4> UsePath;
+
+ // Whether the visiting of the function has been done. Done[0] is for the
+ // case not in OpenMP device context. Done[1] is for the case in OpenMP
+ // device context. We need two sets because diagnostics emission may be
+ // different depending on whether it is in OpenMP device context.
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> DoneMap[2];
+
+ // Emission state of the root node of the current use graph.
+ bool ShouldEmitRootNode;
+
+ // Current OpenMP device context level. It is initialized to 0 and each
+ // entering of device context increases it by 1 and each exit decreases
+ // it by 1. Non-zero value indicates it is currently in device context.
+ unsigned InOMPDeviceContext;
+
+ DeferredDiagnosticsEmitter(Sema &S)
+ : Inherited(S), ShouldEmitRootNode(false), InOMPDeviceContext(0) {}
+
+ void VisitOMPTargetDirective(OMPTargetDirective *Node) {
+ ++InOMPDeviceContext;
+ Inherited::VisitOMPTargetDirective(Node);
+ --InOMPDeviceContext;
+ }
+
+ void visitUsedDecl(SourceLocation Loc, Decl *D) {
+ if (isa<VarDecl>(D))
+ return;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ checkFunc(Loc, FD);
+ else
+ Inherited::visitUsedDecl(Loc, D);
+ }
+
+ void checkVar(VarDecl *VD) {
+ assert(VD->isFileVarDecl() &&
+ "Should only check file-scope variables");
+ if (auto *Init = VD->getInit()) {
+ auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD);
+ bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost ||
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Any);
+ if (IsDev)
+ ++InOMPDeviceContext;
+ this->Visit(Init);
+ if (IsDev)
+ --InOMPDeviceContext;
+ }
+ }
+
+ void checkFunc(SourceLocation Loc, FunctionDecl *FD) {
+ auto &Done = DoneMap[InOMPDeviceContext > 0 ? 1 : 0];
+ FunctionDecl *Caller = UsePath.empty() ? nullptr : UsePath.back();
+ if ((!ShouldEmitRootNode && !S.getLangOpts().OpenMP && !Caller) ||
+ S.shouldIgnoreInHostDeviceCheck(FD) || InUsePath.count(FD))
+ return;
+ // Finalize analysis of OpenMP-specific constructs.
+ if (Caller && S.LangOpts.OpenMP && UsePath.size() == 1)
+ S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc);
+ if (Caller)
+ S.DeviceKnownEmittedFns[FD] = {Caller, Loc};
+ // Always emit deferred diagnostics for the direct users. This does not
+ // lead to explosion of diagnostics since each user is visited at most
+ // twice.
+ if (ShouldEmitRootNode || InOMPDeviceContext)
+ emitDeferredDiags(FD, Caller);
+ // Do not revisit a function if the function body has been completely
+ // visited before.
+ if (!Done.insert(FD).second)
+ return;
+ InUsePath.insert(FD);
+ UsePath.push_back(FD);
+ if (auto *S = FD->getBody()) {
+ this->Visit(S);
+ }
+ UsePath.pop_back();
+ InUsePath.erase(FD);
+ }
+
+ void checkRecordedDecl(Decl *D) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ ShouldEmitRootNode = S.getEmissionStatus(FD, /*Final=*/true) ==
+ Sema::FunctionEmissionStatus::Emitted;
+ checkFunc(SourceLocation(), FD);
+ } else
+ checkVar(cast<VarDecl>(D));
+ }
+
+ // Emit any deferred diagnostics for FD
+ void emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) {
+ auto It = S.DeviceDeferredDiags.find(FD);
+ if (It == S.DeviceDeferredDiags.end())
+ return;
+ bool HasWarningOrError = false;
+ bool FirstDiag = true;
+ for (PartialDiagnosticAt &PDAt : It->second) {
+ // Respect error limit.
+ if (S.Diags.hasFatalErrorOccurred())
+ return;
+ const SourceLocation &Loc = PDAt.first;
+ const PartialDiagnostic &PD = PDAt.second;
+ HasWarningOrError |=
+ S.getDiagnostics().getDiagnosticLevel(PD.getDiagID(), Loc) >=
+ DiagnosticsEngine::Warning;
+ {
+ DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID()));
+ PD.Emit(Builder);
+ }
+ // Emit the note on the first diagnostic in case too many diagnostics
+ // cause the note not emitted.
+ if (FirstDiag && HasWarningOrError && ShowCallStack) {
+ emitCallStackNotes(S, FD);
+ FirstDiag = false;
+ }
+ }
}
- S.DeviceDeferredDiags.erase(It);
+};
+} // namespace
+
+void Sema::emitDeferredDiags() {
+ if (ExternalSource)
+ ExternalSource->ReadDeclsToCheckForDeferredDiags(
+ DeclsToCheckForDeferredDiags);
+
+ if ((DeviceDeferredDiags.empty() && !LangOpts.OpenMP) ||
+ DeclsToCheckForDeferredDiags.empty())
+ return;
- // FIXME: Should this be called after every warning/error emitted in the loop
- // above, instead of just once per function? That would be consistent with
- // how we handle immediate errors, but it also seems like a bit much.
- if (HasWarningOrError && ShowCallStack)
- emitCallStackNotes(S, FD);
+ DeferredDiagnosticsEmitter DDE(*this);
+ for (auto D : DeclsToCheckForDeferredDiags)
+ DDE.checkRecordedDecl(D);
}
// In CUDA, there are some constructs which may appear in semantically-valid
@@ -1517,71 +1695,6 @@ Sema::DeviceDiagBuilder::~DeviceDiagBuilder() {
}
}
-// Indicate that this function (and thus everything it transtively calls) will
-// be codegen'ed, and emit any deferred diagnostics on this function and its
-// (transitive) callees.
-void Sema::markKnownEmitted(
- Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee,
- SourceLocation OrigLoc,
- const llvm::function_ref<bool(Sema &, FunctionDecl *)> IsKnownEmitted) {
- // Nothing to do if we already know that FD is emitted.
- if (IsKnownEmitted(S, OrigCallee)) {
- assert(!S.DeviceCallGraph.count(OrigCallee));
- return;
- }
-
- // We've just discovered that OrigCallee is known-emitted. Walk our call
- // graph to see what else we can now discover also must be emitted.
-
- struct CallInfo {
- FunctionDecl *Caller;
- FunctionDecl *Callee;
- SourceLocation Loc;
- };
- llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}};
- llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen;
- Seen.insert(OrigCallee);
- while (!Worklist.empty()) {
- CallInfo C = Worklist.pop_back_val();
- assert(!IsKnownEmitted(S, C.Callee) &&
- "Worklist should not contain known-emitted functions.");
- S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc};
- emitDeferredDiags(S, C.Callee, C.Caller);
-
- // If this is a template instantiation, explore its callgraph as well:
- // Non-dependent calls are part of the template's callgraph, while dependent
- // calls are part of to the instantiation's call graph.
- if (auto *Templ = C.Callee->getPrimaryTemplate()) {
- FunctionDecl *TemplFD = Templ->getAsFunction();
- if (!Seen.count(TemplFD) && !S.DeviceKnownEmittedFns.count(TemplFD)) {
- Seen.insert(TemplFD);
- Worklist.push_back(
- {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc});
- }
- }
-
- // Add all functions called by Callee to our worklist.
- auto CGIt = S.DeviceCallGraph.find(C.Callee);
- if (CGIt == S.DeviceCallGraph.end())
- continue;
-
- for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc :
- CGIt->second) {
- FunctionDecl *NewCallee = FDLoc.first;
- SourceLocation CallLoc = FDLoc.second;
- if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee))
- continue;
- Seen.insert(NewCallee);
- Worklist.push_back(
- {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc});
- }
-
- // C.Callee is now known-emitted, so we no longer need to maintain its list
- // of callees in DeviceCallGraph.
- S.DeviceCallGraph.erase(CGIt);
- }
-}
-
Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
if (LangOpts.OpenMP)
return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
@@ -1589,10 +1702,59 @@ Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
+
+ if (getLangOpts().SYCLIsDevice)
+ return SYCLDiagIfDeviceCode(Loc, DiagID);
+
return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID,
getCurFunctionDecl(), *this);
}
+void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
+ if (isUnevaluatedContext())
+ return;
+
+ Decl *C = cast<Decl>(getCurLexicalContext());
+
+ // Memcpy operations for structs containing a member with unsupported type
+ // are ok, though.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(C)) {
+ if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
+ MD->isTrivial())
+ return;
+
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(MD))
+ if (Ctor->isCopyOrMoveConstructor() && Ctor->isTrivial())
+ return;
+ }
+
+ auto CheckType = [&](QualType Ty) {
+ if (Ty->isDependentType())
+ return;
+
+ if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) ||
+ ((Ty->isFloat128Type() ||
+ (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) &&
+ !Context.getTargetInfo().hasFloat128Type()) ||
+ (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
+ !Context.getTargetInfo().hasInt128Type())) {
+ targetDiag(Loc, diag::err_device_unsupported_type)
+ << D << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
+ << Context.getTargetInfo().getTriple().str();
+ targetDiag(D->getLocation(), diag::note_defined_here) << D;
+ }
+ };
+
+ QualType Ty = D->getType();
+ CheckType(Ty);
+
+ if (const auto *FPTy = dyn_cast<FunctionProtoType>(Ty)) {
+ for (const auto &ParamTy : FPTy->param_types())
+ CheckType(ParamTy);
+ CheckType(FPTy->getReturnType());
+ }
+}
+
/// Looks through the macro-expansion chain for the given
/// location, looking for a macro expansion with the given name.
/// If one is found, returns true and sets the location to that
@@ -1794,7 +1956,7 @@ void Sema::PopCompoundScope() {
/// Determine whether any errors occurred within this function/method/
/// block.
bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
- return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
+ return getCurFunction()->hasUnrecoverableErrorOccurred();
}
void Sema::setFunctionHasBranchIntoScope() {
@@ -2246,16 +2408,8 @@ std::string Sema::getOpenCLExtensionsFromTypeExtMap(FunctionType *FT) {
template <typename T, typename MapT>
std::string Sema::getOpenCLExtensionsFromExtMap(T *FDT, MapT &Map) {
- std::string ExtensionNames = "";
auto Loc = Map.find(FDT);
-
- for (auto const& I : Loc->second) {
- ExtensionNames += I;
- ExtensionNames += " ";
- }
- ExtensionNames.pop_back();
-
- return ExtensionNames;
+ return llvm::join(Loc->second, " ");
}
bool Sema::isOpenCLDisabledDecl(Decl *FD) {
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index cd2a65276b09..b354e810974c 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -256,12 +256,15 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action,
PragmaClangSectionKind SecKind, StringRef SecName) {
PragmaClangSection *CSec;
+ int SectionFlags = ASTContext::PSF_Read;
switch (SecKind) {
case PragmaClangSectionKind::PCSK_BSS:
CSec = &PragmaClangBSSSection;
+ SectionFlags |= ASTContext::PSF_Write | ASTContext::PSF_ZeroInit;
break;
case PragmaClangSectionKind::PCSK_Data:
CSec = &PragmaClangDataSection;
+ SectionFlags |= ASTContext::PSF_Write;
break;
case PragmaClangSectionKind::PCSK_Rodata:
CSec = &PragmaClangRodataSection;
@@ -271,6 +274,7 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
break;
case PragmaClangSectionKind::PCSK_Text:
CSec = &PragmaClangTextSection;
+ SectionFlags |= ASTContext::PSF_Execute;
break;
default:
llvm_unreachable("invalid clang section kind");
@@ -281,8 +285,11 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
return;
}
+ if (UnifySection(SecName, SectionFlags, PragmaLoc))
+ return;
+
CSec->Valid = true;
- CSec->SectionName = SecName;
+ CSec->SectionName = std::string(SecName);
CSec->PragmaLocation = PragmaLoc;
}
@@ -407,6 +414,70 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
}
+void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
+ PragmaMsStackAction Action,
+ PragmaFloatControlKind Value) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
+ if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) &&
+ !(CurContext->isTranslationUnit()) && !CurContext->isNamespace()) {
+ // Push and pop can only occur at file or namespace scope.
+ Diag(Loc, diag::err_pragma_fc_pp_scope);
+ return;
+ }
+ switch (Value) {
+ default:
+ llvm_unreachable("invalid pragma float_control kind");
+ case PFC_Precise:
+ NewFPFeatures.setFPPreciseEnabled(true);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ break;
+ case PFC_NoPrecise:
+ if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict)
+ Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
+ else if (CurFPFeatures.getAllowFEnvAccess())
+ Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
+ else
+ NewFPFeatures.setFPPreciseEnabled(false);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ break;
+ case PFC_Except:
+ if (!isPreciseFPEnabled())
+ Diag(Loc, diag::err_pragma_fc_except_requires_precise);
+ else
+ NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ break;
+ case PFC_NoExcept:
+ NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewValue);
+ break;
+ case PFC_Push:
+ FpPragmaStack.Act(Loc, Sema::PSK_Push_Set, StringRef(),
+ NewFPFeatures.getAsOpaqueInt());
+ break;
+ case PFC_Pop:
+ if (FpPragmaStack.Stack.empty()) {
+ Diag(Loc, diag::warn_pragma_pop_failed) << "float_control"
+ << "stack empty";
+ return;
+ }
+ FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt());
+ NewValue = FpPragmaStack.CurrentValue;
+ break;
+ }
+ FPOptionsOverride NewOverrides;
+ if (NewValue != FpPragmaStack.DefaultValue)
+ NewOverrides.getFromOpaqueInt(NewValue);
+ CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
+}
+
void Sema::ActOnPragmaMSPointersToMembers(
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
SourceLocation PragmaLoc) {
@@ -423,83 +494,52 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode);
}
-template<typename ValueType>
-void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
- PragmaMsStackAction Action,
- llvm::StringRef StackSlotLabel,
- ValueType Value) {
- if (Action == PSK_Reset) {
- CurrentValue = DefaultValue;
- CurrentPragmaLocation = PragmaLocation;
- return;
- }
- if (Action & PSK_Push)
- Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation,
- PragmaLocation);
- else if (Action & PSK_Pop) {
- if (!StackSlotLabel.empty()) {
- // If we've got a label, try to find it and jump there.
- auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) {
- return x.StackSlotLabel == StackSlotLabel;
- });
- // If we found the label so pop from there.
- if (I != Stack.rend()) {
- CurrentValue = I->Value;
- CurrentPragmaLocation = I->PragmaLocation;
- Stack.erase(std::prev(I.base()), Stack.end());
- }
- } else if (!Stack.empty()) {
- // We do not have a label, just pop the last entry.
- CurrentValue = Stack.back().Value;
- CurrentPragmaLocation = Stack.back().PragmaLocation;
- Stack.pop_back();
- }
- }
- if (Action & PSK_Set) {
- CurrentValue = Value;
- CurrentPragmaLocation = PragmaLocation;
- }
-}
-
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *Decl) {
- auto Section = Context.SectionInfos.find(SectionName);
- if (Section == Context.SectionInfos.end()) {
+ SourceLocation PragmaLocation;
+ if (auto A = Decl->getAttr<SectionAttr>())
+ if (A->isImplicit())
+ PragmaLocation = A->getLocation();
+ auto SectionIt = Context.SectionInfos.find(SectionName);
+ if (SectionIt == Context.SectionInfos.end()) {
Context.SectionInfos[SectionName] =
- ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags);
+ ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags);
return false;
}
// A pre-declared section takes precedence w/o diagnostic.
- if (Section->second.SectionFlags == SectionFlags ||
- !(Section->second.SectionFlags & ASTContext::PSF_Implicit))
+ const auto &Section = SectionIt->second;
+ if (Section.SectionFlags == SectionFlags ||
+ ((SectionFlags & ASTContext::PSF_Implicit) &&
+ !(Section.SectionFlags & ASTContext::PSF_Implicit)))
return false;
- auto OtherDecl = Section->second.Decl;
- Diag(Decl->getLocation(), diag::err_section_conflict)
- << Decl << OtherDecl;
- Diag(OtherDecl->getLocation(), diag::note_declared_at)
- << OtherDecl->getName();
- if (auto A = Decl->getAttr<SectionAttr>())
- if (A->isImplicit())
- Diag(A->getLocation(), diag::note_pragma_entered_here);
- if (auto A = OtherDecl->getAttr<SectionAttr>())
- if (A->isImplicit())
- Diag(A->getLocation(), diag::note_pragma_entered_here);
+ Diag(Decl->getLocation(), diag::err_section_conflict) << Decl << Section;
+ if (Section.Decl)
+ Diag(Section.Decl->getLocation(), diag::note_declared_at)
+ << Section.Decl->getName();
+ if (PragmaLocation.isValid())
+ Diag(PragmaLocation, diag::note_pragma_entered_here);
+ if (Section.PragmaSectionLocation.isValid())
+ Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
return true;
}
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
SourceLocation PragmaSectionLocation) {
- auto Section = Context.SectionInfos.find(SectionName);
- if (Section != Context.SectionInfos.end()) {
- if (Section->second.SectionFlags == SectionFlags)
+ auto SectionIt = Context.SectionInfos.find(SectionName);
+ if (SectionIt != Context.SectionInfos.end()) {
+ const auto &Section = SectionIt->second;
+ if (Section.SectionFlags == SectionFlags)
return false;
- if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) {
+ if (!(Section.SectionFlags & ASTContext::PSF_Implicit)) {
Diag(PragmaSectionLocation, diag::err_section_conflict)
- << "this" << "a prior #pragma section";
- Diag(Section->second.PragmaSectionLocation,
- diag::note_pragma_entered_here);
+ << "this" << Section;
+ if (Section.Decl)
+ Diag(Section.Decl->getLocation(), diag::note_declared_at)
+ << Section.Decl->getName();
+ if (Section.PragmaSectionLocation.isValid())
+ Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
return true;
}
}
@@ -926,31 +966,85 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType,
}
}
-void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) {
+void Sema::ActOnPragmaFPContract(SourceLocation Loc,
+ LangOptions::FPModeKind FPC) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
switch (FPC) {
- case LangOptions::FPC_On:
- FPFeatures.setAllowFPContractWithinStatement();
+ case LangOptions::FPM_On:
+ NewFPFeatures.setAllowFPContractWithinStatement();
break;
- case LangOptions::FPC_Fast:
- FPFeatures.setAllowFPContractAcrossStatement();
+ case LangOptions::FPM_Fast:
+ NewFPFeatures.setAllowFPContractAcrossStatement();
break;
- case LangOptions::FPC_Off:
- FPFeatures.setDisallowFPContract();
+ case LangOptions::FPM_Off:
+ NewFPFeatures.setDisallowFPContract();
break;
}
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+ FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(),
+ NewFPFeatures.getAsOpaqueInt());
}
-void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) {
- switch (FPC) {
- case LangOptions::FEA_On:
- FPFeatures.setAllowFEnvAccess();
- break;
- case LangOptions::FEA_Off:
- FPFeatures.setDisallowFEnvAccess();
- break;
- }
+void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
+ NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue);
+ FPOptionsOverride NewOverrides(NewValue);
+ CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
}
+void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
+ NewFPFeatures.setRoundingModeOverride(FPR);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue);
+ FPOptionsOverride NewOverrides(NewValue);
+ CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
+}
+
+void Sema::setExceptionMode(SourceLocation Loc,
+ LangOptions::FPExceptionModeKind FPE) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
+ NewFPFeatures.setFPExceptionModeOverride(FPE);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue);
+ FPOptionsOverride NewOverrides(NewValue);
+ CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
+}
+
+void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
+ unsigned NewValue = FpPragmaStack.hasValue()
+ ? FpPragmaStack.CurrentValue
+ : CurFPFeatureOverrides().getAsOpaqueInt();
+ FPOptionsOverride NewFPFeatures(NewValue);
+ if (IsEnabled) {
+ // Verify Microsoft restriction:
+ // You can't enable fenv_access unless precise semantics are enabled.
+ // Precise semantics can be enabled either by the float_control
+ // pragma, or by using the /fp:precise or /fp:strict compiler options
+ if (!isPreciseFPEnabled())
+ Diag(Loc, diag::err_pragma_fenv_requires_precise);
+ NewFPFeatures.setAllowFEnvAccessOverride(true);
+ } else
+ NewFPFeatures.setAllowFEnvAccessOverride(false);
+ NewValue = NewFPFeatures.getAsOpaqueInt();
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue);
+ FPOptionsOverride NewOverrides(NewValue);
+ CurFPFeatures = NewOverrides.applyOverrides(getLangOpts());
+}
void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr,
SourceLocation Loc) {
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
new file mode 100644
index 000000000000..74c4b9e16f74
--- /dev/null
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -0,0 +1,964 @@
+//===--- SemaAvailability.cpp - Availability attribute handling -----------===//
+//
+// 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 file processes the availability attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+using namespace sema;
+
+static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
+ const Decl *D) {
+ // Check each AvailabilityAttr to find the one for this platform.
+ for (const auto *A : D->attrs()) {
+ if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
+ // FIXME: this is copied from CheckAvailability. We should try to
+ // de-duplicate.
+
+ // Check if this is an App Extension "platform", and if so chop off
+ // the suffix for matching with the actual platform.
+ StringRef ActualPlatform = Avail->getPlatform()->getName();
+ StringRef RealizedPlatform = ActualPlatform;
+ if (Context.getLangOpts().AppExt) {
+ size_t suffix = RealizedPlatform.rfind("_app_extension");
+ if (suffix != StringRef::npos)
+ RealizedPlatform = RealizedPlatform.slice(0, suffix);
+ }
+
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+
+ // Match the platform name.
+ if (RealizedPlatform == TargetPlatform)
+ return Avail;
+ }
+ }
+ return nullptr;
+}
+
+/// The diagnostic we should emit for \c D, and the declaration that
+/// originated it, or \c AR_Available.
+///
+/// \param D The declaration to check.
+/// \param Message If non-null, this will be populated with the message from
+/// the availability attribute that is selected.
+/// \param ClassReceiver If we're checking the the method of a class message
+/// send, the class. Otherwise nullptr.
+static std::pair<AvailabilityResult, const NamedDecl *>
+ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
+ std::string *Message,
+ ObjCInterfaceDecl *ClassReceiver) {
+ AvailabilityResult Result = D->getAvailability(Message);
+
+ // For typedefs, if the typedef declaration appears available look
+ // to the underlying type to see if it is more restrictive.
+ while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
+ if (Result == AR_Available) {
+ if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
+ D = TT->getDecl();
+ Result = D->getAvailability(Message);
+ continue;
+ }
+ }
+ break;
+ }
+
+ // Forward class declarations get their attributes from their definition.
+ if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (IDecl->getDefinition()) {
+ D = IDecl->getDefinition();
+ Result = D->getAvailability(Message);
+ }
+ }
+
+ if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
+ if (Result == AR_Available) {
+ const DeclContext *DC = ECD->getDeclContext();
+ if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
+ Result = TheEnumDecl->getAvailability(Message);
+ D = TheEnumDecl;
+ }
+ }
+
+ // For +new, infer availability from -init.
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (S.NSAPIObj && ClassReceiver) {
+ ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
+ S.NSAPIObj->getInitSelector());
+ if (Init && Result == AR_Available && MD->isClassMethod() &&
+ MD->getSelector() == S.NSAPIObj->getNewSelector() &&
+ MD->definedInNSObject(S.getASTContext())) {
+ Result = Init->getAvailability(Message);
+ D = Init;
+ }
+ }
+ }
+
+ return {Result, D};
+}
+
+
+/// whether we should emit a diagnostic for \c K and \c DeclVersion in
+/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
+/// in a deprecated context, but not the other way around.
+static bool
+ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
+ VersionTuple DeclVersion, Decl *Ctx,
+ const NamedDecl *OffendingDecl) {
+ assert(K != AR_Available && "Expected an unavailable declaration here!");
+
+ // Checks if we should emit the availability diagnostic in the context of C.
+ auto CheckContext = [&](const Decl *C) {
+ if (K == AR_NotYetIntroduced) {
+ if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
+ if (AA->getIntroduced() >= DeclVersion)
+ return true;
+ } else if (K == AR_Deprecated) {
+ if (C->isDeprecated())
+ return true;
+ } else if (K == AR_Unavailable) {
+ // It is perfectly fine to refer to an 'unavailable' Objective-C method
+ // when it is referenced from within the @implementation itself. In this
+ // context, we interpret unavailable as a form of access control.
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
+ if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
+ if (MD->getClassInterface() == Impl->getClassInterface())
+ return true;
+ }
+ }
+ }
+
+ if (C->isUnavailable())
+ return true;
+ return false;
+ };
+
+ do {
+ if (CheckContext(Ctx))
+ return false;
+
+ // An implementation implicitly has the availability of the interface.
+ // Unless it is "+load" method.
+ if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
+ if (MethodD->isClassMethod() &&
+ MethodD->getSelector().getAsString() == "load")
+ return true;
+
+ if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
+ if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
+ if (CheckContext(Interface))
+ return false;
+ }
+ // A category implicitly has the availability of the interface.
+ else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
+ if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
+ if (CheckContext(Interface))
+ return false;
+ } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
+
+ return true;
+}
+
+static bool
+shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
+ const VersionTuple &DeploymentVersion,
+ const VersionTuple &DeclVersion) {
+ const auto &Triple = Context.getTargetInfo().getTriple();
+ VersionTuple ForceAvailabilityFromVersion;
+ switch (Triple.getOS()) {
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
+ break;
+ case llvm::Triple::WatchOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
+ break;
+ default:
+ // New targets should always warn about availability.
+ return Triple.getVendor() == llvm::Triple::Apple;
+ }
+ return DeploymentVersion >= ForceAvailabilityFromVersion ||
+ DeclVersion >= ForceAvailabilityFromVersion;
+}
+
+static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
+ for (Decl *Ctx = OrigCtx; Ctx;
+ Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
+ if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
+ return cast<NamedDecl>(Ctx);
+ if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
+ if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
+ return Imp->getClassInterface();
+ return CD;
+ }
+ }
+
+ return dyn_cast<NamedDecl>(OrigCtx);
+}
+
+namespace {
+
+struct AttributeInsertion {
+ StringRef Prefix;
+ SourceLocation Loc;
+ StringRef Suffix;
+
+ static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
+ return {" ", D->getEndLoc(), ""};
+ }
+ static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
+ return {" ", Loc, ""};
+ }
+ static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
+ return {"", D->getBeginLoc(), "\n"};
+ }
+};
+
+} // end anonymous namespace
+
+/// Tries to parse a string as ObjC method name.
+///
+/// \param Name The string to parse. Expected to originate from availability
+/// attribute argument.
+/// \param SlotNames The vector that will be populated with slot names. In case
+/// of unsuccessful parsing can contain invalid data.
+/// \returns A number of method parameters if parsing was successful, None
+/// otherwise.
+static Optional<unsigned>
+tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
+ const LangOptions &LangOpts) {
+ // Accept replacements starting with - or + as valid ObjC method names.
+ if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
+ Name = Name.drop_front(1);
+ if (Name.empty())
+ return None;
+ Name.split(SlotNames, ':');
+ unsigned NumParams;
+ if (Name.back() == ':') {
+ // Remove an empty string at the end that doesn't represent any slot.
+ SlotNames.pop_back();
+ NumParams = SlotNames.size();
+ } else {
+ if (SlotNames.size() != 1)
+ // Not a valid method name, just a colon-separated string.
+ return None;
+ NumParams = 0;
+ }
+ // Verify all slot names are valid.
+ bool AllowDollar = LangOpts.DollarIdents;
+ for (StringRef S : SlotNames) {
+ if (S.empty())
+ continue;
+ if (!isValidIdentifier(S, AllowDollar))
+ return None;
+ }
+ return NumParams;
+}
+
+/// Returns a source location in which it's appropriate to insert a new
+/// attribute for the given declaration \D.
+static Optional<AttributeInsertion>
+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 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;
+ // Insert after the 'struct'/whatever keyword.
+ return AttributeInsertion::createInsertionAfter(Loc);
+ }
+ return AttributeInsertion::createInsertionBefore(D);
+}
+
+/// Actually emit an availability diagnostic for a reference to an unavailable
+/// decl.
+///
+/// \param Ctx The context that the reference occurred in
+/// \param ReferringDecl The exact declaration that was referenced.
+/// \param OffendingDecl A related decl to \c ReferringDecl that has an
+/// availability attribute corresponding to \c K attached to it. Note that this
+/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
+/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
+/// and OffendingDecl is the EnumDecl.
+static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
+ Decl *Ctx, const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
+ StringRef Message,
+ ArrayRef<SourceLocation> Locs,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
+ // Diagnostics for deprecated or unavailable.
+ unsigned diag, diag_message, diag_fwdclass_message;
+ unsigned diag_available_here = diag::note_availability_specified_here;
+ SourceLocation NoteLocation = OffendingDecl->getLocation();
+
+ // Matches 'diag::note_property_attribute' options.
+ unsigned property_note_select;
+
+ // Matches diag::note_availability_specified_here.
+ unsigned available_here_select_kind;
+
+ VersionTuple DeclVersion;
+ if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
+ DeclVersion = AA->getIntroduced();
+
+ if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
+ OffendingDecl))
+ return;
+
+ SourceLocation Loc = Locs.front();
+
+ // The declaration can have multiple availability attributes, we are looking
+ // at one of them.
+ const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
+ if (A && A->isInherited()) {
+ for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
+ Redecl = Redecl->getPreviousDecl()) {
+ const AvailabilityAttr *AForRedecl =
+ getAttrForPlatform(S.Context, Redecl);
+ if (AForRedecl && !AForRedecl->isInherited()) {
+ // If D is a declaration with inherited attributes, the note should
+ // point to the declaration with actual attributes.
+ NoteLocation = Redecl->getLocation();
+ break;
+ }
+ }
+ }
+
+ switch (K) {
+ case AR_NotYetIntroduced: {
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(S.getASTContext(), OffendingDecl);
+ VersionTuple Introduced = AA->getIntroduced();
+
+ bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
+ S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
+ Introduced);
+ unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
+ S.getASTContext().getTargetInfo().getPlatformName()));
+
+ S.Diag(Loc, Warning) << OffendingDecl << PlatformName
+ << Introduced.getAsString();
+
+ S.Diag(OffendingDecl->getLocation(),
+ diag::note_partial_availability_specified_here)
+ << OffendingDecl << PlatformName << Introduced.getAsString()
+ << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
+
+ if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
+ if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
+ if (TD->getDeclName().isEmpty()) {
+ S.Diag(TD->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Anonymous*/ 1 << TD->getKindName();
+ return;
+ }
+ auto FixitNoteDiag =
+ S.Diag(Enclosing->getLocation(),
+ diag::note_decl_unguarded_availability_silence)
+ << /*Named*/ 0 << Enclosing;
+ // Don't offer a fixit for declarations with availability attributes.
+ if (Enclosing->hasAttr<AvailabilityAttr>())
+ return;
+ if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
+ return;
+ Optional<AttributeInsertion> Insertion = createAttributeInsertion(
+ Enclosing, S.getSourceManager(), S.getLangOpts());
+ if (!Insertion)
+ return;
+ std::string PlatformName =
+ AvailabilityAttr::getPlatformNameSourceSpelling(
+ S.getASTContext().getTargetInfo().getPlatformName())
+ .lower();
+ std::string Introduced =
+ OffendingDecl->getVersionIntroduced().getAsString();
+ FixitNoteDiag << FixItHint::CreateInsertion(
+ Insertion->Loc,
+ (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
+ "(" + Introduced + "))" + Insertion->Suffix)
+ .str());
+ }
+ return;
+ }
+ case AR_Deprecated:
+ diag = !ObjCPropertyAccess ? diag::warn_deprecated
+ : diag::warn_property_method_deprecated;
+ diag_message = diag::warn_deprecated_message;
+ diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
+ property_note_select = /* deprecated */ 0;
+ available_here_select_kind = /* deprecated */ 2;
+ if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
+ NoteLocation = AL->getLocation();
+ break;
+
+ case AR_Unavailable:
+ diag = !ObjCPropertyAccess ? diag::err_unavailable
+ : diag::err_property_method_unavailable;
+ diag_message = diag::err_unavailable_message;
+ diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
+ property_note_select = /* unavailable */ 1;
+ available_here_select_kind = /* unavailable */ 0;
+
+ if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
+ if (AL->isImplicit() && AL->getImplicitReason()) {
+ // Most of these failures are due to extra restrictions in ARC;
+ // reflect that in the primary diagnostic when applicable.
+ auto flagARCError = [&] {
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ S.getSourceManager().isInSystemHeader(
+ OffendingDecl->getLocation()))
+ diag = diag::err_unavailable_in_arc;
+ };
+
+ switch (AL->getImplicitReason()) {
+ case UnavailableAttr::IR_None: break;
+
+ case UnavailableAttr::IR_ARCForbiddenType:
+ flagARCError();
+ diag_available_here = diag::note_arc_forbidden_type;
+ break;
+
+ case UnavailableAttr::IR_ForbiddenWeak:
+ if (S.getLangOpts().ObjCWeakRuntime)
+ diag_available_here = diag::note_arc_weak_disabled;
+ else
+ diag_available_here = diag::note_arc_weak_no_runtime;
+ break;
+
+ case UnavailableAttr::IR_ARCForbiddenConversion:
+ flagARCError();
+ diag_available_here = diag::note_performs_forbidden_arc_conversion;
+ break;
+
+ case UnavailableAttr::IR_ARCInitReturnsUnrelated:
+ flagARCError();
+ diag_available_here = diag::note_arc_init_returns_unrelated;
+ break;
+
+ case UnavailableAttr::IR_ARCFieldWithOwnership:
+ flagARCError();
+ diag_available_here = diag::note_arc_field_with_ownership;
+ break;
+ }
+ }
+ }
+ break;
+
+ case AR_Available:
+ llvm_unreachable("Warning for availability of available declaration?");
+ }
+
+ SmallVector<FixItHint, 12> FixIts;
+ if (K == AR_Deprecated) {
+ StringRef Replacement;
+ if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
+ Replacement = AL->getReplacement();
+ if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
+ Replacement = AL->getReplacement();
+
+ CharSourceRange UseRange;
+ if (!Replacement.empty())
+ UseRange =
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
+ if (UseRange.isValid()) {
+ if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
+ Selector Sel = MethodDecl->getSelector();
+ SmallVector<StringRef, 12> SelectorSlotNames;
+ Optional<unsigned> NumParams = tryParseObjCMethodName(
+ Replacement, SelectorSlotNames, S.getLangOpts());
+ if (NumParams && NumParams.getValue() == Sel.getNumArgs()) {
+ assert(SelectorSlotNames.size() == Locs.size());
+ for (unsigned I = 0; I < Locs.size(); ++I) {
+ if (!Sel.getNameForSlot(I).empty()) {
+ CharSourceRange NameRange = CharSourceRange::getCharRange(
+ Locs[I], S.getLocForEndOfToken(Locs[I]));
+ FixIts.push_back(FixItHint::CreateReplacement(
+ NameRange, SelectorSlotNames[I]));
+ } else
+ FixIts.push_back(
+ FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
+ }
+ } else
+ FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
+ } else
+ FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
+ }
+ }
+
+ if (!Message.empty()) {
+ S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
+ if (ObjCProperty)
+ S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
+ << ObjCProperty->getDeclName() << property_note_select;
+ } else if (!UnknownObjCClass) {
+ S.Diag(Loc, diag) << ReferringDecl << FixIts;
+ if (ObjCProperty)
+ S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
+ << ObjCProperty->getDeclName() << property_note_select;
+ } else {
+ S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
+ S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
+ }
+
+ S.Diag(NoteLocation, diag_available_here)
+ << OffendingDecl << available_here_select_kind;
+}
+
+void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+ assert(DD.Kind == DelayedDiagnostic::Availability &&
+ "Expected an availability diagnostic here");
+
+ DD.Triggered = true;
+ DoEmitAvailabilityWarning(
+ *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
+ DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
+ DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
+ DD.getObjCProperty(), false);
+}
+
+static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
+ const NamedDecl *ReferringDecl,
+ const NamedDecl *OffendingDecl,
+ StringRef Message,
+ ArrayRef<SourceLocation> Locs,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
+ // Delay if we're currently parsing a declaration.
+ if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+ S.DelayedDiagnostics.add(
+ DelayedDiagnostic::makeAvailability(
+ AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
+ ObjCProperty, Message, ObjCPropertyAccess));
+ return;
+ }
+
+ Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
+ DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
+ Message, Locs, UnknownObjCClass, ObjCProperty,
+ ObjCPropertyAccess);
+}
+
+namespace {
+
+/// Returns true if the given statement can be a body-like child of \p Parent.
+bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
+ switch (Parent->getStmtClass()) {
+ case Stmt::IfStmtClass:
+ return cast<IfStmt>(Parent)->getThen() == S ||
+ cast<IfStmt>(Parent)->getElse() == S;
+ case Stmt::WhileStmtClass:
+ return cast<WhileStmt>(Parent)->getBody() == S;
+ case Stmt::DoStmtClass:
+ return cast<DoStmt>(Parent)->getBody() == S;
+ case Stmt::ForStmtClass:
+ return cast<ForStmt>(Parent)->getBody() == S;
+ case Stmt::CXXForRangeStmtClass:
+ return cast<CXXForRangeStmt>(Parent)->getBody() == S;
+ case Stmt::ObjCForCollectionStmtClass:
+ return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return cast<SwitchCase>(Parent)->getSubStmt() == S;
+ default:
+ return false;
+ }
+}
+
+class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
+ const Stmt *Target;
+
+public:
+ bool VisitStmt(Stmt *S) { return S != Target; }
+
+ /// Returns true if the given statement is present in the given declaration.
+ static bool isContained(const Stmt *Target, const Decl *D) {
+ StmtUSEFinder Visitor;
+ Visitor.Target = Target;
+ return !Visitor.TraverseDecl(const_cast<Decl *>(D));
+ }
+};
+
+/// Traverses the AST and finds the last statement that used a given
+/// declaration.
+class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
+ const Decl *D;
+
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ if (DRE->getDecl() == D)
+ return false;
+ return true;
+ }
+
+ static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
+ const CompoundStmt *Scope) {
+ LastDeclUSEFinder Visitor;
+ Visitor.D = D;
+ for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) {
+ const Stmt *S = *I;
+ if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
+ return S;
+ }
+ return nullptr;
+ }
+};
+
+/// This class implements -Wunguarded-availability.
+///
+/// This is done with a traversal of the AST of a function that makes reference
+/// to a partially available declaration. Whenever we encounter an \c if of the
+/// form: \c if(@available(...)), we use the version from the condition to visit
+/// the then statement.
+class DiagnoseUnguardedAvailability
+ : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
+ typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
+
+ Sema &SemaRef;
+ Decl *Ctx;
+
+ /// Stack of potentially nested 'if (@available(...))'s.
+ SmallVector<VersionTuple, 8> AvailabilityStack;
+ SmallVector<const Stmt *, 16> StmtStack;
+
+ void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
+ ObjCInterfaceDecl *ClassReceiver = nullptr);
+
+public:
+ DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
+ : SemaRef(SemaRef), Ctx(Ctx) {
+ AvailabilityStack.push_back(
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion());
+ }
+
+ bool TraverseDecl(Decl *D) {
+ // Avoid visiting nested functions to prevent duplicate warnings.
+ if (!D || isa<FunctionDecl>(D))
+ return true;
+ return Base::TraverseDecl(D);
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ if (!S)
+ return true;
+ StmtStack.push_back(S);
+ bool Result = Base::TraverseStmt(S);
+ StmtStack.pop_back();
+ return Result;
+ }
+
+ void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
+
+ bool TraverseIfStmt(IfStmt *If);
+
+ bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
+
+ // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
+ // to any useful diagnostics.
+ bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
+
+ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
+ if (PRE->isClassReceiver())
+ DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
+ return true;
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
+ if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
+ ObjCInterfaceDecl *ID = nullptr;
+ QualType ReceiverTy = Msg->getClassReceiver();
+ if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
+ ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
+
+ DiagnoseDeclAvailability(
+ D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
+ }
+ return true;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ DiagnoseDeclAvailability(DRE->getDecl(),
+ SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
+ return true;
+ }
+
+ bool VisitMemberExpr(MemberExpr *ME) {
+ DiagnoseDeclAvailability(ME->getMemberDecl(),
+ SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
+ return true;
+ }
+
+ bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
+ SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
+ << (!SemaRef.getLangOpts().ObjC);
+ return true;
+ }
+
+ bool VisitTypeLoc(TypeLoc Ty);
+};
+
+void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
+ NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
+ AvailabilityResult Result;
+ const NamedDecl *OffendingDecl;
+ std::tie(Result, OffendingDecl) =
+ ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
+ if (Result != AR_Available) {
+ // All other diagnostic kinds have already been handled in
+ // DiagnoseAvailabilityOfDecl.
+ if (Result != AR_NotYetIntroduced)
+ return;
+
+ const AvailabilityAttr *AA =
+ getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
+ VersionTuple Introduced = AA->getIntroduced();
+
+ if (AvailabilityStack.back() >= Introduced)
+ return;
+
+ // If the context of this function is less available than D, we should not
+ // emit a diagnostic.
+ if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
+ OffendingDecl))
+ return;
+
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ unsigned DiagKind =
+ shouldDiagnoseAvailabilityByDefault(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
+ ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
+ SemaRef.getASTContext().getTargetInfo().getPlatformName()));
+
+ SemaRef.Diag(Range.getBegin(), DiagKind)
+ << Range << D << PlatformName << Introduced.getAsString();
+
+ SemaRef.Diag(OffendingDecl->getLocation(),
+ diag::note_partial_availability_specified_here)
+ << OffendingDecl << PlatformName << Introduced.getAsString()
+ << SemaRef.Context.getTargetInfo()
+ .getPlatformMinVersion()
+ .getAsString();
+
+ auto FixitDiag =
+ SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
+ << Range << D
+ << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
+ : /*__builtin_available*/ 1);
+
+ // Find the statement which should be enclosed in the if @available check.
+ if (StmtStack.empty())
+ return;
+ const Stmt *StmtOfUse = StmtStack.back();
+ const CompoundStmt *Scope = nullptr;
+ for (const Stmt *S : llvm::reverse(StmtStack)) {
+ if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
+ Scope = CS;
+ break;
+ }
+ if (isBodyLikeChildStmt(StmtOfUse, S)) {
+ // The declaration won't be seen outside of the statement, so we don't
+ // have to wrap the uses of any declared variables in if (@available).
+ // Therefore we can avoid setting Scope here.
+ break;
+ }
+ StmtOfUse = S;
+ }
+ const Stmt *LastStmtOfUse = nullptr;
+ if (isa<DeclStmt>(StmtOfUse) && Scope) {
+ for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
+ if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
+ LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
+ break;
+ }
+ }
+ }
+
+ const SourceManager &SM = SemaRef.getSourceManager();
+ SourceLocation IfInsertionLoc =
+ SM.getExpansionLoc(StmtOfUse->getBeginLoc());
+ SourceLocation StmtEndLoc =
+ SM.getExpansionRange(
+ (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
+ .getEnd();
+ if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
+ return;
+
+ StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
+ const char *ExtraIndentation = " ";
+ std::string FixItString;
+ llvm::raw_string_ostream FixItOS(FixItString);
+ FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
+ : "__builtin_available")
+ << "("
+ << AvailabilityAttr::getPlatformNameSourceSpelling(
+ SemaRef.getASTContext().getTargetInfo().getPlatformName())
+ << " " << Introduced.getAsString() << ", *)) {\n"
+ << Indentation << ExtraIndentation;
+ FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
+ SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
+ StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/false);
+ if (ElseInsertionLoc.isInvalid())
+ ElseInsertionLoc =
+ Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
+ FixItOS.str().clear();
+ FixItOS << "\n"
+ << Indentation << "} else {\n"
+ << Indentation << ExtraIndentation
+ << "// Fallback on earlier versions\n"
+ << Indentation << "}";
+ FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
+ }
+}
+
+bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
+ const Type *TyPtr = Ty.getTypePtr();
+ SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
+
+ if (Range.isInvalid())
+ return true;
+
+ if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
+ TagDecl *TD = TT->getDecl();
+ DiagnoseDeclAvailability(TD, Range);
+
+ } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
+ TypedefNameDecl *D = TD->getDecl();
+ DiagnoseDeclAvailability(D, Range);
+
+ } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
+ if (NamedDecl *D = ObjCO->getInterface())
+ DiagnoseDeclAvailability(D, Range);
+ }
+
+ return true;
+}
+
+bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
+ VersionTuple CondVersion;
+ if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
+ CondVersion = E->getVersion();
+
+ // If we're using the '*' case here or if this check is redundant, then we
+ // use the enclosing version to check both branches.
+ if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
+ return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
+ } else {
+ // This isn't an availability checking 'if', we can just continue.
+ return Base::TraverseIfStmt(If);
+ }
+
+ AvailabilityStack.push_back(CondVersion);
+ bool ShouldContinue = TraverseStmt(If->getThen());
+ AvailabilityStack.pop_back();
+
+ return ShouldContinue && TraverseStmt(If->getElse());
+}
+
+} // end anonymous namespace
+
+void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
+ Stmt *Body = nullptr;
+
+ if (auto *FD = D->getAsFunction()) {
+ // FIXME: We only examine the pattern decl for availability violations now,
+ // but we should also examine instantiated templates.
+ if (FD->isTemplateInstantiation())
+ return;
+
+ Body = FD->getBody();
+ } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ Body = MD->getBody();
+ else if (auto *BD = dyn_cast<BlockDecl>(D))
+ Body = BD->getBody();
+
+ assert(Body && "Need a body here!");
+
+ DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
+}
+
+void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
+ ArrayRef<SourceLocation> Locs,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess,
+ bool AvoidPartialAvailabilityChecks,
+ ObjCInterfaceDecl *ClassReceiver) {
+ std::string Message;
+ AvailabilityResult Result;
+ const NamedDecl* OffendingDecl;
+ // See if this declaration is unavailable, deprecated, or partial.
+ std::tie(Result, OffendingDecl) =
+ ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
+ if (Result == AR_Available)
+ return;
+
+ if (Result == AR_NotYetIntroduced) {
+ if (AvoidPartialAvailabilityChecks)
+ return;
+
+ // We need to know the @available context in the current function to
+ // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
+ // when we're done parsing the current function.
+ if (getCurFunctionOrMethodDecl()) {
+ getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ } else if (getCurBlock() || getCurLambda()) {
+ getCurFunction()->HasPotentialAvailabilityViolations = true;
+ return;
+ }
+ }
+
+ const ObjCPropertyDecl *ObjCPDecl = nullptr;
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
+ AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
+ if (PDeclResult == Result)
+ ObjCPDecl = PD;
+ }
+ }
+
+ EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
+ UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
+}
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 0c61057e1072..283a04683a32 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -14,8 +14,10 @@
#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Cuda.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/SemaInternal.h"
@@ -210,6 +212,20 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
llvm_unreachable("All cases should've been handled by now.");
}
+template <typename AttrT> static bool hasImplicitAttr(const FunctionDecl *D) {
+ if (!D)
+ return false;
+ if (auto *A = D->getAttr<AttrT>())
+ return A->isImplicit();
+ return D->isImplicit();
+}
+
+bool Sema::isCUDAImplicitHostDeviceFunction(const FunctionDecl *D) {
+ bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D);
+ bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D);
+ return IsImplicitDevAttr && IsImplicitHostAttr;
+}
+
void Sema::EraseUnwantedCUDAMatches(
const FunctionDecl *Caller,
SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) {
@@ -425,6 +441,10 @@ bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) {
if (CD->getParent()->isDynamicClass())
return false;
+ // Union ctor does not call ctors of its data members.
+ if (CD->getParent()->isUnion())
+ return true;
+
// The only form of initializer allowed is an empty constructor.
// This will recursively check all base classes and member initializers
if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) {
@@ -464,6 +484,11 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) {
if (ClassDecl->isDynamicClass())
return false;
+ // Union does not have base class and union dtor does not call dtors of its
+ // data members.
+ if (DD->getParent()->isUnion())
+ return true;
+
// Only empty destructors are allowed. This will recursively check
// destructors for all base classes...
if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) {
@@ -503,9 +528,14 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) {
// constructor according to CUDA rules. This deviates from NVCC,
// but allows us to handle things like constexpr constructors.
if (!AllowedInit &&
- (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>()))
- AllowedInit = VD->getInit()->isConstantInitializer(
- Context, VD->getType()->isReferenceType());
+ (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) {
+ auto *Init = VD->getInit();
+ AllowedInit =
+ ((VD->getType()->isDependentType() || Init->isValueDependent()) &&
+ VD->isConstexpr()) ||
+ Init->isConstantInitializer(Context,
+ VD->getType()->isReferenceType());
+ }
// Also make sure that destructor, if there is one, is empty.
if (AllowedInit)
@@ -602,6 +632,13 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}
+void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) {
+ if (getLangOpts().CUDAIsDevice && VD->isConstexpr() &&
+ (VD->isFileVarDecl() || VD->isStaticDataMember())) {
+ VD->addAttr(CUDAConstantAttr::CreateImplicit(getASTContext()));
+ }
+}
+
Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
@@ -674,25 +711,6 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// Otherwise, mark the call in our call graph so we can traverse it later.
bool CallerKnownEmitted =
getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted;
- if (CallerKnownEmitted) {
- // Host-side references to a __global__ function refer to the stub, so the
- // function itself is never emitted and therefore should not be marked.
- if (!shouldIgnoreInHostDeviceCheck(Callee))
- markKnownEmitted(
- *this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) {
- return S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
- });
- } else {
- // If we have
- // host fn calls kernel fn calls host+device,
- // the HD function does not get instantiated on the host. We model this by
- // omitting at the call to the kernel from the callgraph. This ensures
- // that, when compiling for host, only HD functions actually called from the
- // host get marked as known-emitted.
- if (!shouldIgnoreInHostDeviceCheck(Callee))
- DeviceCallGraph[Caller].insert({Callee, Loc});
- }
-
DeviceDiagBuilder::Kind DiagKind = [this, Caller, Callee,
CallerKnownEmitted] {
switch (IdentifyCUDAPreference(Caller, Callee)) {
@@ -729,20 +747,58 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack;
}
+// Check the wrong-sided reference capture of lambda for CUDA/HIP.
+// A lambda function may capture a stack variable by reference when it is
+// defined and uses the capture by reference when the lambda is called. When
+// the capture and use happen on different sides, the capture is invalid and
+// should be diagnosed.
+void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee,
+ const sema::Capture &Capture) {
+ // In host compilation we only need to check lambda functions emitted on host
+ // side. In such lambda functions, a reference capture is invalid only
+ // if the lambda structure is populated by a device function or kernel then
+ // is passed to and called by a host function. However that is impossible,
+ // since a device function or kernel can only call a device function, also a
+ // kernel cannot pass a lambda back to a host function since we cannot
+ // define a kernel argument type which can hold the lambda before the lambda
+ // itself is defined.
+ if (!LangOpts.CUDAIsDevice)
+ return;
+
+ // File-scope lambda can only do init captures for global variables, which
+ // results in passing by value for these global variables.
+ FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
+ if (!Caller)
+ return;
+
+ // In device compilation, we only need to check lambda functions which are
+ // emitted on device side. For such lambdas, a reference capture is invalid
+ // only if the lambda structure is populated by a host function then passed
+ // to and called in a device function or kernel.
+ bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>();
+ bool CallerIsHost =
+ !Caller->hasAttr<CUDAGlobalAttr>() && !Caller->hasAttr<CUDADeviceAttr>();
+ bool ShouldCheck = CalleeIsDevice && CallerIsHost;
+ if (!ShouldCheck || !Capture.isReferenceCapture())
+ return;
+ auto DiagKind = DeviceDiagBuilder::K_Deferred;
+ if (Capture.isVariableCapture()) {
+ DeviceDiagBuilder(DiagKind, Capture.getLocation(),
+ diag::err_capture_bad_target, Callee, *this)
+ << Capture.getVariable();
+ } else if (Capture.isThisCapture()) {
+ DeviceDiagBuilder(DiagKind, Capture.getLocation(),
+ diag::err_capture_bad_target_this_ptr, Callee, *this);
+ }
+ return;
+}
+
void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
if (Method->hasAttr<CUDAHostAttr>() || Method->hasAttr<CUDADeviceAttr>())
return;
- FunctionDecl *CurFn = dyn_cast<FunctionDecl>(CurContext);
- if (!CurFn)
- return;
- CUDAFunctionTarget Target = IdentifyCUDATarget(CurFn);
- if (Target == CFT_Global || Target == CFT_Device) {
- Method->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- } else if (Target == CFT_HostDevice) {
- Method->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- Method->addAttr(CUDAHostAttr::CreateImplicit(Context));
- }
+ Method->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ Method->addAttr(CUDAHostAttr::CreateImplicit(Context));
}
void Sema::checkCUDATargetOverload(FunctionDecl *NewFD,
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index a905ebc67305..2efe26052c78 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -48,7 +48,8 @@ enum CastType {
CT_Reinterpret, ///< reinterpret_cast
CT_Dynamic, ///< dynamic_cast
CT_CStyle, ///< (Type)expr
- CT_Functional ///< Type(expr)
+ CT_Functional, ///< Type(expr)
+ CT_Addrspace ///< addrspace_cast
};
namespace {
@@ -88,6 +89,7 @@ namespace {
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
void CheckCStyleCast();
void CheckBuiltinBitCast();
+ void CheckAddrspaceCast();
void updatePartOfExplicitCastFlags(CastExpr *CE) {
// Walk down from the CE to the OrigSrcExpr, and mark all immediate
@@ -159,6 +161,30 @@ namespace {
PlaceholderKind = (BuiltinType::Kind) 0;
}
};
+
+ void CheckNoDeref(Sema &S, const QualType FromType, const QualType ToType,
+ SourceLocation OpLoc) {
+ if (const auto *PtrType = dyn_cast<PointerType>(FromType)) {
+ if (PtrType->getPointeeType()->hasAttr(attr::NoDeref)) {
+ if (const auto *DestType = dyn_cast<PointerType>(ToType)) {
+ if (!DestType->getPointeeType()->hasAttr(attr::NoDeref)) {
+ S.Diag(OpLoc, diag::warn_noderef_to_dereferenceable_pointer);
+ }
+ }
+ }
+ }
+ }
+
+ struct CheckNoDerefRAII {
+ CheckNoDerefRAII(CastOperation &Op) : Op(Op) {}
+ ~CheckNoDerefRAII() {
+ if (!Op.SrcExpr.isInvalid())
+ CheckNoDeref(Op.Self, Op.SrcExpr.get()->getType(), Op.ResultType,
+ Op.OpRange.getBegin());
+ }
+
+ CastOperation &Op;
+ };
}
static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
@@ -225,12 +251,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
unsigned &msg);
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
- SourceRange OpRange,
- unsigned &msg,
+ SourceRange OpRange, unsigned &msg,
CastKind &Kind);
+static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
+ QualType DestType, bool CStyle,
+ unsigned &msg, CastKind &Kind);
-
-/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
+/// ActOnCXXNamedCast - Parse
+/// {dynamic,static,reinterpret,const,addrspace}_cast's.
ExprResult
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation LAngleBracketLoc, Declarator &D,
@@ -272,6 +300,16 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
+ case tok::kw_addrspace_cast:
+ if (!TypeDependent) {
+ Op.CheckAddrspaceCast();
+ if (Op.SrcExpr.isInvalid())
+ return ExprError();
+ }
+ return Op.complete(CXXAddrspaceCastExpr::Create(
+ Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
+ DestTInfo, OpLoc, Parens.getEnd(), AngleBrackets));
+
case tok::kw_const_cast:
if (!TypeDependent) {
Op.CheckConstCast();
@@ -375,6 +413,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case CT_Const:
case CT_Reinterpret:
case CT_Dynamic:
+ case CT_Addrspace:
return false;
// These do.
@@ -708,6 +747,8 @@ static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK,
/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime-
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
@@ -861,6 +902,8 @@ void CastOperation::CheckDynamicCast() {
/// const char *str = "literal";
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (ValueKind == VK_RValue)
SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
@@ -878,6 +921,18 @@ void CastOperation::CheckConstCast() {
SrcExpr = ExprError();
}
+void CastOperation::CheckAddrspaceCast() {
+ unsigned msg = diag::err_bad_cxx_cast_generic;
+ auto TCR =
+ TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg, Kind);
+ if (TCR != TC_Success && msg != 0) {
+ Self.Diag(OpRange.getBegin(), msg)
+ << CT_Addrspace << SrcExpr.get()->getType() << DestType << OpRange;
+ }
+ if (!isValidCast(TCR))
+ SrcExpr = ExprError();
+}
+
/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
/// or downcast between respective pointers or references.
static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
@@ -1018,6 +1073,8 @@ void CastOperation::CheckReinterpretCast() {
/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making
/// implicit conversions explicit and getting rid of data loss warnings.
void CastOperation::CheckStaticCast() {
+ CheckNoDerefRAII NoderefCheck(*this);
+
if (isPlaceholder()) {
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid())
@@ -1961,7 +2018,7 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
<< FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText);
}
-static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
+static void checkIntToPointerCast(bool CStyle, const SourceRange &OpRange,
const Expr *SrcExpr, QualType DestType,
Sema &Self) {
QualType SrcType = SrcExpr->getType();
@@ -1983,7 +2040,7 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
unsigned Diag = DestType->isVoidPointerType() ?
diag::warn_int_to_void_pointer_cast
: diag::warn_int_to_pointer_cast;
- Self.Diag(Loc, Diag) << SrcType << DestType;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
}
}
@@ -2062,6 +2119,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
// FIXME: Use a specific diagnostic for the rest of these cases.
case OK_VectorComponent: inappropriate = "vector element"; break;
+ case OK_MatrixComponent:
+ inappropriate = "matrix element";
+ break;
case OK_ObjCProperty: inappropriate = "property expression"; break;
case OK_ObjCSubscript: inappropriate = "container subscripting expression";
break;
@@ -2204,13 +2264,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
// type large enough to hold it; except in Microsoft mode, where the
// integral type size doesn't matter (except we don't allow bool).
- bool MicrosoftException = Self.getLangOpts().MicrosoftExt &&
- !DestType->isBooleanType();
if ((Self.Context.getTypeSize(SrcType) >
- Self.Context.getTypeSize(DestType)) &&
- !MicrosoftException) {
- msg = diag::err_bad_reinterpret_cast_small_int;
- return TC_Failed;
+ Self.Context.getTypeSize(DestType))) {
+ bool MicrosoftException =
+ Self.getLangOpts().MicrosoftExt && !DestType->isBooleanType();
+ if (MicrosoftException) {
+ unsigned Diag = SrcType->isVoidPointerType()
+ ? diag::warn_void_pointer_to_int_cast
+ : diag::warn_pointer_to_int_cast;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
+ } else {
+ msg = diag::err_bad_reinterpret_cast_small_int;
+ return TC_Failed;
+ }
}
Kind = CK_PointerToIntegral;
return TC_Success;
@@ -2218,8 +2284,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
assert(destIsPtr && "One type must be a pointer");
- checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType,
- Self);
+ checkIntToPointerCast(CStyle, OpRange, SrcExpr.get(), DestType, Self);
// C++ 5.2.10p5: A value of integral or enumeration type can be explicitly
// converted to a pointer.
// C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not
@@ -2311,6 +2376,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return SuccessResult;
}
+ // Diagnose address space conversion in nested pointers.
+ QualType DestPtee = DestType->getPointeeType().isNull()
+ ? DestType->getPointeeType()
+ : DestType->getPointeeType()->getPointeeType();
+ QualType SrcPtee = SrcType->getPointeeType().isNull()
+ ? SrcType->getPointeeType()
+ : SrcType->getPointeeType()->getPointeeType();
+ while (!DestPtee.isNull() && !SrcPtee.isNull()) {
+ if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) {
+ Self.Diag(OpRange.getBegin(),
+ diag::warn_bad_cxx_cast_nested_pointer_addr_space)
+ << CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange();
+ break;
+ }
+ DestPtee = DestPtee->getPointeeType();
+ SrcPtee = SrcPtee->getPointeeType();
+ }
+
// C++ 5.2.10p7: A pointer to an object can be explicitly converted to
// a pointer to an object of different type.
// Void pointers are not specified, but supported by every compiler out there.
@@ -2321,7 +2404,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
- unsigned &msg) {
+ unsigned &msg, CastKind &Kind) {
if (!Self.getLangOpts().OpenCL)
// FIXME: As compiler doesn't have any information about overlapping addr
// spaces at the moment we have to be permissive here.
@@ -2330,6 +2413,9 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
// non-OpenCL mode too, we fast-path above because no other languages
// define overlapping address spaces currently.
auto SrcType = SrcExpr.get()->getType();
+ // FIXME: Should this be generalized to references? The reference parameter
+ // however becomes a reference pointee type here and therefore rejected.
+ // Perhaps this is the right behavior though according to C++.
auto SrcPtrType = SrcType->getAs<PointerType>();
if (!SrcPtrType)
return TC_NotApplicable;
@@ -2338,9 +2424,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
auto SrcPointeeType = SrcPtrType->getPointeeType();
auto DestPointeeType = DestPtrType->getPointeeType();
- if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace())
- return TC_NotApplicable;
- if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) {
+ if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) {
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
return TC_Failed;
}
@@ -2348,10 +2432,15 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType());
auto DestPointeeTypeWithoutAS =
Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType());
- return Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
- DestPointeeTypeWithoutAS)
- ? TC_Success
- : TC_NotApplicable;
+ if (Self.Context.hasSameType(SrcPointeeTypeWithoutAS,
+ DestPointeeTypeWithoutAS)) {
+ Kind = SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()
+ ? CK_NoOp
+ : CK_AddressSpaceConversion;
+ return TC_Success;
+ } else {
+ return TC_NotApplicable;
+ }
}
void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
@@ -2378,9 +2467,9 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
const PointerType *SrcPPtr = cast<PointerType>(SrcPtr);
QualType DestPPointee = DestPPtr->getPointeeType();
QualType SrcPPointee = SrcPPtr->getPointeeType();
- if (Nested ? DestPPointee.getAddressSpace() !=
- SrcPPointee.getAddressSpace()
- : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) {
+ if (Nested
+ ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace()
+ : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) {
Self.Diag(OpRange.getBegin(), DiagID)
<< SrcType << DestType << Sema::AA_Casting
<< SrcExpr.get()->getSourceRange();
@@ -2482,22 +2571,21 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
Sema::CheckedConversionKind CCK =
FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
- tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg);
+ tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg,
+ Kind);
if (SrcExpr.isInvalid())
return;
- if (isValidCast(tcr))
- Kind = CK_AddressSpaceConversion;
-
if (tcr == TC_NotApplicable) {
- // ... or if that is not possible, a static_cast, ignoring const, ...
+ // ... or if that is not possible, a static_cast, ignoring const and
+ // addr space, ...
tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind,
BasePath, ListInitialization);
if (SrcExpr.isInvalid())
return;
if (tcr == TC_NotApplicable) {
- // ... and finally a reinterpret_cast, ignoring const.
+ // ... and finally a reinterpret_cast, ignoring const and addr space.
tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true,
OpRange, msg, Kind);
if (SrcExpr.isInvalid())
@@ -2629,6 +2717,13 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // Allow casting a sizeless built-in type to itself.
+ if (DestType->isSizelessBuiltinType() &&
+ Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ Kind = CK_NoOp;
+ return;
+ }
+
if (!DestType->isScalarType() && !DestType->isVectorType()) {
const RecordType *DestRecordTy = DestType->getAs<RecordType>();
@@ -2724,6 +2819,20 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // Can't cast to or from bfloat
+ if (DestType->isBFloat16Type() && !SrcType->isBFloat16Type()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_to_bfloat16)
+ << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ if (SrcType->isBFloat16Type() && !DestType->isBFloat16Type()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_from_bfloat16)
+ << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+
// If either type is a pointer, the other type has to be either an
// integer or a pointer.
if (!DestType->isArithmeticType()) {
@@ -2734,8 +2843,8 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
- checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(),
- DestType, Self);
+ checkIntToPointerCast(/* CStyle */ true, OpRange, SrcExpr.get(), DestType,
+ Self);
} else if (!SrcType->isArithmeticType()) {
if (!DestType->isIntegralType(Self.Context) &&
DestType->isArithmeticType()) {
@@ -2745,6 +2854,25 @@ void CastOperation::CheckCStyleCast() {
SrcExpr = ExprError();
return;
}
+
+ if ((Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) &&
+ !DestType->isBooleanType()) {
+ // C 6.3.2.3p6: Any pointer type may be converted to an integer type.
+ // Except as previously specified, the result is implementation-defined.
+ // If the result cannot be represented in the integer type, the behavior
+ // is undefined. The result need not be in the range of values of any
+ // integer type.
+ unsigned Diag;
+ if (SrcType->isVoidPointerType())
+ Diag = DestType->isEnumeralType() ? diag::warn_void_pointer_to_enum_cast
+ : diag::warn_void_pointer_to_int_cast;
+ else if (DestType->isEnumeralType())
+ Diag = diag::warn_pointer_to_enum_cast;
+ else
+ Diag = diag::warn_pointer_to_int_cast;
+ Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange;
+ }
}
if (Self.getLangOpts().OpenCL &&
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 74742023d1b3..509d88e25000 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/NSAPI.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -87,6 +88,7 @@
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -236,8 +238,8 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
}
Expr::EvalResult AlignResult;
unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1;
- // We can't check validity of alignment if it is type dependent.
- if (!AlignOp->isInstantiationDependent() &&
+ // We can't check validity of alignment if it is value dependent.
+ if (!AlignOp->isValueDependent() &&
AlignOp->EvaluateAsInt(AlignResult, S.Context,
Expr::SE_AllowSideEffects)) {
llvm::APSInt AlignValue = AlignResult.Val.getInt();
@@ -282,48 +284,60 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
return false;
}
-static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) {
+static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall,
+ unsigned BuiltinID) {
if (checkArgCount(S, TheCall, 3))
return true;
// First two arguments should be integers.
for (unsigned I = 0; I < 2; ++I) {
- ExprResult Arg = TheCall->getArg(I);
+ ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I));
+ if (Arg.isInvalid()) return true;
+ TheCall->setArg(I, Arg.get());
+
QualType Ty = Arg.get()->getType();
if (!Ty->isIntegerType()) {
S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_int)
<< Ty << Arg.get()->getSourceRange();
return true;
}
- InitializedEntity Entity = InitializedEntity::InitializeParameter(
- S.getASTContext(), Ty, /*consume*/ false);
- Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
- if (Arg.isInvalid())
- return true;
- TheCall->setArg(I, Arg.get());
}
// Third argument should be a pointer to a non-const integer.
// IRGen correctly handles volatile, restrict, and address spaces, and
// the other qualifiers aren't possible.
{
- ExprResult Arg = TheCall->getArg(2);
+ ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2));
+ if (Arg.isInvalid()) return true;
+ TheCall->setArg(2, Arg.get());
+
QualType Ty = Arg.get()->getType();
const auto *PtrTy = Ty->getAs<PointerType>();
- if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() &&
- !PtrTy->getPointeeType().isConstQualified())) {
+ if (!PtrTy ||
+ !PtrTy->getPointeeType()->isIntegerType() ||
+ PtrTy->getPointeeType().isConstQualified()) {
S.Diag(Arg.get()->getBeginLoc(),
diag::err_overflow_builtin_must_be_ptr_int)
- << Ty << Arg.get()->getSourceRange();
+ << Ty << Arg.get()->getSourceRange();
return true;
}
- InitializedEntity Entity = InitializedEntity::InitializeParameter(
- S.getASTContext(), Ty, /*consume*/ false);
- Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
- if (Arg.isInvalid())
- return true;
- TheCall->setArg(2, Arg.get());
}
+
+ // Disallow signed ExtIntType args larger than 128 bits to mul function until
+ // we improve backend support.
+ if (BuiltinID == Builtin::BI__builtin_mul_overflow) {
+ for (unsigned I = 0; I < 3; ++I) {
+ const auto Arg = TheCall->getArg(I);
+ // Third argument will be a pointer.
+ auto Ty = I < 2 ? Arg->getType() : Arg->getType()->getPointeeType();
+ if (Ty->isExtIntType() && Ty->isSignedIntegerType() &&
+ S.getASTContext().getIntWidth(Ty) > 128)
+ return S.Diag(Arg->getBeginLoc(),
+ diag::err_overflow_builtin_ext_int_max_size)
+ << 128;
+ }
+ }
+
return false;
}
@@ -390,13 +404,194 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
return false;
}
+namespace {
+
+class EstimateSizeFormatHandler
+ : public analyze_format_string::FormatStringHandler {
+ size_t Size;
+
+public:
+ EstimateSizeFormatHandler(StringRef Format)
+ : Size(std::min(Format.find(0), Format.size()) +
+ 1 /* null byte always written by sprintf */) {}
+
+ bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+ const char *, unsigned SpecifierLen) override {
+
+ const size_t FieldWidth = computeFieldWidth(FS);
+ const size_t Precision = computePrecision(FS);
+
+ // The actual format.
+ switch (FS.getConversionSpecifier().getKind()) {
+ // Just a char.
+ case analyze_format_string::ConversionSpecifier::cArg:
+ case analyze_format_string::ConversionSpecifier::CArg:
+ Size += std::max(FieldWidth, (size_t)1);
+ break;
+ // Just an integer.
+ case analyze_format_string::ConversionSpecifier::dArg:
+ case analyze_format_string::ConversionSpecifier::DArg:
+ case analyze_format_string::ConversionSpecifier::iArg:
+ case analyze_format_string::ConversionSpecifier::oArg:
+ case analyze_format_string::ConversionSpecifier::OArg:
+ case analyze_format_string::ConversionSpecifier::uArg:
+ case analyze_format_string::ConversionSpecifier::UArg:
+ case analyze_format_string::ConversionSpecifier::xArg:
+ case analyze_format_string::ConversionSpecifier::XArg:
+ Size += std::max(FieldWidth, Precision);
+ break;
+
+ // %g style conversion switches between %f or %e style dynamically.
+ // %f always takes less space, so default to it.
+ case analyze_format_string::ConversionSpecifier::gArg:
+ case analyze_format_string::ConversionSpecifier::GArg:
+
+ // Floating point number in the form '[+]ddd.ddd'.
+ case analyze_format_string::ConversionSpecifier::fArg:
+ case analyze_format_string::ConversionSpecifier::FArg:
+ Size += std::max(FieldWidth, 1 /* integer part */ +
+ (Precision ? 1 + Precision
+ : 0) /* period + decimal */);
+ break;
+
+ // Floating point number in the form '[-]d.ddde[+-]dd'.
+ case analyze_format_string::ConversionSpecifier::eArg:
+ case analyze_format_string::ConversionSpecifier::EArg:
+ Size +=
+ std::max(FieldWidth,
+ 1 /* integer part */ +
+ (Precision ? 1 + Precision : 0) /* period + decimal */ +
+ 1 /* e or E letter */ + 2 /* exponent */);
+ break;
+
+ // Floating point number in the form '[-]0xh.hhhhp±dd'.
+ case analyze_format_string::ConversionSpecifier::aArg:
+ case analyze_format_string::ConversionSpecifier::AArg:
+ Size +=
+ std::max(FieldWidth,
+ 2 /* 0x */ + 1 /* integer part */ +
+ (Precision ? 1 + Precision : 0) /* period + decimal */ +
+ 1 /* p or P letter */ + 1 /* + or - */ + 1 /* value */);
+ break;
+
+ // Just a string.
+ case analyze_format_string::ConversionSpecifier::sArg:
+ case analyze_format_string::ConversionSpecifier::SArg:
+ Size += FieldWidth;
+ break;
+
+ // Just a pointer in the form '0xddd'.
+ case analyze_format_string::ConversionSpecifier::pArg:
+ Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision);
+ break;
+
+ // A plain percent.
+ case analyze_format_string::ConversionSpecifier::PercentArg:
+ Size += 1;
+ break;
+
+ default:
+ break;
+ }
+
+ Size += FS.hasPlusPrefix() || FS.hasSpacePrefix();
+
+ if (FS.hasAlternativeForm()) {
+ switch (FS.getConversionSpecifier().getKind()) {
+ default:
+ break;
+ // Force a leading '0'.
+ case analyze_format_string::ConversionSpecifier::oArg:
+ Size += 1;
+ break;
+ // Force a leading '0x'.
+ case analyze_format_string::ConversionSpecifier::xArg:
+ case analyze_format_string::ConversionSpecifier::XArg:
+ Size += 2;
+ break;
+ // Force a period '.' before decimal, even if precision is 0.
+ case analyze_format_string::ConversionSpecifier::aArg:
+ case analyze_format_string::ConversionSpecifier::AArg:
+ case analyze_format_string::ConversionSpecifier::eArg:
+ case analyze_format_string::ConversionSpecifier::EArg:
+ case analyze_format_string::ConversionSpecifier::fArg:
+ case analyze_format_string::ConversionSpecifier::FArg:
+ case analyze_format_string::ConversionSpecifier::gArg:
+ case analyze_format_string::ConversionSpecifier::GArg:
+ Size += (Precision ? 0 : 1);
+ break;
+ }
+ }
+ assert(SpecifierLen <= Size && "no underflow");
+ Size -= SpecifierLen;
+ return true;
+ }
+
+ size_t getSizeLowerBound() const { return Size; }
+
+private:
+ static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) {
+ const analyze_format_string::OptionalAmount &FW = FS.getFieldWidth();
+ size_t FieldWidth = 0;
+ if (FW.getHowSpecified() == analyze_format_string::OptionalAmount::Constant)
+ FieldWidth = FW.getConstantAmount();
+ return FieldWidth;
+ }
+
+ static size_t computePrecision(const analyze_printf::PrintfSpecifier &FS) {
+ const analyze_format_string::OptionalAmount &FW = FS.getPrecision();
+ size_t Precision = 0;
+
+ // See man 3 printf for default precision value based on the specifier.
+ switch (FW.getHowSpecified()) {
+ case analyze_format_string::OptionalAmount::NotSpecified:
+ switch (FS.getConversionSpecifier().getKind()) {
+ default:
+ break;
+ case analyze_format_string::ConversionSpecifier::dArg: // %d
+ case analyze_format_string::ConversionSpecifier::DArg: // %D
+ case analyze_format_string::ConversionSpecifier::iArg: // %i
+ Precision = 1;
+ break;
+ case analyze_format_string::ConversionSpecifier::oArg: // %d
+ case analyze_format_string::ConversionSpecifier::OArg: // %D
+ case analyze_format_string::ConversionSpecifier::uArg: // %d
+ case analyze_format_string::ConversionSpecifier::UArg: // %D
+ case analyze_format_string::ConversionSpecifier::xArg: // %d
+ case analyze_format_string::ConversionSpecifier::XArg: // %D
+ Precision = 1;
+ break;
+ case analyze_format_string::ConversionSpecifier::fArg: // %f
+ case analyze_format_string::ConversionSpecifier::FArg: // %F
+ case analyze_format_string::ConversionSpecifier::eArg: // %e
+ case analyze_format_string::ConversionSpecifier::EArg: // %E
+ case analyze_format_string::ConversionSpecifier::gArg: // %g
+ case analyze_format_string::ConversionSpecifier::GArg: // %G
+ Precision = 6;
+ break;
+ case analyze_format_string::ConversionSpecifier::pArg: // %d
+ Precision = 1;
+ break;
+ }
+ break;
+ case analyze_format_string::OptionalAmount::Constant:
+ Precision = FW.getConstantAmount();
+ break;
+ default:
+ break;
+ }
+ return Precision;
+ }
+};
+
+} // namespace
+
/// Check a call to BuiltinID for buffer overflows. If BuiltinID is a
/// __builtin_*_chk function, then use the object size argument specified in the
/// source. Otherwise, infer the object size using __builtin_object_size.
void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
CallExpr *TheCall) {
// FIXME: There are some more useful checks we could be doing here:
- // - Analyze the format string of sprintf to see how much of buffer is used.
// - Evaluate strlen of strcpy arguments, use as object size.
if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
@@ -407,12 +602,55 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (!BuiltinID)
return;
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
+
unsigned DiagID = 0;
bool IsChkVariant = false;
+ Optional<llvm::APSInt> UsedSize;
unsigned SizeIndex, ObjectIndex;
switch (BuiltinID) {
default:
return;
+ case Builtin::BIsprintf:
+ case Builtin::BI__builtin___sprintf_chk: {
+ size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3;
+ auto *FormatExpr = TheCall->getArg(FormatIndex)->IgnoreParenImpCasts();
+
+ if (auto *Format = dyn_cast<StringLiteral>(FormatExpr)) {
+
+ if (!Format->isAscii() && !Format->isUTF8())
+ return;
+
+ StringRef FormatStrRef = Format->getString();
+ EstimateSizeFormatHandler H(FormatStrRef);
+ const char *FormatBytes = FormatStrRef.data();
+ const ConstantArrayType *T =
+ Context.getAsConstantArrayType(Format->getType());
+ assert(T && "String literal not of constant array type!");
+ size_t TypeSize = T->getSize().getZExtValue();
+
+ // In case there's a null byte somewhere.
+ size_t StrLen =
+ std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0));
+ if (!analyze_format_string::ParsePrintfString(
+ H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
+ Context.getTargetInfo(), false)) {
+ DiagID = diag::warn_fortify_source_format_overflow;
+ UsedSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound())
+ .extOrTrunc(SizeTypeWidth);
+ if (BuiltinID == Builtin::BI__builtin___sprintf_chk) {
+ IsChkVariant = true;
+ ObjectIndex = 2;
+ } else {
+ IsChkVariant = false;
+ ObjectIndex = 0;
+ }
+ break;
+ }
+ }
+ return;
+ }
case Builtin::BI__builtin___memcpy_chk:
case Builtin::BI__builtin___memmove_chk:
case Builtin::BI__builtin___memset_chk:
@@ -505,19 +743,19 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
return;
// Get the object size in the target's size_t width.
- const TargetInfo &TI = getASTContext().getTargetInfo();
- unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
}
// Evaluate the number of bytes of the object that this call will use.
- Expr::EvalResult Result;
- Expr *UsedSizeArg = TheCall->getArg(SizeIndex);
- if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext()))
- return;
- llvm::APSInt UsedSize = Result.Val.getInt();
+ if (!UsedSize) {
+ Expr::EvalResult Result;
+ Expr *UsedSizeArg = TheCall->getArg(SizeIndex);
+ if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext()))
+ return;
+ UsedSize = Result.Val.getInt().extOrTrunc(SizeTypeWidth);
+ }
- if (UsedSize.ule(ObjectSize))
+ if (UsedSize.getValue().ule(ObjectSize))
return;
StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID);
@@ -533,7 +771,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
PDiag(DiagID)
<< FunctionName << ObjectSize.toString(/*Radix=*/10)
- << UsedSize.toString(/*Radix=*/10));
+ << UsedSize.getValue().toString(/*Radix=*/10));
}
static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
@@ -1152,6 +1390,49 @@ CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall,
return true;
}
+static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
+ SourceLocation CallSiteLoc);
+
+bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
+ switch (TI.getTriple().getArch()) {
+ default:
+ // Some builtins don't require additional checking, so just consider these
+ // acceptable.
+ return false;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ return CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ return CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ return CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
+ case llvm::Triple::hexagon:
+ return CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::systemz:
+ return CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall);
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return CheckX86BuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ return CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::amdgcn:
+ return CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall);
+ }
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
@@ -1421,6 +1702,19 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_nontemporal_load:
case Builtin::BI__builtin_nontemporal_store:
return SemaBuiltinNontemporalOverloaded(TheCallResult);
+ case Builtin::BI__builtin_memcpy_inline: {
+ clang::Expr *SizeOp = TheCall->getArg(2);
+ // We warn about copying to or from `nullptr` pointers when `size` is
+ // greater than 0. When `size` is value dependent we cannot evaluate its
+ // value so we bail out.
+ if (SizeOp->isValueDependent())
+ break;
+ if (!SizeOp->EvaluateKnownConstInt(Context).isNullValue()) {
+ CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
+ CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc());
+ }
+ break;
+ }
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case Builtin::BI##ID: \
@@ -1447,7 +1741,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_mul_overflow:
- if (SemaBuiltinOverflow(*this, TheCall))
+ if (SemaBuiltinOverflow(*this, TheCall, BuiltinID))
return ExprError();
break;
case Builtin::BI__builtin_operator_new:
@@ -1515,6 +1809,36 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.IntTy);
break;
}
+ case Builtin::BI__builtin_expect_with_probability: {
+ // We first want to ensure we are called with 3 arguments
+ if (checkArgCount(*this, TheCall, 3))
+ return ExprError();
+ // then check probability is constant float in range [0.0, 1.0]
+ const Expr *ProbArg = TheCall->getArg(2);
+ SmallVector<PartialDiagnosticAt, 8> Notes;
+ Expr::EvalResult Eval;
+ Eval.Diag = &Notes;
+ if ((!ProbArg->EvaluateAsConstantExpr(Eval, Expr::EvaluateForCodeGen,
+ Context)) ||
+ !Eval.Val.isFloat()) {
+ Diag(ProbArg->getBeginLoc(), diag::err_probability_not_constant_float)
+ << ProbArg->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : Notes)
+ Diag(PDiag.first, PDiag.second);
+ return ExprError();
+ }
+ llvm::APFloat Probability = Eval.Val.getFloat();
+ bool LoseInfo = false;
+ Probability.convert(llvm::APFloat::IEEEdouble(),
+ llvm::RoundingMode::Dynamic, &LoseInfo);
+ if (!(Probability >= llvm::APFloat(0.0) &&
+ Probability <= llvm::APFloat(1.0))) {
+ Diag(ProbArg->getBeginLoc(), diag::err_probability_out_of_range)
+ << ProbArg->getSourceRange();
+ return ExprError();
+ }
+ break;
+ }
case Builtin::BI__builtin_preserve_access_index:
if (SemaBuiltinPreserveAI(*this, TheCall))
return ExprError();
@@ -1608,62 +1932,55 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
case Builtin::BI__builtin_os_log_format:
+ Cleanup.setExprNeedsCleanups(true);
+ LLVM_FALLTHROUGH;
case Builtin::BI__builtin_os_log_format_buffer_size:
if (SemaBuiltinOSLogFormat(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_frame_address:
+ case Builtin::BI__builtin_return_address: {
+ if (SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF))
+ return ExprError();
+
+ // -Wframe-address warning if non-zero passed to builtin
+ // return/frame address.
+ Expr::EvalResult Result;
+ if (TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) &&
+ Result.Val.getInt() != 0)
+ Diag(TheCall->getBeginLoc(), diag::warn_frame_address)
+ << ((BuiltinID == Builtin::BI__builtin_return_address)
+ ? "__builtin_return_address"
+ : "__builtin_frame_address")
+ << TheCall->getSourceRange();
+ break;
+ }
+
+ case Builtin::BI__builtin_matrix_transpose:
+ return SemaBuiltinMatrixTranspose(TheCall, TheCallResult);
+
+ case Builtin::BI__builtin_matrix_column_major_load:
+ return SemaBuiltinMatrixColumnMajorLoad(TheCall, TheCallResult);
+
+ case Builtin::BI__builtin_matrix_column_major_store:
+ return SemaBuiltinMatrixColumnMajorStore(TheCall, TheCallResult);
}
// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) {
- switch (Context.getTargetInfo().getTriple().getArch()) {
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::aarch64_be:
- if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::bpfeb:
- case llvm::Triple::bpfel:
- if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::hexagon:
- if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::systemz:
- if (CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall))
- return ExprError();
- break;
- default:
- break;
+ if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) {
+ assert(Context.getAuxTargetInfo() &&
+ "Aux Target Builtin, but not an aux target?");
+
+ if (CheckTSBuiltinFunctionCall(
+ *Context.getAuxTargetInfo(),
+ Context.BuiltinInfo.getAuxBuiltinID(BuiltinID), TheCall))
+ return ExprError();
+ } else {
+ if (CheckTSBuiltinFunctionCall(Context.getTargetInfo(), BuiltinID,
+ TheCall))
+ return ExprError();
}
}
@@ -1697,6 +2014,9 @@ static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {
case NeonTypeFlags::Float64:
assert(!shift && "cannot shift float types!");
return (1 << IsQuad) - 1;
+ case NeonTypeFlags::BFloat16:
+ assert(!shift && "cannot shift float types!");
+ return (4 << IsQuad) - 1;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
@@ -1736,11 +2056,135 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
return Context.FloatTy;
case NeonTypeFlags::Float64:
return Context.DoubleTy;
+ case NeonTypeFlags::BFloat16:
+ return Context.BFloat16Ty;
}
llvm_unreachable("Invalid NeonTypeFlag!");
}
-bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ // Range check SVE intrinsics that take immediate values.
+ SmallVector<std::tuple<int,int,int>, 3> ImmChecks;
+
+ switch (BuiltinID) {
+ default:
+ return false;
+#define GET_SVE_IMMEDIATE_CHECK
+#include "clang/Basic/arm_sve_sema_rangechecks.inc"
+#undef GET_SVE_IMMEDIATE_CHECK
+ }
+
+ // Perform all the immediate checks for this builtin call.
+ bool HasError = false;
+ for (auto &I : ImmChecks) {
+ int ArgNum, CheckTy, ElementSizeInBits;
+ std::tie(ArgNum, CheckTy, ElementSizeInBits) = I;
+
+ typedef bool(*OptionSetCheckFnTy)(int64_t Value);
+
+ // Function that checks whether the operand (ArgNum) is an immediate
+ // that is one of the predefined values.
+ auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm,
+ int ErrDiag) -> bool {
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ llvm::APSInt Imm;
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Imm))
+ return true;
+
+ if (!CheckImm(Imm.getSExtValue()))
+ return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange();
+ return false;
+ };
+
+ switch ((SVETypeFlags::ImmCheckType)CheckTy) {
+ case SVETypeFlags::ImmCheck0_31:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 31))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck0_13:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 13))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck1_16:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 16))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck0_7:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 7))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckExtract:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0,
+ (2048 / ElementSizeInBits) - 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckShiftRight:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckShiftRightNarrow:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1,
+ ElementSizeInBits / 2))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckShiftLeft:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0,
+ ElementSizeInBits - 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckLaneIndex:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0,
+ (128 / (1 * ElementSizeInBits)) - 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckLaneIndexCompRotate:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0,
+ (128 / (2 * ElementSizeInBits)) - 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckLaneIndexDot:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0,
+ (128 / (4 * ElementSizeInBits)) - 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckComplexRot90_270:
+ if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; },
+ diag::err_rotation_argument_to_cadd))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheckComplexRotAll90:
+ if (CheckImmediateInSet(
+ [](int64_t V) {
+ return V == 0 || V == 90 || V == 180 || V == 270;
+ },
+ diag::err_rotation_argument_to_cmla))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck0_1:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 1))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck0_2:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 2))
+ HasError = true;
+ break;
+ case SVETypeFlags::ImmCheck0_3:
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 3))
+ HasError = true;
+ break;
+ }
+ }
+
+ return HasError;
+}
+
+bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI,
+ unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
uint64_t mask = 0;
unsigned TV = 0;
@@ -1774,12 +2218,11 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
QualType RHSTy = RHS.get()->getType();
- llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
+ llvm::Triple::ArchType Arch = TI.getTriple().getArch();
bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be;
- bool IsInt64Long =
- Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
+ bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong;
QualType EltTy =
getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long);
if (HasConstPtr)
@@ -1817,6 +2260,47 @@ bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
}
+bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
+ bool Err = false;
+ switch (BuiltinID) {
+ default:
+ return false;
+#include "clang/Basic/arm_cde_builtin_sema.inc"
+ }
+
+ if (Err)
+ return true;
+
+ return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true);
+}
+
+bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI,
+ const Expr *CoprocArg, bool WantCDE) {
+ if (isConstantEvaluated())
+ return false;
+
+ // We can't check the value of a dependent argument.
+ if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent())
+ return false;
+
+ llvm::APSInt CoprocNoAP;
+ bool IsICE = CoprocArg->isIntegerConstantExpr(CoprocNoAP, Context);
+ (void)IsICE;
+ assert(IsICE && "Coprocossor immediate is not a constant expression");
+ int64_t CoprocNo = CoprocNoAP.getExtValue();
+ assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative");
+
+ uint32_t CDECoprocMask = TI.getARMCDECoprocMask();
+ bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo));
+
+ if (IsCDECoproc != WantCDE)
+ return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc)
+ << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange();
+
+ return false;
+}
+
bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth) {
assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
@@ -1932,7 +2416,8 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
return false;
}
-bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
BuiltinID == ARM::BI__builtin_arm_ldaex ||
BuiltinID == ARM::BI__builtin_arm_strex ||
@@ -1955,10 +2440,12 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
BuiltinID == ARM::BI__builtin_arm_wsrp)
return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
- if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
+ if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
return true;
if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
return true;
+ if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall))
+ return true;
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
@@ -1981,11 +2468,33 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case ARM::BI__builtin_arm_isb:
case ARM::BI__builtin_arm_dbg:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15);
- }
-}
-
-bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
- CallExpr *TheCall) {
+ case ARM::BI__builtin_arm_cdp:
+ case ARM::BI__builtin_arm_cdp2:
+ case ARM::BI__builtin_arm_mcr:
+ case ARM::BI__builtin_arm_mcr2:
+ case ARM::BI__builtin_arm_mrc:
+ case ARM::BI__builtin_arm_mrc2:
+ case ARM::BI__builtin_arm_mcrr:
+ case ARM::BI__builtin_arm_mcrr2:
+ case ARM::BI__builtin_arm_mrrc:
+ case ARM::BI__builtin_arm_mrrc2:
+ case ARM::BI__builtin_arm_ldc:
+ case ARM::BI__builtin_arm_ldcl:
+ case ARM::BI__builtin_arm_ldc2:
+ case ARM::BI__builtin_arm_ldc2l:
+ case ARM::BI__builtin_arm_stc:
+ case ARM::BI__builtin_arm_stcl:
+ case ARM::BI__builtin_arm_stc2:
+ case ARM::BI__builtin_arm_stc2l:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15) ||
+ CheckARMCoprocessorImmediate(TI, TheCall->getArg(0),
+ /*WantCDE*/ false);
+ }
+}
+
+bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
+ unsigned BuiltinID,
+ CallExpr *TheCall) {
if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
BuiltinID == AArch64::BI__builtin_arm_ldaex ||
BuiltinID == AArch64::BI__builtin_arm_strex ||
@@ -2030,7 +2539,10 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
if (BuiltinID == AArch64::BI__getReg)
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31);
- if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
+ if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
+ return true;
+
+ if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
return true;
// For intrinsics which take an immediate value as part of the instruction,
@@ -2049,17 +2561,33 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
- assert(BuiltinID == BPF::BI__builtin_preserve_field_info &&
+ assert((BuiltinID == BPF::BI__builtin_preserve_field_info ||
+ BuiltinID == BPF::BI__builtin_btf_type_id) &&
"unexpected ARM builtin");
if (checkArgCount(*this, TheCall, 2))
return true;
+ Expr *Arg;
+ if (BuiltinID == BPF::BI__builtin_btf_type_id) {
+ // The second argument needs to be a constant int
+ llvm::APSInt Value;
+ Arg = TheCall->getArg(1);
+ if (!Arg->isIntegerConstantExpr(Value, Context)) {
+ Diag(Arg->getBeginLoc(), diag::err_btf_type_id_not_const)
+ << 2 << Arg->getSourceRange();
+ return true;
+ }
+
+ TheCall->setType(Context.UnsignedIntTy);
+ return false;
+ }
+
// The first argument needs to be a record field access.
// If it is an array element access, we delay decision
// to BPF backend to check whether the access is a
// field access or not.
- Expr *Arg = TheCall->getArg(0);
+ Arg = TheCall->getArg(0);
if (Arg->getType()->getAsPlaceholderType() ||
(Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
!dyn_cast<MemberExpr>(Arg->IgnoreParens()) &&
@@ -2070,8 +2598,9 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
}
// The second argument needs to be a constant int
+ Arg = TheCall->getArg(1);
llvm::APSInt Value;
- if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) {
+ if (!Arg->isIntegerConstantExpr(Value, Context)) {
Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const)
<< 2 << Arg->getSourceRange();
return true;
@@ -2081,825 +2610,6 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
return false;
}
-bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
- struct BuiltinAndString {
- unsigned BuiltinID;
- const char *Str;
- };
-
- static BuiltinAndString ValidCPU[] = {
- { Hexagon::BI__builtin_HEXAGON_A6_vcmpbeq_notany, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_A6_vminub_RdP, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_F2_dfadd, "v66" },
- { Hexagon::BI__builtin_HEXAGON_F2_dfsub, "v66" },
- { Hexagon::BI__builtin_HEXAGON_M2_mnaci, "v66" },
- { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffub, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S2_mask, "v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_vsplatrbp, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_vtrunehb_ppp, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_S6_vtrunohb_ppp, "v62,v65,v66" },
- };
-
- static BuiltinAndString ValidHVX[] = {
- { Hexagon::BI__builtin_HEXAGON_V6_hi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_hi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lo, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lo_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_extractw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_extractw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplath, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplath_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_not, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_not_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_pred_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsb, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsb_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddcarrysat, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddcarrysat_128B, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_valignb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_valignb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_valignbi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vand, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vand_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandqrt, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvqv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvqv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvrt, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslhv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslhv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslwv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vaslwv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrhv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasr_into, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasr_into_128B, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vasrwv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vassign, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vassign_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vassignp, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vassignp_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgb, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgb_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguw, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguw_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcl0h, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcl0h_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcl0w, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcl0w_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcombine, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vcombine_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vd0, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vd0_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdd0, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdd0_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdelta, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdelta_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlalignb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlalignb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrb_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlut4, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlut4_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxb_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmaxw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminb_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vminw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyih, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmux, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vmux_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgb, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgb_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnavgw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnormamth, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnormamth_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnot, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vnot_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackeb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackeb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackeh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackeh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackob, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackob_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackoh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackoh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw_128B, "v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrdelta, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrdelta_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_128B, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_128B, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B, "v65" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vror, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vror_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrotr, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrotr_128B, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundhb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundhb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundhub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundhub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundwh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundwh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatdw, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatdw_128B, "v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsathub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsathub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatwh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsatwh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufeh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufeh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffob, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffob_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vshufoh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubhw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv_128B, "v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubw, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubw_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vswap, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vswap_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackob, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackob_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackub, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackub_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vxor, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vxor_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vzb, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vzb_128B, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vzh, "v60,v62,v65,v66" },
- { Hexagon::BI__builtin_HEXAGON_V6_vzh_128B, "v60,v62,v65,v66" },
- };
-
- // Sort the tables on first execution so we can binary search them.
- auto SortCmp = [](const BuiltinAndString &LHS, const BuiltinAndString &RHS) {
- return LHS.BuiltinID < RHS.BuiltinID;
- };
- static const bool SortOnce =
- (llvm::sort(ValidCPU, SortCmp),
- llvm::sort(ValidHVX, SortCmp), true);
- (void)SortOnce;
- auto LowerBoundCmp = [](const BuiltinAndString &BI, unsigned BuiltinID) {
- return BI.BuiltinID < BuiltinID;
- };
-
- const TargetInfo &TI = Context.getTargetInfo();
-
- const BuiltinAndString *FC =
- llvm::lower_bound(ValidCPU, BuiltinID, LowerBoundCmp);
- if (FC != std::end(ValidCPU) && FC->BuiltinID == BuiltinID) {
- const TargetOptions &Opts = TI.getTargetOpts();
- StringRef CPU = Opts.CPU;
- if (!CPU.empty()) {
- assert(CPU.startswith("hexagon") && "Unexpected CPU name");
- CPU.consume_front("hexagon");
- SmallVector<StringRef, 3> CPUs;
- StringRef(FC->Str).split(CPUs, ',');
- if (llvm::none_of(CPUs, [CPU](StringRef S) { return S == CPU; }))
- return Diag(TheCall->getBeginLoc(),
- diag::err_hexagon_builtin_unsupported_cpu);
- }
- }
-
- const BuiltinAndString *FH =
- llvm::lower_bound(ValidHVX, BuiltinID, LowerBoundCmp);
- if (FH != std::end(ValidHVX) && FH->BuiltinID == BuiltinID) {
- if (!TI.hasFeature("hvx"))
- return Diag(TheCall->getBeginLoc(),
- diag::err_hexagon_builtin_requires_hvx);
-
- SmallVector<StringRef, 3> HVXs;
- StringRef(FH->Str).split(HVXs, ',');
- bool IsValid = llvm::any_of(HVXs,
- [&TI] (StringRef V) {
- std::string F = "hvx" + V.str();
- return TI.hasFeature(F);
- });
- if (!IsValid)
- return Diag(TheCall->getBeginLoc(),
- diag::err_hexagon_builtin_unsupported_hvx);
- }
-
- return false;
-}
-
bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
struct ArgInfo {
uint8_t OpNum;
@@ -2916,7 +2626,7 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
{ Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} },
{ Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} },
{ Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} },
- { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 0 }} },
+ { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 1 }} },
{ Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} },
{ Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} },
{ Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} },
@@ -3137,17 +2847,17 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
- return CheckHexagonBuiltinCpu(BuiltinID, TheCall) ||
- CheckHexagonBuiltinArgument(BuiltinID, TheCall);
+ return CheckHexagonBuiltinArgument(BuiltinID, TheCall);
}
-bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
- return CheckMipsBuiltinCpu(BuiltinID, TheCall) ||
+bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI,
+ unsigned BuiltinID, CallExpr *TheCall) {
+ return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) ||
CheckMipsBuiltinArgument(BuiltinID, TheCall);
}
-bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
- const TargetInfo &TI = Context.getTargetInfo();
+bool Sema::CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
if (Mips::BI__builtin_mips_addu_qb <= BuiltinID &&
BuiltinID <= Mips::BI__builtin_mips_lwx) {
@@ -3340,10 +3050,14 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 2; break;
case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 4; break;
case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 8; break;
+ case Mips::BI__builtin_msa_ldr_d: i = 1; l = -4096; u = 4088; m = 8; break;
+ case Mips::BI__builtin_msa_ldr_w: i = 1; l = -2048; u = 2044; m = 4; break;
case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 1; break;
case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 2; break;
case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 4; break;
case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 8; break;
+ case Mips::BI__builtin_msa_str_d: i = 2; l = -4096; u = 4088; m = 8; break;
+ case Mips::BI__builtin_msa_str_w: i = 2; l = -2048; u = 2044; m = 4; break;
}
if (!m)
@@ -3353,15 +3067,13 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
SemaBuiltinConstantArgMultiple(TheCall, i, m);
}
-bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
unsigned i = 0, l = 0, u = 0;
bool Is64BitBltin = BuiltinID == PPC::BI__builtin_divde ||
BuiltinID == PPC::BI__builtin_divdeu ||
BuiltinID == PPC::BI__builtin_bpermd;
- bool IsTarget64Bit = Context.getTargetInfo()
- .getTypeWidth(Context
- .getTargetInfo()
- .getIntPtrType()) == 64;
+ bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64;
bool IsBltinExtDiv = BuiltinID == PPC::BI__builtin_divwe ||
BuiltinID == PPC::BI__builtin_divweu ||
BuiltinID == PPC::BI__builtin_divde ||
@@ -3371,14 +3083,13 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt)
<< TheCall->getSourceRange();
- if ((IsBltinExtDiv && !Context.getTargetInfo().hasFeature("extdiv")) ||
- (BuiltinID == PPC::BI__builtin_bpermd &&
- !Context.getTargetInfo().hasFeature("bpermd")))
+ if ((IsBltinExtDiv && !TI.hasFeature("extdiv")) ||
+ (BuiltinID == PPC::BI__builtin_bpermd && !TI.hasFeature("bpermd")))
return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_only_on_pwr7)
<< TheCall->getSourceRange();
auto SemaVSXCheck = [&](CallExpr *TheCall) -> bool {
- if (!Context.getTargetInfo().hasFeature("vsx"))
+ if (!TI.hasFeature("vsx"))
return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_only_on_pwr7)
<< TheCall->getSourceRange();
return false;
@@ -3414,10 +3125,75 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
SemaBuiltinConstantArgRange(TheCall, 1, 0, 1);
case PPC::BI__builtin_pack_vector_int128:
return SemaVSXCheck(TheCall);
+ case PPC::BI__builtin_altivec_vgnb:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7);
+ case PPC::BI__builtin_vsx_xxeval:
+ return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255);
+ case PPC::BI__builtin_altivec_vsldbi:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7);
+ case PPC::BI__builtin_altivec_vsrdbi:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7);
+ case PPC::BI__builtin_vsx_xxpermx:
+ return SemaBuiltinConstantArgRange(TheCall, 3, 0, 7);
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
+bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ // position of memory order and scope arguments in the builtin
+ unsigned OrderIndex, ScopeIndex;
+ switch (BuiltinID) {
+ case AMDGPU::BI__builtin_amdgcn_atomic_inc32:
+ case AMDGPU::BI__builtin_amdgcn_atomic_inc64:
+ case AMDGPU::BI__builtin_amdgcn_atomic_dec32:
+ case AMDGPU::BI__builtin_amdgcn_atomic_dec64:
+ OrderIndex = 2;
+ ScopeIndex = 3;
+ break;
+ case AMDGPU::BI__builtin_amdgcn_fence:
+ OrderIndex = 0;
+ ScopeIndex = 1;
+ break;
+ default:
+ return false;
+ }
+
+ ExprResult Arg = TheCall->getArg(OrderIndex);
+ auto ArgExpr = Arg.get();
+ Expr::EvalResult ArgResult;
+
+ if (!ArgExpr->EvaluateAsInt(ArgResult, Context))
+ return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int)
+ << ArgExpr->getType();
+ int ord = ArgResult.Val.getInt().getZExtValue();
+
+ // Check valididty of memory ordering as per C11 / C++11's memody model.
+ switch (static_cast<llvm::AtomicOrderingCABI>(ord)) {
+ case llvm::AtomicOrderingCABI::acquire:
+ case llvm::AtomicOrderingCABI::release:
+ case llvm::AtomicOrderingCABI::acq_rel:
+ case llvm::AtomicOrderingCABI::seq_cst:
+ break;
+ default: {
+ return Diag(ArgExpr->getBeginLoc(),
+ diag::warn_atomic_op_has_invalid_memory_order)
+ << ArgExpr->getSourceRange();
+ }
+ }
+
+ Arg = TheCall->getArg(ScopeIndex);
+ ArgExpr = Arg.get();
+ Expr::EvalResult ArgResult1;
+ // Check that sync scope is a constant literal
+ if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, Expr::EvaluateForCodeGen,
+ Context))
+ return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal)
+ << ArgExpr->getType();
+
+ return false;
+}
+
bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
if (BuiltinID == SystemZ::BI__builtin_tabort) {
@@ -3486,7 +3262,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
/// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *).
/// This checks that the target supports __builtin_cpu_supports and
/// that the string argument is constant and valid.
-static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
+static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI,
+ CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(0);
// Check if the argument is a string literal.
@@ -3497,7 +3274,7 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
// Check the contents of the string.
StringRef Feature =
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
- if (!S.Context.getTargetInfo().validateCpuSupports(Feature))
+ if (!TI.validateCpuSupports(Feature))
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports)
<< Arg->getSourceRange();
return false;
@@ -3506,7 +3283,7 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *).
/// This checks that the target supports __builtin_cpu_is and
/// that the string argument is constant and valid.
-static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) {
+static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI, CallExpr *TheCall) {
Expr *Arg = TheCall->getArg(0);
// Check if the argument is a string literal.
@@ -3517,7 +3294,7 @@ static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) {
// Check the contents of the string.
StringRef Feature =
cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
- if (!S.Context.getTargetInfo().validateCpuIs(Feature))
+ if (!TI.validateCpuIs(Feature))
return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
<< Arg->getSourceRange();
return false;
@@ -3831,6 +3608,64 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID,
<< Arg->getSourceRange();
}
+enum { TileRegLow = 0, TileRegHigh = 7 };
+
+bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall,
+ ArrayRef<int> ArgNums) {
+ for (int ArgNum : ArgNums) {
+ if (SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh))
+ return true;
+ }
+ return false;
+}
+
+bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, int ArgNum) {
+ return SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh);
+}
+
+bool Sema::CheckX86BuiltinTileDuplicate(CallExpr *TheCall,
+ ArrayRef<int> ArgNums) {
+ // Because the max number of tile register is TileRegHigh + 1, so here we use
+ // each bit to represent the usage of them in bitset.
+ std::bitset<TileRegHigh + 1> ArgValues;
+ for (int ArgNum : ArgNums) {
+ llvm::APSInt Arg;
+ SemaBuiltinConstantArg(TheCall, ArgNum, Arg);
+ int ArgExtValue = Arg.getExtValue();
+ assert((ArgExtValue >= TileRegLow || ArgExtValue <= TileRegHigh) &&
+ "Incorrect tile register num.");
+ if (ArgValues.test(ArgExtValue))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_x86_builtin_tile_arg_duplicate)
+ << TheCall->getArg(ArgNum)->getSourceRange();
+ ArgValues.set(ArgExtValue);
+ }
+ return false;
+}
+
+bool Sema::CheckX86BuiltinTileRangeAndDuplicate(CallExpr *TheCall,
+ ArrayRef<int> ArgNums) {
+ return CheckX86BuiltinTileArgumentsRange(TheCall, ArgNums) ||
+ CheckX86BuiltinTileDuplicate(TheCall, ArgNums);
+}
+
+bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
+ switch (BuiltinID) {
+ default:
+ return false;
+ case X86::BI__builtin_ia32_tileloadd64:
+ case X86::BI__builtin_ia32_tileloaddt164:
+ case X86::BI__builtin_ia32_tilestored64:
+ case X86::BI__builtin_ia32_tilezero:
+ return CheckX86BuiltinTileArgumentsRange(TheCall, 0);
+ case X86::BI__builtin_ia32_tdpbssd:
+ case X86::BI__builtin_ia32_tdpbsud:
+ case X86::BI__builtin_ia32_tdpbusd:
+ case X86::BI__builtin_ia32_tdpbuud:
+ case X86::BI__builtin_ia32_tdpbf16ps:
+ return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2});
+ }
+}
static bool isX86_32Builtin(unsigned BuiltinID) {
// These builtins only work on x86-32 targets.
switch (BuiltinID) {
@@ -3842,15 +3677,16 @@ static bool isX86_32Builtin(unsigned BuiltinID) {
return false;
}
-bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+ CallExpr *TheCall) {
if (BuiltinID == X86::BI__builtin_cpu_supports)
- return SemaBuiltinCpuSupports(*this, TheCall);
+ return SemaBuiltinCpuSupports(*this, TI, TheCall);
if (BuiltinID == X86::BI__builtin_cpu_is)
- return SemaBuiltinCpuIs(*this, TheCall);
+ return SemaBuiltinCpuIs(*this, TI, TheCall);
// Check for 32-bit only builtins on a 64-bit target.
- const llvm::Triple &TT = Context.getTargetInfo().getTriple();
+ const llvm::Triple &TT = TI.getTriple();
if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID))
return Diag(TheCall->getCallee()->getBeginLoc(),
diag::err_32_bit_builtin_64_bit_tgt);
@@ -3863,6 +3699,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckX86BuiltinGatherScatterScale(BuiltinID, TheCall))
return true;
+ // If the intrinsic has a tile arguments, make sure they are valid.
+ if (CheckX86BuiltinTileArguments(BuiltinID, TheCall))
+ return true;
+
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
int i = 0, l = 0, u = 0;
@@ -4473,6 +4313,24 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
}
+ if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) {
+ auto *AA = FDecl->getAttr<AllocAlignAttr>();
+ const Expr *Arg = Args[AA->getParamIndex().getASTIndex()];
+ if (!Arg->isValueDependent()) {
+ Expr::EvalResult Align;
+ if (Arg->EvaluateAsInt(Align, Context)) {
+ const llvm::APSInt &I = Align.Val.getInt();
+ if (!I.isPowerOf2())
+ Diag(Arg->getExprLoc(), diag::warn_alignment_not_power_of_two)
+ << Arg->getSourceRange();
+
+ if (I > Sema::MaximumAlignment)
+ Diag(Arg->getExprLoc(), diag::warn_assume_aligned_too_great)
+ << Arg->getSourceRange() << Sema::MaximumAlignment;
+ }
+ }
+ }
+
if (FD)
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
}
@@ -5491,6 +5349,15 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// gracefully.
TheCall->setType(ResultType);
+ // Prohibit use of _ExtInt with atomic builtins.
+ // The arguments would have already been converted to the first argument's
+ // type, so only need to check the first argument.
+ const auto *ExtIntValType = ValType->getAs<ExtIntType>();
+ if (ExtIntValType && !llvm::isPowerOf2_64(ExtIntValType->getNumBits())) {
+ Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size);
+ return ExprError();
+ }
+
return TheCallResult;
}
@@ -6193,11 +6060,9 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
<< Arg->getSourceRange();
- // Alignment calculations can wrap around if it's greater than 2**29.
- unsigned MaximumAlignment = 536870912;
- if (Result > MaximumAlignment)
+ if (Result > Sema::MaximumAlignment)
Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
- << Arg->getSourceRange() << MaximumAlignment;
+ << Arg->getSourceRange() << Sema::MaximumAlignment;
}
if (NumArgs > 2) {
@@ -6412,7 +6277,8 @@ static bool IsShiftedByte(llvm::APSInt Value) {
/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is
/// a constant expression representing an arbitrary byte value shifted left by
/// a multiple of 8 bits.
-bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) {
+bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum,
+ unsigned ArgBits) {
llvm::APSInt Result;
// We can't check the value of a dependent argument.
@@ -6424,6 +6290,10 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) {
if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
return true;
+ // Truncate to the given size.
+ Result = Result.getLoBits(ArgBits);
+ Result.setIsUnsigned(true);
+
if (IsShiftedByte(Result))
return false;
@@ -6437,7 +6307,8 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) {
/// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some
/// Arm MVE intrinsics.
bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
- int ArgNum) {
+ int ArgNum,
+ unsigned ArgBits) {
llvm::APSInt Result;
// We can't check the value of a dependent argument.
@@ -6449,6 +6320,10 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
return true;
+ // Truncate to the given size.
+ Result = Result.getLoBits(ArgBits);
+ Result.setIsUnsigned(true);
+
// Check to see if it's in either of the required forms.
if (IsShiftedByte(Result) ||
(Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF))
@@ -10228,6 +10103,9 @@ struct IntRange {
false/*NonNegative*/);
}
+ if (const auto *EIT = dyn_cast<ExtIntType>(T))
+ return IntRange(EIT->getNumBits(), EIT->isUnsigned());
+
const BuiltinType *BT = cast<BuiltinType>(T);
assert(BT->isInteger());
@@ -10251,6 +10129,9 @@ struct IntRange {
if (const EnumType *ET = dyn_cast<EnumType>(T))
T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr();
+ if (const auto *EIT = dyn_cast<ExtIntType>(T))
+ return IntRange(EIT->getNumBits(), EIT->isUnsigned());
+
const BuiltinType *BT = cast<BuiltinType>(T);
assert(BT->isInteger());
@@ -12064,27 +11945,31 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
}
}
-static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
SourceLocation CC, QualType T);
static void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool &ICContext) {
E = E->IgnoreParenImpCasts();
- if (isa<ConditionalOperator>(E))
- return CheckConditionalOperator(S, cast<ConditionalOperator>(E), CC, T);
+ if (auto *CO = dyn_cast<AbstractConditionalOperator>(E))
+ return CheckConditionalOperator(S, CO, CC, T);
AnalyzeImplicitConversions(S, E, CC);
if (E->getType() != T)
return CheckImplicitConversion(S, E, T, CC, &ICContext);
}
-static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
+static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
SourceLocation CC, QualType T) {
AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
+ Expr *TrueExpr = E->getTrueExpr();
+ if (auto *BCO = dyn_cast<BinaryConditionalOperator>(E))
+ TrueExpr = BCO->getCommon();
+
bool Suspicious = false;
- CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
+ CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious);
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
if (T->isBooleanType())
@@ -12103,7 +11988,7 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
if (E->getType() == T) return;
Suspicious = false;
- CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(),
+ CheckImplicitConversion(S, TrueExpr->IgnoreParenImpCasts(),
E->getType(), CC, &Suspicious);
if (!Suspicious)
CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(),
@@ -12120,24 +12005,44 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
}
-/// AnalyzeImplicitConversions - Find and report any interesting
-/// implicit conversions in the given expression. There are a couple
-/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
- bool IsListInit/*= false*/) {
+namespace {
+struct AnalyzeImplicitConversionsWorkItem {
+ Expr *E;
+ SourceLocation CC;
+ bool IsListInit;
+};
+}
+
+/// Data recursive variant of AnalyzeImplicitConversions. Subexpressions
+/// that should be visited are added to WorkList.
+static void AnalyzeImplicitConversions(
+ Sema &S, AnalyzeImplicitConversionsWorkItem Item,
+ llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) {
+ Expr *OrigE = Item.E;
+ SourceLocation CC = Item.CC;
+
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
// Propagate whether we are in a C++ list initialization expression.
// If so, we do not issue warnings for implicit int-float conversion
// precision loss, because C++11 narrowing already handles it.
- IsListInit =
- IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
+ bool IsListInit = Item.IsListInit ||
+ (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
if (E->isTypeDependent() || E->isValueDependent())
return;
- if (const auto *UO = dyn_cast<UnaryOperator>(E))
+ Expr *SourceExpr = E;
+ // Examine, but don't traverse into the source expression of an
+ // OpaqueValueExpr, since it may have multiple parents and we don't want to
+ // emit duplicate diagnostics. Its fine to examine the form or attempt to
+ // evaluate it in the context of checking the specific conversion to T though.
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (auto *Src = OVE->getSourceExpr())
+ SourceExpr = Src;
+
+ if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr))
if (UO->getOpcode() == UO_Not &&
UO->getSubExpr()->isKnownToHaveBooleanValue())
S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool)
@@ -12146,21 +12051,20 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
- if (isa<ConditionalOperator>(E)) {
- ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ if (auto *CO = dyn_cast<AbstractConditionalOperator>(SourceExpr)) {
CheckConditionalOperator(S, CO, CC, T);
return;
}
// Check implicit argument conversions for function calls.
- if (CallExpr *Call = dyn_cast<CallExpr>(E))
+ if (CallExpr *Call = dyn_cast<CallExpr>(SourceExpr))
CheckImplicitArgumentConversions(S, Call, CC);
// Go ahead and check any implicit conversions we might have skipped.
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
- if (E->getType() != T)
- CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit);
+ if (SourceExpr->getType() != T)
+ CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit);
// Now continue drilling into this expression.
@@ -12170,7 +12074,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
// FIXME: Use a more uniform representation for this.
for (auto *SE : POE->semantics())
if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
- AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit);
+ WorkList.push_back({OVE->getSourceExpr(), CC, IsListInit});
}
// Skip past explicit casts.
@@ -12178,7 +12082,8 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
E = CE->getSubExpr()->IgnoreParenImpCasts();
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
- return AnalyzeImplicitConversions(S, E, CC, IsListInit);
+ WorkList.push_back({E, CC, IsListInit});
+ return;
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -12217,7 +12122,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
// Ignore checking string literals that are in logical and operators.
// This is a common pattern for asserts.
continue;
- AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit);
+ WorkList.push_back({ChildExpr, CC, IsListInit});
}
if (BO && BO->isLogicalOp()) {
@@ -12241,6 +12146,17 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
}
}
+/// AnalyzeImplicitConversions - Find and report any interesting
+/// implicit conversions in the given expression. There are a couple
+/// of competing diagnostics here, -Wconversion and -Wsign-compare.
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
+ bool IsListInit/*= false*/) {
+ llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList;
+ WorkList.push_back({OrigE, CC, IsListInit});
+ while (!WorkList.empty())
+ AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList);
+}
+
/// Diagnose integer type and any valid implicit conversion to it.
static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) {
// Taking into account implicit conversions,
@@ -13182,6 +13098,11 @@ public:
}
void VisitCallExpr(const CallExpr *CE) {
+ // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
+
+ if (CE->isUnevaluatedBuiltinCall(Context))
+ return;
+
// C++11 [intro.execution]p15:
// When calling a function [...], every value computation and side effect
// associated with any argument expression, or with the postfix expression
@@ -13189,10 +13110,165 @@ public:
// expression or statement in the body of the function [and thus before
// the value computation of its result].
SequencedSubexpression Sequenced(*this);
- SemaRef.runWithSufficientStackSpace(CE->getExprLoc(),
- [&] { Base::VisitCallExpr(CE); });
+ SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] {
+ // C++17 [expr.call]p5
+ // The postfix-expression is sequenced before each expression in the
+ // expression-list and any default argument. [...]
+ SequenceTree::Seq CalleeRegion;
+ SequenceTree::Seq OtherRegion;
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ CalleeRegion = Tree.allocate(Region);
+ OtherRegion = Tree.allocate(Region);
+ } else {
+ CalleeRegion = Region;
+ OtherRegion = Region;
+ }
+ SequenceTree::Seq OldRegion = Region;
- // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
+ // Visit the callee expression first.
+ Region = CalleeRegion;
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ SequencedSubexpression Sequenced(*this);
+ Visit(CE->getCallee());
+ } else {
+ Visit(CE->getCallee());
+ }
+
+ // Then visit the argument expressions.
+ Region = OtherRegion;
+ for (const Expr *Argument : CE->arguments())
+ Visit(Argument);
+
+ Region = OldRegion;
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ Tree.merge(CalleeRegion);
+ Tree.merge(OtherRegion);
+ }
+ });
+ }
+
+ void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) {
+ // C++17 [over.match.oper]p2:
+ // [...] the operator notation is first transformed to the equivalent
+ // function-call notation as summarized in Table 12 (where @ denotes one
+ // of the operators covered in the specified subclause). However, the
+ // operands are sequenced in the order prescribed for the built-in
+ // operator (Clause 8).
+ //
+ // From the above only overloaded binary operators and overloaded call
+ // operators have sequencing rules in C++17 that we need to handle
+ // separately.
+ if (!SemaRef.getLangOpts().CPlusPlus17 ||
+ (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call))
+ return VisitCallExpr(CXXOCE);
+
+ enum {
+ NoSequencing,
+ LHSBeforeRHS,
+ RHSBeforeLHS,
+ LHSBeforeRest
+ } SequencingKind;
+ switch (CXXOCE->getOperator()) {
+ case OO_Equal:
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ case OO_StarEqual:
+ case OO_SlashEqual:
+ case OO_PercentEqual:
+ case OO_CaretEqual:
+ case OO_AmpEqual:
+ case OO_PipeEqual:
+ case OO_LessLessEqual:
+ case OO_GreaterGreaterEqual:
+ SequencingKind = RHSBeforeLHS;
+ break;
+
+ case OO_LessLess:
+ case OO_GreaterGreater:
+ case OO_AmpAmp:
+ case OO_PipePipe:
+ case OO_Comma:
+ case OO_ArrowStar:
+ case OO_Subscript:
+ SequencingKind = LHSBeforeRHS;
+ break;
+
+ case OO_Call:
+ SequencingKind = LHSBeforeRest;
+ break;
+
+ default:
+ SequencingKind = NoSequencing;
+ break;
+ }
+
+ if (SequencingKind == NoSequencing)
+ return VisitCallExpr(CXXOCE);
+
+ // This is a call, so all subexpressions are sequenced before the result.
+ SequencedSubexpression Sequenced(*this);
+
+ SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] {
+ assert(SemaRef.getLangOpts().CPlusPlus17 &&
+ "Should only get there with C++17 and above!");
+ assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) &&
+ "Should only get there with an overloaded binary operator"
+ " or an overloaded call operator!");
+
+ if (SequencingKind == LHSBeforeRest) {
+ assert(CXXOCE->getOperator() == OO_Call &&
+ "We should only have an overloaded call operator here!");
+
+ // This is very similar to VisitCallExpr, except that we only have the
+ // C++17 case. The postfix-expression is the first argument of the
+ // CXXOperatorCallExpr. The expressions in the expression-list, if any,
+ // are in the following arguments.
+ //
+ // Note that we intentionally do not visit the callee expression since
+ // it is just a decayed reference to a function.
+ SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region);
+ SequenceTree::Seq ArgsRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
+ assert(CXXOCE->getNumArgs() >= 1 &&
+ "An overloaded call operator must have at least one argument"
+ " for the postfix-expression!");
+ const Expr *PostfixExpr = CXXOCE->getArgs()[0];
+ llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1,
+ CXXOCE->getNumArgs() - 1);
+
+ // Visit the postfix-expression first.
+ {
+ Region = PostfixExprRegion;
+ SequencedSubexpression Sequenced(*this);
+ Visit(PostfixExpr);
+ }
+
+ // Then visit the argument expressions.
+ Region = ArgsRegion;
+ for (const Expr *Arg : Args)
+ Visit(Arg);
+
+ Region = OldRegion;
+ Tree.merge(PostfixExprRegion);
+ Tree.merge(ArgsRegion);
+ } else {
+ assert(CXXOCE->getNumArgs() == 2 &&
+ "Should only have two arguments here!");
+ assert((SequencingKind == LHSBeforeRHS ||
+ SequencingKind == RHSBeforeLHS) &&
+ "Unexpected sequencing kind!");
+
+ // We do not visit the callee expression since it is just a decayed
+ // reference to a function.
+ const Expr *E1 = CXXOCE->getArg(0);
+ const Expr *E2 = CXXOCE->getArg(1);
+ if (SequencingKind == RHSBeforeLHS)
+ std::swap(E1, E2);
+
+ return VisitSequencedExpressions(E1, E2);
+ }
+ });
}
void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
@@ -13323,11 +13399,12 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
// C99 6.9.1p5: If the declarator includes a parameter type list, the
// declaration of each parameter shall include an identifier.
- if (CheckParameterNames &&
- Param->getIdentifier() == nullptr &&
- !Param->isImplicit() &&
- !getLangOpts().CPlusPlus)
- Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ if (CheckParameterNames && Param->getIdentifier() == nullptr &&
+ !Param->isImplicit() && !getLangOpts().CPlusPlus) {
+ // Diagnose this as an extension in C17 and earlier.
+ if (!getLangOpts().C2x)
+ Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x);
+ }
// C99 6.7.5.3p12:
// If the function declarator is not part of a definition of that
@@ -13380,17 +13457,233 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
return HasInvalidParm;
}
-/// A helper function to get the alignment of a Decl referred to by DeclRefExpr
-/// or MemberExpr.
-static CharUnits getDeclAlign(Expr *E, CharUnits TypeAlign,
- ASTContext &Context) {
- if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
- return Context.getDeclAlign(DRE->getDecl());
+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
+/// class object.
+static std::pair<CharUnits, CharUnits>
+getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType,
+ CharUnits BaseAlignment, CharUnits Offset,
+ ASTContext &Ctx) {
+ for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE;
+ ++PathI) {
+ const CXXBaseSpecifier *Base = *PathI;
+ const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
+ if (Base->isVirtual()) {
+ // The complete object may have a lower alignment than the non-virtual
+ // alignment of the base, in which case the base may be misaligned. Choose
+ // the smaller of the non-virtual alignment and BaseAlignment, which is a
+ // conservative lower bound of the complete object alignment.
+ CharUnits NonVirtualAlignment =
+ Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment();
+ BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment);
+ Offset = CharUnits::Zero();
+ } else {
+ const ASTRecordLayout &RL =
+ Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl());
+ Offset += RL.getBaseClassOffset(BaseDecl);
+ }
+ DerivedType = Base->getType();
+ }
+
+ return std::make_pair(BaseAlignment, Offset);
+}
- if (const auto *ME = dyn_cast<MemberExpr>(E))
- return Context.getDeclAlign(ME->getMemberDecl());
+/// Compute the alignment and offset of a binary additive operator.
+static Optional<std::pair<CharUnits, CharUnits>>
+getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
+ bool IsSub, ASTContext &Ctx) {
+ QualType PointeeType = PtrE->getType()->getPointeeType();
- return TypeAlign;
+ if (!PointeeType->isConstantSizeType())
+ return llvm::None;
+
+ auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx);
+
+ if (!P)
+ return llvm::None;
+
+ llvm::APSInt IdxRes;
+ CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType);
+ if (IntE->isIntegerConstantExpr(IdxRes, Ctx)) {
+ CharUnits Offset = EltSize * IdxRes.getExtValue();
+ if (IsSub)
+ Offset = -Offset;
+ return std::make_pair(P->first, P->second + Offset);
+ }
+
+ // If the integer expression isn't a constant expression, compute the lower
+ // bound of the alignment using the alignment and offset of the pointer
+ // expression and the element size.
+ return std::make_pair(
+ P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize),
+ CharUnits::Zero());
+}
+
+/// 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) {
+ E = E->IgnoreParens();
+ switch (E->getStmtClass()) {
+ default:
+ break;
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::ImplicitCastExprClass: {
+ auto *CE = cast<CastExpr>(E);
+ const Expr *From = CE->getSubExpr();
+ switch (CE->getCastKind()) {
+ default:
+ break;
+ case CK_NoOp:
+ return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBase: {
+ auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+ if (!P)
+ break;
+ return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first,
+ P->second, Ctx);
+ }
+ }
+ break;
+ }
+ case Stmt::ArraySubscriptExprClass: {
+ auto *ASE = cast<ArraySubscriptExpr>(E);
+ return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(),
+ false, Ctx);
+ }
+ case Stmt::DeclRefExprClass: {
+ if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
+ // FIXME: If VD is captured by copy or is an escaping __block variable,
+ // use the alignment of VD's type.
+ if (!VD->getType()->isReferenceType())
+ return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero());
+ if (VD->hasInit())
+ return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx);
+ }
+ break;
+ }
+ case Stmt::MemberExprClass: {
+ auto *ME = cast<MemberExpr>(E);
+ auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD || FD->getType()->isReferenceType())
+ break;
+ Optional<std::pair<CharUnits, CharUnits>> P;
+ if (ME->isArrow())
+ P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx);
+ else
+ P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx);
+ if (!P)
+ break;
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
+ uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex());
+ return std::make_pair(P->first,
+ P->second + CharUnits::fromQuantity(Offset));
+ }
+ case Stmt::UnaryOperatorClass: {
+ auto *UO = cast<UnaryOperator>(E);
+ switch (UO->getOpcode()) {
+ default:
+ break;
+ case UO_Deref:
+ return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx);
+ }
+ break;
+ }
+ case Stmt::BinaryOperatorClass: {
+ auto *BO = cast<BinaryOperator>(E);
+ auto Opcode = BO->getOpcode();
+ switch (Opcode) {
+ default:
+ break;
+ case BO_Comma:
+ return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx);
+ }
+ break;
+ }
+ }
+ return llvm::None;
+}
+
+/// 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) {
+ E = E->IgnoreParens();
+ switch (E->getStmtClass()) {
+ default:
+ break;
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::ImplicitCastExprClass: {
+ auto *CE = cast<CastExpr>(E);
+ const Expr *From = CE->getSubExpr();
+ switch (CE->getCastKind()) {
+ default:
+ break;
+ case CK_NoOp:
+ return getBaseAlignmentAndOffsetFromPtr(From, Ctx);
+ case CK_ArrayToPointerDecay:
+ return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBase: {
+ auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx);
+ if (!P)
+ break;
+ return getDerivedToBaseAlignmentAndOffset(
+ CE, From->getType()->getPointeeType(), P->first, P->second, Ctx);
+ }
+ }
+ break;
+ }
+ case Stmt::CXXThisExprClass: {
+ auto *RD = E->getType()->getPointeeType()->getAsCXXRecordDecl();
+ CharUnits Alignment = Ctx.getASTRecordLayout(RD).getNonVirtualAlignment();
+ return std::make_pair(Alignment, CharUnits::Zero());
+ }
+ case Stmt::UnaryOperatorClass: {
+ auto *UO = cast<UnaryOperator>(E);
+ if (UO->getOpcode() == UO_AddrOf)
+ return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx);
+ break;
+ }
+ case Stmt::BinaryOperatorClass: {
+ auto *BO = cast<BinaryOperator>(E);
+ auto Opcode = BO->getOpcode();
+ switch (Opcode) {
+ default:
+ break;
+ case BO_Add:
+ case BO_Sub: {
+ const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS();
+ if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType())
+ std::swap(LHS, RHS);
+ return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub,
+ Ctx);
+ }
+ case BO_Comma:
+ return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx);
+ }
+ break;
+ }
+ }
+ return llvm::None;
+}
+
+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 =
+ getBaseAlignmentAndOffsetFromPtr(E, S.Context);
+
+ if (P)
+ return P->first.alignmentAtOffset(P->second);
+
+ // If that failed, return the type's alignment.
+ return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());
}
/// CheckCastAlign - Implements -Wcast-align, which warns when a
@@ -13420,21 +13713,13 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
if (!SrcPtr) return;
QualType SrcPointee = SrcPtr->getPointeeType();
- // Whitelist casts from cv void*. We already implicitly
- // whitelisted casts to cv void*, since they have alignment 1.
- // Also whitelist casts involving incomplete types, which implicitly
+ // Explicitly allow casts from cv void*. We already implicitly
+ // allowed casts to cv void*, since they have alignment 1.
+ // Also allow casts involving incomplete types, which implicitly
// includes 'void'.
if (SrcPointee->isIncompleteType()) return;
- CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee);
-
- if (auto *CE = dyn_cast<CastExpr>(Op)) {
- if (CE->getCastKind() == CK_ArrayToPointerDecay)
- SrcAlign = getDeclAlign(CE->getSubExpr(), SrcAlign, Context);
- } else if (auto *UO = dyn_cast<UnaryOperator>(Op)) {
- if (UO->getOpcode() == UO_AddrOf)
- SrcAlign = getDeclAlign(UO->getSubExpr(), SrcAlign, Context);
- }
+ CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this);
if (SrcAlign >= DestAlign) return;
@@ -13916,7 +14201,7 @@ static bool isSetterLikeSelector(Selector sel) {
if (str.startswith("set"))
str = str.substr(3);
else if (str.startswith("add")) {
- // Specially whitelist 'addOperationWithBlock:'.
+ // Specially allow 'addOperationWithBlock:'.
if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock"))
return false;
str = str.substr(3);
@@ -14242,12 +14527,12 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
return;
unsigned Attributes = PD->getPropertyAttributes();
- if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) {
+ if (Attributes & ObjCPropertyAttribute::kind_assign) {
// when 'assign' attribute was not explicitly specified
// by user, ignore it and rely on property type itself
// for lifetime info.
unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten();
- if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) &&
+ if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) &&
LHSType->isObjCRetainableType())
return;
@@ -14259,8 +14544,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
}
RHS = cast->getSubExpr();
}
- }
- else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) {
+ } else if (Attributes & ObjCPropertyAttribute::kind_weak) {
if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
return;
}
@@ -15045,3 +15329,259 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
_2, _3, _4));
}
+
+ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall,
+ ExprResult CallResult) {
+ if (checkArgCount(*this, TheCall, 1))
+ return ExprError();
+
+ ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0));
+ if (MatrixArg.isInvalid())
+ return MatrixArg;
+ Expr *Matrix = MatrixArg.get();
+
+ auto *MType = Matrix->getType()->getAs<ConstantMatrixType>();
+ if (!MType) {
+ Diag(Matrix->getBeginLoc(), diag::err_builtin_matrix_arg);
+ return ExprError();
+ }
+
+ // Create returned matrix type by swapping rows and columns of the argument
+ // matrix type.
+ QualType ResultType = Context.getConstantMatrixType(
+ MType->getElementType(), MType->getNumColumns(), MType->getNumRows());
+
+ // Change the return type to the type of the returned matrix.
+ TheCall->setType(ResultType);
+
+ // Update call argument to use the possibly converted matrix argument.
+ TheCall->setArg(0, Matrix);
+ return CallResult;
+}
+
+// Get and verify the matrix dimensions.
+static llvm::Optional<unsigned>
+getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) {
+ llvm::APSInt Value(64);
+ SourceLocation ErrorPos;
+ if (!Expr->isIntegerConstantExpr(Value, S.Context, &ErrorPos)) {
+ S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg)
+ << Name;
+ return {};
+ }
+ uint64_t Dim = Value.getZExtValue();
+ if (!ConstantMatrixType::isDimensionValid(Dim)) {
+ S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension)
+ << Name << ConstantMatrixType::getMaxElementsPerDimension();
+ return {};
+ }
+ return Dim;
+}
+
+ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
+ ExprResult CallResult) {
+ if (!getLangOpts().MatrixTypes) {
+ Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
+ return ExprError();
+ }
+
+ if (checkArgCount(*this, TheCall, 4))
+ return ExprError();
+
+ unsigned PtrArgIdx = 0;
+ Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
+ Expr *RowsExpr = TheCall->getArg(1);
+ Expr *ColumnsExpr = TheCall->getArg(2);
+ Expr *StrideExpr = TheCall->getArg(3);
+
+ bool ArgError = false;
+
+ // Check pointer argument.
+ {
+ ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
+ if (PtrConv.isInvalid())
+ return PtrConv;
+ PtrExpr = PtrConv.get();
+ TheCall->setArg(0, PtrExpr);
+ if (PtrExpr->isTypeDependent()) {
+ TheCall->setType(Context.DependentTy);
+ return TheCall;
+ }
+ }
+
+ auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
+ QualType ElementTy;
+ if (!PtrTy) {
+ Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+ << PtrArgIdx + 1;
+ ArgError = true;
+ } else {
+ ElementTy = PtrTy->getPointeeType().getUnqualifiedType();
+
+ if (!ConstantMatrixType::isValidElementType(ElementTy)) {
+ Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+ << PtrArgIdx + 1;
+ ArgError = true;
+ }
+ }
+
+ // Apply default Lvalue conversions and convert the expression to size_t.
+ auto ApplyArgumentConversions = [this](Expr *E) {
+ ExprResult Conv = DefaultLvalueConversion(E);
+ if (Conv.isInvalid())
+ return Conv;
+
+ return tryConvertExprToType(Conv.get(), Context.getSizeType());
+ };
+
+ // Apply conversion to row and column expressions.
+ ExprResult RowsConv = ApplyArgumentConversions(RowsExpr);
+ if (!RowsConv.isInvalid()) {
+ RowsExpr = RowsConv.get();
+ TheCall->setArg(1, RowsExpr);
+ } else
+ RowsExpr = nullptr;
+
+ ExprResult ColumnsConv = ApplyArgumentConversions(ColumnsExpr);
+ if (!ColumnsConv.isInvalid()) {
+ ColumnsExpr = ColumnsConv.get();
+ TheCall->setArg(2, ColumnsExpr);
+ } else
+ ColumnsExpr = nullptr;
+
+ // If any 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())) {
+ TheCall->setType(Context.DependentTy);
+ return CallResult;
+ }
+
+ // Check row and column dimenions.
+ llvm::Optional<unsigned> MaybeRows;
+ if (RowsExpr)
+ MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this);
+
+ llvm::Optional<unsigned> MaybeColumns;
+ if (ColumnsExpr)
+ MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this);
+
+ // Check stride argument.
+ ExprResult StrideConv = ApplyArgumentConversions(StrideExpr);
+ if (StrideConv.isInvalid())
+ return ExprError();
+ StrideExpr = StrideConv.get();
+ TheCall->setArg(3, StrideExpr);
+
+ llvm::APSInt Value(64);
+ if (MaybeRows && StrideExpr->isIntegerConstantExpr(Value, Context)) {
+ uint64_t Stride = Value.getZExtValue();
+ if (Stride < *MaybeRows) {
+ Diag(StrideExpr->getBeginLoc(),
+ diag::err_builtin_matrix_stride_too_small);
+ ArgError = true;
+ }
+ }
+
+ if (ArgError || !MaybeRows || !MaybeColumns)
+ return ExprError();
+
+ TheCall->setType(
+ Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns));
+ return CallResult;
+}
+
+ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
+ ExprResult CallResult) {
+ if (checkArgCount(*this, TheCall, 3))
+ return ExprError();
+
+ unsigned PtrArgIdx = 1;
+ Expr *MatrixExpr = TheCall->getArg(0);
+ Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
+ Expr *StrideExpr = TheCall->getArg(2);
+
+ bool ArgError = false;
+
+ {
+ ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr);
+ if (MatrixConv.isInvalid())
+ return MatrixConv;
+ MatrixExpr = MatrixConv.get();
+ TheCall->setArg(0, MatrixExpr);
+ }
+ if (MatrixExpr->isTypeDependent()) {
+ TheCall->setType(Context.DependentTy);
+ return TheCall;
+ }
+
+ auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>();
+ if (!MatrixTy) {
+ Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_matrix_arg) << 0;
+ ArgError = true;
+ }
+
+ {
+ ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
+ if (PtrConv.isInvalid())
+ return PtrConv;
+ PtrExpr = PtrConv.get();
+ TheCall->setArg(1, PtrExpr);
+ if (PtrExpr->isTypeDependent()) {
+ TheCall->setType(Context.DependentTy);
+ return TheCall;
+ }
+ }
+
+ // Check pointer argument.
+ auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
+ if (!PtrTy) {
+ Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg)
+ << PtrArgIdx + 1;
+ ArgError = true;
+ } else {
+ QualType ElementTy = PtrTy->getPointeeType();
+ if (ElementTy.isConstQualified()) {
+ Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const);
+ ArgError = true;
+ }
+ ElementTy = ElementTy.getUnqualifiedType().getCanonicalType();
+ if (MatrixTy &&
+ !Context.hasSameType(ElementTy, MatrixTy->getElementType())) {
+ Diag(PtrExpr->getBeginLoc(),
+ diag::err_builtin_matrix_pointer_arg_mismatch)
+ << ElementTy << MatrixTy->getElementType();
+ ArgError = true;
+ }
+ }
+
+ // Apply default Lvalue conversions and convert the stride expression to
+ // size_t.
+ {
+ ExprResult StrideConv = DefaultLvalueConversion(StrideExpr);
+ if (StrideConv.isInvalid())
+ return StrideConv;
+
+ StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType());
+ if (StrideConv.isInvalid())
+ return StrideConv;
+ StrideExpr = StrideConv.get();
+ TheCall->setArg(2, StrideExpr);
+ }
+
+ // Check stride argument.
+ llvm::APSInt Value(64);
+ if (MatrixTy && StrideExpr->isIntegerConstantExpr(Value, Context)) {
+ uint64_t Stride = Value.getZExtValue();
+ if (Stride < MatrixTy->getNumRows()) {
+ Diag(StrideExpr->getBeginLoc(),
+ diag::err_builtin_matrix_stride_too_small);
+ ArgError = true;
+ }
+ }
+
+ if (ArgError)
+ return ExprError();
+
+ return CallResult;
+}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 7260977c634d..0a8a27068ebf 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -9,25 +9,36 @@
// This file defines the code-completion semantic actions.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/QualTypeNames.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Designator.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -36,7 +47,9 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <list>
#include <map>
#include <string>
@@ -1676,11 +1689,9 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
Results.AddResult(Result("class", CCP_Type));
Results.AddResult(Result("wchar_t", CCP_Type));
- // typename qualified-id
+ // typename name
Builder.AddTypedTextChunk("typename");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddPlaceholderChunk("qualifier");
- Builder.AddTextChunk("::");
Builder.AddPlaceholderChunk("name");
Results.AddResult(Result(Builder.TakeString()));
@@ -1807,6 +1818,18 @@ static void AddTypedefResult(ResultBuilder &Results) {
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
+// using name = type
+static void AddUsingAliasResult(CodeCompletionBuilder &Builder,
+ ResultBuilder &Results) {
+ Builder.AddTypedTextChunk("using");
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("name");
+ Builder.AddChunk(CodeCompletionString::CK_Equal);
+ Builder.AddPlaceholderChunk("type");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(CodeCompletionResult(Builder.TakeString()));
+}
+
static bool WantTypesInContext(Sema::ParserCompletionContext CCC,
const LangOptions &LangOpts) {
switch (CCC) {
@@ -2050,6 +2073,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
+ if (SemaRef.getLangOpts().CPlusPlus11)
+ AddUsingAliasResult(Builder, Results);
+
// using typename qualifier::name (only in a dependent context)
if (SemaRef.CurContext->isDependentContext()) {
Builder.AddTypedTextChunk("using typename");
@@ -2130,6 +2156,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
case Sema::PCC_RecoveryInFunction:
case Sema::PCC_Statement: {
+ if (SemaRef.getLangOpts().CPlusPlus11)
+ AddUsingAliasResult(Builder, Results);
+
AddTypedefResult(Results);
if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() &&
@@ -2748,7 +2777,7 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
std::string Result;
if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
- Result = Param->getIdentifier()->getName();
+ Result = std::string(Param->getIdentifier()->getName());
QualType Type = Param->getType();
if (ObjCSubsts)
@@ -2787,7 +2816,7 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param,
// for the block; just use the parameter type as a placeholder.
std::string Result;
if (!ObjCMethodParam && Param->getIdentifier())
- Result = Param->getIdentifier()->getName();
+ Result = std::string(Param->getIdentifier()->getName());
QualType Type = Param->getType().getUnqualifiedType();
@@ -3002,7 +3031,7 @@ static void AddTemplateParameterChunks(
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*P)) {
if (NTTP->getIdentifier())
- PlaceholderStr = NTTP->getIdentifier()->getName();
+ PlaceholderStr = std::string(NTTP->getIdentifier()->getName());
NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);
HasDefaultArg = NTTP->hasDefaultArgument();
} else {
@@ -3705,8 +3734,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Result.addBriefComment(RC->getBriefText(S.getASTContext()));
}
AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result);
- Result.AddTextChunk(
- Result.getAllocator().CopyString(FDecl->getNameAsString()));
+
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ FDecl->getDeclName().print(OS, Policy);
+ Result.AddTextChunk(Result.getAllocator().CopyString(OS.str()));
} else {
Result.AddResultTypeChunk(Result.getAllocator().CopyString(
Proto->getReturnType().getAsString(Policy)));
@@ -4329,7 +4361,7 @@ static void AddLambdaCompletion(ResultBuilder &Results,
First = false;
constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!";
- std::string Type = NamePlaceholder;
+ std::string Type = std::string(NamePlaceholder);
Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts));
llvm::StringRef Prefix, Suffix;
std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder);
@@ -4719,6 +4751,386 @@ 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) {
+ if (auto *RD = BaseType->getAsRecordDecl())
+ return RD;
+
+ if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) {
+ if (const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(
+ TST->getTemplateName().getAsTemplateDecl())) {
+ return TD->getTemplatedDecl();
+ }
+ }
+
+ return nullptr;
+}
+
+namespace {
+// Collects completion-relevant information about a concept-constrainted type T.
+// In particular, examines the constraint expressions to find members of T.
+//
+// The design is very simple: we walk down each constraint looking for
+// expressions of the form T.foo().
+// If we're extra lucky, the return type is specified.
+// We don't do any clever handling of && or || in constraint expressions, we
+// take members from both branches.
+//
+// For example, given:
+// template <class T> concept X = requires (T t, string& s) { t.print(s); };
+// template <X U> void foo(U u) { u.^ }
+// We want to suggest the inferred member function 'print(string)'.
+// We see that u has type U, so X<U> holds.
+// X<U> requires t.print(s) to be valid, where t has type U (substituted for T).
+// By looking at the CallExpr we find the signature of print().
+//
+// While we tend to know in advance which kind of members (access via . -> ::)
+// we want, it's simpler just to gather them all and post-filter.
+//
+// FIXME: some of this machinery could be used for non-concept type-parms too,
+// enabling completion for type parameters based on other uses of that param.
+//
+// FIXME: there are other cases where a type can be constrained by a concept,
+// e.g. inside `if constexpr(ConceptSpecializationExpr) { ... }`
+class ConceptInfo {
+public:
+ // Describes a likely member of a type, inferred by concept constraints.
+ // Offered as a code completion for T. T-> and T:: contexts.
+ struct Member {
+ // Always non-null: we only handle members with ordinary identifier names.
+ const IdentifierInfo *Name = nullptr;
+ // Set for functions we've seen called.
+ // 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;
+ // Whether this is accessed as T.member, T->member, or T::member.
+ enum AccessOperator {
+ Colons,
+ Arrow,
+ Dot,
+ } Operator = Dot;
+ // What's known about the type of a variable or return type of a function.
+ const TypeConstraint *ResultType = nullptr;
+ // FIXME: also track:
+ // - kind of entity (function/variable/type), to expose structured results
+ // - template args kinds/types, as a proxy for template params
+
+ // For now we simply return these results as "pattern" strings.
+ CodeCompletionString *render(Sema &S, CodeCompletionAllocator &Alloc,
+ CodeCompletionTUInfo &Info) const {
+ CodeCompletionBuilder B(Alloc, Info);
+ // Result type
+ if (ResultType) {
+ std::string AsString;
+ {
+ llvm::raw_string_ostream OS(AsString);
+ QualType ExactType = deduceType(*ResultType);
+ if (!ExactType.isNull())
+ ExactType.print(OS, getCompletionPrintingPolicy(S));
+ else
+ ResultType->print(OS, getCompletionPrintingPolicy(S));
+ }
+ B.AddResultTypeChunk(Alloc.CopyString(AsString));
+ }
+ // Member name
+ B.AddTypedTextChunk(Alloc.CopyString(Name->getName()));
+ // Function argument list
+ if (ArgTypes) {
+ B.AddChunk(clang::CodeCompletionString::CK_LeftParen);
+ bool First = true;
+ for (QualType Arg : *ArgTypes) {
+ if (First)
+ First = false;
+ else {
+ B.AddChunk(clang::CodeCompletionString::CK_Comma);
+ B.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace);
+ }
+ B.AddPlaceholderChunk(Alloc.CopyString(
+ Arg.getAsString(getCompletionPrintingPolicy(S))));
+ }
+ B.AddChunk(clang::CodeCompletionString::CK_RightParen);
+ }
+ return B.TakeString();
+ }
+ };
+
+ // BaseType is the type parameter T to infer members from.
+ // T must be accessible within S, as we use it to find the template entity
+ // that T is attached to in order to gather the relevant constraints.
+ ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) {
+ auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S);
+ for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity))
+ believe(E, &BaseType);
+ }
+
+ std::vector<Member> members() {
+ std::vector<Member> Results;
+ for (const auto &E : this->Results)
+ Results.push_back(E.second);
+ llvm::sort(Results, [](const Member &L, const Member &R) {
+ return L.Name->getName() < R.Name->getName();
+ });
+ return Results;
+ }
+
+private:
+ // Infer members of T, given that the expression E (dependent on T) is true.
+ void believe(const Expr *E, const TemplateTypeParmType *T) {
+ if (!E || !T)
+ return;
+ if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(E)) {
+ // If the concept is
+ // template <class A, class B> concept CD = f<A, B>();
+ // And the concept specialization is
+ // CD<int, T>
+ // Then we're substituting T for B, so we want to make f<A, B>() true
+ // by adding members to B - i.e. believe(f<A, B>(), B);
+ //
+ // For simplicity:
+ // - we don't attempt to substitute int for A
+ // - when T is used in other ways (like CD<T*>) we ignore it
+ ConceptDecl *CD = CSE->getNamedConcept();
+ TemplateParameterList *Params = CD->getTemplateParameters();
+ unsigned Index = 0;
+ for (const auto &Arg : CSE->getTemplateArguments()) {
+ if (Index >= Params->size())
+ break; // Won't happen in valid code.
+ if (isApprox(Arg, T)) {
+ auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Params->getParam(Index));
+ if (!TTPD)
+ continue;
+ // T was used as an argument, and bound to the parameter TT.
+ auto *TT = cast<TemplateTypeParmType>(TTPD->getTypeForDecl());
+ // So now we know the constraint as a function of TT is true.
+ believe(CD->getConstraintExpr(), TT);
+ // (concepts themselves have no associated constraints to require)
+ }
+
+ ++Index;
+ }
+ } else if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ // For A && B, we can infer members from both branches.
+ // For A || B, the union is still more useful than the intersection.
+ if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+ believe(BO->getLHS(), T);
+ believe(BO->getRHS(), T);
+ }
+ } else if (auto *RE = dyn_cast<RequiresExpr>(E)) {
+ // A requires(){...} lets us infer members from each requirement.
+ for (const concepts::Requirement *Req : RE->getRequirements()) {
+ if (!Req->isDependent())
+ continue; // Can't tell us anything about T.
+ // Now Req cannot a substitution-error: those aren't dependent.
+
+ if (auto *TR = dyn_cast<concepts::TypeRequirement>(Req)) {
+ // Do a full traversal so we get `foo` from `typename T::foo::bar`.
+ QualType AssertedType = TR->getType()->getType();
+ ValidVisitor(this, T).TraverseType(AssertedType);
+ } else if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) {
+ ValidVisitor Visitor(this, T);
+ // If we have a type constraint on the value of the expression,
+ // AND the whole outer expression describes a member, then we'll
+ // be able to use the constraint to provide the return type.
+ if (ER->getReturnTypeRequirement().isTypeConstraint()) {
+ Visitor.OuterType =
+ ER->getReturnTypeRequirement().getTypeConstraint();
+ Visitor.OuterExpr = ER->getExpr();
+ }
+ Visitor.TraverseStmt(ER->getExpr());
+ } else if (auto *NR = dyn_cast<concepts::NestedRequirement>(Req)) {
+ believe(NR->getConstraintExpr(), T);
+ }
+ }
+ }
+ }
+
+ // This visitor infers members of T based on traversing expressions/types
+ // that involve T. It is invoked with code known to be valid for T.
+ class ValidVisitor : public RecursiveASTVisitor<ValidVisitor> {
+ ConceptInfo *Outer;
+ const TemplateTypeParmType *T;
+
+ CallExpr *Caller = nullptr;
+ Expr *Callee = nullptr;
+
+ public:
+ // If set, OuterExpr is constrained by OuterType.
+ Expr *OuterExpr = nullptr;
+ const TypeConstraint *OuterType = nullptr;
+
+ ValidVisitor(ConceptInfo *Outer, const TemplateTypeParmType *T)
+ : Outer(Outer), T(T) {
+ assert(T);
+ }
+
+ // In T.foo or T->foo, `foo` is a member function/variable.
+ bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+ const Type *Base = E->getBaseType().getTypePtr();
+ bool IsArrow = E->isArrow();
+ if (Base->isPointerType() && IsArrow) {
+ IsArrow = false;
+ Base = Base->getPointeeType().getTypePtr();
+ }
+ if (isApprox(Base, T))
+ addValue(E, E->getMember(), IsArrow ? Member::Arrow : Member::Dot);
+ return true;
+ }
+
+ // In T::foo, `foo` is a static member function/variable.
+ bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ if (E->getQualifier() && isApprox(E->getQualifier()->getAsType(), T))
+ addValue(E, E->getDeclName(), Member::Colons);
+ return true;
+ }
+
+ // In T::typename foo, `foo` is a type.
+ bool VisitDependentNameType(DependentNameType *DNT) {
+ const auto *Q = DNT->getQualifier();
+ if (Q && isApprox(Q->getAsType(), T))
+ addType(DNT->getIdentifier());
+ return true;
+ }
+
+ // In T::foo::bar, `foo` must be a type.
+ // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-(
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) {
+ if (NNSL) {
+ NestedNameSpecifier *NNS = NNSL.getNestedNameSpecifier();
+ const auto *Q = NNS->getPrefix();
+ if (Q && isApprox(Q->getAsType(), T))
+ addType(NNS->getAsIdentifier());
+ }
+ // FIXME: also handle T::foo<X>::bar
+ return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL);
+ }
+
+ // FIXME also handle T::foo<X>
+
+ // Track the innermost caller/callee relationship so we can tell if a
+ // nested expr is being called as a function.
+ bool VisitCallExpr(CallExpr *CE) {
+ Caller = CE;
+ Callee = CE->getCallee();
+ return true;
+ }
+
+ private:
+ void addResult(Member &&M) {
+ auto R = Outer->Results.try_emplace(M.Name);
+ Member &O = R.first->second;
+ // Overwrite existing if the new member has more info.
+ // The preference of . vs :: vs -> is fairly arbitrary.
+ if (/*Inserted*/ R.second ||
+ std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr,
+ M.Operator) > std::make_tuple(O.ArgTypes.hasValue(),
+ O.ResultType != nullptr,
+ O.Operator))
+ O = std::move(M);
+ }
+
+ void addType(const IdentifierInfo *Name) {
+ if (!Name)
+ return;
+ Member M;
+ M.Name = Name;
+ M.Operator = Member::Colons;
+ addResult(std::move(M));
+ }
+
+ void addValue(Expr *E, DeclarationName Name,
+ Member::AccessOperator Operator) {
+ if (!Name.isIdentifier())
+ return;
+ Member Result;
+ Result.Name = Name.getAsIdentifierInfo();
+ Result.Operator = Operator;
+ // If this is the callee of an immediately-enclosing CallExpr, then
+ // treat it as a method, otherwise it's a variable.
+ if (Caller != nullptr && Callee == E) {
+ Result.ArgTypes.emplace();
+ for (const auto *Arg : Caller->arguments())
+ Result.ArgTypes->push_back(Arg->getType());
+ if (Caller == OuterExpr) {
+ Result.ResultType = OuterType;
+ }
+ } else {
+ if (E == OuterExpr)
+ Result.ResultType = OuterType;
+ }
+ addResult(std::move(Result));
+ }
+ };
+
+ static bool isApprox(const TemplateArgument &Arg, const Type *T) {
+ return Arg.getKind() == TemplateArgument::Type &&
+ isApprox(Arg.getAsType().getTypePtr(), T);
+ }
+
+ static bool isApprox(const Type *T1, const Type *T2) {
+ return T1 && T2 &&
+ T1->getCanonicalTypeUnqualified() ==
+ T2->getCanonicalTypeUnqualified();
+ }
+
+ // Returns the DeclContext immediately enclosed by the template parameter
+ // scope. For primary templates, this is the templated (e.g.) CXXRecordDecl.
+ // For specializations, this is e.g. ClassTemplatePartialSpecializationDecl.
+ static DeclContext *getTemplatedEntity(const TemplateTypeParmDecl *D,
+ Scope *S) {
+ if (D == nullptr)
+ return nullptr;
+ Scope *Inner = nullptr;
+ while (S) {
+ if (S->isTemplateParamScope() && S->isDeclScope(D))
+ return Inner ? Inner->getEntity() : nullptr;
+ Inner = S;
+ S = S->getParent();
+ }
+ return nullptr;
+ }
+
+ // Gets all the type constraint expressions that might apply to the type
+ // variables associated with DC (as returned by getTemplatedEntity()).
+ static SmallVector<const Expr *, 1>
+ constraintsForTemplatedEntity(DeclContext *DC) {
+ SmallVector<const Expr *, 1> Result;
+ if (DC == nullptr)
+ return Result;
+ // Primary templates can have constraints.
+ if (const auto *TD = cast<Decl>(DC)->getDescribedTemplate())
+ TD->getAssociatedConstraints(Result);
+ // Partial specializations may have constraints.
+ if (const auto *CTPSD =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(DC))
+ CTPSD->getAssociatedConstraints(Result);
+ if (const auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(DC))
+ VTPSD->getAssociatedConstraints(Result);
+ return Result;
+ }
+
+ // Attempt to find the unique type satisfying a constraint.
+ // This lets us show e.g. `int` instead of `std::same_as<int>`.
+ static QualType deduceType(const TypeConstraint &T) {
+ // Assume a same_as<T> return type constraint is std::same_as or equivalent.
+ // In this case the return type is T.
+ DeclarationName DN = T.getNamedConcept()->getDeclName();
+ if (DN.isIdentifier() && DN.getAsIdentifierInfo()->isStr("same_as"))
+ if (const auto *Args = T.getTemplateArgsAsWritten())
+ if (Args->getNumTemplateArgs() == 1) {
+ const auto &Arg = Args->arguments().front().getArgument();
+ if (Arg.getKind() == TemplateArgument::Type)
+ return Arg.getAsType();
+ }
+ return {};
+ }
+
+ llvm::DenseMap<const IdentifierInfo *, Member> Results;
+};
+} // namespace
+
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Expr *OtherOpBase,
SourceLocation OpLoc, bool IsArrow,
@@ -4767,37 +5179,46 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Base = ConvertedBase.get();
QualType BaseType = Base->getType();
+ if (BaseType.isNull())
+ return false;
ExprValueKind BaseKind = Base->getValueKind();
if (IsArrow) {
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
BaseType = Ptr->getPointeeType();
BaseKind = VK_LValue;
- } else if (BaseType->isObjCObjectPointerType())
- /*Do nothing*/;
- else
+ } else if (BaseType->isObjCObjectPointerType() ||
+ BaseType->isTemplateTypeParmType()) {
+ // Both cases (dot/arrow) handled below.
+ } else {
return false;
+ }
}
- if (const RecordType *Record = BaseType->getAs<RecordType>()) {
+ if (RecordDecl *RD = getAsRecordDecl(BaseType)) {
AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
- Record->getDecl(),
- std::move(AccessOpFixIt));
- } else if (const auto *TST =
- BaseType->getAs<TemplateSpecializationType>()) {
- TemplateName TN = TST->getTemplateName();
- if (const auto *TD =
- dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) {
- CXXRecordDecl *RD = TD->getTemplatedDecl();
- AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
- RD, std::move(AccessOpFixIt));
+ RD, std::move(AccessOpFixIt));
+ } else if (const auto *TTPT =
+ dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {
+ auto Operator =
+ IsArrow ? ConceptInfo::Member::Arrow : ConceptInfo::Member::Dot;
+ for (const auto &R : ConceptInfo(*TTPT, S).members()) {
+ if (R.Operator != Operator)
+ continue;
+ CodeCompletionResult Result(
+ R.render(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo()));
+ if (AccessOpFixIt)
+ Result.FixIts.push_back(*AccessOpFixIt);
+ Results.AddResult(std::move(Result));
}
- } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) {
- if (auto *RD = ICNT->getDecl())
- AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind,
- RD, std::move(AccessOpFixIt));
} else if (!IsArrow && BaseType->isObjCObjectPointerType()) {
- // Objective-C property reference.
+ // Objective-C property reference. Bail if we're performing fix-it code
+ // completion since Objective-C properties are normally backed by ivars,
+ // most Objective-C fix-its here would have little value.
+ if (AccessOpFixIt.hasValue()) {
+ return false;
+ }
AddedPropertiesSet AddedProperties;
if (const ObjCObjectPointerType *ObjCPtr =
@@ -4817,7 +5238,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
/*InOriginalClass*/ false);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCObjectType())) {
- // Objective-C instance variable access.
+ // Objective-C instance variable access. Bail if we're performing fix-it
+ // code completion since Objective-C properties are normally backed by
+ // ivars, most Objective-C fix-its here would have little value.
+ if (AccessOpFixIt.hasValue()) {
+ return false;
+ }
ObjCInterfaceDecl *Class = nullptr;
if (const ObjCObjectPointerType *ObjCPtr =
BaseType->getAs<ObjCObjectPointerType>())
@@ -5282,6 +5708,44 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp(
return QualType();
}
+void Sema::CodeCompleteDesignator(const QualType BaseType,
+ llvm::ArrayRef<Expr *> InitExprs,
+ const Designation &D) {
+ if (BaseType.isNull())
+ return;
+ // FIXME: Handle nested designations, e.g. : .x.^
+ if (!D.empty())
+ return;
+
+ const auto *RD = getAsRecordDecl(BaseType);
+ if (!RD)
+ return;
+ if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ // Template might not be instantiated yet, fall back to primary template in
+ // such cases.
+ if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared)
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ }
+ if (RD->fields().empty())
+ return;
+
+ CodeCompletionContext CCC(CodeCompletionContext::CCC_DotMemberAccess,
+ BaseType);
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(), CCC);
+
+ Results.EnterNewScope();
+ for (const auto *FD : RD->fields()) {
+ // FIXME: Make use of previous designators to mark any fields before those
+ // inaccessible, and also compute the next initializer priority.
+ ResultBuilder::Result Result(FD, Results.getBasePriority(FD));
+ Results.AddResult(Result, CurContext, /*Hiding=*/nullptr);
+ }
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
+}
+
void Sema::CodeCompleteInitializer(Scope *S, Decl *D) {
ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D);
if (!VD) {
@@ -5297,7 +5761,7 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) {
CodeCompleteExpression(S, Data);
}
-void Sema::CodeCompleteAfterIf(Scope *S) {
+void Sema::CodeCompleteAfterIf(Scope *S, bool IsBracedThen) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
mapCodeCompletionContext(*this, PCC_Statement));
@@ -5314,15 +5778,25 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
// "else" block
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
+
+ auto AddElseBodyPattern = [&] {
+ if (IsBracedThen) {
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddPlaceholderChunk("statements");
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ } else {
+ Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("statement");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ }
+ };
Builder.AddTypedTextChunk("else");
- if (Results.includeCodePatterns()) {
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddPlaceholderChunk("statements");
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddChunk(CodeCompletionString::CK_RightBrace);
- }
+ if (Results.includeCodePatterns())
+ AddElseBodyPattern();
Results.AddResult(Builder.TakeString());
// "else if" block
@@ -5335,12 +5809,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
Builder.AddPlaceholderChunk("expression");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
if (Results.includeCodePatterns()) {
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddPlaceholderChunk("statements");
- Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- Builder.AddChunk(CodeCompletionString::CK_RightBrace);
+ AddElseBodyPattern();
}
Results.AddResult(Builder.TakeString());
@@ -5393,13 +5862,14 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
// Always pretend to enter a context to ensure that a dependent type
// resolves to a dependent record.
DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true);
- if (!Ctx)
- return;
// Try to instantiate any non-dependent declaration contexts before
- // we look in them.
- if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
- return;
+ // we look in them. Bail out if we fail.
+ NestedNameSpecifier *NNS = SS.getScopeRep();
+ if (NNS != nullptr && SS.isValid() && !NNS->isDependent()) {
+ if (Ctx == nullptr || RequireCompleteDeclContext(SS, Ctx))
+ return;
+ }
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(), CC);
@@ -5409,21 +5879,34 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
// The "template" keyword can follow "::" in the grammar, but only
// put it into the grammar if the nested-name-specifier is dependent.
- NestedNameSpecifier *NNS = SS.getScopeRep();
+ // FIXME: results is always empty, this appears to be dead.
if (!Results.empty() && NNS->isDependent())
Results.AddResult("template");
+ // If the scope is a concept-constrained type parameter, infer nested
+ // members based on the constraints.
+ if (const auto *TTPT =
+ dyn_cast_or_null<TemplateTypeParmType>(NNS->getAsType())) {
+ for (const auto &R : ConceptInfo(*TTPT, S).members()) {
+ if (R.Operator != ConceptInfo::Member::Colons)
+ continue;
+ Results.AddResult(CodeCompletionResult(
+ R.render(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo())));
+ }
+ }
+
// Add calls to overridden virtual functions, if there are any.
//
// FIXME: This isn't wonderful, because we don't know whether we're actually
// in a context that permits expressions. This is a general issue with
// qualified-id completions.
- if (!EnteringContext)
+ if (Ctx && !EnteringContext)
MaybeAddOverrideCalls(*this, Ctx, Results);
Results.ExitScope();
- if (CodeCompleter->includeNamespaceLevelDecls() ||
- (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) {
+ if (Ctx &&
+ (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) {
CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType);
LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer,
/*IncludeGlobalScope=*/true,
@@ -5785,6 +6268,53 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
Results.data(), Results.size());
}
+void Sema::CodeCompleteAfterFunctionEquals(Declarator &D) {
+ if (!LangOpts.CPlusPlus11)
+ return;
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Other);
+ auto ShouldAddDefault = [&D, this]() {
+ if (!D.isFunctionDeclarator())
+ return false;
+ auto &Id = D.getName();
+ if (Id.getKind() == UnqualifiedIdKind::IK_DestructorName)
+ return true;
+ // FIXME(liuhui): Ideally, we should check the constructor parameter list to
+ // verify that it is the default, copy or move constructor?
+ if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName &&
+ D.getFunctionTypeInfo().NumParams <= 1)
+ return true;
+ if (Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId) {
+ auto Op = Id.OperatorFunctionId.Operator;
+ // FIXME(liuhui): Ideally, we should check the function parameter list to
+ // verify that it is the copy or move assignment?
+ if (Op == OverloadedOperatorKind::OO_Equal)
+ return true;
+ if (LangOpts.CPlusPlus20 &&
+ (Op == OverloadedOperatorKind::OO_EqualEqual ||
+ Op == OverloadedOperatorKind::OO_ExclaimEqual ||
+ Op == OverloadedOperatorKind::OO_Less ||
+ Op == OverloadedOperatorKind::OO_LessEqual ||
+ Op == OverloadedOperatorKind::OO_Greater ||
+ Op == OverloadedOperatorKind::OO_GreaterEqual ||
+ Op == OverloadedOperatorKind::OO_Spaceship))
+ return true;
+ }
+ return false;
+ };
+
+ Results.EnterNewScope();
+ if (ShouldAddDefault())
+ Results.AddResult("default");
+ // FIXME(liuhui): Ideally, we should only provide `delete` completion for the
+ // first function declaration.
+ Results.AddResult("delete");
+ Results.ExitScope();
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
+}
+
/// Macro that optionally prepends an "@" to the string literal passed in via
/// Keyword, depending on whether NeedAt is true or false.
#define OBJC_AT_KEYWORD_NAME(NeedAt, Keyword) ((NeedAt) ? "@" Keyword : Keyword)
@@ -6063,22 +6593,24 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) {
Attributes |= NewFlag;
// Check for collisions with "readonly".
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
+ (Attributes & ObjCPropertyAttribute::kind_readwrite))
return true;
// Check for more than one of { assign, copy, retain, strong, weak }.
unsigned AssignCopyRetMask =
Attributes &
- (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_unsafe_unretained |
- ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain |
- ObjCDeclSpec::DQ_PR_strong | ObjCDeclSpec::DQ_PR_weak);
- if (AssignCopyRetMask && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong &&
- AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak)
+ (ObjCPropertyAttribute::kind_assign |
+ ObjCPropertyAttribute::kind_unsafe_unretained |
+ ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak);
+ if (AssignCopyRetMask &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_assign &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_unsafe_unretained &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_copy &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_retain &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_strong &&
+ AssignCopyRetMask != ObjCPropertyAttribute::kind_weak)
return true;
return false;
@@ -6094,32 +6626,41 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_readonly))
Results.AddResult(CodeCompletionResult("readonly"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_assign))
Results.AddResult(CodeCompletionResult("assign"));
if (!ObjCPropertyFlagConflicts(Attributes,
- ObjCDeclSpec::DQ_PR_unsafe_unretained))
+ ObjCPropertyAttribute::kind_unsafe_unretained))
Results.AddResult(CodeCompletionResult("unsafe_unretained"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_readwrite))
Results.AddResult(CodeCompletionResult("readwrite"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_retain))
Results.AddResult(CodeCompletionResult("retain"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_strong))
Results.AddResult(CodeCompletionResult("strong"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_copy))
Results.AddResult(CodeCompletionResult("copy"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_nonatomic))
Results.AddResult(CodeCompletionResult("nonatomic"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_atomic))
Results.AddResult(CodeCompletionResult("atomic"));
// Only suggest "weak" if we're compiling for ARC-with-weak-references or GC.
if (getLangOpts().ObjCWeak || getLangOpts().getGC() != LangOptions::NonGC)
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak))
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_weak))
Results.AddResult(CodeCompletionResult("weak"));
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_setter)) {
CodeCompletionBuilder Setter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
Setter.AddTypedTextChunk("setter");
@@ -6127,7 +6668,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Setter.AddPlaceholderChunk("method");
Results.AddResult(CodeCompletionResult(Setter.TakeString()));
}
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) {
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_getter)) {
CodeCompletionBuilder Getter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
Getter.AddTypedTextChunk("getter");
@@ -6135,7 +6677,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Getter.AddPlaceholderChunk("method");
Results.AddResult(CodeCompletionResult(Getter.TakeString()));
}
- if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nullability)) {
+ if (!ObjCPropertyFlagConflicts(Attributes,
+ ObjCPropertyAttribute::kind_nullability)) {
Results.AddResult(CodeCompletionResult("nonnull"));
Results.AddResult(CodeCompletionResult("nullable"));
Results.AddResult(CodeCompletionResult("null_unspecified"));
@@ -7602,7 +8145,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
} Key(Allocator, PropName->getName());
// The uppercased name of the property name.
- std::string UpperKey = PropName->getName();
+ std::string UpperKey = std::string(PropName->getName());
if (!UpperKey.empty())
UpperKey[0] = toUppercase(UpperKey[0]);
@@ -7660,8 +8203,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddChunk(CodeCompletionString::CK_RightParen);
}
- Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName()));
- Builder.AddTypedTextChunk(":");
+ Builder.AddTypedTextChunk(
+ Allocator.CopyString(SelectorId->getName() + ":"));
AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy,
Builder);
Builder.AddTextChunk(Key);
@@ -8249,39 +8792,43 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
Selector Sel = Method->getSelector();
- // Add the first part of the selector to the pattern.
- Builder.AddTypedTextChunk(
- Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));
-
- // Add parameters to the pattern.
- unsigned I = 0;
- for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd; (void)++P, ++I) {
- // Add the part of the selector name.
- if (I == 0)
- Builder.AddTypedTextChunk(":");
- else if (I < Sel.getNumArgs()) {
- Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
- Builder.AddTypedTextChunk(
- Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));
- } else
- break;
-
- // Add the parameter type.
- QualType ParamType;
- if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- ParamType = (*P)->getType();
- else
- ParamType = (*P)->getOriginalType();
- ParamType = ParamType.substObjCTypeArgs(
- Context, {}, ObjCSubstitutionContext::Parameter);
- AttributedType::stripOuterNullability(ParamType);
- AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context,
- Policy, Builder);
+ if (Sel.isUnarySelector()) {
+ // Unary selectors have no arguments.
+ Builder.AddTypedTextChunk(
+ Builder.getAllocator().CopyString(Sel.getNameForSlot(0)));
+ } else {
+ // Add all parameters to the pattern.
+ unsigned I = 0;
+ for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; (void)++P, ++I) {
+ // Add the part of the selector name.
+ if (I == 0)
+ Builder.AddTypedTextChunk(
+ Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));
+ else if (I < Sel.getNumArgs()) {
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddTypedTextChunk(
+ Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":"));
+ } else
+ break;
- if (IdentifierInfo *Id = (*P)->getIdentifier())
- Builder.AddTextChunk(Builder.getAllocator().CopyString(Id->getName()));
+ // Add the parameter type.
+ QualType ParamType;
+ if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
+ ParamType = (*P)->getType();
+ else
+ ParamType = (*P)->getOriginalType();
+ ParamType = ParamType.substObjCTypeArgs(
+ Context, {}, ObjCSubstitutionContext::Parameter);
+ AttributedType::stripOuterNullability(ParamType);
+ AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(),
+ Context, Policy, Builder);
+
+ if (IdentifierInfo *Id = (*P)->getIdentifier())
+ Builder.AddTextChunk(
+ Builder.getAllocator().CopyString(Id->getName()));
+ }
}
if (Method->isVariadic()) {
@@ -8723,7 +9270,16 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
if (++Count == 2500) // If we happen to hit a huge directory,
break; // bail out early so we're not too slow.
StringRef Filename = llvm::sys::path::filename(It->path());
- switch (It->type()) {
+
+ // To know whether a symlink should be treated as file or a directory, we
+ // have to stat it. This should be cheap enough as there shouldn't be many
+ // symlinks.
+ llvm::sys::fs::file_type Type = It->type();
+ if (Type == llvm::sys::fs::file_type::symlink_file) {
+ if (auto FileStatus = FS.status(It->path()))
+ Type = FileStatus->getType();
+ }
+ switch (Type) {
case llvm::sys::fs::file_type::directory_file:
// All entries in a framework directory must have a ".framework" suffix,
// but the suffix does not appear in the source code's include/import.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 018ac2d7dc9d..ddd95faebe99 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -17,7 +17,10 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/Template.h"
-#include "clang/AST/ExprCXX.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "llvm/ADT/DenseMap.h"
@@ -25,21 +28,47 @@
using namespace clang;
using namespace sema;
-bool
-Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken,
- bool *PossibleNonPrimary,
- bool IsTrailingRequiresClause) {
+namespace {
+class LogicalBinOp {
+ OverloadedOperatorKind Op = OO_None;
+ const Expr *LHS = nullptr;
+ const Expr *RHS = nullptr;
+
+public:
+ LogicalBinOp(const Expr *E) {
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
+ LHS = BO->getLHS();
+ RHS = BO->getRHS();
+ } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
+ Op = OO->getOperator();
+ LHS = OO->getArg(0);
+ RHS = OO->getArg(1);
+ }
+ }
+
+ bool isAnd() const { return Op == OO_AmpAmp; }
+ bool isOr() const { return Op == OO_PipePipe; }
+ explicit operator bool() const { return isAnd() || isOr(); }
+
+ const Expr *getLHS() const { return LHS; }
+ const Expr *getRHS() const { return RHS; }
+};
+}
+
+bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
+ Token NextToken, bool *PossibleNonPrimary,
+ bool IsTrailingRequiresClause) {
// C++2a [temp.constr.atomic]p1
// ..E shall be a constant expression of type bool.
ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
- if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
- if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
- return CheckConstraintExpression(BinOp->getLHS(), NextToken,
- PossibleNonPrimary) &&
- CheckConstraintExpression(BinOp->getRHS(), NextToken,
- PossibleNonPrimary);
+ if (LogicalBinOp BO = ConstraintExpression) {
+ return CheckConstraintExpression(BO.getLHS(), NextToken,
+ PossibleNonPrimary) &&
+ CheckConstraintExpression(BO.getRHS(), NextToken,
+ PossibleNonPrimary);
} else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
return CheckConstraintExpression(C->getSubExpr(), NextToken,
PossibleNonPrimary);
@@ -57,7 +86,7 @@ Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken,
(NextToken.is(tok::l_paren) &&
(IsTrailingRequiresClause ||
(Type->isDependentType() &&
- IsDependentFunctionNameExpr(ConstraintExpression)) ||
+ isa<UnresolvedLookupExpr>(ConstraintExpression)) ||
Type->isFunctionType() ||
Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
// We have the following case:
@@ -96,39 +125,37 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
- if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
- if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
- if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction,
- Evaluator))
- return true;
+ if (LogicalBinOp BO = ConstraintExpr) {
+ if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
+ Evaluator))
+ return true;
- bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
- if (BO->getOpcode() == BO_LOr && IsLHSSatisfied)
- // [temp.constr.op] p3
- // A disjunction is a constraint taking two operands. To determine if
- // a disjunction is satisfied, the satisfaction of the first operand
- // 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;
+ if (BO.isOr() && IsLHSSatisfied)
+ // [temp.constr.op] p3
+ // A disjunction is a constraint taking two operands. To determine if
+ // a disjunction is satisfied, the satisfaction of the first operand
+ // 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;
- if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied)
- // [temp.constr.op] p2
- // A conjunction is a constraint taking two operands. 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. Otherwise, the conjunction is satisfied if and only if
- // the second operand is satisfied.
- return false;
+ if (BO.isAnd() && !IsLHSSatisfied)
+ // [temp.constr.op] p2
+ // A conjunction is a constraint taking two operands. 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. Otherwise, the conjunction is satisfied if and only if
+ // the second operand is satisfied.
+ return false;
- return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction,
- std::forward<AtomicEvaluator>(Evaluator));
- }
- }
- else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
+ return calculateConstraintSatisfaction(
+ S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
+ } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
std::forward<AtomicEvaluator>(Evaluator));
+ }
// An atomic constraint expression
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
@@ -164,9 +191,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
return false;
}
-template <typename TemplateDeclT>
static bool calculateConstraintSatisfaction(
- Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
@@ -179,8 +205,9 @@ static bool calculateConstraintSatisfaction(
{
TemplateDeductionInfo Info(TemplateNameLoc);
Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
- Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
- Info, AtomicExpr->getSourceRange());
+ Sema::InstantiatingTemplate::ConstraintSubstitution{},
+ const_cast<NamedDecl *>(Template), Info,
+ AtomicExpr->getSourceRange());
if (Inst.isInvalid())
return ExprError();
// We do not want error diagnostics escaping here.
@@ -227,8 +254,7 @@ static bool calculateConstraintSatisfaction(
});
}
-template<typename TemplateDeclT>
-static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
+static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
ArrayRef<const Expr *> ConstraintExprs,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange,
@@ -246,8 +272,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
}
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
- Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
- TemplateIDRange);
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
if (Inst.isInvalid())
return true;
@@ -269,36 +295,45 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
return false;
}
-bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
-}
+bool Sema::CheckConstraintSatisfaction(
+ const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
+ ConstraintSatisfaction &OutSatisfaction) {
+ if (ConstraintExprs.empty()) {
+ OutSatisfaction.IsSatisfied = true;
+ return false;
+ }
-bool
-Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
-}
+ llvm::FoldingSetNodeID ID;
+ void *InsertPos;
+ ConstraintSatisfaction *Satisfaction = nullptr;
+ bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
+ if (ShouldCache) {
+ ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
+ Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
+ if (Satisfaction) {
+ OutSatisfaction = *Satisfaction;
+ return false;
+ }
+ Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs);
+ } else {
+ Satisfaction = &OutSatisfaction;
+ }
+ if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ *Satisfaction)) {
+ if (ShouldCache)
+ delete Satisfaction;
+ return true;
+ }
-bool
-Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
- return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- Satisfaction);
+ if (ShouldCache) {
+ // We cannot use InsertNode here because CheckConstraintSatisfaction might
+ // have invalidated it.
+ SatisfactionCache.InsertNode(Satisfaction);
+ OutSatisfaction = *Satisfaction;
+ }
+ return false;
}
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
@@ -310,6 +345,30 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
});
}
+bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
+ ConstraintSatisfaction &Satisfaction,
+ SourceLocation UsageLoc) {
+ const Expr *RC = FD->getTrailingRequiresClause();
+ if (RC->isInstantiationDependent()) {
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = const_cast<CXXRecordDecl *>(Method->getParent());
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+ // We substitute with empty arguments in order to rebuild the atomic
+ // constraint in a constant-evaluated context.
+ // FIXME: Should this be a dedicated TreeTransform?
+ return CheckConstraintSatisfaction(
+ FD, {RC}, /*TemplateArgs=*/{},
+ SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+ Satisfaction);
+}
+
bool Sema::EnsureTemplateArgumentListConstraints(
TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange) {
@@ -336,6 +395,118 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
+static void diagnoseUnsatisfiedRequirement(Sema &S,
+ concepts::ExprRequirement *Req,
+ bool First) {
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
+ switch (Req->getSatisfactionStatus()) {
+ case concepts::ExprRequirement::SS_Dependent:
+ llvm_unreachable("Diagnosing a dependent requirement");
+ break;
+ case concepts::ExprRequirement::SS_ExprSubstitutionFailure: {
+ auto *SubstDiag = Req->getExprSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_expr_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_NoexceptNotMet:
+ S.Diag(Req->getNoexceptLoc(),
+ diag::note_expr_requirement_noexcept_not_met)
+ << (int)First << Req->getExpr();
+ break;
+ case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: {
+ auto *SubstDiag =
+ Req->getReturnTypeRequirement().getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity
+ << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_expr_requirement_type_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ break;
+ }
+ case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: {
+ ConceptSpecializationExpr *ConstraintExpr =
+ Req->getReturnTypeRequirementSubstitutedConstraintExpr();
+ if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1)
+ // A simple case - expr type is the type being constrained and the concept
+ // was not provided arguments.
+ S.Diag(ConstraintExpr->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied_simple)
+ << (int)First << S.BuildDecltypeType(Req->getExpr(),
+ Req->getExpr()->getBeginLoc())
+ << ConstraintExpr->getNamedConcept();
+ else
+ S.Diag(ConstraintExpr->getBeginLoc(),
+ diag::note_expr_requirement_constraints_not_satisfied)
+ << (int)First << ConstraintExpr;
+ S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction());
+ break;
+ }
+ case concepts::ExprRequirement::SS_Satisfied:
+ llvm_unreachable("We checked this above");
+ }
+}
+
+static void diagnoseUnsatisfiedRequirement(Sema &S,
+ concepts::TypeRequirement *Req,
+ bool First) {
+ assert(!Req->isSatisfied()
+ && "Diagnose() can only be used on an unsatisfied requirement");
+ switch (Req->getSatisfactionStatus()) {
+ case concepts::TypeRequirement::SS_Dependent:
+ llvm_unreachable("Diagnosing a dependent requirement");
+ return;
+ case concepts::TypeRequirement::SS_SubstitutionFailure: {
+ auto *SubstDiag = Req->getSubstitutionDiagnostic();
+ if (!SubstDiag->DiagMessage.empty())
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_type_requirement_substitution_error) << (int)First
+ << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_type_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ return;
+ }
+ default:
+ llvm_unreachable("Unknown satisfaction status");
+ return;
+ }
+}
+
+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;
+ else
+ S.Diag(SubstDiag->DiagLoc,
+ diag::note_nested_requirement_unknown_substitution_error)
+ << (int)First << SubstDiag->SubstitutedEntity;
+ return;
+ }
+ S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First);
+}
+
+
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
Expr *SubstExpr,
bool First = true) {
@@ -412,6 +583,19 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
}
S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
return;
+ } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
+ for (concepts::Requirement *Req : RE->getRequirements())
+ if (!Req->isDependent() && !Req->isSatisfied()) {
+ if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
+ diagnoseUnsatisfiedRequirement(S, E, First);
+ else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req))
+ diagnoseUnsatisfiedRequirement(S, T, First);
+ else
+ diagnoseUnsatisfiedRequirement(
+ S, cast<concepts::NestedRequirement>(Req), First);
+ break;
+ }
+ return;
}
S.Diag(SubstExpr->getSourceRange().getBegin(),
@@ -434,11 +618,11 @@ static void diagnoseUnsatisfiedConstraintExpr(
Record.template get<Expr *>(), First);
}
-void Sema::DiagnoseUnsatisfiedConstraint(
- const ConstraintSatisfaction& Satisfaction) {
+void
+Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
- bool First = true;
for (auto &Pair : Satisfaction.Details) {
diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
First = false;
@@ -446,10 +630,10 @@ void Sema::DiagnoseUnsatisfiedConstraint(
}
void Sema::DiagnoseUnsatisfiedConstraint(
- const ASTConstraintSatisfaction &Satisfaction) {
+ const ASTConstraintSatisfaction &Satisfaction,
+ bool First) {
assert(!Satisfaction.IsSatisfied &&
"Attempted to diagnose a satisfied constraint");
- bool First = true;
for (auto &Pair : Satisfaction) {
diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
First = false;
@@ -523,6 +707,10 @@ 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()));
std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
N.getAtomicConstraint()->ParameterMapping->begin());
return false;
@@ -561,19 +749,16 @@ 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();
- if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
- if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
- auto LHS = fromConstraintExpr(S, D, BO->getLHS());
- if (!LHS)
- return None;
- auto RHS = fromConstraintExpr(S, D, BO->getRHS());
- if (!RHS)
- return None;
+ if (LogicalBinOp BO = E) {
+ auto LHS = fromConstraintExpr(S, D, BO.getLHS());
+ if (!LHS)
+ return None;
+ auto RHS = fromConstraintExpr(S, D, BO.getRHS());
+ if (!RHS)
+ return None;
- return NormalizedConstraint(
- S.Context, std::move(*LHS), std::move(*RHS),
- BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
- }
+ return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
+ BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
} else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
const NormalizedConstraint *SubNF;
{
@@ -826,3 +1011,67 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
<< AmbiguousAtomic2->getSourceRange();
return true;
}
+
+concepts::ExprRequirement::ExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ ReturnTypeRequirement Req, SatisfactionStatus Status,
+ ConceptSpecializationExpr *SubstitutedConstraintExpr) :
+ Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
+ Status == SS_Dependent &&
+ (E->containsUnexpandedParameterPack() ||
+ Req.containsUnexpandedParameterPack()),
+ Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc),
+ TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr),
+ Status(Status) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+ assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==
+ (SubstitutedConstraintExpr != nullptr));
+}
+
+concepts::ExprRequirement::ExprRequirement(
+ SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
+ SourceLocation NoexceptLoc, ReturnTypeRequirement Req) :
+ Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
+ Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
+ Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+ Status(SS_ExprSubstitutionFailure) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+}
+
+concepts::ExprRequirement::ReturnTypeRequirement::
+ReturnTypeRequirement(TemplateParameterList *TPL) :
+ TypeConstraintInfo(TPL, 0) {
+ assert(TPL->size() == 1);
+ const TypeConstraint *TC =
+ cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
+ assert(TC &&
+ "TPL must have a template type parameter with a type constraint");
+ auto *Constraint =
+ cast_or_null<ConceptSpecializationExpr>(
+ TC->getImmediatelyDeclaredConstraint());
+ bool Dependent = false;
+ if (Constraint->getTemplateArgsAsWritten()) {
+ for (auto &ArgLoc :
+ Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) {
+ if (ArgLoc.getArgument().isDependent()) {
+ Dependent = true;
+ break;
+ }
+ }
+ }
+ TypeConstraintInfo.setInt(Dependent ? 1 : 0);
+}
+
+concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
+ Requirement(RK_Type, T->getType()->isDependentType(),
+ T->getType()->containsUnexpandedParameterPack(),
+ // We reach this ctor with either dependent types (in which
+ // IsSatisfied doesn't matter) or with non-dependent type in
+ // which the existence of the type indicates satisfaction.
+ /*IsSatisfied=*/true
+ ), Value(T),
+ Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {}
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 6dc9e342beb9..992cccac6405 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -24,6 +24,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/SmallSet.h"
using namespace clang;
using namespace sema;
@@ -390,7 +391,13 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
return nullptr;
Expr *JustAddress = AddressExpr.get();
- // FIXME: Check that the type of AddressExpr is void*
+
+ // Check that the type of AddressExpr is void*
+ if (!JustAddress->getType().getTypePtr()->isVoidPointerType())
+ S.Diag(cast<CallExpr>(JustAddress)->getCalleeDecl()->getLocation(),
+ diag::warn_coroutine_handle_address_invalid_return_type)
+ << JustAddress->getType();
+
return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
JustAddress);
}
@@ -502,8 +509,9 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
return nullptr;
auto *ScopeInfo = getCurFunction();
- // Build a list of arguments, based on the coroutine functions arguments,
- // that will be passed to the promise type's constructor.
+
+ // Build a list of arguments, based on the coroutine function's arguments,
+ // that if present will be passed to the promise type's constructor.
llvm::SmallVector<Expr *, 4> CtorArgExprs;
// Add implicit object parameter.
@@ -519,6 +527,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
}
}
+ // Add the coroutine function's parameters.
auto &Moves = ScopeInfo->CoroutineParameterMoves;
for (auto *PD : FD->parameters()) {
if (PD->getType()->isDependentType())
@@ -540,28 +549,33 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
CtorArgExprs.push_back(RefExpr.get());
}
- // Create an initialization sequence for the promise type using the
- // constructor arguments, wrapped in a parenthesized list expression.
- Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(),
- CtorArgExprs, FD->getLocation());
- InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
- InitializationKind Kind = InitializationKind::CreateForInit(
- VD->getLocation(), /*DirectInit=*/true, PLE);
- InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs,
- /*TopLevelOfInitList=*/false,
- /*TreatUnavailableAsInvalid=*/false);
-
- // Attempt to initialize the promise type with the arguments.
- // If that fails, fall back to the promise type's default constructor.
- if (InitSeq) {
- ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs);
- if (Result.isInvalid()) {
- VD->setInvalidDecl();
- } else if (Result.get()) {
- VD->setInit(MaybeCreateExprWithCleanups(Result.get()));
- VD->setInitStyle(VarDecl::CallInit);
- CheckCompleteVariableDeclaration(VD);
- }
+ // If we have a non-zero number of constructor arguments, try to use them.
+ // Otherwise, fall back to the promise type's default constructor.
+ if (!CtorArgExprs.empty()) {
+ // Create an initialization sequence for the promise type using the
+ // constructor arguments, wrapped in a parenthesized list expression.
+ Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(),
+ CtorArgExprs, FD->getLocation());
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
+ InitializationKind Kind = InitializationKind::CreateForInit(
+ VD->getLocation(), /*DirectInit=*/true, PLE);
+ InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs,
+ /*TopLevelOfInitList=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
+
+ // Attempt to initialize the promise type with the arguments.
+ // If that fails, fall back to the promise type's default constructor.
+ if (InitSeq) {
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs);
+ if (Result.isInvalid()) {
+ VD->setInvalidDecl();
+ } else if (Result.get()) {
+ VD->setInit(MaybeCreateExprWithCleanups(Result.get()));
+ VD->setInitStyle(VarDecl::CallInit);
+ CheckCompleteVariableDeclaration(VD);
+ }
+ } else
+ ActOnUninitializedDecl(VD);
} else
ActOnUninitializedDecl(VD);
@@ -597,6 +611,80 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc,
return ScopeInfo;
}
+/// Recursively check \p E and all its children to see if any call target
+/// (including constructor call) is declared noexcept. Also any value returned
+/// from the call has a noexcept destructor.
+static void checkNoThrow(Sema &S, const Stmt *E,
+ llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) {
+ auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
+ // In the case of dtor, the call to dtor is implicit and hence we should
+ // pass nullptr to canCalleeThrow.
+ if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ // co_await promise.final_suspend() could end up calling
+ // __builtin_coro_resume for symmetric transfer if await_suspend()
+ // returns a handle. In that case, even __builtin_coro_resume is not
+ // declared as noexcept and may throw, it does not throw _into_ the
+ // coroutine that just suspended, but rather throws back out from
+ // whoever called coroutine_handle::resume(), hence we claim that
+ // logically it does not throw.
+ if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+ return;
+ }
+ if (ThrowingDecls.empty()) {
+ // First time seeing an error, emit the error message.
+ S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(),
+ diag::err_coroutine_promise_final_suspend_requires_nothrow);
+ }
+ ThrowingDecls.insert(D);
+ }
+ };
+ auto SC = E->getStmtClass();
+ if (SC == Expr::CXXConstructExprClass) {
+ auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor();
+ checkDeclNoexcept(Ctor);
+ // Check the corresponding destructor of the constructor.
+ checkDeclNoexcept(Ctor->getParent()->getDestructor(), true);
+ } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
+ SC == Expr::CXXOperatorCallExprClass) {
+ if (!cast<CallExpr>(E)->isTypeDependent()) {
+ checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl());
+ auto ReturnType = cast<CallExpr>(E)->getCallReturnType(S.getASTContext());
+ // Check the destructor of the call return type, if any.
+ if (ReturnType.isDestructedType() ==
+ QualType::DestructionKind::DK_cxx_destructor) {
+ const auto *T =
+ cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
+ checkDeclNoexcept(
+ dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true);
+ }
+ }
+ }
+ for (const auto *Child : E->children()) {
+ if (!Child)
+ continue;
+ checkNoThrow(S, Child, ThrowingDecls);
+ }
+}
+
+bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {
+ llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls;
+ // We first collect all declarations that should not throw but not declared
+ // with noexcept. We then sort them based on the location before printing.
+ // This is to avoid emitting the same note multiple times on the same
+ // declaration, and also provide a deterministic order for the messages.
+ checkNoThrow(*this, FinalSuspend, ThrowingDecls);
+ auto SortedDecls = llvm::SmallVector<const Decl *, 4>{ThrowingDecls.begin(),
+ ThrowingDecls.end()};
+ sort(SortedDecls, [](const Decl *A, const Decl *B) {
+ return A->getEndLoc() < B->getEndLoc();
+ });
+ for (const auto *D : SortedDecls) {
+ Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept);
+ }
+ return ThrowingDecls.empty();
+}
+
bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
StringRef Keyword) {
if (!checkCoroutineContext(*this, KWLoc, Keyword))
@@ -639,7 +727,7 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
return true;
StmtResult FinalSuspend = buildSuspends("final_suspend");
- if (FinalSuspend.isInvalid())
+ if (FinalSuspend.isInvalid() || !checkFinalSuspendNoThrow(FinalSuspend.get()))
return true;
ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 507e4a6cd436..3e2b61ae8cdf 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
#include "clang/AST/StmtCXX.h"
@@ -47,6 +48,7 @@
#include <algorithm>
#include <cstring>
#include <functional>
+#include <unordered_map>
using namespace clang;
using namespace sema;
@@ -136,6 +138,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw___bf16:
case tok::kw__Float16:
case tok::kw___float128:
case tok::kw_wchar_t:
@@ -747,7 +750,10 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
Diag(IILoc, IsTemplateName ? diag::err_no_member_template
: diag::err_typename_nested_not_found)
<< II << DC << SS->getRange();
- else if (isDependentScopeSpecifier(*SS)) {
+ else if (SS->isValid() && SS->getScopeRep()->containsErrors()) {
+ SuggestedType =
+ ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get();
+ } else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S))
DiagID = diag::ext_typename_missing;
@@ -924,7 +930,7 @@ Corrected:
return NameClassification::NonType(D);
}
- if (getLangOpts().CPlusPlus2a && SS.isEmpty() && NextToken.is(tok::less)) {
+ if (getLangOpts().CPlusPlus20 && SS.isEmpty() && NextToken.is(tok::less)) {
// In C++20 onwards, this could be an ADL-only call to a function
// template, and we're required to assume that this is a template name.
//
@@ -1067,7 +1073,7 @@ Corrected:
Result, /*AllowFunctionTemplates=*/true,
/*AllowDependent=*/false,
/*AllowNonTemplateFunctions*/ SS.isEmpty() &&
- getLangOpts().CPlusPlus2a))) {
+ getLangOpts().CPlusPlus20))) {
// C++ [temp.names]p3:
// After name lookup (3.4) finds that a name is a template-name or that
// an operator-function-id or a literal- operator-id refers to a set of
@@ -1153,6 +1159,10 @@ Corrected:
return ParsedType::make(T);
}
+ if (isa<ConceptDecl>(FirstDecl))
+ return NameClassification::Concept(
+ TemplateName(cast<TemplateDecl>(FirstDecl)));
+
// We can have a type template here if we're classifying a template argument.
if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) &&
!isa<VarTemplateDecl>(FirstDecl))
@@ -1250,47 +1260,8 @@ Sema::getTemplateNameKindForDiagnostics(TemplateName Name) {
return TemplateNameKindForDiagnostics::DependentTemplate;
}
-// Determines the context to return to after temporarily entering a
-// context. This depends in an unnecessarily complicated way on the
-// exact ordering of callbacks from the parser.
-DeclContext *Sema::getContainingDC(DeclContext *DC) {
-
- // Functions defined inline within classes aren't parsed until we've
- // finished parsing the top-level class, so the top-level class is
- // the context we'll need to return to.
- // A Lambda call operator whose parent is a class must not be treated
- // as an inline member function. A Lambda can be used legally
- // either as an in-class member initializer or a default argument. These
- // are parsed once the class has been marked complete and so the containing
- // context would be the nested class (when the lambda is defined in one);
- // If the class is not complete, then the lambda is being used in an
- // ill-formed fashion (such as to specify the width of a bit-field, or
- // in an array-bound) - in which case we still want to return the
- // lexically containing DC (which could be a nested class).
- if (isa<FunctionDecl>(DC) && !isLambdaCallOperator(DC)) {
- DC = DC->getLexicalParent();
-
- // A function not defined within a class will always return to its
- // lexical context.
- if (!isa<CXXRecordDecl>(DC))
- return DC;
-
- // A C++ inline method/friend is parsed *after* the topmost class
- // it was declared in is fully parsed ("complete"); the topmost
- // class is the context we need to return to.
- while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent()))
- DC = RD;
-
- // Return the declaration context of the topmost class the inline method is
- // declared in.
- return DC;
- }
-
- return DC->getLexicalParent();
-}
-
void Sema::PushDeclContext(Scope *S, DeclContext *DC) {
- assert(getContainingDC(DC) == CurContext &&
+ assert(DC->getLexicalParent() == CurContext &&
"The next DeclContext should be lexically contained in the current one.");
CurContext = DC;
S->setEntity(DC);
@@ -1299,7 +1270,7 @@ void Sema::PushDeclContext(Scope *S, DeclContext *DC) {
void Sema::PopDeclContext() {
assert(CurContext && "DeclContext imbalance!");
- CurContext = getContainingDC(CurContext);
+ CurContext = CurContext->getLexicalParent();
assert(CurContext && "Popped translation unit!");
}
@@ -1351,6 +1322,12 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) {
CurContext = DC;
S->setEntity(DC);
+
+ if (S->getParent()->isTemplateParamScope()) {
+ // Also set the corresponding entities for all immediately-enclosing
+ // template parameter scopes.
+ EnterTemplatedContext(S->getParent(), DC);
+ }
}
void Sema::ExitDeclaratorContext(Scope *S) {
@@ -1366,6 +1343,49 @@ void Sema::ExitDeclaratorContext(Scope *S) {
// disappear.
}
+void Sema::EnterTemplatedContext(Scope *S, DeclContext *DC) {
+ assert(S->isTemplateParamScope() &&
+ "expected to be initializing a template parameter scope");
+
+ // C++20 [temp.local]p7:
+ // In the definition of a member of a class template that appears outside
+ // of the class template definition, the name of a member of the class
+ // template hides the name of a template-parameter of any enclosing class
+ // templates (but not a template-parameter of the member if the member is a
+ // class or function template).
+ // C++20 [temp.local]p9:
+ // In the definition of a class template or in the definition of a member
+ // of such a template that appears outside of the template definition, for
+ // each non-dependent base class (13.8.2.1), if the name of the base class
+ // or the name of a member of the base class is the same as the name of a
+ // template-parameter, the base class name or member name hides the
+ // template-parameter name (6.4.10).
+ //
+ // This means that a template parameter scope should be searched immediately
+ // after searching the DeclContext for which it is a template parameter
+ // scope. For example, for
+ // template<typename T> template<typename U> template<typename V>
+ // void N::A<T>::B<U>::f(...)
+ // we search V then B<U> (and base classes) then U then A<T> (and base
+ // classes) then T then N then ::.
+ unsigned ScopeDepth = getTemplateDepth(S);
+ for (; S && S->isTemplateParamScope(); S = S->getParent(), --ScopeDepth) {
+ DeclContext *SearchDCAfterScope = DC;
+ for (; DC; DC = DC->getLookupParent()) {
+ if (const TemplateParameterList *TPL =
+ cast<Decl>(DC)->getDescribedTemplateParams()) {
+ unsigned DCDepth = TPL->getDepth() + 1;
+ if (DCDepth > ScopeDepth)
+ continue;
+ if (ScopeDepth == DCDepth)
+ SearchDCAfterScope = DC = DC->getLookupParent();
+ break;
+ }
+ }
+ S->setLookupEntity(SearchDCAfterScope);
+ }
+}
+
void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
// We assume that the caller has already called
// ActOnReenterTemplateScope so getTemplatedDecl() works.
@@ -2586,11 +2606,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
- NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid());
+ NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl());
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
+ else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr))
+ NewAttr = S.mergeImportModuleAttr(D, *IMA);
+ else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
+ NewAttr = S.mergeImportNameAttr(D, *INA);
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
@@ -2707,6 +2731,18 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
--E;
continue;
}
+ } else if (isa<LoaderUninitializedAttr>(NewAttribute)) {
+ // If there is a C definition followed by a redeclaration with this
+ // attribute then there are two different definitions. In C++, prefer the
+ // standard diagnostics.
+ if (!S.getLangOpts().CPlusPlus) {
+ S.Diag(NewAttribute->getLocation(),
+ diag::err_loader_uninitialized_redeclaration);
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
+ NewAttributes.erase(NewAttributes.begin() + I);
+ --E;
+ continue;
+ }
} else if (isa<SelectAnyAttr>(NewAttribute) &&
cast<VarDecl>(New)->isInline() &&
!cast<VarDecl>(New)->isInlineSpecified()) {
@@ -2716,6 +2752,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
// honored it.
++I;
continue;
+ } else if (isa<OMPDeclareVariantAttr>(NewAttribute)) {
+ // We allow to add OMP[Begin]DeclareVariantAttr to be added to
+ // declarations after defintions.
+ ++I;
+ continue;
}
S.Diag(NewAttribute->getLocation(),
@@ -2736,23 +2777,21 @@ static void diagnoseMissingConstinit(Sema &S, const VarDecl *InitDecl,
// enough of the attribute list spelling information to extract that without
// heroics.
std::string SuitableSpelling;
- if (S.getLangOpts().CPlusPlus2a)
- SuitableSpelling =
- S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit});
+ if (S.getLangOpts().CPlusPlus20)
+ SuitableSpelling = std::string(
+ S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit}));
if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
- SuitableSpelling = S.PP.getLastMacroWithSpelling(
- InsertLoc,
- {tok::l_square, tok::l_square, S.PP.getIdentifierInfo("clang"),
- tok::coloncolon,
- S.PP.getIdentifierInfo("require_constant_initialization"),
- tok::r_square, tok::r_square});
+ SuitableSpelling = std::string(S.PP.getLastMacroWithSpelling(
+ InsertLoc, {tok::l_square, tok::l_square,
+ S.PP.getIdentifierInfo("clang"), tok::coloncolon,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_square, tok::r_square}));
if (SuitableSpelling.empty())
- SuitableSpelling = S.PP.getLastMacroWithSpelling(
- InsertLoc,
- {tok::kw___attribute, tok::l_paren, tok::r_paren,
- S.PP.getIdentifierInfo("require_constant_initialization"),
- tok::r_paren, tok::r_paren});
- if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus2a)
+ SuitableSpelling = std::string(S.PP.getLastMacroWithSpelling(
+ InsertLoc, {tok::kw___attribute, tok::l_paren, tok::r_paren,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_paren, tok::r_paren}));
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus20)
SuitableSpelling = "constinit";
if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
SuitableSpelling = "[[clang::require_constant_initialization]]";
@@ -3884,11 +3923,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
if (!NewArray->isIncompleteArrayType() && !NewArray->isDependentType()) {
for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD;
PrevVD = PrevVD->getPreviousDecl()) {
- const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType());
+ QualType PrevVDTy = PrevVD->getType();
if (PrevVDTy->isIncompleteArrayType() || PrevVDTy->isDependentType())
continue;
- if (!Context.hasSameType(NewArray, PrevVDTy))
+ if (!Context.hasSameType(New->getType(), PrevVDTy))
return diagnoseVarDeclTypeMismatch(*this, New, PrevVD);
}
}
@@ -4344,6 +4383,87 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) {
}
}
+namespace {
+struct NonCLikeKind {
+ enum {
+ None,
+ BaseClass,
+ DefaultMemberInit,
+ Lambda,
+ Friend,
+ OtherMember,
+ Invalid,
+ } Kind = None;
+ SourceRange Range;
+
+ explicit operator bool() { return Kind != None; }
+};
+}
+
+/// Determine whether a class is C-like, according to the rules of C++
+/// [dcl.typedef] for anonymous classes with typedef names for linkage.
+static NonCLikeKind getNonCLikeKindForAnonymousStruct(const CXXRecordDecl *RD) {
+ if (RD->isInvalidDecl())
+ return {NonCLikeKind::Invalid, {}};
+
+ // C++ [dcl.typedef]p9: [P1766R1]
+ // An unnamed class with a typedef name for linkage purposes shall not
+ //
+ // -- have any base classes
+ if (RD->getNumBases())
+ return {NonCLikeKind::BaseClass,
+ SourceRange(RD->bases_begin()->getBeginLoc(),
+ RD->bases_end()[-1].getEndLoc())};
+ bool Invalid = false;
+ for (Decl *D : RD->decls()) {
+ // Don't complain about things we already diagnosed.
+ if (D->isInvalidDecl()) {
+ Invalid = true;
+ continue;
+ }
+
+ // -- have any [...] default member initializers
+ if (auto *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->hasInClassInitializer()) {
+ auto *Init = FD->getInClassInitializer();
+ return {NonCLikeKind::DefaultMemberInit,
+ Init ? Init->getSourceRange() : D->getSourceRange()};
+ }
+ continue;
+ }
+
+ // FIXME: We don't allow friend declarations. This violates the wording of
+ // P1766, but not the intent.
+ if (isa<FriendDecl>(D))
+ return {NonCLikeKind::Friend, D->getSourceRange()};
+
+ // -- declare any members other than non-static data members, member
+ // enumerations, or member classes,
+ if (isa<StaticAssertDecl>(D) || isa<IndirectFieldDecl>(D) ||
+ isa<EnumDecl>(D))
+ continue;
+ auto *MemberRD = dyn_cast<CXXRecordDecl>(D);
+ if (!MemberRD) {
+ if (D->isImplicit())
+ continue;
+ return {NonCLikeKind::OtherMember, D->getSourceRange()};
+ }
+
+ // -- contain a lambda-expression,
+ if (MemberRD->isLambda())
+ return {NonCLikeKind::Lambda, MemberRD->getSourceRange()};
+
+ // and all member classes shall also satisfy these requirements
+ // (recursively).
+ if (MemberRD->isThisDeclarationADefinition()) {
+ if (auto Kind = getNonCLikeKindForAnonymousStruct(MemberRD))
+ return Kind;
+ }
+ }
+
+ return {Invalid ? NonCLikeKind::Invalid : NonCLikeKind::None, {}};
+}
+
void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
TypedefNameDecl *NewTD) {
if (TagFromDeclSpec->isInvalidDecl())
@@ -4364,27 +4484,51 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
return;
}
- // If we've already computed linkage for the anonymous tag, then
- // adding a typedef name for the anonymous decl can change that
- // linkage, which might be a serious problem. Diagnose this as
- // unsupported and ignore the typedef name. TODO: we should
- // pursue this as a language defect and establish a formal rule
- // for how to handle it.
- if (TagFromDeclSpec->hasLinkageBeenComputed()) {
- Diag(NewTD->getLocation(), diag::err_typedef_changes_linkage);
+ // C++ [dcl.typedef]p9: [P1766R1, applied as DR]
+ // An unnamed class with a typedef name for linkage purposes shall [be
+ // C-like].
+ //
+ // FIXME: Also diagnose if we've already computed the linkage. That ideally
+ // shouldn't happen, but there are constructs that the language rule doesn't
+ // disallow for which we can't reasonably avoid computing linkage early.
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TagFromDeclSpec);
+ NonCLikeKind NonCLike = RD ? getNonCLikeKindForAnonymousStruct(RD)
+ : NonCLikeKind();
+ bool ChangesLinkage = TagFromDeclSpec->hasLinkageBeenComputed();
+ if (NonCLike || ChangesLinkage) {
+ if (NonCLike.Kind == NonCLikeKind::Invalid)
+ return;
+
+ unsigned DiagID = diag::ext_non_c_like_anon_struct_in_typedef;
+ if (ChangesLinkage) {
+ // If the linkage changes, we can't accept this as an extension.
+ if (NonCLike.Kind == NonCLikeKind::None)
+ DiagID = diag::err_typedef_changes_linkage;
+ else
+ DiagID = diag::err_non_c_like_anon_struct_in_typedef;
+ }
- SourceLocation tagLoc = TagFromDeclSpec->getInnerLocStart();
- tagLoc = getLocForEndOfToken(tagLoc);
+ SourceLocation FixitLoc =
+ getLocForEndOfToken(TagFromDeclSpec->getInnerLocStart());
+ llvm::SmallString<40> TextToInsert;
+ TextToInsert += ' ';
+ TextToInsert += NewTD->getIdentifier()->getName();
- llvm::SmallString<40> textToInsert;
- textToInsert += ' ';
- textToInsert += NewTD->getIdentifier()->getName();
- Diag(tagLoc, diag::note_typedef_changes_linkage)
- << FixItHint::CreateInsertion(tagLoc, textToInsert);
- return;
+ Diag(FixitLoc, DiagID)
+ << isa<TypeAliasDecl>(NewTD)
+ << FixItHint::CreateInsertion(FixitLoc, TextToInsert);
+ if (NonCLike.Kind != NonCLikeKind::None) {
+ Diag(NonCLike.Range.getBegin(), diag::note_non_c_like_anon_struct)
+ << NonCLike.Kind - 1 << NonCLike.Range;
+ }
+ Diag(NewTD->getLocation(), diag::note_typedef_for_linkage_here)
+ << NewTD << isa<TypeAliasDecl>(NewTD);
+
+ if (ChangesLinkage)
+ return;
}
- // Otherwise, set this is the anon-decl typedef for the tag.
+ // Otherwise, set this as the anon-decl typedef for the tag.
TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
}
@@ -4915,6 +5059,10 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// define non-static data members. [Note: nested types and
// functions cannot be declared within an anonymous union. ]
for (auto *Mem : Record->decls()) {
+ // Ignore invalid declarations; we already diagnosed them.
+ if (Mem->isInvalidDecl())
+ continue;
+
if (auto *FD = dyn_cast<FieldDecl>(Mem)) {
// C++ [class.union]p3:
// An anonymous union shall not have private or protected
@@ -5138,8 +5286,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
Chain.push_back(Anon);
RecordDecl *RecordDef = Record->getDefinition();
- if (RequireCompleteType(Anon->getLocation(), RecTy,
- diag::err_field_incomplete) ||
+ if (RequireCompleteSizedType(Anon->getLocation(), RecTy,
+ diag::err_field_incomplete_or_sizeless) ||
InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef,
AS_none, Chain)) {
Anon->setInvalidDecl();
@@ -6142,6 +6290,8 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) {
if (Decl->getType().hasAddressSpace())
return;
+ if (Decl->getType()->isDependentType())
+ return;
if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) {
QualType Type = Var->getType();
if (Type->isSamplerT() || Type->isVoidType())
@@ -6468,6 +6618,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
return true;
if (DC->isRecord())
return false;
+ if (isa<RequiresExprBodyDecl>(DC))
+ return false;
llvm_unreachable("Unexpected context");
}
@@ -6753,28 +6905,49 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
- if (RD->isLocalClass())
+ // Walk up the enclosing DeclContexts to check for any that are
+ // incompatible with static data members.
+ const DeclContext *FunctionOrMethod = nullptr;
+ const CXXRecordDecl *AnonStruct = nullptr;
+ for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) {
+ if (Ctxt->isFunctionOrMethod()) {
+ FunctionOrMethod = Ctxt;
+ break;
+ }
+ const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt);
+ if (ParentDecl && !ParentDecl->getDeclName()) {
+ AnonStruct = ParentDecl;
+ break;
+ }
+ }
+ if (FunctionOrMethod) {
+ // C++ [class.static.data]p5: A local class shall not have static data
+ // members.
Diag(D.getIdentifierLoc(),
diag::err_static_data_member_not_allowed_in_local_class)
- << Name << RD->getDeclName();
-
- // C++98 [class.union]p1: If a union contains a static data member,
- // the program is ill-formed. C++11 drops this restriction.
- if (RD->isUnion())
+ << Name << RD->getDeclName() << RD->getTagKind();
+ } else if (AnonStruct) {
+ // C++ [class.static.data]p4: Unnamed classes and classes contained
+ // directly or indirectly within unnamed classes shall not contain
+ // static data members.
+ Diag(D.getIdentifierLoc(),
+ diag::err_static_data_member_not_allowed_in_anon_struct)
+ << Name << AnonStruct->getTagKind();
+ Invalid = true;
+ } else if (RD->isUnion()) {
+ // C++98 [class.union]p1: If a union contains a static data member,
+ // the program is ill-formed. C++11 drops this restriction.
Diag(D.getIdentifierLoc(),
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_static_data_member_in_union
: diag::ext_static_data_member_in_union) << Name;
- // We conservatively disallow static data members in anonymous structs.
- else if (!RD->getDeclName())
- Diag(D.getIdentifierLoc(),
- diag::err_static_data_member_not_allowed_in_anon_struct)
- << Name << RD->isUnion();
+ }
}
}
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
+ bool InvalidScope = false;
TemplateParams = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
D.getCXXScopeSpec(),
@@ -6782,7 +6955,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? D.getName().TemplateId
: nullptr,
TemplateParamLists,
- /*never a friend*/ false, IsMemberSpecialization, Invalid);
+ /*never a friend*/ false, IsMemberSpecialization, InvalidScope);
+ Invalid |= InvalidScope;
if (TemplateParams) {
if (!TemplateParams->size() &&
@@ -6918,7 +7092,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
diag::err_thread_non_global)
<< DeclSpec::getSpecifierName(TSCS);
else if (!Context.getTargetInfo().isTLSSupported()) {
- if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice ||
+ getLangOpts().SYCLIsDevice) {
// Postpone error emission until we've collected attributes required to
// figure out whether it's a host or device variable and whether the
// error should be ignored.
@@ -6946,6 +7121,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
case CSK_constexpr:
NewVD->setConstexpr(true);
+ MaybeAddCUDAConstantAttr(NewVD);
// C++1z [dcl.spec.constexpr]p1:
// A static data member declared with the constexpr specifier is
// implicitly an inline variable.
@@ -7019,13 +7195,18 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
- if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) {
+ if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice ||
+ getLangOpts().SYCLIsDevice) {
if (EmitTLSUnsupportedError &&
((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
(getLangOpts().OpenMPIsDevice &&
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD))))
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
+
+ if (EmitTLSUnsupportedError &&
+ (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)))
+ targetDiag(D.getIdentifierLoc(), diag::err_thread_unsupported);
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
// storage [duration]."
if (SC == SC_None && S->getFnParent() != nullptr &&
@@ -7680,6 +7861,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() ||
NewVD->hasExternalStorage()) {
if (!T->isSamplerT() &&
+ !T->isDependentType() &&
!(T.getAddressSpace() == LangAS::opencl_constant ||
(T.getAddressSpace() == LangAS::opencl_global &&
(getLangOpts().OpenCLVersion == 200 ||
@@ -7822,6 +8004,12 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
+ if (!NewVD->hasLocalStorage() && T->isSizelessType()) {
+ Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
+ NewVD->setInvalidDecl();
+ return;
+ }
+
if (isVM && NewVD->hasAttr<BlocksAttr>()) {
Diag(NewVD->getLocation(), diag::err_block_on_vm);
NewVD->setInvalidDecl();
@@ -7909,30 +8097,8 @@ struct FindOverriddenMethod {
return false;
}
};
-
-enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted };
} // end anonymous namespace
-/// Report an error regarding overriding, along with any relevant
-/// overridden methods.
-///
-/// \param DiagID the primary error to report.
-/// \param MD the overriding method.
-/// \param OEK which overrides to include as notes.
-static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
- OverrideErrorKind OEK = OEK_All) {
- S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
- for (const CXXMethodDecl *O : MD->overridden_methods()) {
- // This check (& the OEK parameter) could be replaced by a predicate, but
- // without lambdas that would be overkill. This is still nicer than writing
- // out the diag loop 3 times.
- if ((OEK == OEK_All) ||
- (OEK == OEK_NonDeleted && !O->isDeleted()) ||
- (OEK == OEK_Deleted && O->isDeleted()))
- S.Diag(O->getLocation(), diag::note_overridden_virtual_function);
- }
-}
-
/// AddOverriddenMethods - See if a method overrides any in the base classes,
/// and if so, check that it's a valid override and remember it.
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -7941,8 +8107,6 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
FindOverriddenMethod FOM;
FOM.Method = MD;
FOM.S = this;
- bool hasDeletedOverridenMethods = false;
- bool hasNonDeletedOverridenMethods = false;
bool AddedAny = false;
if (DC->lookupInBases(FOM, Paths)) {
for (auto *I : Paths.found_decls()) {
@@ -7952,21 +8116,12 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
!CheckOverridingFunctionAttributes(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
- hasDeletedOverridenMethods |= OldMD->isDeleted();
- hasNonDeletedOverridenMethods |= !OldMD->isDeleted();
AddedAny = true;
}
}
}
}
- if (hasDeletedOverridenMethods && !MD->isDeleted()) {
- ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted);
- }
- if (hasNonDeletedOverridenMethods && MD->isDeleted()) {
- ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted);
- }
-
return AddedAny;
}
@@ -8654,11 +8809,24 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
+ MultiTemplateParamsArg TemplateParamListsRef,
bool &AddToScope) {
QualType R = TInfo->getType();
assert(R->isFunctionType());
+ if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr())
+ Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
+
+ SmallVector<TemplateParameterList *, 4> TemplateParamLists;
+ for (TemplateParameterList *TPL : TemplateParamListsRef)
+ TemplateParamLists.push_back(TPL);
+ if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
+ if (!TemplateParamLists.empty() &&
+ Invented->getDepth() == TemplateParamLists.back()->getDepth())
+ TemplateParamLists.back() = Invented;
+ else
+ TemplateParamLists.push_back(Invented);
+ }
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
@@ -8738,15 +8906,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
- if (TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(),
- D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
- ? D.getName().TemplateId
- : nullptr,
- TemplateParamLists, isFriend, isMemberSpecialization,
- Invalid)) {
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
+ ? D.getName().TemplateId
+ : nullptr,
+ TemplateParamLists, isFriend, isMemberSpecialization,
+ Invalid);
+ if (TemplateParams) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -8779,7 +8948,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.drop_back(1));
+ ArrayRef<TemplateParameterList *>(TemplateParamLists)
+ .drop_back(1));
}
} else {
// This is a function template specialization.
@@ -8914,9 +9084,24 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++11 [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
- if (isa<CXXDestructorDecl>(NewFD) && !getLangOpts().CPlusPlus2a) {
+ if (isa<CXXDestructorDecl>(NewFD) &&
+ (!getLangOpts().CPlusPlus20 || ConstexprKind == CSK_consteval)) {
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
<< ConstexprKind;
+ NewFD->setConstexprKind(getLangOpts().CPlusPlus20 ? CSK_unspecified : CSK_constexpr);
+ }
+ // C++20 [dcl.constexpr]p2: An allocation function, or a
+ // deallocation function shall not be declared with the consteval
+ // specifier.
+ if (ConstexprKind == CSK_consteval &&
+ (NewFD->getOverloadedOperator() == OO_New ||
+ NewFD->getOverloadedOperator() == OO_Array_New ||
+ NewFD->getOverloadedOperator() == OO_Delete ||
+ NewFD->getOverloadedOperator() == OO_Array_Delete)) {
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_invalid_consteval_decl_kind)
+ << NewFD;
+ NewFD->setConstexprKind(CSK_constexpr);
}
}
@@ -8945,8 +9130,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// If a function is defined as defaulted or deleted, mark it as such now.
- // FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function
- // definition kind to FDK_Definition.
+ // We'll do the relevant checks on defaulted / deleted functions later.
switch (D.getFunctionDefinitionKind()) {
case FDK_Declaration:
case FDK_Definition:
@@ -9808,6 +9992,18 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
return false;
}
+// Provide a white-list of attributes that are allowed to be combined with
+// multiversion functions.
+static bool AttrCompatibleWithMultiVersion(attr::Kind Kind,
+ MultiVersionKind MVType) {
+ switch (Kind) {
+ default:
+ return false;
+ case attr::Used:
+ return MVType == MultiVersionKind::Target;
+ }
+}
+
static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
MultiVersionKind MVType) {
for (const Attr *A : FD->attrs()) {
@@ -9823,7 +10019,9 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
return true;
break;
default:
- return true;
+ if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
+ return true;
+ break;
}
}
return false;
@@ -10562,9 +10760,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
return Redeclaration;
}
}
- } else if (CXXConversionDecl *Conversion
- = dyn_cast<CXXConversionDecl>(NewFD)) {
- ActOnConversionDeclarator(Conversion);
} else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(NewFD)) {
if (auto *TD = Guide->getDescribedFunctionTemplate())
CheckDeductionGuideTemplate(TD);
@@ -10581,12 +10776,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (!Method->isFunctionTemplateSpecialization() &&
!Method->getDescribedFunctionTemplate() &&
Method->isCanonicalDecl()) {
- if (AddOverriddenMethods(Method->getParent(), Method)) {
- // If the function was marked as "static", we have a problem.
- if (NewFD->getStorageClass() == SC_Static) {
- ReportOverrides(*this, diag::err_static_overrides_virtual, Method);
- }
- }
+ AddOverriddenMethods(Method->getParent(), Method);
}
if (Method->isVirtual() && NewFD->getTrailingRequiresClause())
// C++2a [class.virtual]p6
@@ -10598,6 +10788,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
checkThisInStaticMemberFunctionType(Method);
}
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
+ ActOnConversionDeclarator(Conversion);
+
// Extra checking for C++ overloaded operators (C++ [over.oper]).
if (NewFD->isOverloadedOperator() &&
CheckOverloadedOperatorDeclaration(NewFD)) {
@@ -11363,6 +11556,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
Expr *Init) {
+ assert(!Init || !Init->containsErrors());
QualType DeducedType = deduceVarTypeFromInitializer(
VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(),
VDecl->getSourceRange(), DirectInit, Init);
@@ -11396,6 +11590,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
SourceLocation Loc) {
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr();
+
if (auto *CE = dyn_cast<ConstantExpr>(Init))
Init = CE->getSubExpr();
@@ -11698,7 +11895,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// TypoExpr.
ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl);
if (!Res.isUsable()) {
+ // There are unresolved typos in Init, just drop them.
+ // FIXME: improve the recovery strategy to preserve the Init.
+ RealDecl->setInvalidDecl();
+ return;
+ }
+ if (Res.get()->containsErrors()) {
+ // Invalidate the decl as we don't know the type for recovery-expr yet.
RealDecl->setInvalidDecl();
+ VDecl->setInit(Res.get());
return;
}
Init = Res.get();
@@ -11790,6 +11995,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}
+ // The LoaderUninitialized attribute acts as a definition (of undef).
+ if (VDecl->hasAttr<LoaderUninitializedAttr>()) {
+ Diag(VDecl->getLocation(), diag::err_loader_uninitialized_cant_init);
+ VDecl->setInvalidDecl();
+ return;
+ }
+
// Get the decls type and save a reference for later, since
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
@@ -11821,7 +12033,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Try to correct any TypoExprs in the initialization arguments.
for (size_t Idx = 0; Idx < Args.size(); ++Idx) {
ExprResult Res = CorrectDelayedTyposInExpr(
- Args[Idx], VDecl, [this, Entity, Kind](Expr *E) {
+ Args[Idx], VDecl, /*RecoverUncorrectedTypos=*/false,
+ [this, Entity, Kind](Expr *E) {
InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E));
return Init.Failed() ? ExprError() : E;
});
@@ -11839,7 +12052,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
/*TreatUnavailableAsInvalid=*/false);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
+ // If the provied initializer fails to initialize the var decl,
+ // we attach a recovery expr for better recovery.
+ auto RecoveryExpr =
+ CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args);
+ if (RecoveryExpr.get())
+ VDecl->setInit(RecoveryExpr.get());
return;
}
@@ -12100,6 +12318,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
VDecl->setInitStyle(VarDecl::ListInit);
}
+ if (LangOpts.OpenMP && VDecl->isFileVarDecl())
+ DeclsToCheckForDeferredDiags.push_back(VDecl);
CheckCompleteVariableDeclaration(VDecl);
}
@@ -12120,7 +12340,7 @@ void Sema::ActOnInitializerError(Decl *D) {
BD->setInvalidDecl();
// Auto types are meaningless if we can't make sense of the initializer.
- if (ParsingInitForAutoVars.count(D)) {
+ if (VD->getType()->isUndeducedType()) {
D->setInvalidDecl();
return;
}
@@ -12203,6 +12423,22 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
return;
}
+ if (!Var->isInvalidDecl() && RealDecl->hasAttr<LoaderUninitializedAttr>()) {
+ if (CXXRecordDecl *RD = Var->getType()->getAsCXXRecordDecl()) {
+ if (!RD->hasTrivialDefaultConstructor()) {
+ Diag(Var->getLocation(), diag::err_loader_uninitialized_trivial_ctor);
+ Var->setInvalidDecl();
+ return;
+ }
+ }
+ if (Var->getStorageClass() == SC_Extern) {
+ Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl)
+ << Var;
+ Var->setInvalidDecl();
+ return;
+ }
+ }
+
VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition();
if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly &&
Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion())
@@ -12260,9 +12496,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (!Var->isInvalidDecl()) {
if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(Type)) {
- if (RequireCompleteType(Var->getLocation(),
- ArrayT->getElementType(),
- diag::err_illegal_decl_array_incomplete_type))
+ if (RequireCompleteSizedType(
+ Var->getLocation(), ArrayT->getElementType(),
+ diag::err_array_incomplete_or_sizeless_type))
Var->setInvalidDecl();
} else if (Var->getStorageClass() == SC_Static) {
// C99 6.9.2p3: If the declaration of an identifier for an object is
@@ -12378,12 +12614,18 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
InitializationSequence InitSeq(*this, Entity, Kind, None);
ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None);
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else if (Init.get()) {
+
+ if (Init.get()) {
Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
// This is important for template substitution.
Var->setInitStyle(VarDecl::CallInit);
+ } else if (Init.isInvalid()) {
+ // If default-init fails, attach a recovery-expr initializer to track
+ // that initialization was attempted and failed.
+ auto RecoveryExpr =
+ CreateRecoveryExpr(Var->getLocation(), Var->getLocation(), {});
+ if (RecoveryExpr.get())
+ Var->setInit(RecoveryExpr.get());
}
CheckCompleteVariableDeclaration(Var);
@@ -12507,6 +12749,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
var->getDeclContext()->getRedeclContext()->isFileContext() &&
var->isExternallyVisible() && var->hasLinkage() &&
!var->isInline() && !var->getDescribedVarTemplate() &&
+ !isa<VarTemplatePartialSpecializationDecl>(var) &&
!isTemplateInstantiation(var->getTemplateSpecializationKind()) &&
!getDiagnostics().isIgnored(diag::warn_missing_variable_declarations,
var->getLocation())) {
@@ -12559,7 +12802,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (GlobalStorage && var->isThisDeclarationADefinition() &&
!inTemplateInstantiation()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
- int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
+ int SectionFlags = ASTContext::PSF_Read;
if (var->getType().isConstQualified())
Stack = &ConstSegStack;
else if (!var->getInit()) {
@@ -12569,14 +12812,19 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Stack = &DataSegStack;
SectionFlags |= ASTContext::PSF_Write;
}
- if (Stack->CurrentValue && !var->hasAttr<SectionAttr>())
+ if (const SectionAttr *SA = var->getAttr<SectionAttr>()) {
+ if (SA->getSyntax() == AttributeCommonInfo::AS_Declspec)
+ SectionFlags |= ASTContext::PSF_Implicit;
+ UnifySection(SA->getName(), SectionFlags, var);
+ } else if (Stack->CurrentValue) {
+ SectionFlags |= ASTContext::PSF_Implicit;
+ auto SectionName = Stack->CurrentValue->getString();
var->addAttr(SectionAttr::CreateImplicit(
- Context, Stack->CurrentValue->getString(),
- Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
- SectionAttr::Declspec_allocate));
- if (const SectionAttr *SA = var->getAttr<SectionAttr>())
- if (UnifySection(SA->getName(), SectionFlags, var))
+ Context, SectionName, Stack->CurrentPragmaLocation,
+ AttributeCommonInfo::AS_Pragma, SectionAttr::Declspec_allocate));
+ if (UnifySection(SectionName, SectionFlags, var))
var->dropAttr<SectionAttr>();
+ }
// Apply the init_seg attribute if this has an initializer. If the
// initializer turns out to not be dynamic, we'll end up ignoring this
@@ -13013,13 +13261,15 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group) {
DeducedDecl = D;
} else if (!Context.hasSameType(DT->getDeducedType(), Deduced)) {
auto *AT = dyn_cast<AutoType>(DT);
- Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
- diag::err_auto_different_deductions)
- << (AT ? (unsigned)AT->getKeyword() : 3)
- << Deduced << DeducedDecl->getDeclName()
- << DT->getDeducedType() << D->getDeclName()
- << DeducedDecl->getInit()->getSourceRange()
- << D->getInit()->getSourceRange();
+ auto Dia = Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_auto_different_deductions)
+ << (AT ? (unsigned)AT->getKeyword() : 3) << Deduced
+ << DeducedDecl->getDeclName() << DT->getDeducedType()
+ << D->getDeclName();
+ if (DeducedDecl->hasInit())
+ Dia << DeducedDecl->getInit()->getSourceRange();
+ if (D->getInit())
+ Dia << D->getInit()->getSourceRange();
D->setInvalidDecl();
break;
}
@@ -13398,9 +13648,28 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
+ // Check if we are in an `omp begin/end declare variant` scope. If we are, and
+ // we define a non-templated function definition, we will create a declaration
+ // instead (=BaseFD), and emit the definition with a mangled name afterwards.
+ // The base function declaration will have the equivalent of an `omp declare
+ // variant` annotation which specifies the mangled definition as a
+ // specialization function under the OpenMP context defined as part of the
+ // `omp begin declare variant`.
+ FunctionDecl *BaseFD = nullptr;
+ if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope() &&
+ TemplateParameterLists.empty())
+ BaseFD = ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
+ ParentScope, D);
+
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists);
- return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
+ Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
+
+ if (BaseFD)
+ ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
+ cast<FunctionDecl>(Dcl), BaseFD);
+
+ return Dcl;
}
void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
@@ -13593,13 +13862,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
VarDecl *VD = C.getCapturedVar();
if (VD->isInitCapture())
S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
- QualType CaptureType = VD->getType();
const bool ByRef = C.getCaptureKind() == LCK_ByRef;
LSI->addCapture(VD, /*IsBlock*/false, ByRef,
/*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
/*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
- CaptureType, /*Invalid*/false);
+ I->getType(), /*Invalid*/false);
} else if (C.capturesThis()) {
LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(),
@@ -13632,7 +13900,9 @@ 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))
- PushExpressionEvaluationContext(ExprEvalContexts.back().Context);
+ PushExpressionEvaluationContext(
+ FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated
+ : ExprEvalContexts.back().Context);
// Check for defining attributes before the check for redefinition.
if (const auto *Attr = FD->getAttr<AliasAttr>()) {
@@ -13996,11 +14266,48 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
: FixItHint{});
}
} else {
+ // Returns true if the token beginning at this Loc is `const`.
+ auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (LocInfo.first.isInvalid())
+ return false;
+
+ bool Invalid = false;
+ StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return false;
+
+ if (LocInfo.second > Buffer.size())
+ return false;
+
+ const char *LexStart = Buffer.data() + LocInfo.second;
+ StringRef StartTok(LexStart, Buffer.size() - LocInfo.second);
+
+ return StartTok.consume_front("const") &&
+ (StartTok.empty() || isWhitespace(StartTok[0]) ||
+ StartTok.startswith("/*") || StartTok.startswith("//"));
+ };
+
+ auto findBeginLoc = [&]() {
+ // If the return type has `const` qualifier, we want to insert
+ // `static` before `const` (and not before the typename).
+ if ((FD->getReturnType()->isAnyPointerType() &&
+ FD->getReturnType()->getPointeeType().isConstQualified()) ||
+ FD->getReturnType().isConstQualified()) {
+ // But only do this if we can determine where the `const` is.
+
+ if (isLocAtConst(FD->getBeginLoc(), getSourceManager(),
+ getLangOpts()))
+
+ return FD->getBeginLoc();
+ }
+ return FD->getTypeSpecStartLoc();
+ };
Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage)
<< /* function */ 1
<< (FD->getStorageClass() == SC_None
- ? FixItHint::CreateInsertion(FD->getTypeSpecStartLoc(),
- "static ")
+ ? FixItHint::CreateInsertion(findBeginLoc(), "static ")
: FixItHint{});
}
@@ -14008,11 +14315,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Warn if K&R function is defined without a previous declaration.
// This warning is issued only if the definition itself does not provide
// a prototype. Only K&R definitions do not provide a prototype.
- // An empty list in a function declarator that is part of a definition
- // of that function specifies that the function has no parameters
- // (C99 6.7.5.3p14)
- if (!FD->hasWrittenPrototype() && FD->getNumParams() > 0 &&
- !LangOpts.CPlusPlus) {
+ if (!FD->hasWrittenPrototype()) {
TypeSourceInfo *TI = FD->getTypeSourceInfo();
TypeLoc TL = TI->getTypeLoc();
FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
@@ -14142,7 +14445,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred() ||
+ if (getDiagnostics().hasUncompilableErrorOccurred() ||
getDiagnostics().getSuppressAllDiagnostics()) {
DiscardCleanupsInEvaluationContext();
}
@@ -14198,10 +14501,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred()) {
+ if (getDiagnostics().hasUncompilableErrorOccurred()) {
DiscardCleanupsInEvaluationContext();
}
+ if (LangOpts.OpenMP || LangOpts.CUDA || LangOpts.SYCLIsDevice) {
+ auto ES = getEmissionStatus(FD);
+ if (ES == Sema::FunctionEmissionStatus::Emitted ||
+ ES == Sema::FunctionEmissionStatus::Unknown)
+ DeclsToCheckForDeferredDiags.push_back(FD);
+ }
+
return dcl;
}
@@ -14333,6 +14643,77 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
return FD;
}
+/// If this function is a C++ replaceable global allocation function
+/// (C++2a [basic.stc.dynamic.allocation], C++2a [new.delete]),
+/// adds any function attributes that we know a priori based on the standard.
+///
+/// We need to check for duplicate attributes both here and where user-written
+/// attributes are applied to declarations.
+void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
+ FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
+ return;
+
+ if (FD->getDeclName().getCXXOverloadedOperator() != OO_New &&
+ FD->getDeclName().getCXXOverloadedOperator() != OO_Array_New)
+ return;
+
+ Optional<unsigned> AlignmentParam;
+ bool IsNothrow = false;
+ if (!FD->isReplaceableGlobalAllocationFunction(&AlignmentParam, &IsNothrow))
+ return;
+
+ // C++2a [basic.stc.dynamic.allocation]p4:
+ // An allocation function that has a non-throwing exception specification
+ // indicates failure by returning a null pointer value. Any other allocation
+ // function never returns a null pointer value and indicates failure only by
+ // throwing an exception [...]
+ if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>())
+ FD->addAttr(ReturnsNonNullAttr::CreateImplicit(Context, FD->getLocation()));
+
+ // C++2a [basic.stc.dynamic.allocation]p2:
+ // An allocation function attempts to allocate the requested amount of
+ // storage. [...] If the request succeeds, the value returned by a
+ // replaceable allocation function is a [...] pointer value p0 different
+ // from any previously returned value p1 [...]
+ //
+ // However, this particular information is being added in codegen,
+ // because there is an opt-out switch for it (-fno-assume-sane-operator-new)
+
+ // C++2a [basic.stc.dynamic.allocation]p2:
+ // An allocation function attempts to allocate the requested amount of
+ // storage. If it is successful, it returns the address of the start of a
+ // block of storage whose length in bytes is at least as large as the
+ // requested size.
+ if (!FD->hasAttr<AllocSizeAttr>()) {
+ FD->addAttr(AllocSizeAttr::CreateImplicit(
+ Context, /*ElemSizeParam=*/ParamIdx(1, FD),
+ /*NumElemsParam=*/ParamIdx(), FD->getLocation()));
+ }
+
+ // C++2a [basic.stc.dynamic.allocation]p3:
+ // For an allocation function [...], the pointer returned on a successful
+ // call shall represent the address of storage that is aligned as follows:
+ // (3.1) If the allocation function takes an argument of type
+ // std​::​align_­val_­t, the storage will have the alignment
+ // specified by the value of this argument.
+ if (AlignmentParam.hasValue() && !FD->hasAttr<AllocAlignAttr>()) {
+ FD->addAttr(AllocAlignAttr::CreateImplicit(
+ Context, ParamIdx(AlignmentParam.getValue(), FD), FD->getLocation()));
+ }
+
+ // FIXME:
+ // C++2a [basic.stc.dynamic.allocation]p3:
+ // For an allocation function [...], the pointer returned on a successful
+ // call shall represent the address of storage that is aligned as follows:
+ // (3.2) Otherwise, if the allocation function is named operator new[],
+ // the storage is aligned for any object that does not have
+ // new-extended alignment ([basic.align]) and is no larger than the
+ // requested size.
+ // (3.3) Otherwise, the storage is aligned for any object that does not
+ // have new-extended alignment and is of the requested size.
+}
+
/// Adds any function attributes that we know a priori based on
/// the declaration of this function.
///
@@ -14433,6 +14814,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
}
+ AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
+
// If C++ exceptions are enabled but we are told extern "C" functions cannot
// throw, add an implicit nothrow attribute to any extern "C" function we come
// across.
@@ -14538,12 +14921,16 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
if (T->isDependentType())
return false;
+ // This doesn't use 'isIntegralType' despite the error message mentioning
+ // integral type because isIntegralType would also allow enum types in C.
if (const BuiltinType *BT = T->getAs<BuiltinType>())
if (BT->isInteger())
return false;
- Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
- return true;
+ if (T->isExtIntType())
+ return false;
+
+ return Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
}
/// Check whether this is a valid redeclaration of a previous enumeration.
@@ -15302,16 +15689,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
-
- // If this is an elaborated-type-specifier for a scoped enumeration,
- // the 'class' keyword is not necessary and not permitted.
- if (TUK == TUK_Reference || TUK == TUK_Friend) {
- if (ScopedEnum)
- Diag(ScopedEnumKWLoc, diag::err_enum_class_reference)
- << PrevEnum->isScoped()
- << FixItHint::CreateRemoval(ScopedEnumKWLoc);
+ if (TUK == TUK_Reference || TUK == TUK_Friend)
return PrevTagDecl;
- }
QualType EnumUnderlyingTy;
if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
@@ -15789,7 +16168,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
assert(isa<ObjCContainerDecl>(IDecl) &&
"ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
DeclContext *OCD = cast<DeclContext>(IDecl);
- assert(getContainingDC(OCD) == CurContext &&
+ assert(OCD->getLexicalParent() == CurContext &&
"The next DeclContext should be lexically contained in the current one.");
CurContext = OCD;
return IDecl;
@@ -15900,6 +16279,10 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
IdentifierInfo *FieldName,
QualType FieldTy, bool IsMsStruct,
Expr *BitWidth, bool *ZeroWidth) {
+ assert(BitWidth);
+ if (BitWidth->containsErrors())
+ return ExprError();
+
// Default to true; that shouldn't confuse checks for emptiness
if (ZeroWidth)
*ZeroWidth = true;
@@ -15907,8 +16290,9 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
// C99 6.7.2.1p4 - verify the field type.
// C++ 9.6p3: A bit-field shall have integral or enumeration type.
if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) {
- // Handle incomplete types with specific error.
- if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete))
+ // Handle incomplete and sizeless types with a specific error.
+ if (RequireCompleteSizedType(FieldLoc, FieldTy,
+ diag::err_field_incomplete_or_sizeless))
return ExprError();
if (FieldName)
return Diag(FieldLoc, diag::err_not_integral_type_bitfield)
@@ -16118,14 +16502,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// If we receive a broken type, recover by assuming 'int' and
// marking this declaration as invalid.
- if (T.isNull()) {
+ if (T.isNull() || T->containsErrors()) {
InvalidDecl = true;
T = Context.IntTy;
}
QualType EltTy = Context.getBaseElementType(T);
- if (!EltTy->isDependentType()) {
- if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) {
+ if (!EltTy->isDependentType() && !EltTy->containsErrors()) {
+ if (RequireCompleteSizedType(Loc, EltTy,
+ diag::err_field_incomplete_or_sizeless)) {
// Fields of incomplete type force their record to be invalid.
Record->setInvalidDecl();
InvalidDecl = true;
@@ -16214,6 +16599,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
BitWidth = nullptr;
ZeroWidth = false;
}
+
+ // Only data members can have in-class initializers.
+ if (BitWidth && !II && InitStyle) {
+ Diag(Loc, diag::err_anon_bitfield_init);
+ InvalidDecl = true;
+ BitWidth = nullptr;
+ ZeroWidth = false;
+ }
}
// Check that 'mutable' is consistent with the type of the declaration.
@@ -16669,8 +17062,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// elsewhere, after synthesized ivars are known.
}
} else if (!FDTy->isDependentType() &&
- RequireCompleteType(FD->getLocation(), FD->getType(),
- diag::err_field_incomplete)) {
+ RequireCompleteSizedType(
+ FD->getLocation(), FD->getType(),
+ diag::err_field_incomplete_or_sizeless)) {
// Incomplete type
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
@@ -16728,8 +17122,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Context, "", UnavailableAttr::IR_ARCFieldWithOwnership,
FD->getLocation()));
} else if (getLangOpts().ObjC &&
- getLangOpts().getGC() != LangOptions::NonGC &&
- Record && !Record->hasObjectMember()) {
+ getLangOpts().getGC() != LangOptions::NonGC && Record &&
+ !Record->hasObjectMember()) {
if (FD->getType()->isObjCObjectPointerType() ||
FD->getType().isObjCGCStrong())
Record->setHasObjectMember(true);
@@ -16793,10 +17187,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
I.setAccess((*I)->getAccess());
}
- if (!CXXRecord->isDependentType()) {
- // Add any implicitly-declared members to this class.
- AddImplicitlyDeclaredMembersToClass(CXXRecord);
+ // Add any implicitly-declared members to this class.
+ AddImplicitlyDeclaredMembersToClass(CXXRecord);
+ if (!CXXRecord->isDependentType()) {
if (!CXXRecord->isInvalidDecl()) {
// If we have virtual base classes, we may end up finding multiple
// final overriders for a given virtual function. Check for this
@@ -17355,9 +17749,11 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
typedef SmallVector<std::unique_ptr<ECDVector>, 3> DuplicatesVector;
typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector;
+
+ // DenseMaps cannot contain the all ones int64_t value, so use unordered_map.
typedef std::unordered_map<int64_t, DeclOrVector> ValueToVectorMap;
- // Use int64_t as a key to avoid needing special handling for DenseMap keys.
+ // Use int64_t as a key to avoid needing special handling for map keys.
auto EnumConstantToKey = [](const EnumConstantDecl *D) {
llvm::APSInt Val = D->getInitVal();
return Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue();
@@ -17787,7 +18183,13 @@ Decl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
-Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
+Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
+ bool Final) {
+ // SYCL functions can be template, so we check if they have appropriate
+ // attribute prior to checking if it is a template.
+ if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelAttr>())
+ return FunctionEmissionStatus::Emitted;
+
// Templates are emitted when they're instantiated.
if (FD->isDependentContext())
return FunctionEmissionStatus::TemplateDiscarded;
@@ -17799,8 +18201,10 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
if (DevTy.hasValue()) {
if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
OMPES = FunctionEmissionStatus::OMPDiscarded;
- else if (DeviceKnownEmittedFns.count(FD) > 0)
+ else if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost ||
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Any) {
OMPES = FunctionEmissionStatus::Emitted;
+ }
}
} else if (LangOpts.OpenMP) {
// In OpenMP 4.5 all the functions are host functions.
@@ -17816,10 +18220,11 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
if (DevTy.hasValue()) {
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
OMPES = FunctionEmissionStatus::OMPDiscarded;
- } else if (DeviceKnownEmittedFns.count(FD) > 0) {
+ } else if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host ||
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Any)
OMPES = FunctionEmissionStatus::Emitted;
- }
- }
+ } else if (Final)
+ OMPES = FunctionEmissionStatus::Emitted;
}
}
if (OMPES == FunctionEmissionStatus::OMPDiscarded ||
@@ -17854,9 +18259,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
// Otherwise, the function is known-emitted if it's in our set of
// known-emitted functions.
- return (DeviceKnownEmittedFns.count(FD) > 0)
- ? FunctionEmissionStatus::Emitted
- : FunctionEmissionStatus::Unknown;
+ return FunctionEmissionStatus::Unknown;
}
bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 5c51b0f9b8cb..1a0594512a60 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -225,8 +225,7 @@ static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL,
/// A helper function to provide Attribute Location for the Attr types
/// AND the ParsedAttr.
template <typename AttrInfo>
-static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value,
- SourceLocation>::type
+static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>
getAttrLoc(const AttrInfo &AL) {
return AL.getLocation();
}
@@ -1100,7 +1099,7 @@ static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AddBuiltinName(BuiltinName);
else
S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name)
- << BuiltinName << AL.getAttrName()->getName();
+ << BuiltinName << AL;
}
// Repeating the same attribute is fine.
@@ -1111,7 +1110,7 @@ static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (HasWildcard && Names.size() > 1)
S.Diag(D->getLocation(),
diag::err_attribute_no_builtin_wildcard_or_builtin_name)
- << AL.getAttrName()->getName();
+ << AL;
if (D->hasAttr<NoBuiltinAttr>())
D->dropAttr<NoBuiltinAttr>();
@@ -1177,8 +1176,7 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) {
if (!RD->hasAttr<ConsumableAttr>()) {
- S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) <<
- RD->getNameAsString();
+ S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD;
return false;
}
@@ -1625,6 +1623,10 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
<< E->getSourceRange();
return;
}
+
+ if (I > Sema::MaximumAlignment)
+ Diag(CI.getLoc(), diag::warn_assume_aligned_too_great)
+ << CI.getRange() << Sema::MaximumAlignment;
}
if (OE) {
@@ -1663,7 +1665,8 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
return;
QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
- if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) {
+ if (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isAlignValT()) {
Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only)
<< &TmpAttr
<< FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange();
@@ -1989,6 +1992,21 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(CA);
}
+static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL;
+ return;
+ }
+
+ const auto *FD = cast<FunctionDecl>(D);
+ if (!FD->isExternallyVisible()) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL));
+}
+
static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL))
return;
@@ -2809,6 +2827,12 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) {
+ // The standard attribute cannot be applied to variable declarations such
+ // as a function pointer.
+ if (isa<VarDecl>(D))
+ S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
+ << AL << "functions, classes, or enumerations";
+
// If this is spelled as the standard C++17 attribute, but not in C++17,
// warn about using it as an extension. If there are attribute arguments,
// then claim it's a C++2a extension instead.
@@ -2816,8 +2840,8 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
// extension warning for C2x mode.
const LangOptions &LO = S.getLangOpts();
if (AL.getNumArgs() == 1) {
- if (LO.CPlusPlus && !LO.CPlusPlus2a)
- S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << 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
// literal. If in C++ mode, but not in C++2a mode, diagnose as an
@@ -3672,7 +3696,7 @@ void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) {
if (!T->isDependentType() && !T->isAnyPointerType() &&
!T->isReferenceType() && !T->isMemberPointerType()) {
Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only)
- << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange();
+ << &TmpAttr << T << D->getSourceRange();
return;
}
@@ -3809,13 +3833,12 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
}
}
- // Alignment calculations can wrap around if it's greater than 2**28.
- unsigned MaxValidAlignment =
- Context.getTargetInfo().getTriple().isOSBinFormatCOFF() ? 8192
- : 268435456;
- if (AlignVal > MaxValidAlignment) {
- Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment
- << E->getSourceRange();
+ unsigned MaximumAlignment = Sema::MaximumAlignment;
+ if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF())
+ MaximumAlignment = std::min(MaximumAlignment, 8192u);
+ if (AlignVal > MaximumAlignment) {
+ Diag(AttrLoc, diag::err_attribute_aligned_too_great)
+ << MaximumAlignment << E->getSourceRange();
return;
}
@@ -3865,6 +3888,7 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
// not specify an alignment that is less strict than the alignment that
// would otherwise be required for the entity being declared.
AlignedAttr *AlignasAttr = nullptr;
+ AlignedAttr *LastAlignedAttr = nullptr;
unsigned Align = 0;
for (auto *I : D->specific_attrs<AlignedAttr>()) {
if (I->isAlignmentDependent())
@@ -3872,9 +3896,13 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
if (I->isAlignas())
AlignasAttr = I;
Align = std::max(Align, I->getAlignment(Context));
+ LastAlignedAttr = I;
}
- if (AlignasAttr && Align) {
+ if (Align && DiagTy->isSizelessType()) {
+ Diag(LastAlignedAttr->getLocation(), diag::err_attribute_sizeless_type)
+ << LastAlignedAttr << DiagTy;
+ } else if (AlignasAttr && Align) {
CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy);
if (NaturalAlign > RequestedAlign)
@@ -3907,15 +3935,15 @@ bool Sema::checkMSInheritanceAttrOnDefinition(
Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
<< 0 /*definition*/;
- Diag(RD->getDefinition()->getLocation(), diag::note_defined_here)
- << RD->getNameAsString();
+ Diag(RD->getDefinition()->getLocation(), diag::note_defined_here) << RD;
return true;
}
/// parseModeAttrArg - Parses attribute mode string and returns parsed type
/// attribute.
static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
- bool &IntegerMode, bool &ComplexMode) {
+ bool &IntegerMode, bool &ComplexMode,
+ bool &ExplicitIEEE) {
IntegerMode = true;
ComplexMode = false;
switch (Str.size()) {
@@ -3936,7 +3964,12 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
case 'X':
DestWidth = 96;
break;
+ case 'K': // KFmode - IEEE quad precision (__float128)
+ ExplicitIEEE = true;
+ DestWidth = Str[1] == 'I' ? 0 : 128;
+ break;
case 'T':
+ ExplicitIEEE = false;
DestWidth = 128;
break;
}
@@ -3997,6 +4030,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
unsigned DestWidth = 0;
bool IntegerMode = true;
bool ComplexMode = false;
+ bool ExplicitIEEE = false;
llvm::APInt VectorSize(64, 0);
if (Str.size() >= 4 && Str[0] == 'V') {
// Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2).
@@ -4009,7 +4043,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
!Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) &&
VectorSize.isPowerOf2()) {
parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth,
- IntegerMode, ComplexMode);
+ IntegerMode, ComplexMode, ExplicitIEEE);
// Avoid duplicate warning from template instantiation.
if (!InInstantiation)
Diag(AttrLoc, diag::warn_vector_mode_deprecated);
@@ -4019,7 +4053,8 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
}
if (!VectorSize)
- parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode);
+ parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode,
+ ExplicitIEEE);
// FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
// and friends, at least with glibc.
@@ -4061,8 +4096,9 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
return;
}
- bool IntegralOrAnyEnumType =
- OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>();
+ bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() &&
+ !OldElemTy->isExtIntType()) ||
+ OldElemTy->getAs<EnumType>();
if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
!IntegralOrAnyEnumType)
@@ -4084,7 +4120,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
NewElemTy = Context.getIntTypeForBitwidth(DestWidth,
OldElemTy->isSignedIntegerType());
else
- NewElemTy = Context.getRealTypeForBitwidth(DestWidth);
+ NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitIEEE);
if (NewElemTy.isNull()) {
Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
@@ -4333,6 +4369,12 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD;
D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL));
+ // In host compilation the kernel is emitted as a stub function, which is
+ // a helper function for launching the kernel. The instructions in the helper
+ // function has nothing to do with the source code of the kernel. Do not emit
+ // debug info for the stub function to avoid confusing the debugger.
+ if (S.LangOpts.HIP && !S.LangOpts.CUDAIsDevice)
+ D->addAttr(NoDebugAttr::CreateImplicit(S.Context));
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4924,9 +4966,9 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
Expr *Arg = AL.getArgAsExpr(1);
if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
return;
- if (Offset) {
+ if (Count < Offset) {
S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
- << &AL << 0 << 0 << Arg->getBeginLoc();
+ << &AL << 0 << Count << Arg->getBeginLoc();
return;
}
}
@@ -4934,17 +4976,58 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
}
-static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+namespace {
+struct IntrinToName {
+ uint32_t Id;
+ int32_t FullName;
+ int32_t ShortName;
+};
+} // unnamed namespace
+
+static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
+ ArrayRef<IntrinToName> Map,
+ const char *IntrinNames) {
if (AliasName.startswith("__arm_"))
AliasName = AliasName.substr(6);
- switch (BuiltinID) {
+ const IntrinToName *It = std::lower_bound(
+ Map.begin(), Map.end(), BuiltinID,
+ [](const IntrinToName &L, unsigned Id) { return L.Id < Id; });
+ if (It == Map.end() || It->Id != BuiltinID)
+ return false;
+ StringRef FullName(&IntrinNames[It->FullName]);
+ if (AliasName == FullName)
+ return true;
+ if (It->ShortName == -1)
+ return false;
+ StringRef ShortName(&IntrinNames[It->ShortName]);
+ return AliasName == ShortName;
+}
+
+static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
#include "clang/Basic/arm_mve_builtin_aliases.inc"
+ // The included file defines:
+ // - ArrayRef<IntrinToName> Map
+ // - const char IntrinNames[]
+ return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
+}
+
+static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
+#include "clang/Basic/arm_cde_builtin_aliases.inc"
+ return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
+}
+
+static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ switch (BuiltinID) {
default:
return false;
+#define GET_SVE_BUILTINS
+#define BUILTIN(name, types, attr) case SVE::BI##name:
+#include "clang/Basic/arm_sve_builtins.inc"
+ return true;
}
}
-static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 1 << AANT_ArgumentIdentifier;
@@ -4953,14 +5036,17 @@ static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
unsigned BuiltinID = Ident->getBuiltinID();
+ StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
- if (!ArmMveAliasValid(BuiltinID,
- cast<FunctionDecl>(D)->getIdentifier()->getName())) {
- S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias);
+ bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
+ if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) ||
+ (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) &&
+ !ArmCdeAliasValid(BuiltinID, AliasName))) {
+ S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
return;
}
- D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident));
+ D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident));
}
//===----------------------------------------------------------------------===//
@@ -5407,9 +5493,9 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
//===----------------------------------------------------------------------===//
UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
- StringRef Uuid) {
+ StringRef UuidAsWritten, MSGuidDecl *GuidDecl) {
if (const auto *UA = D->getAttr<UuidAttr>()) {
- if (UA->getGuid().equals_lower(Uuid))
+ if (declaresSameEntity(UA->getGuidDecl(), GuidDecl))
return nullptr;
if (!UA->getGuid().empty()) {
Diag(UA->getLocation(), diag::err_mismatched_uuid);
@@ -5418,7 +5504,7 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
}
}
- return ::new (Context) UuidAttr(Context, CI, Uuid);
+ return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl);
}
static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5428,13 +5514,14 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- StringRef StrRef;
+ StringRef OrigStrRef;
SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc))
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc))
return;
// GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
// "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former.
+ StringRef StrRef = OrigStrRef;
if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}')
StrRef = StrRef.drop_front().drop_back();
@@ -5456,6 +5543,16 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+ // Convert to our parsed format and canonicalize.
+ MSGuidDecl::Parts Parsed;
+ StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1);
+ StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2);
+ StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3);
+ for (unsigned i = 0; i != 8; ++i)
+ StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2)
+ .getAsInteger(16, Parsed.Part4And5[i]);
+ MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed);
+
// FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
// the only thing in the [] list, the [] too), and add an insertion of
// __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
@@ -5465,7 +5562,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
- UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef);
+ UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid);
if (UA)
D->addAttr(UA);
}
@@ -5795,45 +5892,75 @@ static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
-static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'import_module'" << ExpectedFunction;
- return;
+WebAssemblyImportModuleAttr *
+Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) {
+ auto *FD = cast<FunctionDecl>(D);
+
+ if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
+ if (ExistingAttr->getImportModule() == AL.getImportModule())
+ return nullptr;
+ Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0
+ << ExistingAttr->getImportModule() << AL.getImportModule();
+ Diag(AL.getLoc(), diag::note_previous_attribute);
+ return nullptr;
}
+ if (FD->hasBody()) {
+ Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
+ return nullptr;
+ }
+ return ::new (Context) WebAssemblyImportModuleAttr(Context, AL,
+ AL.getImportModule());
+}
+WebAssemblyImportNameAttr *
+Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) {
auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
- return;
+
+ if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) {
+ if (ExistingAttr->getImportName() == AL.getImportName())
+ return nullptr;
+ Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1
+ << ExistingAttr->getImportName() << AL.getImportName();
+ Diag(AL.getLoc(), diag::note_previous_attribute);
+ return nullptr;
+ }
+ if (FD->hasBody()) {
+ Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
+ return nullptr;
}
+ return ::new (Context) WebAssemblyImportNameAttr(Context, AL,
+ AL.getImportName());
+}
+
+static void
+handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ auto *FD = cast<FunctionDecl>(D);
StringRef Str;
SourceLocation ArgLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
+ if (FD->hasBody()) {
+ S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0;
+ return;
+ }
FD->addAttr(::new (S.Context)
WebAssemblyImportModuleAttr(S.Context, AL, Str));
}
-static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'import_name'" << ExpectedFunction;
- return;
- }
-
+static void
+handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
- return;
- }
StringRef Str;
SourceLocation ArgLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
+ if (FD->hasBody()) {
+ S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1;
+ return;
+ }
FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
}
@@ -6199,11 +6326,6 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc))
return;
- // Currently, there are only two names allowed for a capability: role and
- // mutex (case insensitive). Diagnose other capability names.
- if (!N.equals_lower("mutex") && !N.equals_lower("role"))
- S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N;
-
D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N));
}
@@ -6567,7 +6689,9 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
// If D is a function-like declaration (method, block, or function), then we
// make every parameter psuedo-strong.
- for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) {
+ unsigned NumParams =
+ hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0;
+ for (unsigned I = 0; I != NumParams; ++I) {
auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I));
QualType Ty = PVD->getType();
@@ -6620,7 +6744,7 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
}
-static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+static void handleAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isUsedAsTypeAttr())
return;
// Warn if the parameter is definitely not an output parameter.
@@ -6700,6 +6824,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
switch (AL.getKind()) {
default:
+ if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled)
+ break;
if (!AL.isStmtAttr()) {
// Type attributes are handled elsewhere; silently move on.
assert(AL.isTypeAttr() && "Non-type attribute not handled");
@@ -6722,15 +6848,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr,
MipsInterruptAttr>(S, D, AL);
break;
- case ParsedAttr::AT_NoMips16:
- handleSimpleAttribute<NoMips16Attr>(S, D, AL);
- break;
case ParsedAttr::AT_MicroMips:
handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL);
break;
- case ParsedAttr::AT_NoMicroMips:
- handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL);
- break;
case ParsedAttr::AT_MipsLongCall:
handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
S, D, AL);
@@ -6766,9 +6886,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_WebAssemblyImportName:
handleWebAssemblyImportNameAttr(S, D, AL);
break;
- case ParsedAttr::AT_IBAction:
- handleSimpleAttribute<IBActionAttr>(S, D, AL);
- break;
case ParsedAttr::AT_IBOutlet:
handleIBOutlet(S, D, AL);
break;
@@ -6793,9 +6910,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AlwaysInline:
handleAlwaysInlineAttr(S, D, AL);
break;
- case ParsedAttr::AT_Artificial:
- handleSimpleAttribute<ArtificialAttr>(S, D, AL);
- break;
case ParsedAttr::AT_AnalyzerNoReturn:
handleAnalyzerNoReturnAttr(S, D, AL);
break;
@@ -6825,16 +6939,20 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handlePassObjectSizeAttr(S, D, AL);
break;
case ParsedAttr::AT_Constructor:
- handleConstructorAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CXX11NoReturn:
- handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL);
+ if (S.Context.getTargetInfo().getTriple().isOSAIX())
+ llvm::report_fatal_error(
+ "'constructor' attribute is not yet supported on AIX");
+ else
+ handleConstructorAttr(S, D, AL);
break;
case ParsedAttr::AT_Deprecated:
handleDeprecatedAttr(S, D, AL);
break;
case ParsedAttr::AT_Destructor:
- handleDestructorAttr(S, D, AL);
+ if (S.Context.getTargetInfo().getTriple().isOSAIX())
+ llvm::report_fatal_error("'destructor' attribute is not yet supported on AIX");
+ else
+ handleDestructorAttr(S, D, AL);
break;
case ParsedAttr::AT_EnableIf:
handleEnableIfAttr(S, D, AL);
@@ -6857,15 +6975,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_OptimizeNone:
handleOptimizeNoneAttr(S, D, AL);
break;
- case ParsedAttr::AT_FlagEnum:
- handleSimpleAttribute<FlagEnumAttr>(S, D, AL);
- break;
case ParsedAttr::AT_EnumExtensibility:
handleEnumExtensibilityAttr(S, D, AL);
break;
- case ParsedAttr::AT_Flatten:
- handleSimpleAttribute<FlattenAttr>(S, D, AL);
- break;
case ParsedAttr::AT_SYCLKernel:
handleSYCLKernelAttr(S, D, AL);
break;
@@ -6888,9 +7000,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_CUDAHost:
handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL);
break;
- case ParsedAttr::AT_HIPPinnedShadow:
- handleSimpleAttributeWithExclusions<HIPPinnedShadowAttr, CUDADeviceAttr,
- CUDAConstantAttr>(S, D, AL);
+ case ParsedAttr::AT_CUDADeviceBuiltinSurfaceType:
+ handleSimpleAttributeWithExclusions<CUDADeviceBuiltinSurfaceTypeAttr,
+ CUDADeviceBuiltinTextureTypeAttr>(S, D,
+ AL);
+ break;
+ case ParsedAttr::AT_CUDADeviceBuiltinTextureType:
+ handleSimpleAttributeWithExclusions<CUDADeviceBuiltinTextureTypeAttr,
+ CUDADeviceBuiltinSurfaceTypeAttr>(S, D,
+ AL);
break;
case ParsedAttr::AT_GNUInline:
handleGNUInlineAttr(S, D, AL);
@@ -6901,27 +7019,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Restrict:
handleRestrictAttr(S, D, AL);
break;
- case ParsedAttr::AT_LifetimeBound:
- handleSimpleAttribute<LifetimeBoundAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MayAlias:
- handleSimpleAttribute<MayAliasAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Mode:
handleModeAttr(S, D, AL);
break;
- case ParsedAttr::AT_NoAlias:
- handleSimpleAttribute<NoAliasAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoCommon:
- handleSimpleAttribute<NoCommonAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoSplitStack:
- handleSimpleAttribute<NoSplitStackAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoUniqueAddress:
- handleSimpleAttribute<NoUniqueAddressAttr>(S, D, AL);
- break;
case ParsedAttr::AT_NonNull:
if (auto *PVD = dyn_cast<ParmVarDecl>(D))
handleNonNullAttrParameter(S, PVD, AL);
@@ -6940,9 +7040,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AllocAlign:
handleAllocAlignAttr(S, D, AL);
break;
- case ParsedAttr::AT_Overloadable:
- handleSimpleAttribute<OverloadableAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Ownership:
handleOwnershipAttr(S, D, AL);
break;
@@ -6998,9 +7095,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_ObjCRuntimeName:
handleObjCRuntimeName(S, D, AL);
break;
- case ParsedAttr::AT_ObjCRuntimeVisible:
- handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL);
- break;
case ParsedAttr::AT_ObjCBoxable:
handleObjCBoxable(S, D, AL);
break;
@@ -7018,12 +7112,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
/*IsTemplateInstantiation=*/false);
break;
- case ParsedAttr::AT_NSConsumesSelf:
- handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_OSConsumesThis:
- handleSimpleAttribute<OSConsumesThisAttr>(S, D, AL);
- break;
case ParsedAttr::AT_OSReturnsRetainedOnZero:
handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>(
S, D, AL, isValidOSObjectOutParameter(D),
@@ -7057,11 +7145,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_VecTypeHint:
handleVecTypeHint(S, D, AL);
break;
- case ParsedAttr::AT_ConstInit:
- handleSimpleAttribute<ConstInitAttr>(S, D, AL);
- break;
case ParsedAttr::AT_InitPriority:
- handleInitPriorityAttr(S, D, AL);
+ if (S.Context.getTargetInfo().getTriple().isOSAIX())
+ llvm::report_fatal_error(
+ "'init_priority' attribute is not yet supported on AIX");
+ else
+ handleInitPriorityAttr(S, D, AL);
break;
case ParsedAttr::AT_Packed:
handlePackedAttr(S, D, AL);
@@ -7090,12 +7179,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, AL);
break;
- case ParsedAttr::AT_ArcWeakrefUnavailable:
- handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRootClass:
- handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
- break;
case ParsedAttr::AT_ObjCDirect:
handleObjCDirectAttr(S, D, AL);
break;
@@ -7103,27 +7186,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleObjCDirectMembersAttr(S, D, AL);
handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
break;
- case ParsedAttr::AT_ObjCNonLazyClass:
- handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCSubclassingRestricted:
- handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCClassStub:
- handleSimpleAttribute<ObjCClassStubAttr>(S, D, AL);
- break;
case ParsedAttr::AT_ObjCExplicitProtocolImpl:
handleObjCSuppresProtocolAttr(S, D, AL);
break;
- case ParsedAttr::AT_ObjCRequiresPropertyDefs:
- handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Unused:
handleUnusedAttr(S, D, AL);
break;
- case ParsedAttr::AT_ReturnsTwice:
- handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL);
- break;
case ParsedAttr::AT_NotTailCalled:
handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>(
S, D, AL);
@@ -7132,24 +7200,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D,
AL);
break;
- case ParsedAttr::AT_Used:
- handleSimpleAttribute<UsedAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Visibility:
handleVisibilityAttr(S, D, AL, false);
break;
case ParsedAttr::AT_TypeVisibility:
handleVisibilityAttr(S, D, AL, true);
break;
- case ParsedAttr::AT_WarnUnused:
- handleSimpleAttribute<WarnUnusedAttr>(S, D, AL);
- break;
case ParsedAttr::AT_WarnUnusedResult:
handleWarnUnusedResult(S, D, AL);
break;
- case ParsedAttr::AT_Weak:
- handleSimpleAttribute<WeakAttr>(S, D, AL);
- break;
case ParsedAttr::AT_WeakRef:
handleWeakRefAttr(S, D, AL);
break;
@@ -7159,9 +7218,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_TransparentUnion:
handleTransparentUnionAttr(S, D, AL);
break;
- case ParsedAttr::AT_ObjCException:
- handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL);
- break;
case ParsedAttr::AT_ObjCMethodFamily:
handleObjCMethodFamilyAttr(S, D, AL);
break;
@@ -7177,36 +7233,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Sentinel:
handleSentinelAttr(S, D, AL);
break;
- case ParsedAttr::AT_Const:
- handleSimpleAttribute<ConstAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Pure:
- handleSimpleAttribute<PureAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Cleanup:
handleCleanupAttr(S, D, AL);
break;
case ParsedAttr::AT_NoDebug:
handleNoDebugAttr(S, D, AL);
break;
- case ParsedAttr::AT_NoDuplicate:
- handleSimpleAttribute<NoDuplicateAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Convergent:
- handleSimpleAttribute<ConvergentAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoInline:
- handleSimpleAttribute<NoInlineAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg.
- handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoStackProtector:
- // Interacts with -fstack-protector options.
- handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CFICanonicalJumpTable:
- handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL);
+ case ParsedAttr::AT_CmseNSEntry:
+ handleCmseNSEntryAttr(S, D, AL);
break;
case ParsedAttr::AT_StdCall:
case ParsedAttr::AT_CDecl:
@@ -7232,9 +7266,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Pointer:
handleLifetimeCategoryAttr(S, D, AL);
break;
- case ParsedAttr::AT_OpenCLKernel:
- handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL);
- break;
case ParsedAttr::AT_OpenCLAccess:
handleOpenCLAccessAttr(S, D, AL);
break;
@@ -7253,38 +7284,17 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, AL);
break;
- case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
- handleSimpleAttribute<ExcludeFromExplicitInstantiationAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_LTOVisibilityPublic:
- handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL);
- break;
// Microsoft attributes:
- case ParsedAttr::AT_EmptyBases:
- handleSimpleAttribute<EmptyBasesAttr>(S, D, AL);
- break;
case ParsedAttr::AT_LayoutVersion:
handleLayoutVersion(S, D, AL);
break;
- case ParsedAttr::AT_TrivialABI:
- handleSimpleAttribute<TrivialABIAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MSNoVTable:
- handleSimpleAttribute<MSNoVTableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MSStruct:
- handleSimpleAttribute<MSStructAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Uuid:
handleUuidAttr(S, D, AL);
break;
case ParsedAttr::AT_MSInheritance:
handleMSInheritanceAttr(S, D, AL);
break;
- case ParsedAttr::AT_SelectAny:
- handleSimpleAttribute<SelectAnyAttr>(S, D, AL);
- break;
case ParsedAttr::AT_Thread:
handleDeclspecThreadAttr(S, D, AL);
break;
@@ -7303,24 +7313,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AssertSharedLock:
handleAssertSharedLockAttr(S, D, AL);
break;
- case ParsedAttr::AT_GuardedVar:
- handleSimpleAttribute<GuardedVarAttr>(S, D, AL);
- break;
case ParsedAttr::AT_PtGuardedVar:
handlePtGuardedVarAttr(S, D, AL);
break;
- case ParsedAttr::AT_ScopedLockable:
- handleSimpleAttribute<ScopedLockableAttr>(S, D, AL);
- break;
case ParsedAttr::AT_NoSanitize:
handleNoSanitizeAttr(S, D, AL);
break;
case ParsedAttr::AT_NoSanitizeSpecific:
handleNoSanitizeSpecificAttr(S, D, AL);
break;
- case ParsedAttr::AT_NoThreadSafetyAnalysis:
- handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL);
- break;
case ParsedAttr::AT_GuardedBy:
handleGuardedByAttr(S, D, AL);
break;
@@ -7372,12 +7373,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Consumable:
handleConsumableAttr(S, D, AL);
break;
- case ParsedAttr::AT_ConsumableAutoCast:
- handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ConsumableSetOnRead:
- handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL);
- break;
case ParsedAttr::AT_CallableWhen:
handleCallableWhenAttr(S, D, AL);
break;
@@ -7401,16 +7396,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_TypeTagForDatatype:
handleTypeTagForDatatypeAttr(S, D, AL);
break;
- case ParsedAttr::AT_AnyX86NoCallerSavedRegisters:
- handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_RenderScriptKernel:
- handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL);
- break;
+
// XRay attributes.
- case ParsedAttr::AT_XRayInstrument:
- handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL);
- break;
case ParsedAttr::AT_XRayLogArgs:
handleXRayLogArgsAttr(S, D, AL);
break;
@@ -7419,11 +7406,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handlePatchableFunctionEntryAttr(S, D, AL);
break;
- // Move semantics attribute.
- case ParsedAttr::AT_Reinitializes:
- handleSimpleAttribute<ReinitializesAttr>(S, D, AL);
- break;
-
case ParsedAttr::AT_AlwaysDestroy:
case ParsedAttr::AT_NoDestroy:
handleDestroyAttr(S, D, AL);
@@ -7433,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleUninitializedAttr(S, D, AL);
break;
+ case ParsedAttr::AT_LoaderUninitialized:
+ handleSimpleAttribute<LoaderUninitializedAttr>(S, D, AL);
+ break;
+
case ParsedAttr::AT_ObjCExternallyRetained:
handleObjCExternallyRetainedAttr(S, D, AL);
break;
@@ -7445,12 +7431,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleMSAllocatorAttr(S, D, AL);
break;
- case ParsedAttr::AT_ArmMveAlias:
- handleArmMveAliasAttr(S, D, AL);
+ case ParsedAttr::AT_ArmBuiltinAlias:
+ handleArmBuiltinAliasAttr(S, D, AL);
break;
case ParsedAttr::AT_AcquireHandle:
- handeAcquireHandleAttr(S, D, AL);
+ handleAcquireHandleAttr(S, D, AL);
break;
case ParsedAttr::AT_ReleaseHandle:
@@ -7782,534 +7768,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD,
DD.Triggered = true;
}
-static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
- const Decl *D) {
- // Check each AvailabilityAttr to find the one for this platform.
- for (const auto *A : D->attrs()) {
- if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
- // FIXME: this is copied from CheckAvailability. We should try to
- // de-duplicate.
-
- // Check if this is an App Extension "platform", and if so chop off
- // the suffix for matching with the actual platform.
- StringRef ActualPlatform = Avail->getPlatform()->getName();
- StringRef RealizedPlatform = ActualPlatform;
- if (Context.getLangOpts().AppExt) {
- size_t suffix = RealizedPlatform.rfind("_app_extension");
- if (suffix != StringRef::npos)
- RealizedPlatform = RealizedPlatform.slice(0, suffix);
- }
-
- StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
-
- // Match the platform name.
- if (RealizedPlatform == TargetPlatform)
- return Avail;
- }
- }
- return nullptr;
-}
-
-/// The diagnostic we should emit for \c D, and the declaration that
-/// originated it, or \c AR_Available.
-///
-/// \param D The declaration to check.
-/// \param Message If non-null, this will be populated with the message from
-/// the availability attribute that is selected.
-/// \param ClassReceiver If we're checking the the method of a class message
-/// send, the class. Otherwise nullptr.
-static std::pair<AvailabilityResult, const NamedDecl *>
-ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
- std::string *Message,
- ObjCInterfaceDecl *ClassReceiver) {
- AvailabilityResult Result = D->getAvailability(Message);
-
- // For typedefs, if the typedef declaration appears available look
- // to the underlying type to see if it is more restrictive.
- while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (Result == AR_Available) {
- if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
- D = TT->getDecl();
- Result = D->getAvailability(Message);
- continue;
- }
- }
- break;
- }
-
- // Forward class declarations get their attributes from their definition.
- if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
- if (IDecl->getDefinition()) {
- D = IDecl->getDefinition();
- Result = D->getAvailability(Message);
- }
- }
-
- if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
- if (Result == AR_Available) {
- const DeclContext *DC = ECD->getDeclContext();
- if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
- Result = TheEnumDecl->getAvailability(Message);
- D = TheEnumDecl;
- }
- }
-
- // For +new, infer availability from -init.
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (S.NSAPIObj && ClassReceiver) {
- ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
- S.NSAPIObj->getInitSelector());
- if (Init && Result == AR_Available && MD->isClassMethod() &&
- MD->getSelector() == S.NSAPIObj->getNewSelector() &&
- MD->definedInNSObject(S.getASTContext())) {
- Result = Init->getAvailability(Message);
- D = Init;
- }
- }
- }
-
- return {Result, D};
-}
-
-
-/// whether we should emit a diagnostic for \c K and \c DeclVersion in
-/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
-/// in a deprecated context, but not the other way around.
-static bool
-ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
- VersionTuple DeclVersion, Decl *Ctx,
- const NamedDecl *OffendingDecl) {
- assert(K != AR_Available && "Expected an unavailable declaration here!");
-
- // Checks if we should emit the availability diagnostic in the context of C.
- auto CheckContext = [&](const Decl *C) {
- if (K == AR_NotYetIntroduced) {
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
- if (AA->getIntroduced() >= DeclVersion)
- return true;
- } else if (K == AR_Deprecated) {
- if (C->isDeprecated())
- return true;
- } else if (K == AR_Unavailable) {
- // It is perfectly fine to refer to an 'unavailable' Objective-C method
- // when it is referenced from within the @implementation itself. In this
- // context, we interpret unavailable as a form of access control.
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
- if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
- if (MD->getClassInterface() == Impl->getClassInterface())
- return true;
- }
- }
- }
-
- if (C->isUnavailable())
- return true;
- return false;
- };
-
- do {
- if (CheckContext(Ctx))
- return false;
-
- // An implementation implicitly has the availability of the interface.
- // Unless it is "+load" method.
- if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
- if (MethodD->isClassMethod() &&
- MethodD->getSelector().getAsString() == "load")
- return true;
-
- if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
- if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
- if (CheckContext(Interface))
- return false;
- }
- // A category implicitly has the availability of the interface.
- else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
- if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
- if (CheckContext(Interface))
- return false;
- } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
-
- return true;
-}
-
-static bool
-shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
- const VersionTuple &DeploymentVersion,
- const VersionTuple &DeclVersion) {
- const auto &Triple = Context.getTargetInfo().getTriple();
- VersionTuple ForceAvailabilityFromVersion;
- switch (Triple.getOS()) {
- case llvm::Triple::IOS:
- case llvm::Triple::TvOS:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
- break;
- case llvm::Triple::WatchOS:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
- break;
- case llvm::Triple::Darwin:
- case llvm::Triple::MacOSX:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
- break;
- default:
- // New targets should always warn about availability.
- return Triple.getVendor() == llvm::Triple::Apple;
- }
- return DeploymentVersion >= ForceAvailabilityFromVersion ||
- DeclVersion >= ForceAvailabilityFromVersion;
-}
-
-static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
- for (Decl *Ctx = OrigCtx; Ctx;
- Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
- if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
- return cast<NamedDecl>(Ctx);
- if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
- if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
- return Imp->getClassInterface();
- return CD;
- }
- }
-
- return dyn_cast<NamedDecl>(OrigCtx);
-}
-
-namespace {
-
-struct AttributeInsertion {
- StringRef Prefix;
- SourceLocation Loc;
- StringRef Suffix;
-
- static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
- return {" ", D->getEndLoc(), ""};
- }
- static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
- return {" ", Loc, ""};
- }
- static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
- return {"", D->getBeginLoc(), "\n"};
- }
-};
-
-} // end anonymous namespace
-
-/// Tries to parse a string as ObjC method name.
-///
-/// \param Name The string to parse. Expected to originate from availability
-/// attribute argument.
-/// \param SlotNames The vector that will be populated with slot names. In case
-/// of unsuccessful parsing can contain invalid data.
-/// \returns A number of method parameters if parsing was successful, None
-/// otherwise.
-static Optional<unsigned>
-tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
- const LangOptions &LangOpts) {
- // Accept replacements starting with - or + as valid ObjC method names.
- if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
- Name = Name.drop_front(1);
- if (Name.empty())
- return None;
- Name.split(SlotNames, ':');
- unsigned NumParams;
- if (Name.back() == ':') {
- // Remove an empty string at the end that doesn't represent any slot.
- SlotNames.pop_back();
- NumParams = SlotNames.size();
- } else {
- if (SlotNames.size() != 1)
- // Not a valid method name, just a colon-separated string.
- return None;
- NumParams = 0;
- }
- // Verify all slot names are valid.
- bool AllowDollar = LangOpts.DollarIdents;
- for (StringRef S : SlotNames) {
- if (S.empty())
- continue;
- if (!isValidIdentifier(S, AllowDollar))
- return None;
- }
- return NumParams;
-}
-
-/// Returns a source location in which it's appropriate to insert a new
-/// attribute for the given declaration \D.
-static Optional<AttributeInsertion>
-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 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;
- // Insert after the 'struct'/whatever keyword.
- return AttributeInsertion::createInsertionAfter(Loc);
- }
- return AttributeInsertion::createInsertionBefore(D);
-}
-
-/// Actually emit an availability diagnostic for a reference to an unavailable
-/// decl.
-///
-/// \param Ctx The context that the reference occurred in
-/// \param ReferringDecl The exact declaration that was referenced.
-/// \param OffendingDecl A related decl to \c ReferringDecl that has an
-/// availability attribute corresponding to \c K attached to it. Note that this
-/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
-/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
-/// and OffendingDecl is the EnumDecl.
-static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
- Decl *Ctx, const NamedDecl *ReferringDecl,
- const NamedDecl *OffendingDecl,
- StringRef Message,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
- // Diagnostics for deprecated or unavailable.
- unsigned diag, diag_message, diag_fwdclass_message;
- unsigned diag_available_here = diag::note_availability_specified_here;
- SourceLocation NoteLocation = OffendingDecl->getLocation();
-
- // Matches 'diag::note_property_attribute' options.
- unsigned property_note_select;
-
- // Matches diag::note_availability_specified_here.
- unsigned available_here_select_kind;
-
- VersionTuple DeclVersion;
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
- DeclVersion = AA->getIntroduced();
-
- if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
- OffendingDecl))
- return;
-
- SourceLocation Loc = Locs.front();
-
- // The declaration can have multiple availability attributes, we are looking
- // at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
- if (A && A->isInherited()) {
- for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
- Redecl = Redecl->getPreviousDecl()) {
- const AvailabilityAttr *AForRedecl =
- getAttrForPlatform(S.Context, Redecl);
- if (AForRedecl && !AForRedecl->isInherited()) {
- // If D is a declaration with inherited attributes, the note should
- // point to the declaration with actual attributes.
- NoteLocation = Redecl->getLocation();
- break;
- }
- }
- }
-
- switch (K) {
- case AR_NotYetIntroduced: {
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- const AvailabilityAttr *AA =
- getAttrForPlatform(S.getASTContext(), OffendingDecl);
- VersionTuple Introduced = AA->getIntroduced();
-
- bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
- S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
- Introduced);
- unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
-
- std::string PlatformName = AvailabilityAttr::getPrettyPlatformName(
- S.getASTContext().getTargetInfo().getPlatformName());
-
- S.Diag(Loc, Warning) << OffendingDecl << PlatformName
- << Introduced.getAsString();
-
- S.Diag(OffendingDecl->getLocation(),
- diag::note_partial_availability_specified_here)
- << OffendingDecl << PlatformName << Introduced.getAsString()
- << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
-
- if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
- if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
- if (TD->getDeclName().isEmpty()) {
- S.Diag(TD->getLocation(),
- diag::note_decl_unguarded_availability_silence)
- << /*Anonymous*/ 1 << TD->getKindName();
- return;
- }
- auto FixitNoteDiag =
- S.Diag(Enclosing->getLocation(),
- diag::note_decl_unguarded_availability_silence)
- << /*Named*/ 0 << Enclosing;
- // Don't offer a fixit for declarations with availability attributes.
- if (Enclosing->hasAttr<AvailabilityAttr>())
- return;
- if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
- return;
- Optional<AttributeInsertion> Insertion = createAttributeInsertion(
- Enclosing, S.getSourceManager(), S.getLangOpts());
- if (!Insertion)
- return;
- std::string PlatformName =
- AvailabilityAttr::getPlatformNameSourceSpelling(
- S.getASTContext().getTargetInfo().getPlatformName())
- .lower();
- std::string Introduced =
- OffendingDecl->getVersionIntroduced().getAsString();
- FixitNoteDiag << FixItHint::CreateInsertion(
- Insertion->Loc,
- (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
- "(" + Introduced + "))" + Insertion->Suffix)
- .str());
- }
- return;
- }
- case AR_Deprecated:
- diag = !ObjCPropertyAccess ? diag::warn_deprecated
- : diag::warn_property_method_deprecated;
- diag_message = diag::warn_deprecated_message;
- diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
- property_note_select = /* deprecated */ 0;
- available_here_select_kind = /* deprecated */ 2;
- if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
- NoteLocation = AL->getLocation();
- break;
-
- case AR_Unavailable:
- diag = !ObjCPropertyAccess ? diag::err_unavailable
- : diag::err_property_method_unavailable;
- diag_message = diag::err_unavailable_message;
- diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
- property_note_select = /* unavailable */ 1;
- available_here_select_kind = /* unavailable */ 0;
-
- if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
- if (AL->isImplicit() && AL->getImplicitReason()) {
- // Most of these failures are due to extra restrictions in ARC;
- // reflect that in the primary diagnostic when applicable.
- auto flagARCError = [&] {
- if (S.getLangOpts().ObjCAutoRefCount &&
- S.getSourceManager().isInSystemHeader(
- OffendingDecl->getLocation()))
- diag = diag::err_unavailable_in_arc;
- };
-
- switch (AL->getImplicitReason()) {
- case UnavailableAttr::IR_None: break;
-
- case UnavailableAttr::IR_ARCForbiddenType:
- flagARCError();
- diag_available_here = diag::note_arc_forbidden_type;
- break;
-
- case UnavailableAttr::IR_ForbiddenWeak:
- if (S.getLangOpts().ObjCWeakRuntime)
- diag_available_here = diag::note_arc_weak_disabled;
- else
- diag_available_here = diag::note_arc_weak_no_runtime;
- break;
-
- case UnavailableAttr::IR_ARCForbiddenConversion:
- flagARCError();
- diag_available_here = diag::note_performs_forbidden_arc_conversion;
- break;
-
- case UnavailableAttr::IR_ARCInitReturnsUnrelated:
- flagARCError();
- diag_available_here = diag::note_arc_init_returns_unrelated;
- break;
-
- case UnavailableAttr::IR_ARCFieldWithOwnership:
- flagARCError();
- diag_available_here = diag::note_arc_field_with_ownership;
- break;
- }
- }
- }
- break;
-
- case AR_Available:
- llvm_unreachable("Warning for availability of available declaration?");
- }
-
- SmallVector<FixItHint, 12> FixIts;
- if (K == AR_Deprecated) {
- StringRef Replacement;
- if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
- Replacement = AL->getReplacement();
- if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
- Replacement = AL->getReplacement();
-
- CharSourceRange UseRange;
- if (!Replacement.empty())
- UseRange =
- CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
- if (UseRange.isValid()) {
- if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
- Selector Sel = MethodDecl->getSelector();
- SmallVector<StringRef, 12> SelectorSlotNames;
- Optional<unsigned> NumParams = tryParseObjCMethodName(
- Replacement, SelectorSlotNames, S.getLangOpts());
- if (NumParams && NumParams.getValue() == Sel.getNumArgs()) {
- assert(SelectorSlotNames.size() == Locs.size());
- for (unsigned I = 0; I < Locs.size(); ++I) {
- if (!Sel.getNameForSlot(I).empty()) {
- CharSourceRange NameRange = CharSourceRange::getCharRange(
- Locs[I], S.getLocForEndOfToken(Locs[I]));
- FixIts.push_back(FixItHint::CreateReplacement(
- NameRange, SelectorSlotNames[I]));
- } else
- FixIts.push_back(
- FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
- }
- } else
- FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
- } else
- FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
- }
- }
-
- if (!Message.empty()) {
- S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
- if (ObjCProperty)
- S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
- } else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << ReferringDecl << FixIts;
- if (ObjCProperty)
- S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
- } else {
- S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
- S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
- }
-
- S.Diag(NoteLocation, diag_available_here)
- << OffendingDecl << available_here_select_kind;
-}
-
-static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
- Decl *Ctx) {
- assert(DD.Kind == DelayedDiagnostic::Availability &&
- "Expected an availability diagnostic here");
-
- DD.Triggered = true;
- DoEmitAvailabilityWarning(
- S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
- DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
- DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
- DD.getObjCProperty(), false);
-}
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
assert(DelayedDiagnostics.getCurrentPool());
@@ -8343,7 +7801,7 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
// Don't bother giving deprecation/unavailable diagnostics if
// the decl is invalid.
if (!decl->isInvalidDecl())
- handleDelayedAvailabilityCheck(*this, diag, decl);
+ handleDelayedAvailabilityCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
@@ -8373,415 +7831,3 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
assert(curPool && "re-emitting in undelayed context not supported");
curPool->steal(pool);
}
-
-static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
- const NamedDecl *ReferringDecl,
- const NamedDecl *OffendingDecl,
- StringRef Message,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
- // Delay if we're currently parsing a declaration.
- if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
- S.DelayedDiagnostics.add(
- DelayedDiagnostic::makeAvailability(
- AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
- ObjCProperty, Message, ObjCPropertyAccess));
- return;
- }
-
- Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
- DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
- Message, Locs, UnknownObjCClass, ObjCProperty,
- ObjCPropertyAccess);
-}
-
-namespace {
-
-/// Returns true if the given statement can be a body-like child of \p Parent.
-bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
- switch (Parent->getStmtClass()) {
- case Stmt::IfStmtClass:
- return cast<IfStmt>(Parent)->getThen() == S ||
- cast<IfStmt>(Parent)->getElse() == S;
- case Stmt::WhileStmtClass:
- return cast<WhileStmt>(Parent)->getBody() == S;
- case Stmt::DoStmtClass:
- return cast<DoStmt>(Parent)->getBody() == S;
- case Stmt::ForStmtClass:
- return cast<ForStmt>(Parent)->getBody() == S;
- case Stmt::CXXForRangeStmtClass:
- return cast<CXXForRangeStmt>(Parent)->getBody() == S;
- case Stmt::ObjCForCollectionStmtClass:
- return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
- case Stmt::CaseStmtClass:
- case Stmt::DefaultStmtClass:
- return cast<SwitchCase>(Parent)->getSubStmt() == S;
- default:
- return false;
- }
-}
-
-class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
- const Stmt *Target;
-
-public:
- bool VisitStmt(Stmt *S) { return S != Target; }
-
- /// Returns true if the given statement is present in the given declaration.
- static bool isContained(const Stmt *Target, const Decl *D) {
- StmtUSEFinder Visitor;
- Visitor.Target = Target;
- return !Visitor.TraverseDecl(const_cast<Decl *>(D));
- }
-};
-
-/// Traverses the AST and finds the last statement that used a given
-/// declaration.
-class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
- const Decl *D;
-
-public:
- bool VisitDeclRefExpr(DeclRefExpr *DRE) {
- if (DRE->getDecl() == D)
- return false;
- return true;
- }
-
- static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
- const CompoundStmt *Scope) {
- LastDeclUSEFinder Visitor;
- Visitor.D = D;
- for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) {
- const Stmt *S = *I;
- if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
- return S;
- }
- return nullptr;
- }
-};
-
-/// This class implements -Wunguarded-availability.
-///
-/// This is done with a traversal of the AST of a function that makes reference
-/// to a partially available declaration. Whenever we encounter an \c if of the
-/// form: \c if(@available(...)), we use the version from the condition to visit
-/// the then statement.
-class DiagnoseUnguardedAvailability
- : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
- typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
-
- Sema &SemaRef;
- Decl *Ctx;
-
- /// Stack of potentially nested 'if (@available(...))'s.
- SmallVector<VersionTuple, 8> AvailabilityStack;
- SmallVector<const Stmt *, 16> StmtStack;
-
- void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
- ObjCInterfaceDecl *ClassReceiver = nullptr);
-
-public:
- DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
- : SemaRef(SemaRef), Ctx(Ctx) {
- AvailabilityStack.push_back(
- SemaRef.Context.getTargetInfo().getPlatformMinVersion());
- }
-
- bool TraverseDecl(Decl *D) {
- // Avoid visiting nested functions to prevent duplicate warnings.
- if (!D || isa<FunctionDecl>(D))
- return true;
- return Base::TraverseDecl(D);
- }
-
- bool TraverseStmt(Stmt *S) {
- if (!S)
- return true;
- StmtStack.push_back(S);
- bool Result = Base::TraverseStmt(S);
- StmtStack.pop_back();
- return Result;
- }
-
- void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
-
- bool TraverseIfStmt(IfStmt *If);
-
- bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
-
- // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
- // to any useful diagnostics.
- bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
-
- bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
- if (PRE->isClassReceiver())
- DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
- return true;
- }
-
- bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
- if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
- ObjCInterfaceDecl *ID = nullptr;
- QualType ReceiverTy = Msg->getClassReceiver();
- if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
- ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
-
- DiagnoseDeclAvailability(
- D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
- }
- return true;
- }
-
- bool VisitDeclRefExpr(DeclRefExpr *DRE) {
- DiagnoseDeclAvailability(DRE->getDecl(),
- SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
- return true;
- }
-
- bool VisitMemberExpr(MemberExpr *ME) {
- DiagnoseDeclAvailability(ME->getMemberDecl(),
- SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
- return true;
- }
-
- bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
- SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
- << (!SemaRef.getLangOpts().ObjC);
- return true;
- }
-
- bool VisitTypeLoc(TypeLoc Ty);
-};
-
-void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
- NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
- AvailabilityResult Result;
- const NamedDecl *OffendingDecl;
- std::tie(Result, OffendingDecl) =
- ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
- if (Result != AR_Available) {
- // All other diagnostic kinds have already been handled in
- // DiagnoseAvailabilityOfDecl.
- if (Result != AR_NotYetIntroduced)
- return;
-
- const AvailabilityAttr *AA =
- getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
- VersionTuple Introduced = AA->getIntroduced();
-
- if (AvailabilityStack.back() >= Introduced)
- return;
-
- // If the context of this function is less available than D, we should not
- // emit a diagnostic.
- if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
- OffendingDecl))
- return;
-
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- unsigned DiagKind =
- shouldDiagnoseAvailabilityByDefault(
- SemaRef.Context,
- SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
- ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
-
- std::string PlatformName = AvailabilityAttr::getPrettyPlatformName(
- SemaRef.getASTContext().getTargetInfo().getPlatformName());
-
- SemaRef.Diag(Range.getBegin(), DiagKind)
- << Range << D << PlatformName << Introduced.getAsString();
-
- SemaRef.Diag(OffendingDecl->getLocation(),
- diag::note_partial_availability_specified_here)
- << OffendingDecl << PlatformName << Introduced.getAsString()
- << SemaRef.Context.getTargetInfo()
- .getPlatformMinVersion()
- .getAsString();
-
- auto FixitDiag =
- SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
- << Range << D
- << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
- : /*__builtin_available*/ 1);
-
- // Find the statement which should be enclosed in the if @available check.
- if (StmtStack.empty())
- return;
- const Stmt *StmtOfUse = StmtStack.back();
- const CompoundStmt *Scope = nullptr;
- for (const Stmt *S : llvm::reverse(StmtStack)) {
- if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
- Scope = CS;
- break;
- }
- if (isBodyLikeChildStmt(StmtOfUse, S)) {
- // The declaration won't be seen outside of the statement, so we don't
- // have to wrap the uses of any declared variables in if (@available).
- // Therefore we can avoid setting Scope here.
- break;
- }
- StmtOfUse = S;
- }
- const Stmt *LastStmtOfUse = nullptr;
- if (isa<DeclStmt>(StmtOfUse) && Scope) {
- for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
- if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
- LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
- break;
- }
- }
- }
-
- const SourceManager &SM = SemaRef.getSourceManager();
- SourceLocation IfInsertionLoc =
- SM.getExpansionLoc(StmtOfUse->getBeginLoc());
- SourceLocation StmtEndLoc =
- SM.getExpansionRange(
- (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
- .getEnd();
- if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
- return;
-
- StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
- const char *ExtraIndentation = " ";
- std::string FixItString;
- llvm::raw_string_ostream FixItOS(FixItString);
- FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
- : "__builtin_available")
- << "("
- << AvailabilityAttr::getPlatformNameSourceSpelling(
- SemaRef.getASTContext().getTargetInfo().getPlatformName())
- << " " << Introduced.getAsString() << ", *)) {\n"
- << Indentation << ExtraIndentation;
- FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
- SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
- StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
- /*SkipTrailingWhitespaceAndNewLine=*/false);
- if (ElseInsertionLoc.isInvalid())
- ElseInsertionLoc =
- Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
- FixItOS.str().clear();
- FixItOS << "\n"
- << Indentation << "} else {\n"
- << Indentation << ExtraIndentation
- << "// Fallback on earlier versions\n"
- << Indentation << "}";
- FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
- }
-}
-
-bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
- const Type *TyPtr = Ty.getTypePtr();
- SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
-
- if (Range.isInvalid())
- return true;
-
- if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
- TagDecl *TD = TT->getDecl();
- DiagnoseDeclAvailability(TD, Range);
-
- } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
- TypedefNameDecl *D = TD->getDecl();
- DiagnoseDeclAvailability(D, Range);
-
- } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
- if (NamedDecl *D = ObjCO->getInterface())
- DiagnoseDeclAvailability(D, Range);
- }
-
- return true;
-}
-
-bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
- VersionTuple CondVersion;
- if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
- CondVersion = E->getVersion();
-
- // If we're using the '*' case here or if this check is redundant, then we
- // use the enclosing version to check both branches.
- if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
- return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
- } else {
- // This isn't an availability checking 'if', we can just continue.
- return Base::TraverseIfStmt(If);
- }
-
- AvailabilityStack.push_back(CondVersion);
- bool ShouldContinue = TraverseStmt(If->getThen());
- AvailabilityStack.pop_back();
-
- return ShouldContinue && TraverseStmt(If->getElse());
-}
-
-} // end anonymous namespace
-
-void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
- Stmt *Body = nullptr;
-
- if (auto *FD = D->getAsFunction()) {
- // FIXME: We only examine the pattern decl for availability violations now,
- // but we should also examine instantiated templates.
- if (FD->isTemplateInstantiation())
- return;
-
- Body = FD->getBody();
- } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
- Body = MD->getBody();
- else if (auto *BD = dyn_cast<BlockDecl>(D))
- Body = BD->getBody();
-
- assert(Body && "Need a body here!");
-
- DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
-}
-
-void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess,
- bool AvoidPartialAvailabilityChecks,
- ObjCInterfaceDecl *ClassReceiver) {
- std::string Message;
- AvailabilityResult Result;
- const NamedDecl* OffendingDecl;
- // See if this declaration is unavailable, deprecated, or partial.
- std::tie(Result, OffendingDecl) =
- ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
- if (Result == AR_Available)
- return;
-
- if (Result == AR_NotYetIntroduced) {
- if (AvoidPartialAvailabilityChecks)
- return;
-
- // We need to know the @available context in the current function to
- // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
- // when we're done parsing the current function.
- if (getCurFunctionOrMethodDecl()) {
- getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
- return;
- } else if (getCurBlock() || getCurLambda()) {
- getCurFunction()->HasPotentialAvailabilityViolations = true;
- return;
- }
- }
-
- const ObjCPropertyDecl *ObjCPDecl = nullptr;
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
- if (PDeclResult == Result)
- ObjCPDecl = PD;
- }
- }
-
- EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
- UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
-}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 9916d3be77e1..22bf35dbd0cb 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -38,8 +38,9 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include <map>
#include <set>
@@ -51,102 +52,109 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses
- /// the default argument of a parameter to determine whether it
- /// contains any ill-formed subexpressions. For example, this will
- /// diagnose the use of local variables or parameters within the
- /// default argument expression.
- class CheckDefaultArgumentVisitor
- : public StmtVisitor<CheckDefaultArgumentVisitor, bool> {
- Expr *DefaultArg;
- Sema *S;
+/// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses
+/// the default argument of a parameter to determine whether it
+/// contains any ill-formed subexpressions. For example, this will
+/// diagnose the use of local variables or parameters within the
+/// default argument expression.
+class CheckDefaultArgumentVisitor
+ : public ConstStmtVisitor<CheckDefaultArgumentVisitor, bool> {
+ Sema &S;
+ const Expr *DefaultArg;
- public:
- CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
- : DefaultArg(defarg), S(s) {}
-
- bool VisitExpr(Expr *Node);
- bool VisitDeclRefExpr(DeclRefExpr *DRE);
- bool VisitCXXThisExpr(CXXThisExpr *ThisE);
- bool VisitLambdaExpr(LambdaExpr *Lambda);
- bool VisitPseudoObjectExpr(PseudoObjectExpr *POE);
- };
+public:
+ CheckDefaultArgumentVisitor(Sema &S, const Expr *DefaultArg)
+ : S(S), DefaultArg(DefaultArg) {}
+
+ bool VisitExpr(const Expr *Node);
+ bool VisitDeclRefExpr(const DeclRefExpr *DRE);
+ bool VisitCXXThisExpr(const CXXThisExpr *ThisE);
+ bool VisitLambdaExpr(const LambdaExpr *Lambda);
+ bool VisitPseudoObjectExpr(const PseudoObjectExpr *POE);
+};
- /// VisitExpr - Visit all of the children of this expression.
- bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) {
- bool IsInvalid = false;
- for (Stmt *SubStmt : Node->children())
- IsInvalid |= Visit(SubStmt);
- return IsInvalid;
- }
-
- /// VisitDeclRefExpr - Visit a reference to a declaration, to
- /// determine whether this declaration can be used in the default
- /// argument expression.
- bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) {
- NamedDecl *Decl = DRE->getDecl();
- if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(Decl)) {
- // C++ [dcl.fct.default]p9
- // Default arguments are evaluated each time the function is
- // called. The order of evaluation of function arguments is
- // unspecified. Consequently, parameters of a function shall not
- // be used in default argument expressions, even if they are not
- // evaluated. Parameters of a function declared before a default
- // argument expression are in scope and can hide namespace and
- // class member names.
- return S->Diag(DRE->getBeginLoc(),
- diag::err_param_default_argument_references_param)
+/// VisitExpr - Visit all of the children of this expression.
+bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
+ bool IsInvalid = false;
+ for (const Stmt *SubStmt : Node->children())
+ IsInvalid |= Visit(SubStmt);
+ return IsInvalid;
+}
+
+/// VisitDeclRefExpr - Visit a reference to a declaration, to
+/// determine whether this declaration can be used in the default
+/// argument expression.
+bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
+ const NamedDecl *Decl = DRE->getDecl();
+ if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
+ // C++ [dcl.fct.default]p9:
+ // [...] parameters of a function shall not be used in default
+ // argument expressions, even if they are not evaluated. [...]
+ //
+ // C++17 [dcl.fct.default]p9 (by CWG 2082):
+ // [...] A parameter shall not appear as a potentially-evaluated
+ // expression in a default argument. [...]
+ //
+ if (DRE->isNonOdrUse() != NOUR_Unevaluated)
+ return S.Diag(DRE->getBeginLoc(),
+ diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
- } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) {
- // C++ [dcl.fct.default]p7
- // Local variables shall not be used in default argument
- // expressions.
- if (VDecl->isLocalVarDecl())
- return S->Diag(DRE->getBeginLoc(),
- diag::err_param_default_argument_references_local)
- << VDecl->getDeclName() << DefaultArg->getSourceRange();
- }
-
- return false;
- }
-
- /// VisitCXXThisExpr - Visit a C++ "this" expression.
- bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) {
- // C++ [dcl.fct.default]p8:
- // The keyword this shall not be used in a default argument of a
- // member function.
- return S->Diag(ThisE->getBeginLoc(),
- diag::err_param_default_argument_references_this)
- << ThisE->getSourceRange();
+ } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) {
+ // C++ [dcl.fct.default]p7:
+ // Local variables shall not be used in default argument
+ // expressions.
+ //
+ // C++17 [dcl.fct.default]p7 (by CWG 2082):
+ // A local variable shall not appear as a potentially-evaluated
+ // 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.
+ //
+ if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
+ return S.Diag(DRE->getBeginLoc(),
+ diag::err_param_default_argument_references_local)
+ << VDecl->getDeclName() << DefaultArg->getSourceRange();
}
- bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
- bool Invalid = false;
- for (PseudoObjectExpr::semantics_iterator
- i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) {
- Expr *E = *i;
+ return false;
+}
- // Look through bindings.
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) {
- E = OVE->getSourceExpr();
- assert(E && "pseudo-object binding without source expression?");
- }
+/// VisitCXXThisExpr - Visit a C++ "this" expression.
+bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(const CXXThisExpr *ThisE) {
+ // C++ [dcl.fct.default]p8:
+ // The keyword this shall not be used in a default argument of a
+ // member function.
+ return S.Diag(ThisE->getBeginLoc(),
+ diag::err_param_default_argument_references_this)
+ << ThisE->getSourceRange();
+}
- Invalid |= Visit(E);
+bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
+ const PseudoObjectExpr *POE) {
+ bool Invalid = false;
+ for (const Expr *E : POE->semantics()) {
+ // Look through bindings.
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) {
+ E = OVE->getSourceExpr();
+ assert(E && "pseudo-object binding without source expression?");
}
- return Invalid;
+
+ Invalid |= Visit(E);
}
+ return Invalid;
+}
- bool CheckDefaultArgumentVisitor::VisitLambdaExpr(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;
+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);
- }
+ return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg);
}
+} // namespace
void
Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
@@ -246,14 +254,12 @@ void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) {
ComputedEST = EST_None;
}
-bool
-Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
- SourceLocation EqualLoc) {
+ExprResult Sema::ConvertParamDefaultArgument(const ParmVarDecl *Param,
+ Expr *Arg,
+ SourceLocation EqualLoc) {
if (RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
- Param->setInvalidDecl();
+ diag::err_typecheck_decl_incomplete_type))
return true;
- }
// C++ [dcl.fct.default]p5
// A default argument expression is implicitly converted (clause
@@ -274,7 +280,12 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
CheckCompletedExpr(Arg, EqualLoc);
Arg = MaybeCreateExprWithCleanups(Arg);
- // Okay: add the default argument to the parameter
+ return Arg;
+}
+
+void Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
+ SourceLocation EqualLoc) {
+ // Add the default argument to the parameter
Param->setDefaultArg(Arg);
// We have already instantiated this parameter; provide each of the
@@ -288,8 +299,6 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
// We're done tracking this parameter's instantiations.
UnparsedDefaultArgInstantiations.erase(InstPos);
}
-
- return false;
}
/// ActOnParamDefaultArgument - Check whether the default argument
@@ -304,18 +313,22 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
ParmVarDecl *Param = cast<ParmVarDecl>(param);
UnparsedDefaultArgLocs.erase(Param);
+ auto Fail = [&] {
+ Param->setInvalidDecl();
+ Param->setDefaultArg(new (Context) OpaqueValueExpr(
+ EqualLoc, Param->getType().getNonReferenceType(), VK_RValue));
+ };
+
// Default arguments are only permitted in C++
if (!getLangOpts().CPlusPlus) {
Diag(EqualLoc, diag::err_param_default_argument)
<< DefaultArg->getSourceRange();
- Param->setInvalidDecl();
- return;
+ return Fail();
}
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) {
- Param->setInvalidDecl();
- return;
+ return Fail();
}
// C++11 [dcl.fct.default]p3
@@ -324,15 +337,21 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
if (Param->isParameterPack()) {
Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack)
<< DefaultArg->getSourceRange();
+ // Recover by discarding the default argument.
+ Param->setDefaultArg(nullptr);
return;
}
+ ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc);
+ if (Result.isInvalid())
+ return Fail();
+
+ DefaultArg = Result.getAs<Expr>();
+
// Check that the default argument is well-formed
- CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this);
- if (DefaultArgChecker.Visit(DefaultArg)) {
- Param->setInvalidDecl();
- return;
- }
+ CheckDefaultArgumentVisitor DefaultArgChecker(*this, DefaultArg);
+ if (DefaultArgChecker.Visit(DefaultArg))
+ return Fail();
SetParamDefaultArgument(Param, DefaultArg, EqualLoc);
}
@@ -419,14 +438,9 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
}
static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) {
- for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) {
- const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1);
- if (!PVD->hasDefaultArg())
- return false;
- if (!PVD->hasInheritedDefaultArg())
- return true;
- }
- return false;
+ return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) {
+ return P->hasDefaultArg() && !P->hasInheritedDefaultArg();
+ });
}
/// MergeCXXFunctionDecl - Merge two declarations of the same C++
@@ -664,7 +678,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
// for the same class template shall not have equivalent
// parameter-declaration-clauses.
if (isa<CXXDeductionGuideDecl>(New) &&
- !New->isFunctionTemplateSpecialization()) {
+ !New->isFunctionTemplateSpecialization() && isVisible(Old)) {
Diag(New->getLocation(), diag::err_deduction_guide_redeclared);
Diag(Old->getLocation(), diag::note_previous_declaration);
}
@@ -761,7 +775,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
Err << SourceRange(Loc, Loc);
} else if (!CPlusPlus20Specifiers.empty()) {
auto &&Warn = Diag(CPlusPlus20SpecifierLocs.front(),
- getLangOpts().CPlusPlus2a
+ getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_decomp_decl_spec
: diag::ext_decomp_decl_spec);
Warn << (int)CPlusPlus20Specifiers.size()
@@ -778,7 +792,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// C++2a [dcl.struct.bind]p1:
// A cv that includes volatile is deprecated
if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) &&
- getLangOpts().CPlusPlus2a)
+ getLangOpts().CPlusPlus20)
Diag(DS.getVolatileSpecLoc(),
diag::warn_deprecated_volatile_structured_binding);
@@ -952,7 +966,7 @@ static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy,
Arg.getArgument().print(PrintingPolicy, OS);
First = false;
}
- return OS.str();
+ return std::string(OS.str());
}
static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup,
@@ -1052,7 +1066,7 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
TemplateArgumentListInfo &Args;
ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args)
: R(R), Args(Args) {}
- void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override {
S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant)
<< printTemplateArgs(S.Context.getPrintingPolicy(), Args);
}
@@ -1100,16 +1114,17 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc,
}
namespace {
-struct BindingDiagnosticTrap {
+struct InitializingBinding {
Sema &S;
- DiagnosticErrorTrap Trap;
- BindingDecl *BD;
-
- BindingDiagnosticTrap(Sema &S, BindingDecl *BD)
- : S(S), Trap(S.Diags), BD(BD) {}
- ~BindingDiagnosticTrap() {
- if (Trap.hasErrorOccurred())
- S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD;
+ InitializingBinding(Sema &S, BindingDecl *BD) : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::InitializingStructuredBinding;
+ Ctx.PointOfInstantiation = BD->getLocation();
+ Ctx.Entity = BD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~InitializingBinding() {
+ S.popCodeSynthesisContext();
}
};
}
@@ -1158,7 +1173,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
unsigned I = 0;
for (auto *B : Bindings) {
- BindingDiagnosticTrap Trap(S, B);
+ InitializingBinding InitContext(S, B);
SourceLocation Loc = B->getLocation();
ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
@@ -1528,25 +1543,34 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
/// [dcl.fct.default].
void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
unsigned NumParams = FD->getNumParams();
- unsigned p;
+ unsigned ParamIdx = 0;
+
+ // This checking doesn't make sense for explicit specializations; their
+ // default arguments are determined by the declaration we're specializing,
+ // not by FD.
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+ if (auto *FTD = FD->getDescribedFunctionTemplate())
+ if (FTD->isMemberSpecialization())
+ return;
// Find first parameter with a default argument
- for (p = 0; p < NumParams; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
+ for (; ParamIdx < NumParams; ++ParamIdx) {
+ ParmVarDecl *Param = FD->getParamDecl(ParamIdx);
if (Param->hasDefaultArg())
break;
}
- // C++11 [dcl.fct.default]p4:
+ // C++20 [dcl.fct.default]p4:
// In a given function declaration, each parameter subsequent to a parameter
// with a default argument shall have a default argument supplied in this or
- // a previous declaration or shall be a function parameter pack. A default
- // argument shall not be redefined by a later declaration (not even to the
- // same value).
- unsigned LastMissingDefaultArg = 0;
- for (; p < NumParams; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
- if (!Param->hasDefaultArg() && !Param->isParameterPack()) {
+ // a previous declaration, unless the parameter was expanded from a
+ // parameter pack, or shall be a function parameter pack.
+ for (; ParamIdx < NumParams; ++ParamIdx) {
+ ParmVarDecl *Param = FD->getParamDecl(ParamIdx);
+ if (!Param->hasDefaultArg() && !Param->isParameterPack() &&
+ !(CurrentInstantiationScope &&
+ CurrentInstantiationScope->isLocalPackExpansion(Param))) {
if (Param->isInvalidDecl())
/* We already complained about this parameter. */;
else if (Param->getIdentifier())
@@ -1556,21 +1580,6 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
else
Diag(Param->getLocation(),
diag::err_param_default_argument_missing);
-
- LastMissingDefaultArg = p;
- }
- }
-
- if (LastMissingDefaultArg > 0) {
- // Some default arguments were missing. Clear out all of the
- // default arguments up to (and including) the last missing
- // default argument, so that we leave the function parameters
- // in a semantically valid state.
- for (p = 0; p <= LastMissingDefaultArg; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->hasDefaultArg()) {
- Param->setDefaultArg(nullptr);
- }
}
}
}
@@ -1716,7 +1725,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
// - it shall not be virtual; (removed in C++20)
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus20) {
if (Kind == CheckConstexprKind::Diagnose)
Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
} else {
@@ -1856,11 +1865,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
if (Kind == Sema::CheckConstexprKind::Diagnose) {
SemaRef.Diag(
VD->getLocation(),
- SemaRef.getLangOpts().CPlusPlus2a
+ SemaRef.getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_constexpr_local_var_no_init
: diag::ext_constexpr_local_var_no_init)
<< isa<CXXConstructorDecl>(Dcl);
- } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ } else if (!SemaRef.getLangOpts().CPlusPlus20) {
return false;
}
continue;
@@ -1919,7 +1928,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef,
Sema::CheckConstexprKind Kind) {
// In C++20 onwards, there's nothing to check for validity.
if (Kind == Sema::CheckConstexprKind::CheckValid &&
- SemaRef.getLangOpts().CPlusPlus2a)
+ SemaRef.getLangOpts().CPlusPlus20)
return true;
if (Field->isInvalidDecl())
@@ -1941,14 +1950,14 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef,
if (Kind == Sema::CheckConstexprKind::Diagnose) {
if (!Diagnosed) {
SemaRef.Diag(Dcl->getLocation(),
- SemaRef.getLangOpts().CPlusPlus2a
+ SemaRef.getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_constexpr_ctor_missing_init
: diag::ext_constexpr_ctor_missing_init);
Diagnosed = true;
}
SemaRef.Diag(Field->getLocation(),
diag::note_constexpr_ctor_missing_init);
- } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ } else if (!SemaRef.getLangOpts().CPlusPlus20) {
return false;
}
} else if (Field->isAnonymousStructOrUnion()) {
@@ -2132,14 +2141,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
// apply the general constexpr rules.
switch (Kind) {
case Sema::CheckConstexprKind::CheckValid:
- if (!SemaRef.getLangOpts().CPlusPlus2a)
+ if (!SemaRef.getLangOpts().CPlusPlus20)
return false;
break;
case Sema::CheckConstexprKind::Diagnose:
SemaRef.Diag(Body->getBeginLoc(),
- !SemaRef.getLangOpts().CPlusPlus2a
- ? diag::ext_constexpr_function_try_block_cxx2a
+ !SemaRef.getLangOpts().CPlusPlus20
+ ? diag::ext_constexpr_function_try_block_cxx20
: diag::warn_cxx17_compat_constexpr_function_try_block)
<< isa<CXXConstructorDecl>(Dcl);
break;
@@ -2162,14 +2171,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
if (Kind == Sema::CheckConstexprKind::CheckValid) {
// If this is only valid as an extension, report that we don't satisfy the
// constraints of the current language.
- if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) ||
+ if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) ||
(Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17))
return false;
} else if (Cxx2aLoc.isValid()) {
SemaRef.Diag(Cxx2aLoc,
- SemaRef.getLangOpts().CPlusPlus2a
+ SemaRef.getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
- : diag::ext_constexpr_body_invalid_stmt_cxx2a)
+ : diag::ext_constexpr_body_invalid_stmt_cxx20)
<< isa<CXXConstructorDecl>(Dcl);
} else if (Cxx1yLoc.isValid()) {
SemaRef.Diag(Cxx1yLoc,
@@ -2194,10 +2203,10 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
if (Kind == Sema::CheckConstexprKind::Diagnose) {
SemaRef.Diag(
Dcl->getLocation(),
- SemaRef.getLangOpts().CPlusPlus2a
+ SemaRef.getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_constexpr_union_ctor_no_init
: diag::ext_constexpr_union_ctor_no_init);
- } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ } else if (!SemaRef.getLangOpts().CPlusPlus20) {
return false;
}
}
@@ -2306,7 +2315,7 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
!Expr::isPotentialConstantExpr(Dcl, Diags)) {
SemaRef.Diag(Dcl->getLocation(),
diag::ext_constexpr_function_never_constant_expr)
- << isa<CXXConstructorDecl>(Dcl);
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
for (size_t I = 0, N = Diags.size(); I != N; ++I)
SemaRef.Diag(Diags[I].first, Diags[I].second);
// Don't return false here: we allow this for compatibility in
@@ -2417,7 +2426,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
TypeSourceInfo *TInfo,
SourceLocation EllipsisLoc) {
QualType BaseType = TInfo->getType();
-
+ if (BaseType->containsErrors()) {
+ // Already emitted a diagnostic when parsing the error type.
+ return nullptr;
+ }
// C++ [class.union]p1:
// A union shall not have base classes.
if (Class->isUnion()) {
@@ -2821,13 +2833,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
/// if there is an error, and Range is the source range to highlight
/// if there is an error.
///
-/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the
+/// If either InaccessibleBaseID or AmbiguousBaseConvID are 0, then the
/// diagnostic for the respective type of error will be suppressed, but the
/// check for ill-formed code will still be performed.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
- unsigned AmbigiousBaseConvID,
+ unsigned AmbiguousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name,
CXXCastPath *BasePath,
@@ -2853,7 +2865,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
for (const CXXBasePath &PossiblePath : Paths) {
if (PossiblePath.size() == 1) {
Path = &PossiblePath;
- if (AmbigiousBaseConvID)
+ if (AmbiguousBaseConvID)
Diag(Loc, diag::ext_ms_ambiguous_direct_base)
<< Base << Derived << Range;
break;
@@ -2881,7 +2893,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
return false;
}
- if (AmbigiousBaseConvID) {
+ if (AmbiguousBaseConvID) {
// We know that the derived-to-base conversion is ambiguous, and
// we're going to produce a diagnostic. Perform the derived-to-base
// search just one more time to compute all of the possible paths so
@@ -2900,7 +2912,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
// to each base class subobject.
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
- Diag(Loc, AmbigiousBaseConvID)
+ Diag(Loc, AmbiguousBaseConvID)
<< Derived << Base << PathDisplayStr << Range << Name;
}
return true;
@@ -3033,7 +3045,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
<< MD->getDeclName();
}
-void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
+void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent) {
if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>())
return;
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
@@ -3049,12 +3061,22 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
return;
if (MD->size_overridden_methods() > 0) {
- unsigned DiagID = isa<CXXDestructorDecl>(MD)
- ? diag::warn_destructor_marked_not_override_overriding
- : diag::warn_function_marked_not_override_overriding;
- Diag(MD->getLocation(), DiagID) << MD->getDeclName();
- const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
- Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
+ auto EmitDiag = [&](unsigned DiagInconsistent, unsigned DiagSuggest) {
+ unsigned DiagID =
+ Inconsistent && !Diags.isIgnored(DiagInconsistent, MD->getLocation())
+ ? DiagInconsistent
+ : DiagSuggest;
+ Diag(MD->getLocation(), DiagID) << MD->getDeclName();
+ const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
+ Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
+ };
+ if (isa<CXXDestructorDecl>(MD))
+ EmitDiag(
+ diag::warn_inconsistent_destructor_marked_not_override_overriding,
+ diag::warn_suggest_destructor_marked_not_override_overriding);
+ else
+ EmitDiag(diag::warn_inconsistent_function_marked_not_override_overriding,
+ diag::warn_suggest_function_marked_not_override_overriding);
}
}
@@ -5443,6 +5465,15 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// subobjects.
bool VisitVirtualBases = !ClassDecl->isAbstract();
+ // If the destructor exists and has already been marked used in the MS ABI,
+ // then virtual base destructors have already been checked and marked used.
+ // Skip checking them again to avoid duplicate diagnostics.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ CXXDestructorDecl *Dtor = ClassDecl->getDestructor();
+ if (Dtor && Dtor->isUsed())
+ VisitVirtualBases = false;
+ }
+
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
// Bases.
@@ -5477,16 +5508,21 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
DiagnoseUseOfDecl(Dtor, Location);
}
- if (!VisitVirtualBases)
- return;
+ if (VisitVirtualBases)
+ MarkVirtualBaseDestructorsReferenced(Location, ClassDecl,
+ &DirectVirtualBases);
+}
+void Sema::MarkVirtualBaseDestructorsReferenced(
+ SourceLocation Location, CXXRecordDecl *ClassDecl,
+ llvm::SmallPtrSetImpl<const RecordType *> *DirectVirtualBases) {
// Virtual bases.
for (const auto &VBase : ClassDecl->vbases()) {
// Bases are always records in a well-formed non-dependent class.
const RecordType *RT = VBase.getType()->castAs<RecordType>();
- // Ignore direct virtual bases.
- if (DirectVirtualBases.count(RT))
+ // Ignore already visited direct virtual bases.
+ if (DirectVirtualBases && DirectVirtualBases->count(RT))
continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
@@ -5788,6 +5824,23 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) {
// declaration.
return;
+ // Add a context note to explain how we got to any diagnostics produced below.
+ struct MarkingClassDllexported {
+ Sema &S;
+ MarkingClassDllexported(Sema &S, CXXRecordDecl *Class,
+ SourceLocation AttrLoc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::MarkingClassDllexported;
+ Ctx.PointOfInstantiation = AttrLoc;
+ Ctx.Entity = Class;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~MarkingClassDllexported() {
+ S.popCodeSynthesisContext();
+ }
+ } MarkingDllexportedContext(S, Class, ClassAttr->getLocation());
+
if (S.Context.getTargetInfo().getTriple().isWindowsGNUEnvironment())
S.MarkVTableUsed(Class->getLocation(), Class, true);
@@ -5823,13 +5876,7 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) {
// defaulted methods, and the copy and move assignment operators. The
// latter are exported even if they are trivial, because the address of
// an operator can be taken and should compare equal across libraries.
- DiagnosticErrorTrap Trap(S.Diags);
S.MarkFunctionReferenced(Class->getLocation(), MD);
- if (Trap.hasErrorOccurred()) {
- S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class)
- << Class << !S.getLangOpts().CPlusPlus11;
- break;
- }
// There is no later point when we will see the definition of this
// function, so pass it to the consumer now.
@@ -5877,6 +5924,123 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S,
}
}
+static void checkCUDADeviceBuiltinSurfaceClassTemplate(Sema &S,
+ CXXRecordDecl *Class) {
+ bool ErrorReported = false;
+ auto reportIllegalClassTemplate = [&ErrorReported](Sema &S,
+ ClassTemplateDecl *TD) {
+ if (ErrorReported)
+ return;
+ S.Diag(TD->getLocation(),
+ diag::err_cuda_device_builtin_surftex_cls_template)
+ << /*surface*/ 0 << TD;
+ ErrorReported = true;
+ };
+
+ ClassTemplateDecl *TD = Class->getDescribedClassTemplate();
+ if (!TD) {
+ auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class);
+ if (!SD) {
+ S.Diag(Class->getLocation(),
+ diag::err_cuda_device_builtin_surftex_ref_decl)
+ << /*surface*/ 0 << Class;
+ S.Diag(Class->getLocation(),
+ diag::note_cuda_device_builtin_surftex_should_be_template_class)
+ << Class;
+ return;
+ }
+ TD = SD->getSpecializedTemplate();
+ }
+
+ TemplateParameterList *Params = TD->getTemplateParameters();
+ unsigned N = Params->size();
+
+ if (N != 2) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_n_args)
+ << TD << 2;
+ }
+ if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg)
+ << TD << /*1st*/ 0 << /*type*/ 0;
+ }
+ if (N > 1) {
+ auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
+ if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg)
+ << TD << /*2nd*/ 1 << /*integer*/ 1;
+ }
+ }
+}
+
+static void checkCUDADeviceBuiltinTextureClassTemplate(Sema &S,
+ CXXRecordDecl *Class) {
+ bool ErrorReported = false;
+ auto reportIllegalClassTemplate = [&ErrorReported](Sema &S,
+ ClassTemplateDecl *TD) {
+ if (ErrorReported)
+ return;
+ S.Diag(TD->getLocation(),
+ diag::err_cuda_device_builtin_surftex_cls_template)
+ << /*texture*/ 1 << TD;
+ ErrorReported = true;
+ };
+
+ ClassTemplateDecl *TD = Class->getDescribedClassTemplate();
+ if (!TD) {
+ auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class);
+ if (!SD) {
+ S.Diag(Class->getLocation(),
+ diag::err_cuda_device_builtin_surftex_ref_decl)
+ << /*texture*/ 1 << Class;
+ S.Diag(Class->getLocation(),
+ diag::note_cuda_device_builtin_surftex_should_be_template_class)
+ << Class;
+ return;
+ }
+ TD = SD->getSpecializedTemplate();
+ }
+
+ TemplateParameterList *Params = TD->getTemplateParameters();
+ unsigned N = Params->size();
+
+ if (N != 3) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_n_args)
+ << TD << 3;
+ }
+ if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg)
+ << TD << /*1st*/ 0 << /*type*/ 0;
+ }
+ if (N > 1) {
+ auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
+ if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg)
+ << TD << /*2nd*/ 1 << /*integer*/ 1;
+ }
+ }
+ if (N > 2) {
+ auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(2));
+ if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) {
+ reportIllegalClassTemplate(S, TD);
+ S.Diag(TD->getLocation(),
+ diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg)
+ << TD << /*3rd*/ 2 << /*integer*/ 1;
+ }
+ }
+}
+
void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) {
// Mark any compiler-generated routines with the implicit code_seg attribute.
for (auto *Method : Class->methods()) {
@@ -6151,7 +6315,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
case OO_Spaceship:
// No point allowing this if <=> doesn't exist in the current language mode.
- if (!getLangOpts().CPlusPlus2a)
+ if (!getLangOpts().CPlusPlus20)
break;
return DefaultedComparisonKind::ThreeWay;
@@ -6160,7 +6324,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
case OO_Greater:
case OO_GreaterEqual:
// No point allowing this if <=> doesn't exist in the current language mode.
- if (!getLangOpts().CPlusPlus2a)
+ if (!getLangOpts().CPlusPlus20)
break;
return DefaultedComparisonKind::Relational;
@@ -6172,27 +6336,31 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
return DefaultedFunctionKind();
}
-static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
- SourceLocation DefaultLoc) {
- switch (S.getSpecialMember(MD)) {
+static void DefineDefaultedFunction(Sema &S, FunctionDecl *FD,
+ SourceLocation DefaultLoc) {
+ Sema::DefaultedFunctionKind DFK = S.getDefaultedFunctionKind(FD);
+ if (DFK.isComparison())
+ return S.DefineDefaultedComparison(DefaultLoc, FD, DFK.asComparison());
+
+ switch (DFK.asSpecialMember()) {
case Sema::CXXDefaultConstructor:
S.DefineImplicitDefaultConstructor(DefaultLoc,
- cast<CXXConstructorDecl>(MD));
+ cast<CXXConstructorDecl>(FD));
break;
case Sema::CXXCopyConstructor:
- S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD));
break;
case Sema::CXXCopyAssignment:
- S.DefineImplicitCopyAssignment(DefaultLoc, MD);
+ S.DefineImplicitCopyAssignment(DefaultLoc, cast<CXXMethodDecl>(FD));
break;
case Sema::CXXDestructor:
- S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
+ S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(FD));
break;
case Sema::CXXMoveConstructor:
- S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD));
break;
case Sema::CXXMoveAssignment:
- S.DefineImplicitMoveAssignment(DefaultLoc, MD);
+ S.DefineImplicitMoveAssignment(DefaultLoc, cast<CXXMethodDecl>(FD));
break;
case Sema::CXXInvalid:
llvm_unreachable("Invalid special member.");
@@ -6313,6 +6481,27 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
return HasNonDeletedCopyOrMove;
}
+/// Report an error regarding overriding, along with any relevant
+/// overridden methods.
+///
+/// \param DiagID the primary error to report.
+/// \param MD the overriding method.
+static bool
+ReportOverrides(Sema &S, unsigned DiagID, const CXXMethodDecl *MD,
+ llvm::function_ref<bool(const CXXMethodDecl *)> Report) {
+ bool IssuedDiagnostic = false;
+ for (const CXXMethodDecl *O : MD->overridden_methods()) {
+ if (Report(O)) {
+ if (!IssuedDiagnostic) {
+ S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
+ IssuedDiagnostic = true;
+ }
+ S.Diag(O->getLocation(), diag::note_overridden_virtual_function);
+ }
+ }
+ return IssuedDiagnostic;
+}
+
/// Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -6427,21 +6616,64 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// primary comparison functions (==, <=>).
llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons;
- auto CheckForDefaultedFunction = [&](FunctionDecl *FD) {
- if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
+ // Perform checks that can't be done until we know all the properties of a
+ // member function (whether it's defaulted, deleted, virtual, overriding,
+ // ...).
+ auto CheckCompletedMemberFunction = [&](CXXMethodDecl *MD) {
+ // A static function cannot override anything.
+ if (MD->getStorageClass() == SC_Static) {
+ if (ReportOverrides(*this, diag::err_static_overrides_virtual, MD,
+ [](const CXXMethodDecl *) { return true; }))
+ return;
+ }
+
+ // A deleted function cannot override a non-deleted function and vice
+ // versa.
+ if (ReportOverrides(*this,
+ MD->isDeleted() ? diag::err_deleted_override
+ : diag::err_non_deleted_override,
+ MD, [&](const CXXMethodDecl *V) {
+ return MD->isDeleted() != V->isDeleted();
+ })) {
+ if (MD->isDefaulted() && MD->isDeleted())
+ // Explain why this defaulted function was deleted.
+ DiagnoseDeletedDefaultedFunction(MD);
return;
+ }
+
+ // A consteval function cannot override a non-consteval function and vice
+ // versa.
+ if (ReportOverrides(*this,
+ MD->isConsteval() ? diag::err_consteval_override
+ : diag::err_non_consteval_override,
+ MD, [&](const CXXMethodDecl *V) {
+ return MD->isConsteval() != V->isConsteval();
+ })) {
+ if (MD->isDefaulted() && MD->isDeleted())
+ // Explain why this defaulted function was deleted.
+ DiagnoseDeletedDefaultedFunction(MD);
+ return;
+ }
+ };
+
+ auto CheckForDefaultedFunction = [&](FunctionDecl *FD) -> bool {
+ if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
+ return false;
DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
if (DFK.asComparison() == DefaultedComparisonKind::NotEqual ||
- DFK.asComparison() == DefaultedComparisonKind::Relational)
+ DFK.asComparison() == DefaultedComparisonKind::Relational) {
DefaultedSecondaryComparisons.push_back(FD);
- else
- CheckExplicitlyDefaultedFunction(S, FD);
+ return true;
+ }
+
+ CheckExplicitlyDefaultedFunction(S, FD);
+ return false;
};
auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
// Check whether the explicitly-defaulted members are valid.
- CheckForDefaultedFunction(M);
+ bool Incomplete = CheckForDefaultedFunction(M);
// Skip the rest of the checks for a member of a dependent class.
if (Record->isDependentType())
@@ -6488,7 +6720,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// 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())
- DefineImplicitSpecialMember(*this, M, M->getLocation());
+ DefineDefaultedFunction(*this, M, M->getLocation());
+
+ if (!Incomplete)
+ CheckCompletedMemberFunction(M);
};
// Check the destructor before any other member function. We need to
@@ -6524,19 +6759,21 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
}
}
- if (HasMethodWithOverrideControl &&
- HasOverridingMethodWithoutOverrideControl) {
- // At least one method has the 'override' control declared.
- // Diagnose all other overridden methods which do not have 'override'
- // specified on them.
+ if (HasOverridingMethodWithoutOverrideControl) {
+ bool HasInconsistentOverrideControl = HasMethodWithOverrideControl;
for (auto *M : Record->methods())
- DiagnoseAbsenceOfOverrideControl(M);
+ DiagnoseAbsenceOfOverrideControl(M, HasInconsistentOverrideControl);
}
// Check the defaulted secondary comparisons after any other member functions.
- for (FunctionDecl *FD : DefaultedSecondaryComparisons)
+ for (FunctionDecl *FD : DefaultedSecondaryComparisons) {
CheckExplicitlyDefaultedFunction(S, FD);
+ // If this is a member function, we deferred checking it until now.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD))
+ CheckCompletedMemberFunction(MD);
+ }
+
// ms_struct is a request to use the same ABI rules as MSVC. Check
// whether this class uses any C++ features that are implemented
// completely differently in MSVC, and if so, emit a diagnostic.
@@ -6546,7 +6783,11 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// headers, sweeping up a bunch of types that the project doesn't
// really rely on MSVC-compatible layout for. We must therefore
// support "ms_struct except for C++ stuff" as a secondary ABI.
- if (Record->isMsStruct(Context) &&
+ // Don't emit this diagnostic if the feature was enabled as a
+ // language option (as opposed to via a pragma or attribute), as
+ // the option -mms-bitfields otherwise essentially makes it impossible
+ // to build C++ code, unless this diagnostic is turned off.
+ if (Record->isMsStruct(Context) && !Context.getLangOpts().MSBitfields &&
(Record->isPolymorphic() || Record->getNumBases())) {
Diag(Record->getLocation(), diag::warn_cxx_ms_struct);
}
@@ -6581,6 +6822,13 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// is especially required for cases like vtable assumption loads.
MarkVTableUsed(Record->getInnerLocStart(), Record);
}
+
+ if (getLangOpts().CUDA) {
+ if (Record->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>())
+ checkCUDADeviceBuiltinSurfaceClassTemplate(*this, Record);
+ else if (Record->hasAttr<CUDADeviceBuiltinTextureTypeAttr>())
+ checkCUDADeviceBuiltinTextureClassTemplate(*this, Record);
+ }
}
/// Look up the special member function that would be called by a special
@@ -6955,7 +7203,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
// C++2a changes the second bullet to instead delete the function if it's
// defaulted on its first declaration, unless it's "an assignment operator,
// and its return type differs or its parameter type is not a reference".
- bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus2a && First;
+ bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus20 && First;
bool ShouldDeleteForTypeMismatch = false;
unsigned ExpectedParams = 1;
if (CSM == CXXDefaultConstructor || CSM == CXXDestructor)
@@ -7065,7 +7313,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
// FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
- if ((getLangOpts().CPlusPlus2a ||
+ if ((getLangOpts().CPlusPlus20 ||
(getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
: isa<CXXConstructorDecl>(MD))) &&
MD->isConstexpr() && !Constexpr &&
@@ -7083,7 +7331,9 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
// If a function is explicitly defaulted on its first declaration, it is
// implicitly considered to be constexpr if the implicit declaration
// would be.
- MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified);
+ MD->setConstexprKind(
+ Constexpr ? (MD->isConsteval() ? CSK_consteval : CSK_constexpr)
+ : CSK_unspecified);
if (!Type->hasExceptionSpec()) {
// C++2a [except.spec]p3:
@@ -7373,7 +7623,14 @@ private:
/// resolution [...]
CandidateSet.exclude(FD);
- S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+ if (Args[0]->getType()->isOverloadableType())
+ S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+ else {
+ // FIXME: We determine whether this is a valid expression by checking to
+ // see if there's a viable builtin operator candidate for it. That isn't
+ // really what the rules ask us to do, but should give the right results.
+ S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet);
+ }
Result R;
@@ -7438,6 +7695,31 @@ private:
if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
if (auto *BestFD = Best->Function) {
+ // If any callee has an undeduced return type, deduce it now.
+ // FIXME: It's not clear how a failure here should be handled. For
+ // now, we produce an eager diagnostic, because that is forward
+ // compatible with most (all?) other reasonable options.
+ if (BestFD->getReturnType()->isUndeducedType() &&
+ S.DeduceReturnType(BestFD, FD->getLocation(),
+ /*Diagnose=*/false)) {
+ // Don't produce a duplicate error when asked to explain why the
+ // comparison is deleted: we diagnosed that when initially checking
+ // the defaulted operator.
+ if (Diagnose == NoDiagnostics) {
+ S.Diag(
+ FD->getLocation(),
+ diag::err_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(
+ Subobj.Loc,
+ diag::note_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_cannot_deduce_callee)
+ << Subobj.Kind << Subobj.Decl;
+ }
+ return Result::deleted();
+ }
if (auto *Info = S.Context.CompCategories.lookupInfoForType(
BestFD->getCallResultType())) {
R.Category = Info->Kind;
@@ -7826,10 +8108,14 @@ private:
return StmtError();
OverloadedOperatorKind OO = FD->getOverloadedOperator();
- ExprResult Op = S.CreateOverloadedBinOp(
- Loc, BinaryOperator::getOverloadedOpcode(OO), Fns,
- Obj.first.get(), Obj.second.get(), /*PerformADL=*/true,
- /*AllowRewrittenCandidates=*/true, FD);
+ BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(OO);
+ ExprResult Op;
+ if (Type->isOverloadableType())
+ Op = S.CreateOverloadedBinOp(Loc, Opc, Fns, Obj.first.get(),
+ Obj.second.get(), /*PerformADL=*/true,
+ /*AllowRewrittenCandidates=*/true, FD);
+ else
+ Op = S.CreateBuiltinBinOp(Loc, Opc, Obj.first.get(), Obj.second.get());
if (Op.isInvalid())
return StmtError();
@@ -7869,8 +8155,12 @@ private:
llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
Expr *Zero =
IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc);
- ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(),
- Zero, true, true, FD);
+ ExprResult Comp;
+ if (VDRef.get()->getType()->isOverloadableType())
+ Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), Zero, true,
+ true, FD);
+ else
+ Comp = S.CreateBuiltinBinOp(Loc, BO_NE, VDRef.get(), Zero);
if (Comp.isInvalid())
return StmtError();
Sema::ConditionResult Cond = S.ActOnCondition(
@@ -9423,27 +9713,57 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) {
}
void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) {
- auto PrintDiagAndRemoveAttr = [&]() {
+ auto PrintDiagAndRemoveAttr = [&](unsigned N) {
// No diagnostics if this is a template instantiation.
- if (!isTemplateInstantiation(RD.getTemplateSpecializationKind()))
+ if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) {
Diag(RD.getAttr<TrivialABIAttr>()->getLocation(),
diag::ext_cannot_use_trivial_abi) << &RD;
+ Diag(RD.getAttr<TrivialABIAttr>()->getLocation(),
+ diag::note_cannot_use_trivial_abi_reason) << &RD << N;
+ }
RD.dropAttr<TrivialABIAttr>();
};
+ // Ill-formed if the copy and move constructors are deleted.
+ auto HasNonDeletedCopyOrMoveConstructor = [&]() {
+ // If the type is dependent, then assume it might have
+ // implicit copy or move ctor because we won't know yet at this point.
+ if (RD.isDependentType())
+ return true;
+ if (RD.needsImplicitCopyConstructor() &&
+ !RD.defaultedCopyConstructorIsDeleted())
+ return true;
+ if (RD.needsImplicitMoveConstructor() &&
+ !RD.defaultedMoveConstructorIsDeleted())
+ return true;
+ for (const CXXConstructorDecl *CD : RD.ctors())
+ if (CD->isCopyOrMoveConstructor() && !CD->isDeleted())
+ return true;
+ return false;
+ };
+
+ if (!HasNonDeletedCopyOrMoveConstructor()) {
+ PrintDiagAndRemoveAttr(0);
+ return;
+ }
+
// Ill-formed if the struct has virtual functions.
if (RD.isPolymorphic()) {
- PrintDiagAndRemoveAttr();
+ PrintDiagAndRemoveAttr(1);
return;
}
for (const auto &B : RD.bases()) {
// Ill-formed if the base class is non-trivial for the purpose of calls or a
// virtual base.
- if ((!B.getType()->isDependentType() &&
- !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) ||
- B.isVirtual()) {
- PrintDiagAndRemoveAttr();
+ if (!B.getType()->isDependentType() &&
+ !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) {
+ PrintDiagAndRemoveAttr(2);
+ return;
+ }
+
+ if (B.isVirtual()) {
+ PrintDiagAndRemoveAttr(3);
return;
}
}
@@ -9453,14 +9773,14 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) {
// non-trivial for the purpose of calls.
QualType FT = FD->getType();
if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) {
- PrintDiagAndRemoveAttr();
+ PrintDiagAndRemoveAttr(4);
return;
}
if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>())
if (!RT->isDependentType() &&
!cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) {
- PrintDiagAndRemoveAttr();
+ PrintDiagAndRemoveAttr(5);
return;
}
}
@@ -9533,86 +9853,95 @@ static void findImplicitlyDeclaredEqualityComparisons(
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
- if (ClassDecl->needsImplicitDefaultConstructor()) {
- ++getASTContext().NumImplicitDefaultConstructors;
+ // Don't add implicit special members to templated classes.
+ // FIXME: This means unqualified lookups for 'operator=' within a class
+ // template don't work properly.
+ if (!ClassDecl->isDependentType()) {
+ if (ClassDecl->needsImplicitDefaultConstructor()) {
+ ++getASTContext().NumImplicitDefaultConstructors;
- if (ClassDecl->hasInheritedConstructor())
- DeclareImplicitDefaultConstructor(ClassDecl);
- }
+ if (ClassDecl->hasInheritedConstructor())
+ DeclareImplicitDefaultConstructor(ClassDecl);
+ }
- if (ClassDecl->needsImplicitCopyConstructor()) {
- ++getASTContext().NumImplicitCopyConstructors;
+ if (ClassDecl->needsImplicitCopyConstructor()) {
+ ++getASTContext().NumImplicitCopyConstructors;
- // If the properties or semantics of the copy constructor couldn't be
- // determined while the class was being declared, force a declaration
- // of it now.
- if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
- ClassDecl->hasInheritedConstructor())
- DeclareImplicitCopyConstructor(ClassDecl);
- // For the MS ABI we need to know whether the copy ctor is deleted. A
- // prerequisite for deleting the implicit copy ctor is that the class has a
- // move ctor or move assignment that is either user-declared or whose
- // semantics are inherited from a subobject. FIXME: We should provide a more
- // direct way for CodeGen to ask whether the constructor was deleted.
- else if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- (ClassDecl->hasUserDeclaredMoveConstructor() ||
- ClassDecl->needsOverloadResolutionForMoveConstructor() ||
- ClassDecl->hasUserDeclaredMoveAssignment() ||
- ClassDecl->needsOverloadResolutionForMoveAssignment()))
- DeclareImplicitCopyConstructor(ClassDecl);
- }
+ // If the properties or semantics of the copy constructor couldn't be
+ // determined while the class was being declared, force a declaration
+ // of it now.
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
+ ClassDecl->hasInheritedConstructor())
+ DeclareImplicitCopyConstructor(ClassDecl);
+ // For the MS ABI we need to know whether the copy ctor is deleted. A
+ // prerequisite for deleting the implicit copy ctor is that the class has
+ // a move ctor or move assignment that is either user-declared or whose
+ // semantics are inherited from a subobject. FIXME: We should provide a
+ // more direct way for CodeGen to ask whether the constructor was deleted.
+ else if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ (ClassDecl->hasUserDeclaredMoveConstructor() ||
+ ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+ ClassDecl->hasUserDeclaredMoveAssignment() ||
+ ClassDecl->needsOverloadResolutionForMoveAssignment()))
+ DeclareImplicitCopyConstructor(ClassDecl);
+ }
- if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
- ++getASTContext().NumImplicitMoveConstructors;
+ if (getLangOpts().CPlusPlus11 &&
+ ClassDecl->needsImplicitMoveConstructor()) {
+ ++getASTContext().NumImplicitMoveConstructors;
- if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
- ClassDecl->hasInheritedConstructor())
- DeclareImplicitMoveConstructor(ClassDecl);
- }
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+ ClassDecl->hasInheritedConstructor())
+ DeclareImplicitMoveConstructor(ClassDecl);
+ }
- if (ClassDecl->needsImplicitCopyAssignment()) {
- ++getASTContext().NumImplicitCopyAssignmentOperators;
+ if (ClassDecl->needsImplicitCopyAssignment()) {
+ ++getASTContext().NumImplicitCopyAssignmentOperators;
- // If we have a dynamic class, then the copy assignment operator may be
- // virtual, so we have to declare it immediately. This ensures that, e.g.,
- // it shows up in the right place in the vtable and that we diagnose
- // problems with the implicit exception specification.
- if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForCopyAssignment() ||
- ClassDecl->hasInheritedAssignment())
- DeclareImplicitCopyAssignment(ClassDecl);
- }
+ // If we have a dynamic class, then the copy assignment operator may be
+ // virtual, so we have to declare it immediately. This ensures that, e.g.,
+ // it shows up in the right place in the vtable and that we diagnose
+ // problems with the implicit exception specification.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForCopyAssignment() ||
+ ClassDecl->hasInheritedAssignment())
+ DeclareImplicitCopyAssignment(ClassDecl);
+ }
- if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
- ++getASTContext().NumImplicitMoveAssignmentOperators;
+ if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
+ ++getASTContext().NumImplicitMoveAssignmentOperators;
- // Likewise for the move assignment operator.
- if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForMoveAssignment() ||
- ClassDecl->hasInheritedAssignment())
- DeclareImplicitMoveAssignment(ClassDecl);
- }
+ // Likewise for the move assignment operator.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForMoveAssignment() ||
+ ClassDecl->hasInheritedAssignment())
+ DeclareImplicitMoveAssignment(ClassDecl);
+ }
- if (ClassDecl->needsImplicitDestructor()) {
- ++getASTContext().NumImplicitDestructors;
+ if (ClassDecl->needsImplicitDestructor()) {
+ ++getASTContext().NumImplicitDestructors;
- // If we have a dynamic class, then the destructor may be virtual, so we
- // have to declare the destructor immediately. This ensures that, e.g., it
- // shows up in the right place in the vtable and that we diagnose problems
- // with the implicit exception specification.
- if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForDestructor())
- DeclareImplicitDestructor(ClassDecl);
+ // If we have a dynamic class, then the destructor may be virtual, so we
+ // have to declare the destructor immediately. This ensures that, e.g., it
+ // shows up in the right place in the vtable and that we diagnose problems
+ // with the implicit exception specification.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForDestructor())
+ DeclareImplicitDestructor(ClassDecl);
+ }
}
// C++2a [class.compare.default]p3:
// If the member-specification does not explicitly declare any member or
// friend named operator==, an == operator function is declared implicitly
- // for each defaulted three-way comparison operator function defined in the
- // member-specification
+ // for each defaulted three-way comparison operator function defined in
+ // the member-specification
// FIXME: Consider doing this lazily.
- if (getLangOpts().CPlusPlus2a) {
- llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships;
+ // We do this during the initial parse for a class template, not during
+ // instantiation, so that we can handle unqualified lookups for 'operator=='
+ // when parsing the template.
+ if (getLangOpts().CPlusPlus20 && !inTemplateInstantiation()) {
+ llvm::SmallVector<FunctionDecl *, 4> DefaultedSpaceships;
findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl,
DefaultedSpaceships);
for (auto *FD : DefaultedSpaceships)
@@ -9620,19 +9949,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
}
-unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
+unsigned
+Sema::ActOnReenterTemplateScope(Decl *D,
+ llvm::function_ref<Scope *()> EnterScope) {
if (!D)
return 0;
+ AdjustDeclIfTemplate(D);
- // The order of template parameters is not important here. All names
- // get added to the same scope.
+ // In order to get name lookup right, reenter template scopes in order from
+ // outermost to innermost.
SmallVector<TemplateParameterList *, 4> ParameterLists;
-
- if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
- D = TD->getTemplatedDecl();
-
- if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
- ParameterLists.push_back(PSD->getTemplateParameters());
+ DeclContext *LookupDC = dyn_cast<DeclContext>(D);
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i)
@@ -9641,31 +9968,49 @@ unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
ParameterLists.push_back(FTD->getTemplateParameters());
- }
- }
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ LookupDC = VD->getDeclContext();
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate())
+ ParameterLists.push_back(VTD->getTemplateParameters());
+ else if (auto *PSD = dyn_cast<VarTemplatePartialSpecializationDecl>(D))
+ ParameterLists.push_back(PSD->getTemplateParameters());
+ }
+ } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i)
ParameterLists.push_back(TD->getTemplateParameterList(i));
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
ParameterLists.push_back(CTD->getTemplateParameters());
+ else if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
+ ParameterLists.push_back(PSD->getTemplateParameters());
}
}
+ // FIXME: Alias declarations and concepts.
unsigned Count = 0;
+ Scope *InnermostTemplateScope = nullptr;
for (TemplateParameterList *Params : ParameterLists) {
- if (Params->size() > 0)
- // Ignore explicit specializations; they don't contribute to the template
- // depth.
- ++Count;
+ // Ignore explicit specializations; they don't contribute to the template
+ // depth.
+ if (Params->size() == 0)
+ continue;
+
+ InnermostTemplateScope = EnterScope();
for (NamedDecl *Param : *Params) {
if (Param->getDeclName()) {
- S->AddDecl(Param);
+ InnermostTemplateScope->AddDecl(Param);
IdResolver.AddDecl(Param);
}
}
+ ++Count;
+ }
+
+ // Associate the new template scopes with the corresponding entities.
+ if (InnermostTemplateScope) {
+ assert(LookupDC && "no enclosing DeclContext for template lookup");
+ EnterTemplatedContext(InnermostTemplateScope, LookupDC);
}
return Count;
@@ -9717,11 +10062,6 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) {
ParmVarDecl *Param = cast<ParmVarDecl>(ParamD);
- // If this parameter has an unparsed default argument, clear it out
- // to make way for the parsed default argument.
- if (Param->hasUnparsedDefaultArg())
- Param->setDefaultArg(nullptr);
-
S->AddDecl(Param);
if (Param->getDeclName())
IdResolver.AddDecl(Param);
@@ -9855,11 +10195,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
// either there are no other parameters or else all other
// parameters have default arguments.
if (!Constructor->isInvalidDecl() &&
- ((Constructor->getNumParams() == 1) ||
- (Constructor->getNumParams() > 1 &&
- Constructor->getParamDecl(1)->hasDefaultArg())) &&
- Constructor->getTemplateSpecializationKind()
- != TSK_ImplicitInstantiation) {
+ Constructor->hasOneParamOrDefaultArgs() &&
+ Constructor->getTemplateSpecializationKind() !=
+ TSK_ImplicitInstantiation) {
QualType ParamType = Constructor->getParamDecl(0)->getType();
QualType ClassTy = Context.getTagDeclType(ClassDecl);
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
@@ -9944,12 +10282,12 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
// declaration.
QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName);
if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
- Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+ Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name)
<< DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
else if (const TemplateSpecializationType *TST =
DeclaratorType->getAs<TemplateSpecializationType>())
if (TST->isTypeAlias())
- Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+ Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name)
<< DeclaratorType << 1;
// C++ [class.dtor]p2:
@@ -10211,7 +10549,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
- if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a)
+ if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20)
Diag(DS.getExplicitSpecLoc(),
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_explicit_conversion_functions
@@ -10230,15 +10568,12 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
// Make sure we aren't redeclaring the conversion function.
QualType ConvType = Context.getCanonicalType(Conversion->getConversionType());
-
// C++ [class.conv.fct]p1:
// [...] A conversion function is never used to convert a
// (possibly cv-qualified) object to the (possibly cv-qualified)
// same object type (or a reference to it), to a (possibly
// cv-qualified) base class of that type (or a reference to it),
// or to (possibly cv-qualified) void.
- // FIXME: Suppress this warning if the conversion function ends up being a
- // virtual function that overrides a virtual function in a base class.
QualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>())
@@ -10246,6 +10581,8 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
if (Conversion->getTemplateSpecializationKind() != TSK_Undeclared &&
Conversion->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
/* Suppress diagnostics for instantiations. */;
+ else if (Conversion->size_overridden_methods() != 0)
+ /* Suppress diagnostics for overriding virtual function in a base class. */;
else if (ConvType->isRecordType()) {
ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType();
if (ConvType == ClassType)
@@ -10920,8 +11257,7 @@ bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
// is of type std::initializer_list<E> or reference to possibly cv-qualified
// std::initializer_list<E> for some type E, and either there are no other
// parameters or else all other parameters have default arguments.
- if (Ctor->getNumParams() < 1 ||
- (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg()))
+ if (!Ctor->hasOneParamOrDefaultArgs())
return false;
QualType ArgType = Ctor->getParamDecl(0)->getType();
@@ -12960,6 +13296,25 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
}
+void Sema::CheckCompleteDestructorVariant(SourceLocation CurrentLocation,
+ CXXDestructorDecl *Destructor) {
+ if (Destructor->isInvalidDecl())
+ return;
+
+ CXXRecordDecl *ClassDecl = Destructor->getParent();
+ assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ "implicit complete dtors unneeded outside MS ABI");
+ assert(ClassDecl->getNumVBases() > 0 &&
+ "complete dtor only exists for classes with vbases");
+
+ SynthesizedFunctionScope Scope(*this, Destructor);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(CurrentLocation);
+
+ MarkVirtualBaseDestructorsReferenced(Destructor->getLocation(), ClassDecl);
+}
+
/// Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
@@ -12981,7 +13336,7 @@ void Sema::ActOnFinishCXXNonNestedClass() {
SmallVector<CXXMethodDecl*, 4> WorkList;
std::swap(DelayedDllExportMemberFunctions, WorkList);
for (CXXMethodDecl *M : WorkList) {
- DefineImplicitSpecialMember(*this, M, M->getLocation());
+ DefineDefaultedFunction(*this, M, M->getLocation());
// Pass the method to the consumer to get emitted. This is not necessary
// for explicit instantiation definitions, as they will get emitted
@@ -13180,13 +13535,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
// directly construct UnaryOperators here because semantic analysis
// does not permit us to take the address of an xvalue.
Expr *From = FromB.build(S, Loc);
- From = new (S.Context) UnaryOperator(From, UO_AddrOf,
- S.Context.getPointerType(From->getType()),
- VK_RValue, OK_Ordinary, Loc, false);
+ From = UnaryOperator::Create(
+ S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()),
+ VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides());
Expr *To = ToB.build(S, Loc);
- To = new (S.Context) UnaryOperator(To, UO_AddrOf,
- S.Context.getPointerType(To->getType()),
- VK_RValue, OK_Ordinary, Loc, false);
+ To = UnaryOperator::Create(
+ S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()),
+ VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides());
const Type *E = T->getBaseElementTypeUnsafe();
bool NeedsCollectableMemCpy =
@@ -13420,18 +13775,17 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Create the comparison against the array bound.
llvm::APInt Upper
= ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType));
- Expr *Comparison
- = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
- IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
- BO_NE, S.Context.BoolTy,
- VK_RValue, OK_Ordinary, Loc, FPOptions());
+ Expr *Comparison = BinaryOperator::Create(
+ S.Context, IterationVarRefRVal.build(S, Loc),
+ IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE,
+ S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc, S.CurFPFeatureOverrides());
// Create the pre-increment of the iteration variable. We can determine
// whether the increment will overflow based on the value of the array
// bound.
- Expr *Increment = new (S.Context)
- UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType,
- VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue());
+ Expr *Increment = UnaryOperator::Create(
+ S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue,
+ OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatureOverrides());
// Construct the loop that copies all elements of this array.
return S.ActOnForStmt(
@@ -13529,8 +13883,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
Scope *S = getScopeForContext(ClassDecl);
CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
- if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
+ if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) {
+ ClassDecl->setImplicitCopyAssignmentIsDeleted();
SetDeclDeleted(CopyAssignment, ClassLoc);
+ }
if (S)
PushOnScopeChains(CopyAssignment, S, false);
@@ -14642,13 +14998,18 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MarkFunctionReferenced(ConstructLoc, Constructor);
if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
return ExprError();
+ if (getLangOpts().SYCLIsDevice &&
+ !checkSYCLDeviceFunction(ConstructLoc, Constructor))
+ return ExprError();
- return CXXConstructExpr::Create(
- Context, DeclInitType, ConstructLoc, Constructor, Elidable,
- ExprArgs, HadMultipleCandidates, IsListInitialization,
- IsStdInitListInitialization, RequiresZeroInit,
- static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
- ParenRange);
+ return CheckForImmediateInvocation(
+ CXXConstructExpr::Create(
+ Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
+ HadMultipleCandidates, IsListInitialization,
+ IsStdInitListInitialization, RequiresZeroInit,
+ static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
+ ParenRange),
+ Constructor);
}
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
@@ -14726,6 +15087,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
+ // If initializing the variable failed, don't also diagnose problems with
+ // the desctructor, they're likely related.
+ if (VD->getInit() && VD->getInit()->containsErrors())
+ return;
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
if (ClassDecl->isInvalidDecl()) return;
@@ -14752,10 +15117,13 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
// If the destructor is constexpr, check whether the variable has constant
// destruction now.
- if (Destructor->isConstexpr() && VD->getInit() &&
- !VD->getInit()->isValueDependent() && VD->evaluateValue()) {
+ if (Destructor->isConstexpr()) {
+ bool HasConstantInit = false;
+ if (VD->getInit() && !VD->getInit()->isValueDependent())
+ HasConstantInit = VD->evaluateValue();
SmallVector<PartialDiagnosticAt, 8> Notes;
- if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) {
+ if (!VD->evaluateDestruction(Notes) && VD->isConstexpr() &&
+ HasConstantInit) {
Diag(VD->getLocation(),
diag::err_constexpr_var_requires_const_destruction) << VD;
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
@@ -14855,12 +15223,6 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
QualType ResultType =
FnDecl->getType()->castAs<FunctionType>()->getReturnType();
- // Check that the result type is not dependent.
- if (ResultType->isDependentType())
- return SemaRef.Diag(FnDecl->getLocation(),
- diag::err_operator_new_delete_dependent_result_type)
- << FnDecl->getDeclName() << ExpectedResultType;
-
// The operator is valid on any address space for OpenCL.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
if (auto *PtrTy = ResultType->getAs<PointerType>()) {
@@ -14869,10 +15231,16 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
}
// Check that the result type is what we expect.
- if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType)
- return SemaRef.Diag(FnDecl->getLocation(),
- diag::err_operator_new_delete_invalid_result_type)
- << FnDecl->getDeclName() << ExpectedResultType;
+ if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) {
+ // Reject even if the type is dependent; an operator delete function is
+ // required to have a non-dependent result type.
+ return SemaRef.Diag(
+ FnDecl->getLocation(),
+ ResultType->isDependentType()
+ ? diag::err_operator_new_delete_dependent_result_type
+ : diag::err_operator_new_delete_invalid_result_type)
+ << FnDecl->getDeclName() << ExpectedResultType;
+ }
// A function template must have at least 2 parameters.
if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2)
@@ -14886,13 +15254,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
diag::err_operator_new_delete_too_few_parameters)
<< FnDecl->getDeclName();
- // Check the first parameter type is not dependent.
QualType FirstParamType = FnDecl->getParamDecl(0)->getType();
- if (FirstParamType->isDependentType())
- return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag)
- << FnDecl->getDeclName() << ExpectedFirstParamType;
-
- // Check that the first parameter type is what we expect.
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
// The operator is valid on any address space for OpenCL.
if (auto *PtrTy =
@@ -14900,10 +15262,18 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
}
}
+
+ // Check that the first parameter type is what we expect.
if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() !=
- ExpectedFirstParamType)
- return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag)
- << FnDecl->getDeclName() << ExpectedFirstParamType;
+ ExpectedFirstParamType) {
+ // The first parameter type is not allowed to be dependent. As a tentative
+ // DR resolution, we allow a dependent parameter type if it is the right
+ // type anyway, to allow destroying operator delete in class templates.
+ return SemaRef.Diag(FnDecl->getLocation(), FirstParamType->isDependentType()
+ ? DependentParamTypeDiag
+ : InvalidParamTypeDiag)
+ << FnDecl->getDeclName() << ExpectedFirstParamType;
+ }
return false;
}
@@ -15442,6 +15812,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
!BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK))
Invalid = true;
+ if (!Invalid && Mode != 1 && BaseType->isSizelessType()) {
+ Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType;
+ Invalid = true;
+ }
+
if (!Invalid && !ExDeclType->isDependentType() &&
RequireNonAbstractType(Loc, ExDeclType,
diag::err_abstract_type_in_decl,
@@ -16304,9 +16679,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
Diag(Prev->getLocation().isInvalid() ? DelLoc : Prev->getLocation(),
Prev->isImplicit() ? diag::note_previous_implicit_declaration
: diag::note_previous_declaration);
+ // We can't recover from this; the declaration might have already
+ // been used.
+ Fn->setInvalidDecl();
+ return;
}
- // If the declaration wasn't the first, we delete the function anyway for
- // recovery.
+
+ // To maintain the invariant that functions are only deleted on their first
+ // declaration, mark the implicitly-instantiated declaration of the
+ // explicitly-specialized function as deleted instead of marking the
+ // instantiated redeclaration.
Fn = Fn->getCanonicalDecl();
}
@@ -16316,9 +16698,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
Fn->setInvalidDecl();
}
- if (Fn->isDeleted())
- return;
-
// C++11 [basic.start.main]p3:
// A program that defines main as deleted [...] is ill-formed.
if (Fn->isMain())
@@ -16328,25 +16707,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// A deleted function is implicitly inline.
Fn->setImplicitlyInline();
Fn->setDeletedAsWritten();
-
- // See if we're deleting a function which is already known to override a
- // non-deleted virtual function.
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
- bool IssuedDiagnostic = false;
- for (const CXXMethodDecl *O : MD->overridden_methods()) {
- if (!(*MD->begin_overridden_methods())->isDeleted()) {
- if (!IssuedDiagnostic) {
- Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
- IssuedDiagnostic = true;
- }
- Diag(O->getLocation(), diag::note_overridden_virtual_function);
- }
- }
- // If this function was implicitly deleted because it was defaulted,
- // explain why it was deleted.
- if (IssuedDiagnostic && MD->isDefaulted())
- DiagnoseDeletedDefaultedFunction(MD);
- }
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
@@ -16363,7 +16723,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
}
Diag(DefaultLoc, diag::err_default_special_members)
- << getLangOpts().CPlusPlus2a;
+ << getLangOpts().CPlusPlus20;
return;
}
@@ -16377,7 +16737,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
(!isa<CXXConstructorDecl>(FD) &&
FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) {
Diag(DefaultLoc, diag::err_default_special_members)
- << getLangOpts().CPlusPlus2a;
+ << getLangOpts().CPlusPlus20;
return;
}
@@ -16392,7 +16752,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// 'operator<=>' when parsing the '<=>' token.
if (DefKind.isComparison() &&
DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) {
- Diag(DefaultLoc, getLangOpts().CPlusPlus2a
+ Diag(DefaultLoc, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_defaulted_comparison
: diag::ext_defaulted_comparison);
}
@@ -16428,10 +16788,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
if (Primary->getCanonicalDecl()->isDefaulted())
return;
+ // FIXME: Once we support defining comparisons out of class, check for a
+ // defaulted comparison here.
if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
MD->setInvalidDecl();
else
- DefineImplicitSpecialMember(*this, MD, DefaultLoc);
+ DefineDefaultedFunction(*this, MD, DefaultLoc);
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
@@ -16743,7 +17105,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
return;
// Do not mark as used if compiling for the device outside of the target
// region.
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+ if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
!isInOpenMPDeclareTargetContext() &&
!isInOpenMPTargetExecutionDirective()) {
if (!DefinitionRequired)
@@ -17386,3 +17748,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
return NewPD;
}
+
+void Sema::ActOnStartFunctionDeclarationDeclarator(
+ Declarator &Declarator, unsigned TemplateParameterDepth) {
+ auto &Info = InventedParameterInfos.emplace_back();
+ TemplateParameterList *ExplicitParams = nullptr;
+ ArrayRef<TemplateParameterList *> ExplicitLists =
+ Declarator.getTemplateParameterLists();
+ if (!ExplicitLists.empty()) {
+ bool IsMemberSpecialization, IsInvalid;
+ ExplicitParams = MatchTemplateParametersToScopeSpecifier(
+ Declarator.getBeginLoc(), Declarator.getIdentifierLoc(),
+ Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr,
+ ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid,
+ /*SuppressDiagnostic=*/true);
+ }
+ if (ExplicitParams) {
+ Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
+ for (NamedDecl *Param : *ExplicitParams)
+ Info.TemplateParams.push_back(Param);
+ Info.NumExplicitTemplateParams = ExplicitParams->size();
+ } else {
+ Info.AutoTemplateParameterDepth = TemplateParameterDepth;
+ Info.NumExplicitTemplateParams = 0;
+ }
+}
+
+void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) {
+ auto &FSI = InventedParameterInfos.back();
+ if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) {
+ if (FSI.NumExplicitTemplateParams != 0) {
+ TemplateParameterList *ExplicitParams =
+ Declarator.getTemplateParameterLists().back();
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, ExplicitParams->getTemplateLoc(),
+ ExplicitParams->getLAngleLoc(), FSI.TemplateParams,
+ ExplicitParams->getRAngleLoc(),
+ ExplicitParams->getRequiresClause()));
+ } else {
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, SourceLocation(), SourceLocation(), FSI.TemplateParams,
+ SourceLocation(), /*RequiresClause=*/nullptr));
+ }
+ }
+ InventedParameterInfos.pop_back();
+}
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 5fdf6aeed5b4..d376880a40e8 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
@@ -937,8 +938,7 @@ static bool checkTypeParamListConsistency(Sema &S,
// Override the new type parameter's bound type with the previous type,
// so that it's consistent.
- newTypeParam->setTypeSourceInfo(
- S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
+ S.Context.adjustObjCTypeParamBoundType(prevTypeParam, newTypeParam);
continue;
}
@@ -965,8 +965,7 @@ static bool checkTypeParamListConsistency(Sema &S,
}
// Update the new type parameter's bound to match the previous one.
- newTypeParam->setTypeSourceInfo(
- S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
+ S.Context.adjustObjCTypeParamBoundType(prevTypeParam, newTypeParam);
}
return false;
@@ -1273,7 +1272,8 @@ Decl *Sema::ActOnStartProtocolInterface(
static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
ObjCProtocolDecl *&UndefinedProtocol) {
- if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) {
+ if (!PDecl->hasDefinition() ||
+ !PDecl->getDefinition()->isUnconditionallyVisible()) {
UndefinedProtocol = PDecl;
return true;
}
@@ -2360,7 +2360,7 @@ static bool CheckMethodOverrideReturn(Sema &S,
: diag::warn_conflicting_ret_types;
// Mismatches between ObjC pointers go into a different warning
- // category, and sometimes they're even completely whitelisted.
+ // category, and sometimes they're even completely explicitly allowed.
if (const ObjCObjectPointerType *ImplPtrTy =
MethodImpl->getReturnType()->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *IfacePtrTy =
@@ -2444,7 +2444,7 @@ static bool CheckMethodOverrideParam(Sema &S,
: diag::warn_conflicting_param_types;
// Mismatches between ObjC pointers go into a different warning
- // category, and sometimes they're even completely whitelisted.
+ // category, and sometimes they're even completely explicitly allowed..
if (const ObjCObjectPointerType *ImplPtrTy =
ImplTy->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *IfacePtrTy =
@@ -3236,7 +3236,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
return false;
// If either is hidden, it is not considered to match.
- if (left->isHidden() || right->isHidden())
+ if (!left->isUnconditionallyVisible() || !right->isUnconditionallyVisible())
return false;
if (left->isDirectMethod() != right->isDirectMethod())
@@ -3495,7 +3495,7 @@ bool Sema::CollectMultipleMethodsInGlobalPool(
ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
Pos->second.second;
for (ObjCMethodList *M = &MethList; M; M = M->getNext())
- if (M->getMethod() && !M->getMethod()->isHidden()) {
+ if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
Methods.push_back(M->getMethod());
}
@@ -3511,7 +3511,7 @@ bool Sema::CollectMultipleMethodsInGlobalPool(
ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
Pos->second.first;
for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
- if (M->getMethod() && !M->getMethod()->isHidden()) {
+ if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) {
if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
Methods.push_back(M->getMethod());
}
@@ -3558,7 +3558,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
SmallVector<ObjCMethodDecl *, 4> Methods;
for (ObjCMethodList *M = &MethList; M; M = M->getNext()) {
- if (M->getMethod() && !M->getMethod()->isHidden())
+ if (M->getMethod() && M->getMethod()->isUnconditionallyVisible())
return M->getMethod();
}
return nullptr;
@@ -4580,6 +4580,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
<< (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9");
}
+static void mergeObjCDirectMembers(Sema &S, Decl *CD, ObjCMethodDecl *Method) {
+ if (!Method->isDirectMethod() && !Method->hasAttr<UnavailableAttr>() &&
+ CD->hasAttr<ObjCDirectMembersAttr>()) {
+ Method->addAttr(
+ ObjCDirectAttr::CreateImplicit(S.Context, Method->getLocation()));
+ }
+}
+
+static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl,
+ ObjCMethodDecl *Method,
+ ObjCImplDecl *ImpDecl = nullptr) {
+ auto Sel = Method->getSelector();
+ bool isInstance = Method->isInstanceMethod();
+ bool diagnosed = false;
+
+ auto diagClash = [&](const ObjCMethodDecl *IMD) {
+ if (diagnosed || IMD->isImplicit())
+ return;
+ if (Method->isDirectMethod() || IMD->isDirectMethod()) {
+ S.Diag(Method->getLocation(), diag::err_objc_direct_duplicate_decl)
+ << Method->isDirectMethod() << /* method */ 0 << IMD->isDirectMethod()
+ << Method->getDeclName();
+ S.Diag(IMD->getLocation(), diag::note_previous_declaration);
+ diagnosed = true;
+ }
+ };
+
+ // Look for any other declaration of this method anywhere we can see in this
+ // compilation unit.
+ //
+ // We do not use IDecl->lookupMethod() because we have specific needs:
+ //
+ // - we absolutely do not need to walk protocols, because
+ // diag::err_objc_direct_on_protocol has already been emitted
+ // during parsing if there's a conflict,
+ //
+ // - when we do not find a match in a given @interface container,
+ // we need to attempt looking it up in the @implementation block if the
+ // translation unit sees it to find more clashes.
+
+ if (auto *IMD = IDecl->getMethod(Sel, isInstance))
+ diagClash(IMD);
+ else if (auto *Impl = IDecl->getImplementation())
+ if (Impl != ImpDecl)
+ if (auto *IMD = IDecl->getImplementation()->getMethod(Sel, isInstance))
+ diagClash(IMD);
+
+ for (const auto *Cat : IDecl->visible_categories())
+ if (auto *IMD = Cat->getMethod(Sel, isInstance))
+ diagClash(IMD);
+ else if (auto CatImpl = Cat->getImplementation())
+ if (CatImpl != ImpDecl)
+ if (auto *IMD = Cat->getMethod(Sel, isInstance))
+ diagClash(IMD);
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
@@ -4808,9 +4864,9 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
<< ObjCMethod->getDeclName();
}
- } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) {
- ObjCMethod->addAttr(
- ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
+ } else {
+ mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod);
+ checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod, ImpDecl);
}
// Warn if a method declared in a protocol to which a category or
@@ -4831,39 +4887,16 @@ Decl *Sema::ActOnMethodDeclaration(
}
} else {
if (!isa<ObjCProtocolDecl>(ClassDecl)) {
- if (!ObjCMethod->isDirectMethod() &&
- ClassDecl->hasAttr<ObjCDirectMembersAttr>()) {
- ObjCMethod->addAttr(
- ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
- }
+ mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod);
- // There can be a single declaration in any @interface container
- // for a given direct method, look for clashes as we add them.
- //
- // For valid code, we should always know the primary interface
- // declaration by now, however for invalid code we'll keep parsing
- // but we won't find the primary interface and IDecl will be nil.
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
if (!IDecl)
IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface();
-
+ // For valid code, we should always know the primary interface
+ // declaration by now, however for invalid code we'll keep parsing
+ // but we won't find the primary interface and IDecl will be nil.
if (IDecl)
- if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
- ObjCMethod->isInstanceMethod(),
- /*shallowCategoryLookup=*/false,
- /*followSuper=*/false)) {
- if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) {
- // Do not emit a diagnostic for the Protocol case:
- // diag::err_objc_direct_on_protocol has already been emitted
- // during parsing for these with a nicer diagnostic.
- } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) {
- Diag(ObjCMethod->getLocation(),
- diag::err_objc_direct_duplicate_decl)
- << ObjCMethod->isDirectMethod() << IMD->isDirectMethod()
- << ObjCMethod->getDeclName();
- Diag(IMD->getLocation(), diag::note_previous_declaration);
- }
- }
+ checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod);
}
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 5aedbe7644e4..d7695f9d7d7a 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -167,6 +167,14 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
+ // The MSVC compatibility mode doesn't extend to sizeless types,
+ // so diagnose them separately.
+ if (PointeeT->isSizelessType() && Kind != 1) {
+ Diag(Range.getBegin(), diag::err_sizeless_in_exception_spec)
+ << (Kind == 2 ? 1 : 0) << PointeeT << Range;
+ return true;
+ }
+
return false;
}
@@ -991,10 +999,8 @@ static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
return R;
}
-/// Determine whether the callee of a particular function call can throw.
-/// E and D are both optional, but at least one of E and Loc must be specified.
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
- SourceLocation Loc = SourceLocation()) {
+CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -1040,7 +1046,8 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
if (!FT)
return CT_Can;
- FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
+ if (Loc.isValid() || (Loc.isInvalid() && E))
+ FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
@@ -1061,7 +1068,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
if (auto *Dtor = RD->getDestructor()) {
CT = mergeCanThrow(
- CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
}
}
}
@@ -1281,6 +1288,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::CompoundLiteralExprClass:
case Expr::CXXConstCastExprClass:
+ case Expr::CXXAddrspaceCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::BuiltinBitCastExprClass:
// FIXME: Properly determine whether a variably-modified type can throw.
@@ -1290,7 +1298,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
+ case Expr::MatrixSubscriptExprClass:
case Expr::OMPArraySectionExprClass:
+ case Expr::OMPArrayShapingExprClass:
+ case Expr::OMPIteratorExprClass:
case Expr::BinaryOperatorClass:
case Expr::DependentCoawaitExprClass:
case Expr::CompoundAssignOperatorClass:
@@ -1332,6 +1343,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::CXXUnresolvedConstructExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXFoldExprClass:
+ case Expr::RecoveryExprClass:
return CT_Dependent;
case Expr::AsTypeExprClass:
@@ -1386,6 +1398,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
case Expr::ConceptSpecializationExprClass:
+ case Expr::RequiresExprClass:
// These expressions can never throw.
return CT_Cannot;
@@ -1429,6 +1442,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
case Stmt::OMPDistributeSimdDirectiveClass:
case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPDepobjDirectiveClass:
+ case Stmt::OMPScanDirectiveClass:
case Stmt::OMPForDirectiveClass:
case Stmt::OMPForSimdDirectiveClass:
case Stmt::OMPMasterDirectiveClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5f4071924d3f..ccae79636f32 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "TreeTransform.h"
+#include "UsedDeclVisitor.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
@@ -46,8 +47,10 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace sema;
+using llvm::RoundingMode;
/// Determine whether the use of this declaration is valid, without
/// emitting diagnostics.
@@ -245,8 +248,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;
}
- // See if this is a deleted function.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // See if this is a deleted function.
if (FD->isDeleted()) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
if (Ctor && Ctor->isInheritingConstructor())
@@ -259,6 +262,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;
}
+ // [expr.prim.id]p4
+ // A program that refers explicitly or implicitly to a function with a
+ // trailing requires-clause whose constraint-expression is not satisfied,
+ // other than to declare it, is ill-formed. [...]
+ //
+ // 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()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+ // A diagnostic will have already been generated (non-constant
+ // constraint expression, for example)
+ return true;
+ if (!Satisfaction.IsSatisfied) {
+ Diag(Loc,
+ diag::err_reference_to_function_with_unsatisfied_constraints)
+ << D;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ }
+
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
@@ -267,6 +293,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
return true;
+
+ if (getLangOpts().SYCLIsDevice && !checkSYCLDeviceFunction(Loc, FD))
+ return true;
}
if (auto *MD = dyn_cast<CXXMethodDecl>(D)) {
@@ -326,28 +355,25 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
- // [expr.prim.id]p4
- // A program that refers explicitly or implicitly to a function with a
- // trailing requires-clause whose constraint-expression is not satisfied,
- // other than to declare it, is ill-formed. [...]
- //
- // See if this is a function with constraints that need to be satisfied.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (Expr *RC = FD->getTrailingRequiresClause()) {
- ConstraintSatisfaction Satisfaction;
- bool Failed = CheckConstraintSatisfaction(RC, Satisfaction);
- if (Failed)
- // A diagnostic will have already been generated (non-constant
- // constraint expression, for example)
- return true;
- if (!Satisfaction.IsSatisfied) {
- Diag(Loc,
- diag::err_reference_to_function_with_unsatisfied_constraints)
- << D;
- DiagnoseUnsatisfiedConstraint(Satisfaction);
- return true;
- }
- }
+ if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) {
+ if (const auto *VD = dyn_cast<ValueDecl>(D))
+ checkDeviceDecl(VD, Loc);
+
+ if (!Context.getTargetInfo().isTLSSupported())
+ if (const auto *VD = dyn_cast<VarDecl>(D))
+ if (VD->getTLSKind() != VarDecl::TLS_None)
+ targetDiag(*Locs.begin(), diag::err_thread_unsupported);
+ }
+
+ if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
+ !isUnevaluatedContext()) {
+ // C++ [expr.prim.req.nested] p3
+ // A local parameter shall only appear as an unevaluated operand
+ // (Clause 8) within the constraint-expression.
+ Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context)
+ << D;
+ Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+ return true;
}
return false;
@@ -593,6 +619,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
+ // lvalue-to-rvalue conversion cannot be applied to function or array types.
+ if (T->isFunctionType() || T->isArrayType())
+ return E;
+
// We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++.
if (getLangOpts().CPlusPlus &&
@@ -661,6 +691,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
Cleanup.setExprNeedsCleanups(true);
+ if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+ Cleanup.setExprNeedsCleanups(true);
+
// C++ [conv.lval]p3:
// If T is cv std::nullptr_t, the result is a null pointer constant.
CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue;
@@ -697,7 +730,7 @@ ExprResult Sema::CallExprUnaryConversions(Expr *E) {
// to function type.
if (Ty->isFunctionType()) {
Res = ImpCastExprToType(E, Context.getPointerType(Ty),
- CK_FunctionToPointerDecay).get();
+ CK_FunctionToPointerDecay);
if (Res.isInvalid())
return ExprError();
}
@@ -931,6 +964,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
ExprResult ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
+
+ // Copy blocks to the heap.
+ if (ExprRes.get()->getType()->isBlockPointerType())
+ maybeExtendBlockObject(ExprRes);
+
E = ExprRes.get();
// Diagnostics regarding non-POD argument types are
@@ -1375,8 +1413,8 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
bool IsCompAssign = ACK == Sema::ACK_CompAssign;
if ((!IsCompAssign && LEnum && R->isFloatingType()) ||
(REnum && L->isFloatingType())) {
- S.Diag(Loc, S.getLangOpts().CPlusPlus2a
- ? diag::warn_arith_conv_enum_float_cxx2a
+ S.Diag(Loc, S.getLangOpts().CPlusPlus20
+ ? diag::warn_arith_conv_enum_float_cxx20
: diag::warn_arith_conv_enum_float)
<< LHS->getSourceRange() << RHS->getSourceRange()
<< (int)ACK << LEnum << L << R;
@@ -1388,24 +1426,24 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
// If either enumeration type is unnamed, it's less likely that the
// user cares about this, but this situation is still deprecated in
// C++2a. Use a different warning group.
- DiagID = S.getLangOpts().CPlusPlus2a
- ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a
+ DiagID = S.getLangOpts().CPlusPlus20
+ ? diag::warn_arith_conv_mixed_anon_enum_types_cxx20
: diag::warn_arith_conv_mixed_anon_enum_types;
} else if (ACK == Sema::ACK_Conditional) {
// Conditional expressions are separated out because they have
// historically had a different warning flag.
- DiagID = S.getLangOpts().CPlusPlus2a
- ? diag::warn_conditional_mixed_enum_types_cxx2a
+ DiagID = S.getLangOpts().CPlusPlus20
+ ? diag::warn_conditional_mixed_enum_types_cxx20
: diag::warn_conditional_mixed_enum_types;
} else if (ACK == Sema::ACK_Comparison) {
// Comparison expressions are separated out because they have
// historically had a different warning flag.
- DiagID = S.getLangOpts().CPlusPlus2a
- ? diag::warn_comparison_mixed_enum_types_cxx2a
+ DiagID = S.getLangOpts().CPlusPlus20
+ ? diag::warn_comparison_mixed_enum_types_cxx20
: diag::warn_comparison_mixed_enum_types;
} else {
- DiagID = S.getLangOpts().CPlusPlus2a
- ? diag::warn_arith_conv_mixed_enum_types_cxx2a
+ DiagID = S.getLangOpts().CPlusPlus20
+ ? diag::warn_arith_conv_mixed_enum_types_cxx20
: diag::warn_arith_conv_mixed_enum_types;
}
S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
@@ -1466,6 +1504,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
if (LHSType == RHSType)
return LHSType;
+ // ExtInt types aren't subject to conversions between them or normal integers,
+ // so this fails.
+ if(LHSType->isExtIntType() || RHSType->isExtIntType())
+ return QualType();
+
// At this point, we have two different arithmetic types.
// Diagnose attempts to convert between __float128 and long double where
@@ -1750,15 +1793,15 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
// Warn on initializing an array of char from a u8 string literal; this
// becomes ill-formed in C++2a.
- if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus2a &&
+ if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus20 &&
!getLangOpts().Char8 && Kind == StringLiteral::UTF8) {
- Diag(StringTokLocs.front(), diag::warn_cxx2a_compat_utf8_string);
+ Diag(StringTokLocs.front(), diag::warn_cxx20_compat_utf8_string);
// Create removals for all 'u8' prefixes in the string literal(s). This
// ensures C++2a compatibility (but may change the program behavior when
// built by non-Clang compilers for which the execution character set is
// not always UTF-8).
- auto RemovalDiag = PDiag(diag::note_cxx2a_compat_utf8_string_remove_u8);
+ auto RemovalDiag = PDiag(diag::note_cxx20_compat_utf8_string_remove_u8);
SourceLocation RemovalDiagLoc;
for (const Token &Tok : StringToks) {
if (Tok.getKind() == tok::utf8_string_literal) {
@@ -3113,6 +3156,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
return ExprError();
ExprValueKind valueKind = VK_RValue;
+ // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of
+ // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value,
+ // is expanded by some outer '...' in the context of the use.
+ type = type.getNonPackExpansionType();
+
switch (D->getKind()) {
// Ignore all the non-ValueDecl kinds.
#define ABSTRACT_DECL(kind)
@@ -3258,6 +3306,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
llvm_unreachable("building reference to deduction guide");
case Decl::MSProperty:
+ case Decl::MSGuid:
+ // FIXME: Should MSGuidDecl be subject to capture in OpenMP,
+ // or duplicated between host and device?
valueKind = VK_LValue;
break;
@@ -3358,6 +3409,70 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL);
}
+static std::pair<QualType, StringLiteral *>
+GetUniqueStableNameInfo(ASTContext &Context, QualType OpType,
+ SourceLocation OpLoc, PredefinedExpr::IdentKind K) {
+ std::pair<QualType, StringLiteral*> Result{{}, nullptr};
+
+ if (OpType->isDependentType()) {
+ Result.first = Context.DependentTy;
+ return Result;
+ }
+
+ std::string Str = PredefinedExpr::ComputeName(Context, K, OpType);
+ llvm::APInt Length(32, Str.length() + 1);
+ Result.first =
+ Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
+ Result.first = Context.getConstantArrayType(
+ Result.first, Length, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0);
+ Result.second = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
+ /*Pascal*/ false, Result.first, OpLoc);
+ return Result;
+}
+
+ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc,
+ TypeSourceInfo *Operand) {
+ QualType ResultTy;
+ StringLiteral *SL;
+ std::tie(ResultTy, SL) = GetUniqueStableNameInfo(
+ Context, Operand->getType(), OpLoc, PredefinedExpr::UniqueStableNameType);
+
+ return PredefinedExpr::Create(Context, OpLoc, ResultTy,
+ PredefinedExpr::UniqueStableNameType, SL,
+ Operand);
+}
+
+ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc,
+ Expr *E) {
+ QualType ResultTy;
+ StringLiteral *SL;
+ std::tie(ResultTy, SL) = GetUniqueStableNameInfo(
+ Context, E->getType(), OpLoc, PredefinedExpr::UniqueStableNameExpr);
+
+ return PredefinedExpr::Create(Context, OpLoc, ResultTy,
+ PredefinedExpr::UniqueStableNameExpr, SL, E);
+}
+
+ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation L, SourceLocation R,
+ ParsedType Ty) {
+ TypeSourceInfo *TInfo = nullptr;
+ QualType T = GetTypeFromParser(Ty, &TInfo);
+
+ if (T.isNull())
+ return ExprError();
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc);
+
+ return BuildUniqueStableName(OpLoc, TInfo);
+}
+
+ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation L, SourceLocation R,
+ Expr *E) {
+ return BuildUniqueStableName(OpLoc, E);
+}
+
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
PredefinedExpr::IdentKind IK;
@@ -3519,7 +3634,9 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (Invalid)
return ExprError();
- NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP);
+ NumericLiteralParser Literal(TokSpelling, Tok.getLocation(),
+ PP.getSourceManager(), PP.getLangOpts(),
+ PP.getTargetInfo(), PP.getDiagnostics());
if (Literal.hadError)
return ExprError();
@@ -3872,7 +3989,7 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
TraitKind == UETT_PreferredAlignOf)) {
// sizeof(function)/alignof(function) is allowed as an extension.
S.Diag(Loc, diag::ext_sizeof_alignof_function_type)
- << TraitKind << ArgRange;
+ << getTraitSpelling(TraitKind) << ArgRange;
return false;
}
@@ -3881,7 +3998,7 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
if (T->isVoidType()) {
unsigned DiagID = S.LangOpts.OpenCL ? diag::err_opencl_sizeof_alignof_type
: diag::ext_sizeof_alignof_void_type;
- S.Diag(Loc, DiagID) << TraitKind << ArgRange;
+ S.Diag(Loc, DiagID) << getTraitSpelling(TraitKind) << ArgRange;
return false;
}
@@ -3948,7 +4065,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange());
- // Whitelist some types as extensions
+ // Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange(), ExprKind))
return false;
@@ -3958,14 +4075,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// be complete (and will attempt to complete it if it's an array of unknown
// bound).
if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
- if (RequireCompleteType(E->getExprLoc(),
- Context.getBaseElementType(E->getType()),
- diag::err_sizeof_alignof_incomplete_type, ExprKind,
- E->getSourceRange()))
+ if (RequireCompleteSizedType(
+ E->getExprLoc(), Context.getBaseElementType(E->getType()),
+ diag::err_sizeof_alignof_incomplete_or_sizeless_type,
+ getTraitSpelling(ExprKind), E->getSourceRange()))
return true;
} else {
- if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type,
- ExprKind, E->getSourceRange()))
+ if (RequireCompleteSizedExprType(
+ E, diag::err_sizeof_alignof_incomplete_or_sizeless_type,
+ getTraitSpelling(ExprKind), E->getSourceRange()))
return true;
}
@@ -3975,7 +4093,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
if (ExprTy->isFunctionType()) {
Diag(E->getExprLoc(), diag::err_sizeof_alignof_function_type)
- << ExprKind << E->getSourceRange();
+ << getTraitSpelling(ExprKind) << E->getSourceRange();
return true;
}
@@ -4057,19 +4175,19 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
- // Whitelist some types as extensions
+ // Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
ExprKind))
return false;
- if (RequireCompleteType(OpLoc, ExprType,
- diag::err_sizeof_alignof_incomplete_type,
- ExprKind, ExprRange))
+ if (RequireCompleteSizedType(
+ OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type,
+ getTraitSpelling(ExprKind), ExprRange))
return true;
if (ExprType->isFunctionType()) {
Diag(OpLoc, diag::err_sizeof_alignof_function_type)
- << ExprKind << ExprRange;
+ << getTraitSpelling(ExprKind) << ExprRange;
return true;
}
@@ -4168,6 +4286,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::Complex:
case Type::Vector:
case Type::ExtVector:
+ case Type::ConstantMatrix:
case Type::Record:
case Type::Enum:
case Type::Elaborated:
@@ -4177,6 +4296,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::ObjCObjectPointer:
case Type::ObjCTypeParam:
case Type::Pipe:
+ case Type::ExtInt:
llvm_unreachable("type class is never variably-modified!");
case Type::Adjusted:
T = cast<AdjustedType>(Ty)->getOriginalType();
@@ -4442,7 +4562,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
if (base && !base->getType().isNull() &&
base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection))
return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(),
- /*Length=*/nullptr, rbLoc);
+ SourceLocation(), /*Length*/ nullptr,
+ /*Stride=*/nullptr, rbLoc);
// Since this might be a postfix expression, get rid of ParenListExprs.
if (isa<ParenListExpr>(base)) {
@@ -4451,8 +4572,55 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
base = result.get();
}
+ // Check if base and idx form a MatrixSubscriptExpr.
+ //
+ // Helper to check for comma expressions, which are not allowed as indices for
+ // matrix subscript expressions.
+ auto CheckAndReportCommaError = [this, base, rbLoc](Expr *E) {
+ if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isCommaOp()) {
+ Diag(E->getExprLoc(), diag::err_matrix_subscript_comma)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ return true;
+ }
+ return false;
+ };
+ // The matrix subscript operator ([][])is considered a single operator.
+ // Separating the index expressions by parenthesis is not allowed.
+ if (base->getType()->isSpecificPlaceholderType(
+ BuiltinType::IncompleteMatrixIdx) &&
+ !isa<MatrixSubscriptExpr>(base)) {
+ Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ return ExprError();
+ }
+ // If the base is either a MatrixSubscriptExpr or a matrix type, try to create
+ // a new MatrixSubscriptExpr.
+ auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base);
+ if (matSubscriptE) {
+ if (CheckAndReportCommaError(idx))
+ return ExprError();
+
+ assert(matSubscriptE->isIncomplete() &&
+ "base has to be an incomplete matrix subscript");
+ return CreateBuiltinMatrixSubscriptExpr(
+ matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc);
+ }
+ Expr *matrixBase = base;
+ bool IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
+ if (!IsMSPropertySubscript) {
+ ExprResult result = CheckPlaceholderExpr(base);
+ if (!result.isInvalid())
+ matrixBase = result.get();
+ }
+ if (matrixBase->getType()->isMatrixType()) {
+ if (CheckAndReportCommaError(idx))
+ return ExprError();
+
+ return CreateBuiltinMatrixSubscriptExpr(matrixBase, idx, nullptr, rbLoc);
+ }
+
// A comma-expression as the index is deprecated in C++2a onwards.
- if (getLangOpts().CPlusPlus2a &&
+ if (getLangOpts().CPlusPlus20 &&
((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
(isa<CXXOperatorCallExpr>(idx) &&
cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
@@ -4465,7 +4633,6 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// operand might be an overloadable type, in which case the overload
// resolution for the operator overload should get the first crack
// at the overload.
- bool IsMSPropertySubscript = false;
if (base->getType()->isNonOverloadPlaceholderType()) {
IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base);
if (!IsMSPropertySubscript) {
@@ -4526,6 +4693,79 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
return Res;
}
+ExprResult Sema::tryConvertExprToType(Expr *E, QualType Ty) {
+ InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty);
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(E->getBeginLoc(), SourceLocation());
+ InitializationSequence InitSeq(*this, Entity, Kind, E);
+ return InitSeq.Perform(*this, Entity, Kind, E);
+}
+
+ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
+ Expr *ColumnIdx,
+ SourceLocation RBLoc) {
+ ExprResult BaseR = CheckPlaceholderExpr(Base);
+ if (BaseR.isInvalid())
+ return BaseR;
+ Base = BaseR.get();
+
+ ExprResult RowR = CheckPlaceholderExpr(RowIdx);
+ if (RowR.isInvalid())
+ return RowR;
+ RowIdx = RowR.get();
+
+ if (!ColumnIdx)
+ return new (Context) MatrixSubscriptExpr(
+ Base, RowIdx, ColumnIdx, Context.IncompleteMatrixIdxTy, RBLoc);
+
+ // Build an unanalyzed expression if any of the operands is type-dependent.
+ if (Base->isTypeDependent() || RowIdx->isTypeDependent() ||
+ ColumnIdx->isTypeDependent())
+ return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
+ Context.DependentTy, RBLoc);
+
+ ExprResult ColumnR = CheckPlaceholderExpr(ColumnIdx);
+ if (ColumnR.isInvalid())
+ return ColumnR;
+ ColumnIdx = ColumnR.get();
+
+ // Check that IndexExpr is an integer expression. If it is a constant
+ // expression, check that it is less than Dim (= the number of elements in the
+ // corresponding dimension).
+ auto IsIndexValid = [&](Expr *IndexExpr, unsigned Dim,
+ bool IsColumnIdx) -> Expr * {
+ if (!IndexExpr->getType()->isIntegerType() &&
+ !IndexExpr->isTypeDependent()) {
+ Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_not_integer)
+ << IsColumnIdx;
+ return nullptr;
+ }
+
+ llvm::APSInt Idx;
+ if (IndexExpr->isIntegerConstantExpr(Idx, Context) &&
+ (Idx < 0 || Idx >= Dim)) {
+ Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range)
+ << IsColumnIdx << Dim;
+ return nullptr;
+ }
+
+ ExprResult ConvExpr =
+ tryConvertExprToType(IndexExpr, Context.getSizeType());
+ assert(!ConvExpr.isInvalid() &&
+ "should be able to convert any integer type to size type");
+ return ConvExpr.get();
+ };
+
+ auto *MTy = Base->getType()->getAs<ConstantMatrixType>();
+ RowIdx = IsIndexValid(RowIdx, MTy->getNumRows(), false);
+ ColumnIdx = IsIndexValid(ColumnIdx, MTy->getNumColumns(), true);
+ if (!RowIdx || !ColumnIdx)
+ return ExprError();
+
+ return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
+ MTy->getElementType(), RBLoc);
+}
+
void Sema::CheckAddressOfNoDeref(const Expr *E) {
ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back();
const Expr *StrippedExpr = E->IgnoreParenImpCasts();
@@ -4573,7 +4813,9 @@ void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) {
ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
Expr *LowerBound,
- SourceLocation ColonLoc, Expr *Length,
+ SourceLocation ColonLocFirst,
+ SourceLocation ColonLocSecond,
+ Expr *Length, Expr *Stride,
SourceLocation RBLoc) {
if (Base->getType()->isPlaceholderType() &&
!Base->getType()->isSpecificPlaceholderType(
@@ -4601,15 +4843,25 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
return ExprError();
Length = Result.get();
}
+ if (Stride && Stride->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult Result = CheckPlaceholderExpr(Stride);
+ if (Result.isInvalid())
+ return ExprError();
+ Result = DefaultLvalueConversion(Result.get());
+ if (Result.isInvalid())
+ return ExprError();
+ Stride = Result.get();
+ }
// Build an unanalyzed expression if either operand is type-dependent.
if (Base->isTypeDependent() ||
(LowerBound &&
(LowerBound->isTypeDependent() || LowerBound->isValueDependent())) ||
- (Length && (Length->isTypeDependent() || Length->isValueDependent()))) {
- return new (Context)
- OMPArraySectionExpr(Base, LowerBound, Length, Context.DependentTy,
- VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
+ (Length && (Length->isTypeDependent() || Length->isValueDependent())) ||
+ (Stride && (Stride->isTypeDependent() || Stride->isValueDependent()))) {
+ return new (Context) OMPArraySectionExpr(
+ Base, LowerBound, Length, Stride, Context.DependentTy, VK_LValue,
+ OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
}
// Perform default conversions.
@@ -4653,6 +4905,20 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
Diag(Length->getExprLoc(), diag::warn_omp_section_is_char)
<< 1 << Length->getSourceRange();
}
+ if (Stride) {
+ ExprResult Res =
+ PerformOpenMPImplicitIntegerConversion(Stride->getExprLoc(), Stride);
+ if (Res.isInvalid())
+ return ExprError(Diag(Stride->getExprLoc(),
+ diag::err_omp_typecheck_section_not_integer)
+ << 1 << Stride->getSourceRange());
+ Stride = Res.get();
+
+ if (Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_U))
+ Diag(Stride->getExprLoc(), diag::warn_omp_section_is_char)
+ << 1 << Stride->getSourceRange();
+ }
// C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
// C++ [expr.sub]p1: The type "T" shall be a completely-defined object
@@ -4671,7 +4937,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
if (LowerBound && !OriginalTy->isAnyPointerType()) {
Expr::EvalResult Result;
if (LowerBound->EvaluateAsInt(Result, Context)) {
- // OpenMP 4.5, [2.4 Array Sections]
+ // OpenMP 5.0, [2.1.5 Array Sections]
// The array section must be a subset of the original array.
llvm::APSInt LowerBoundValue = Result.Val.getInt();
if (LowerBoundValue.isNegative()) {
@@ -4685,7 +4951,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
if (Length) {
Expr::EvalResult Result;
if (Length->EvaluateAsInt(Result, Context)) {
- // OpenMP 4.5, [2.4 Array Sections]
+ // OpenMP 5.0, [2.1.5 Array Sections]
// The length must evaluate to non-negative integers.
llvm::APSInt LengthValue = Result.Val.getInt();
if (LengthValue.isNegative()) {
@@ -4695,17 +4961,32 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
return ExprError();
}
}
- } else if (ColonLoc.isValid() &&
+ } else if (ColonLocFirst.isValid() &&
(OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() &&
!OriginalTy->isVariableArrayType()))) {
- // OpenMP 4.5, [2.4 Array Sections]
+ // OpenMP 5.0, [2.1.5 Array Sections]
// When the size of the array dimension is not known, the length must be
// specified explicitly.
- Diag(ColonLoc, diag::err_omp_section_length_undefined)
+ Diag(ColonLocFirst, diag::err_omp_section_length_undefined)
<< (!OriginalTy.isNull() && OriginalTy->isArrayType());
return ExprError();
}
+ if (Stride) {
+ Expr::EvalResult Result;
+ if (Stride->EvaluateAsInt(Result, Context)) {
+ // OpenMP 5.0, [2.1.5 Array Sections]
+ // The stride must evaluate to a positive integer.
+ llvm::APSInt StrideValue = Result.Val.getInt();
+ if (!StrideValue.isStrictlyPositive()) {
+ Diag(Stride->getExprLoc(), diag::err_omp_section_stride_non_positive)
+ << StrideValue.toString(/*Radix=*/10, /*Signed=*/true)
+ << Stride->getSourceRange();
+ return ExprError();
+ }
+ }
+ }
+
if (!Base->getType()->isSpecificPlaceholderType(
BuiltinType::OMPArraySection)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(Base);
@@ -4713,9 +4994,371 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
return ExprError();
Base = Result.get();
}
- return new (Context)
- OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy,
- VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
+ return new (Context) OMPArraySectionExpr(
+ Base, LowerBound, Length, Stride, Context.OMPArraySectionTy, VK_LValue,
+ OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
+}
+
+ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
+ ArrayRef<Expr *> Dims,
+ ArrayRef<SourceRange> Brackets) {
+ if (Base->getType()->isPlaceholderType()) {
+ ExprResult Result = CheckPlaceholderExpr(Base);
+ if (Result.isInvalid())
+ return ExprError();
+ Result = DefaultLvalueConversion(Result.get());
+ if (Result.isInvalid())
+ return ExprError();
+ Base = Result.get();
+ }
+ QualType BaseTy = Base->getType();
+ // Delay analysis of the types/expressions if instantiation/specialization is
+ // required.
+ if (!BaseTy->isPointerType() && Base->isTypeDependent())
+ return OMPArrayShapingExpr::Create(Context, Context.DependentTy, Base,
+ LParenLoc, RParenLoc, Dims, Brackets);
+ if (!BaseTy->isPointerType() ||
+ (!Base->isTypeDependent() &&
+ BaseTy->getPointeeType()->isIncompleteType()))
+ return ExprError(Diag(Base->getExprLoc(),
+ diag::err_omp_non_pointer_type_array_shaping_base)
+ << Base->getSourceRange());
+
+ SmallVector<Expr *, 4> NewDims;
+ bool ErrorFound = false;
+ for (Expr *Dim : Dims) {
+ if (Dim->getType()->isPlaceholderType()) {
+ ExprResult Result = CheckPlaceholderExpr(Dim);
+ if (Result.isInvalid()) {
+ ErrorFound = true;
+ continue;
+ }
+ Result = DefaultLvalueConversion(Result.get());
+ if (Result.isInvalid()) {
+ ErrorFound = true;
+ continue;
+ }
+ Dim = Result.get();
+ }
+ if (!Dim->isTypeDependent()) {
+ ExprResult Result =
+ PerformOpenMPImplicitIntegerConversion(Dim->getExprLoc(), Dim);
+ if (Result.isInvalid()) {
+ ErrorFound = true;
+ Diag(Dim->getExprLoc(), diag::err_omp_typecheck_shaping_not_integer)
+ << Dim->getSourceRange();
+ continue;
+ }
+ Dim = Result.get();
+ Expr::EvalResult EvResult;
+ if (!Dim->isValueDependent() && Dim->EvaluateAsInt(EvResult, Context)) {
+ // OpenMP 5.0, [2.1.4 Array Shaping]
+ // Each si is an integral type expression that must evaluate to a
+ // positive integer.
+ llvm::APSInt Value = EvResult.Val.getInt();
+ if (!Value.isStrictlyPositive()) {
+ Diag(Dim->getExprLoc(), diag::err_omp_shaping_dimension_not_positive)
+ << Value.toString(/*Radix=*/10, /*Signed=*/true)
+ << Dim->getSourceRange();
+ ErrorFound = true;
+ continue;
+ }
+ }
+ }
+ NewDims.push_back(Dim);
+ }
+ if (ErrorFound)
+ return ExprError();
+ return OMPArrayShapingExpr::Create(Context, Context.OMPArrayShapingTy, Base,
+ LParenLoc, RParenLoc, NewDims, Brackets);
+}
+
+ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc,
+ SourceLocation LLoc, SourceLocation RLoc,
+ ArrayRef<OMPIteratorData> Data) {
+ SmallVector<OMPIteratorExpr::IteratorDefinition, 4> ID;
+ bool IsCorrect = true;
+ for (const OMPIteratorData &D : Data) {
+ TypeSourceInfo *TInfo = nullptr;
+ SourceLocation StartLoc;
+ QualType DeclTy;
+ if (!D.Type.getAsOpaquePtr()) {
+ // OpenMP 5.0, 2.1.6 Iterators
+ // In an iterator-specifier, if the iterator-type is not specified then
+ // the type of that iterator is of int type.
+ DeclTy = Context.IntTy;
+ StartLoc = D.DeclIdentLoc;
+ } else {
+ DeclTy = GetTypeFromParser(D.Type, &TInfo);
+ StartLoc = TInfo->getTypeLoc().getBeginLoc();
+ }
+
+ bool IsDeclTyDependent = DeclTy->isDependentType() ||
+ DeclTy->containsUnexpandedParameterPack() ||
+ DeclTy->isInstantiationDependentType();
+ if (!IsDeclTyDependent) {
+ if (!DeclTy->isIntegralType(Context) && !DeclTy->isAnyPointerType()) {
+ // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++
+ // The iterator-type must be an integral or pointer type.
+ Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer)
+ << DeclTy;
+ IsCorrect = false;
+ continue;
+ }
+ if (DeclTy.isConstant(Context)) {
+ // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++
+ // The iterator-type must not be const qualified.
+ Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer)
+ << DeclTy;
+ IsCorrect = false;
+ continue;
+ }
+ }
+
+ // Iterator declaration.
+ assert(D.DeclIdent && "Identifier expected.");
+ // Always try to create iterator declarator to avoid extra error messages
+ // about unknown declarations use.
+ auto *VD = VarDecl::Create(Context, CurContext, StartLoc, D.DeclIdentLoc,
+ D.DeclIdent, DeclTy, TInfo, SC_None);
+ VD->setImplicit();
+ if (S) {
+ // Check for conflicting previous declaration.
+ DeclarationNameInfo NameInfo(VD->getDeclName(), D.DeclIdentLoc);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ ForVisibleRedeclaration);
+ Previous.suppressDiagnostics();
+ LookupName(Previous, S);
+
+ FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage=*/false,
+ /*AllowInlineNamespace=*/false);
+ if (!Previous.empty()) {
+ NamedDecl *Old = Previous.getRepresentativeDecl();
+ Diag(D.DeclIdentLoc, diag::err_redefinition) << VD->getDeclName();
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ } else {
+ PushOnScopeChains(VD, S);
+ }
+ } else {
+ CurContext->addDecl(VD);
+ }
+ Expr *Begin = D.Range.Begin;
+ if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) {
+ ExprResult BeginRes =
+ PerformImplicitConversion(Begin, DeclTy, AA_Converting);
+ Begin = BeginRes.get();
+ }
+ Expr *End = D.Range.End;
+ if (!IsDeclTyDependent && End && !End->isTypeDependent()) {
+ ExprResult EndRes = PerformImplicitConversion(End, DeclTy, AA_Converting);
+ End = EndRes.get();
+ }
+ Expr *Step = D.Range.Step;
+ if (!IsDeclTyDependent && Step && !Step->isTypeDependent()) {
+ if (!Step->getType()->isIntegralType(Context)) {
+ Diag(Step->getExprLoc(), diag::err_omp_iterator_step_not_integral)
+ << Step << Step->getSourceRange();
+ IsCorrect = false;
+ continue;
+ }
+ llvm::APSInt Result;
+ bool IsConstant = Step->isIntegerConstantExpr(Result, Context);
+ // OpenMP 5.0, 2.1.6 Iterators, Restrictions
+ // If the step expression of a range-specification equals zero, the
+ // behavior is unspecified.
+ if (IsConstant && Result.isNullValue()) {
+ Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero)
+ << Step << Step->getSourceRange();
+ IsCorrect = false;
+ continue;
+ }
+ }
+ if (!Begin || !End || !IsCorrect) {
+ IsCorrect = false;
+ continue;
+ }
+ OMPIteratorExpr::IteratorDefinition &IDElem = ID.emplace_back();
+ IDElem.IteratorDecl = VD;
+ IDElem.AssignmentLoc = D.AssignLoc;
+ IDElem.Range.Begin = Begin;
+ IDElem.Range.End = End;
+ IDElem.Range.Step = Step;
+ IDElem.ColonLoc = D.ColonLoc;
+ IDElem.SecondColonLoc = D.SecColonLoc;
+ }
+ if (!IsCorrect) {
+ // Invalidate all created iterator declarations if error is found.
+ for (const OMPIteratorExpr::IteratorDefinition &D : ID) {
+ if (Decl *ID = D.IteratorDecl)
+ ID->setInvalidDecl();
+ }
+ return ExprError();
+ }
+ SmallVector<OMPIteratorHelperData, 4> Helpers;
+ if (!CurContext->isDependentContext()) {
+ // Build number of ityeration for each iteration range.
+ // Ni = ((Stepi > 0) ? ((Endi + Stepi -1 - Begini)/Stepi) :
+ // ((Begini-Stepi-1-Endi) / -Stepi);
+ for (OMPIteratorExpr::IteratorDefinition &D : ID) {
+ // (Endi - Begini)
+ ExprResult Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, D.Range.End,
+ D.Range.Begin);
+ if(!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ ExprResult St, St1;
+ if (D.Range.Step) {
+ St = D.Range.Step;
+ // (Endi - Begini) + Stepi
+ Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, Res.get(), St.get());
+ if (!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // (Endi - Begini) + Stepi - 1
+ Res =
+ CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, Res.get(),
+ ActOnIntegerConstant(D.AssignmentLoc, 1).get());
+ if (!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // ((Endi - Begini) + Stepi - 1) / Stepi
+ Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Div, Res.get(), St.get());
+ if (!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ St1 = CreateBuiltinUnaryOp(D.AssignmentLoc, UO_Minus, D.Range.Step);
+ // (Begini - Endi)
+ ExprResult Res1 = CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub,
+ D.Range.Begin, D.Range.End);
+ if (!Res1.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // (Begini - Endi) - Stepi
+ Res1 =
+ CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, Res1.get(), St1.get());
+ if (!Res1.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // (Begini - Endi) - Stepi - 1
+ Res1 =
+ CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, Res1.get(),
+ ActOnIntegerConstant(D.AssignmentLoc, 1).get());
+ if (!Res1.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // ((Begini - Endi) - Stepi - 1) / (-Stepi)
+ Res1 =
+ CreateBuiltinBinOp(D.AssignmentLoc, BO_Div, Res1.get(), St1.get());
+ if (!Res1.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ // Stepi > 0.
+ ExprResult CmpRes =
+ CreateBuiltinBinOp(D.AssignmentLoc, BO_GT, D.Range.Step,
+ ActOnIntegerConstant(D.AssignmentLoc, 0).get());
+ if (!CmpRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ Res = ActOnConditionalOp(D.AssignmentLoc, D.AssignmentLoc, CmpRes.get(),
+ Res.get(), Res1.get());
+ if (!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ }
+ Res = ActOnFinishFullExpr(Res.get(), /*DiscardedValue=*/false);
+ if (!Res.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+
+ // Build counter update.
+ // Build counter.
+ auto *CounterVD =
+ VarDecl::Create(Context, CurContext, D.IteratorDecl->getBeginLoc(),
+ D.IteratorDecl->getBeginLoc(), nullptr,
+ Res.get()->getType(), nullptr, SC_None);
+ CounterVD->setImplicit();
+ ExprResult RefRes =
+ BuildDeclRefExpr(CounterVD, CounterVD->getType(), VK_LValue,
+ D.IteratorDecl->getBeginLoc());
+ // Build counter update.
+ // I = Begini + counter * Stepi;
+ ExprResult UpdateRes;
+ if (D.Range.Step) {
+ UpdateRes = CreateBuiltinBinOp(
+ D.AssignmentLoc, BO_Mul,
+ DefaultLvalueConversion(RefRes.get()).get(), St.get());
+ } else {
+ UpdateRes = DefaultLvalueConversion(RefRes.get());
+ }
+ if (!UpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ UpdateRes = CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, D.Range.Begin,
+ UpdateRes.get());
+ if (!UpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ ExprResult VDRes =
+ BuildDeclRefExpr(cast<VarDecl>(D.IteratorDecl),
+ cast<VarDecl>(D.IteratorDecl)->getType(), VK_LValue,
+ D.IteratorDecl->getBeginLoc());
+ UpdateRes = CreateBuiltinBinOp(D.AssignmentLoc, BO_Assign, VDRes.get(),
+ UpdateRes.get());
+ if (!UpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ UpdateRes =
+ ActOnFinishFullExpr(UpdateRes.get(), /*DiscardedValue=*/true);
+ if (!UpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ ExprResult CounterUpdateRes =
+ CreateBuiltinUnaryOp(D.AssignmentLoc, UO_PreInc, RefRes.get());
+ if (!CounterUpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ CounterUpdateRes =
+ ActOnFinishFullExpr(CounterUpdateRes.get(), /*DiscardedValue=*/true);
+ if (!CounterUpdateRes.isUsable()) {
+ IsCorrect = false;
+ continue;
+ }
+ OMPIteratorHelperData &HD = Helpers.emplace_back();
+ HD.CounterVD = CounterVD;
+ HD.Upper = Res.get();
+ HD.Update = UpdateRes.get();
+ HD.CounterUpdate = CounterUpdateRes.get();
+ }
+ } else {
+ Helpers.assign(ID.size(), {});
+ }
+ if (!IsCorrect) {
+ // Invalidate all created iterator declarations if error is found.
+ for (const OMPIteratorExpr::IteratorDefinition &D : ID) {
+ if (Decl *ID = D.IteratorDecl)
+ ID->setInvalidDecl();
+ }
+ return ExprError();
+ }
+ return OMPIteratorExpr::Create(Context, Context.OMPIteratorTy, IteratorKwLoc,
+ LLoc, RLoc, ID, Helpers);
}
ExprResult
@@ -4873,8 +5516,9 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// See IsCForbiddenLValueType.
if (!ResultType.hasQualifiers()) VK = VK_RValue;
} else if (!ResultType->isDependentType() &&
- RequireCompleteType(LLoc, ResultType,
- diag::err_subscript_incomplete_type, BaseExpr))
+ RequireCompleteSizedType(
+ LLoc, ResultType,
+ diag::err_subscript_incomplete_or_sizeless_type, BaseExpr))
return ExprError();
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
@@ -4914,6 +5558,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
if (Param->hasUnparsedDefaultArg()) {
+ // If we've already cleared out the location for the default argument,
+ // that means we're parsing it right now.
+ if (!UnparsedDefaultArgLocs.count(Param)) {
+ Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+ Diag(CallLoc, diag::note_recursive_default_argument_used_here);
+ Param->setInvalidDecl();
+ return true;
+ }
+
Diag(CallLoc,
diag::err_use_of_default_argument_to_function_declared_later) <<
FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
@@ -4922,90 +5575,11 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
return true;
}
- if (Param->hasUninstantiatedDefaultArg()) {
- Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
-
- EnterExpressionEvaluationContext EvalContext(
- *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
-
- // Instantiate the expression.
- //
- // FIXME: Pass in a correct Pattern argument, otherwise
- // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
- //
- // template<typename T>
- // struct A {
- // static int FooImpl();
- //
- // template<typename Tp>
- // // bug: default argument A<T>::FooImpl() is evaluated with 2-level
- // // template argument list [[T], [Tp]], should be [[Tp]].
- // friend A<Tp> Foo(int a);
- // };
- //
- // template<typename T>
- // A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList MutiLevelArgList
- = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
-
- InstantiatingTemplate Inst(*this, CallLoc, Param,
- MutiLevelArgList.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);
- LocalInstantiationScope Local(*this);
- runWithSufficientStackSpace(CallLoc, [&] {
- Result = SubstInitializer(UninstExpr, MutiLevelArgList,
- /*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);
- }
- }
-
- // If the default argument expression is not set yet, we are building it now.
- if (!Param->hasInit()) {
- Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
- Param->setInvalidDecl();
+ if (Param->hasUninstantiatedDefaultArg() &&
+ InstantiateDefaultArgument(CallLoc, FD, Param))
return true;
- }
+
+ assert(Param->hasInit() && "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
@@ -5038,6 +5612,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
FunctionDecl *FD, ParmVarDecl *Param) {
+ assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
return ExprError();
return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
@@ -5183,7 +5758,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// Emit the location of the prototype.
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
- Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl;
+ Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
return true;
}
@@ -5228,7 +5803,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// Emit the location of the prototype.
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
- Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl;
+ Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl;
// This deletes the extra arguments.
Call->shrinkNumArgs(NumParams);
@@ -5341,9 +5916,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
for (Expr *A : Args.slice(ArgIx)) {
ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl);
Invalid |= Arg.isInvalid();
- // Copy blocks to the heap.
- if (A->getType()->isBlockPointerType())
- maybeExtendBlockObject(Arg);
AllArgs.push_back(Arg.get());
}
}
@@ -5476,7 +6048,10 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
// These are always invalid as call arguments and should be reported.
case BuiltinType::BoundMember:
case BuiltinType::BuiltinFn:
+ case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::OMPArraySection:
+ case BuiltinType::OMPArrayShaping:
+ case BuiltinType::OMPIterator:
return true;
}
@@ -5599,7 +6174,8 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
if (Callee->getMinRequiredArguments() > ArgExprs.size())
return;
- if (const EnableIfAttr *Attr = S.CheckEnableIf(Callee, ArgExprs, true)) {
+ if (const EnableIfAttr *Attr =
+ S.CheckEnableIf(Callee, Fn->getBeginLoc(), ArgExprs, true)) {
S.Diag(Fn->getBeginLoc(),
isa<CXXMethodDecl>(Callee)
? diag::err_ovl_no_viable_member_function_in_call
@@ -5706,13 +6282,17 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn)) {
if (ULE->hasExplicitTemplateArgs() &&
ULE->decls_begin() == ULE->decls_end()) {
- Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus2a
+ Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_adl_only_template_id
: diag::ext_adl_only_template_id)
<< ULE->getName();
}
}
+ if (LangOpts.OpenMP)
+ Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig);
+
return Call;
}
@@ -6123,6 +6703,18 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (NDecl)
DiagnoseSentinelCalls(NDecl, LParenLoc, Args);
+ // Warn for unions passing across security boundary (CMSE).
+ if (FuncT != nullptr && FuncT->getCmseNSCallAttr()) {
+ for (unsigned i = 0, e = Args.size(); i != e; i++) {
+ if (const auto *RT =
+ dyn_cast<RecordType>(Args[i]->getType().getCanonicalType())) {
+ if (RT->getDecl()->isOrContainsUnion())
+ Diag(Args[i]->getBeginLoc(), diag::warn_cmse_nonsecure_union)
+ << 0 << i;
+ }
+ }
+ }
+
// Do special checking on direct calls to functions.
if (FDecl) {
if (CheckFunctionCall(FDecl, TheCall, Proto))
@@ -6140,7 +6732,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
return ExprError();
}
- return MaybeBindToTemporary(TheCall);
+ return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FDecl);
}
ExprResult
@@ -6163,10 +6755,10 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
QualType literalType = TInfo->getType();
if (literalType->isArrayType()) {
- if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType),
- diag::err_illegal_decl_array_incomplete_type,
- SourceRange(LParenLoc,
- LiteralExpr->getSourceRange().getEnd())))
+ if (RequireCompleteSizedType(
+ LParenLoc, Context.getBaseElementType(literalType),
+ diag::err_array_incomplete_or_sizeless_type,
+ SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())))
return ExprError();
if (literalType->isVariableArrayType())
return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init)
@@ -6240,14 +6832,24 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
return ExprError();
}
- // Compound literals that have automatic storage duration are destroyed at
- // the end of the scope. Emit diagnostics if it is or contains a C union type
- // that is non-trivial to destruct.
- if (!isFileScope)
+ if (!isFileScope && !getLangOpts().CPlusPlus) {
+ // Compound literals that have automatic storage duration are destroyed at
+ // the end of the scope in C; in C++, they're just temporaries.
+
+ // Emit diagnostics if it is or contains a C union type that is non-trivial
+ // to destruct.
if (E->getType().hasNonTrivialToPrimitiveDestructCUnion())
checkNonTrivialCUnion(E->getType(), E->getExprLoc(),
NTCUC_CompoundLiteral, NTCUK_Destruct);
+ // Diagnose jumps that enter or exit the lifetime of the compound literal.
+ if (literalType.isDestructedType()) {
+ Cleanup.setExprNeedsCleanups(true);
+ ExprCleanupObjects.push_back(E);
+ getCurFunction()->setHasBranchProtectedScope();
+ }
+ }
+
if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() ||
E->getType().hasNonTrivialToPrimitiveCopyCUnion())
checkNonTrivialCUnionInInitializer(E->getInitializer(),
@@ -6313,7 +6915,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
// already diagnose use of (non-C++20) C99 designator syntax.
if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator &&
!DiagnosedNestedDesignator && !DiagnosedMixedDesignator) {
- Diag(FirstDesignator, getLangOpts().CPlusPlus2a
+ Diag(FirstDesignator, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_designated_init
: diag::ext_cxx_designated_init);
} else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) {
@@ -7459,7 +8061,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// The OpenCL operator with a vector condition is sufficiently
// different to merit its own checker.
- if (getLangOpts().OpenCL && Cond.get()->getType()->isVectorType())
+ if ((getLangOpts().OpenCL && Cond.get()->getType()->isVectorType()) ||
+ Cond.get()->getType()->isExtVectorType())
return OpenCLCheckVectorConditional(*this, Cond, LHS, RHS, QuestionLoc);
// First, check the condition.
@@ -7509,6 +8112,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
return ResTy;
}
+ // And if they're both bfloat (which isn't arithmetic), that's fine too.
+ if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) {
+ return LHSTy;
+ }
+
// If both operands are the same structure or union type, the result is that
// type.
if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3
@@ -7559,6 +8167,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
/*IsIntFirstExpr=*/false))
return LHSTy;
+ // Allow ?: operations in which both operands have the same
+ // built-in sizeless type.
+ if (LHSTy->isSizelessBuiltinType() && LHSTy == RHSTy)
+ return LHSTy;
+
// 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
// likely forgot to take the address of the other expression.
@@ -8002,6 +8615,24 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
ColonLoc, result, VK, OK);
}
+// Check if we have a conversion between incompatible cmse function pointer
+// types, that is, a conversion between a function pointer with the
+// cmse_nonsecure_call attribute and one without.
+static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType,
+ QualType ToType) {
+ if (const auto *ToFn =
+ dyn_cast<FunctionType>(S.Context.getCanonicalType(ToType))) {
+ if (const auto *FromFn =
+ dyn_cast<FunctionType>(S.Context.getCanonicalType(FromType))) {
+ FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo();
+ FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo();
+
+ return ToEInfo.getCmseNSCall() != FromEInfo.getCmseNSCall();
+ }
+ }
+ return false;
+}
+
// checkPointerTypesForAssignment - This is a very tricky routine (despite
// being closely modeled after the C99 spec:-). The odd characteristic of this
// routine is it effectively iqnores the qualifiers on the top level pointee.
@@ -8133,11 +8764,15 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
}
// General pointer incompatibility takes priority over qualifiers.
+ if (RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType())
+ return Sema::IncompatibleFunctionPointer;
return Sema::IncompatiblePointer;
}
if (!S.getLangOpts().CPlusPlus &&
S.IsFunctionConversion(ltrans, rtrans, ltrans))
- return Sema::IncompatiblePointer;
+ return Sema::IncompatibleFunctionPointer;
+ if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
+ return Sema::IncompatibleFunctionPointer;
return ConvTy;
}
@@ -8248,7 +8883,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc,
/// type ElementType.
static bool isVector(QualType QT, QualType ElementType) {
if (const VectorType *VT = QT->getAs<VectorType>())
- return VT->getElementType() == ElementType;
+ return VT->getElementType().getCanonicalType() == ElementType;
return false;
}
@@ -8691,7 +9326,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
ImplicitConversionSequence ICS =
TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false);
@@ -8786,7 +9421,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
if (getLangOpts().ObjC &&
(CheckObjCBridgeRelatedConversions(E->getBeginLoc(), LHSType,
E->getType(), E, Diagnose) ||
- ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) {
+ CheckConversionToObjCLiteral(LHSType, E, Diagnose))) {
if (!Diagnose)
return Incompatible;
// Replace the expression with a corrected version and continue so we
@@ -9083,7 +9718,13 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
// Reject cases where the scalar type is not a constant and has a higher
// Order than the vector element type.
llvm::APFloat Result(0.0);
- bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context);
+
+ // Determine whether this is a constant scalar. In the event that the
+ // value is dependent (and thus cannot be evaluated by the constant
+ // evaluator), skip the evaluation. This will then diagnose once the
+ // expression is instantiated.
+ bool CstScalar = Scalar->get()->isValueDependent() ||
+ Scalar->get()->EvaluateAsFloat(Result, S.Context);
int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
if (!CstScalar && Order < 0)
return true;
@@ -9106,7 +9747,8 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
ScalarCast = CK_IntegralToFloating;
} else
return true;
- }
+ } else if (ScalarTy->isEnumeralType())
+ return true;
// Adjust scalar if desired.
if (Scalar) {
@@ -9395,6 +10037,9 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
/*AllowBothBool*/getLangOpts().AltiVec,
/*AllowBoolConversions*/false);
+ if (!IsDiv && (LHS.get()->getType()->isConstantMatrixType() ||
+ RHS.get()->getType()->isConstantMatrixType()))
+ return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign);
QualType compType = UsualArithmeticConversions(
LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
@@ -9509,9 +10154,10 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
assert(ResType->isAnyPointerType() && !ResType->isDependentType());
QualType PointeeTy = ResType->getPointeeType();
- return S.RequireCompleteType(Loc, PointeeTy,
- diag::err_typecheck_arithmetic_incomplete_type,
- PointeeTy, Operand->getSourceRange());
+ return S.RequireCompleteSizedType(
+ Loc, PointeeTy,
+ diag::err_typecheck_arithmetic_incomplete_or_sizeless_type,
+ Operand->getSourceRange());
}
/// Check the validity of an arithmetic pointer operand.
@@ -9565,10 +10211,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
// if both are pointers check if operation is valid wrt address spaces
- if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
- const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>();
- const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>();
- if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
+ if (isLHSPointer && isRHSPointer) {
+ if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/
@@ -9715,6 +10359,11 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
+ if (LHS.get()->getType()->isConstantMatrixType() ||
+ RHS.get()->getType()->isConstantMatrixType()) {
+ return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy);
+ }
+
QualType compType = UsualArithmeticConversions(
LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
@@ -9810,6 +10459,11 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
+ if (LHS.get()->getType()->isConstantMatrixType() ||
+ RHS.get()->getType()->isConstantMatrixType()) {
+ return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy);
+ }
+
QualType compType = UsualArithmeticConversions(
LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
@@ -9933,14 +10587,19 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
<< RHS.get()->getSourceRange());
return;
}
- llvm::APInt LeftBits(Right.getBitWidth(),
- S.Context.getTypeSize(LHS.get()->getType()));
+
+ QualType LHSExprType = LHS.get()->getType();
+ uint64_t LeftSize = LHSExprType->isExtIntType()
+ ? S.Context.getIntWidth(LHSExprType)
+ : S.Context.getTypeSize(LHSExprType);
+ llvm::APInt LeftBits(Right.getBitWidth(), LeftSize);
if (Right.uge(LeftBits)) {
S.DiagRuntimeBehavior(Loc, RHS.get(),
S.PDiag(diag::warn_shift_gt_typewidth)
<< RHS.get()->getSourceRange());
return;
}
+
if (Opc != BO_Shl)
return;
@@ -9960,7 +10619,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
// If LHS does not have a signed type and non-negative value
// then, the behavior is undefined before C++2a. Warn about it.
if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() &&
- !S.getLangOpts().CPlusPlus2a) {
+ !S.getLangOpts().CPlusPlus20) {
S.DiagRuntimeBehavior(Loc, LHS.get(),
S.PDiag(diag::warn_shift_lhs_negative)
<< LHS.get()->getSourceRange());
@@ -10440,7 +11099,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
// C++2a [depr.array.comp]:
// Equality and relational comparisons ([expr.eq], [expr.rel]) between two
// operands of array type are deprecated.
- if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() &&
+ if (S.getLangOpts().CPlusPlus20 && LHSStripped->getType()->isArrayType() &&
RHSStripped->getType()->isArrayType()) {
S.Diag(Loc, diag::warn_depr_array_comparison)
<< LHS->getSourceRange() << RHS->getSourceRange()
@@ -10897,11 +11556,22 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C99 6.5.9p2 and C99 6.5.8p2
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
RCanPointeeTy.getUnqualifiedType())) {
- // Valid unless a relational comparison of function pointers
- if (IsRelational && LCanPointeeTy->isFunctionType()) {
- Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
- << LHSType << RHSType << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
+ if (IsRelational) {
+ // Pointers both need to point to complete or incomplete types
+ if ((LCanPointeeTy->isIncompleteType() !=
+ RCanPointeeTy->isIncompleteType()) &&
+ !getLangOpts().C11) {
+ Diag(Loc, diag::ext_typecheck_compare_complete_incomplete_pointers)
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange()
+ << LHSType << RHSType << LCanPointeeTy->isIncompleteType()
+ << RCanPointeeTy->isIncompleteType();
+ }
+ if (LCanPointeeTy->isFunctionType()) {
+ // Valid unless a relational comparison of function pointers
+ Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ }
}
} else if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
@@ -10917,8 +11587,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
- const PointerType *LHSPtr = LHSType->castAs<PointerType>();
- if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) {
+ if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */
@@ -11316,12 +11985,12 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
if (XorStr == "xor")
return;
- std::string LHSStr = Lexer::getSourceText(
+ std::string LHSStr = std::string(Lexer::getSourceText(
CharSourceRange::getTokenRange(LHSInt->getSourceRange()),
- S.getSourceManager(), S.getLangOpts());
- std::string RHSStr = Lexer::getSourceText(
+ S.getSourceManager(), S.getLangOpts()));
+ std::string RHSStr = std::string(Lexer::getSourceText(
CharSourceRange::getTokenRange(RHSInt->getSourceRange()),
- S.getSourceManager(), S.getLangOpts());
+ S.getSourceManager(), S.getLangOpts()));
if (Negative) {
RightSideValue = -RightSideValue;
@@ -11401,6 +12070,83 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
return GetSignedVectorType(LHS.get()->getType());
}
+QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ bool IsCompAssign) {
+ if (!IsCompAssign) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
+
+ // For conversion purposes, we ignore any qualifiers.
+ // For example, "const float" and "float" are equivalent.
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
+
+ const MatrixType *LHSMatType = LHSType->getAs<MatrixType>();
+ const MatrixType *RHSMatType = RHSType->getAs<MatrixType>();
+ assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
+
+ if (Context.hasSameType(LHSType, RHSType))
+ return LHSType;
+
+ // Type conversion may change LHS/RHS. Keep copies to the original results, in
+ // case we have to return InvalidOperands.
+ ExprResult OriginalLHS = LHS;
+ ExprResult OriginalRHS = RHS;
+ if (LHSMatType && !RHSMatType) {
+ RHS = tryConvertExprToType(RHS.get(), LHSMatType->getElementType());
+ if (!RHS.isInvalid())
+ return LHSType;
+
+ return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
+ }
+
+ if (!LHSMatType && RHSMatType) {
+ LHS = tryConvertExprToType(LHS.get(), RHSMatType->getElementType());
+ if (!LHS.isInvalid())
+ return RHSType;
+ return InvalidOperands(Loc, OriginalLHS, OriginalRHS);
+ }
+
+ return InvalidOperands(Loc, LHS, RHS);
+}
+
+QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ bool IsCompAssign) {
+ if (!IsCompAssign) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
+
+ auto *LHSMatType = LHS.get()->getType()->getAs<ConstantMatrixType>();
+ auto *RHSMatType = RHS.get()->getType()->getAs<ConstantMatrixType>();
+ assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
+
+ if (LHSMatType && RHSMatType) {
+ if (LHSMatType->getNumColumns() != RHSMatType->getNumRows())
+ return InvalidOperands(Loc, LHS, RHS);
+
+ if (!Context.hasSameType(LHSMatType->getElementType(),
+ RHSMatType->getElementType()))
+ return InvalidOperands(Loc, LHS, RHS);
+
+ return Context.getConstantMatrixType(LHSMatType->getElementType(),
+ LHSMatType->getNumRows(),
+ RHSMatType->getNumColumns());
+ }
+ return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
+}
+
inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
@@ -12086,7 +12832,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
CheckForNullPointerDereference(*this, LHSExpr);
- if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) {
+ if (getLangOpts().CPlusPlus20 && LHSType.isVolatileQualified()) {
if (CompoundType.isNull()) {
// C++2a [expr.ass]p5:
// A simple-assignment whose left operand is of a volatile-qualified
@@ -12132,8 +12878,8 @@ static bool IgnoreCommaOperand(const Expr *E) {
}
// Look for instances where it is likely the comma operator is confused with
-// another operator. There is a whitelist of acceptable expressions for the
-// left hand side of the comma operator, otherwise emit a warning.
+// another operator. There is an explicit list of acceptable expressions for
+// the left hand side of the comma operator, otherwise emit a warning.
void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
// No warnings in macros
if (Loc.isMacroID())
@@ -12143,10 +12889,10 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
if (inTemplateInstantiation())
return;
- // Scope isn't fine-grained enough to whitelist the specific cases, so
+ // Scope isn't fine-grained enough to explicitly list the specific cases, so
// instead, skip more than needed, then call back into here with the
// CommaVisitor in SemaStmt.cpp.
- // The whitelisted locations are the initialization and increment portions
+ // The listed locations are the initialization and increment portions
// of a for loop. The additional checks are on the condition of
// if statements, do/while loops, and for loops.
// Differences in scope flags for C89 mode requires the extra logic.
@@ -12289,7 +13035,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, S))
return QualType();
- if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) {
+ if (S.getLangOpts().CPlusPlus20 && ResType.isVolatileQualified()) {
// C++2a [expr.pre.inc]p1, [expr.post.inc]p1:
// An operand with volatile-qualified type is deprecated
S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile)
@@ -12321,6 +13067,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
/// - *(x + 1) -> x, if x is an array
/// - &"123"[2] -> 0
/// - & __real__ x -> x
+///
+/// FIXME: We don't recurse to the RHS of a comma, nor handle pointers to
+/// members.
static ValueDecl *getPrimaryDecl(Expr *E) {
switch (E->getStmtClass()) {
case Stmt::DeclRefExprClass:
@@ -12361,19 +13110,22 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
// If the result of an implicit cast is an l-value, we care about
// the sub-expression; otherwise, the result here doesn't matter.
return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr());
+ case Stmt::CXXUuidofExprClass:
+ return cast<CXXUuidofExpr>(E)->getGuidDecl();
default:
return nullptr;
}
}
namespace {
- enum {
- AO_Bit_Field = 0,
- AO_Vector_Element = 1,
- AO_Property_Expansion = 2,
- AO_Register_Variable = 3,
- AO_No_Error = 4
- };
+enum {
+ AO_Bit_Field = 0,
+ AO_Vector_Element = 1,
+ AO_Property_Expansion = 2,
+ AO_Register_Variable = 3,
+ AO_Matrix_Element = 4,
+ AO_No_Error = 5
+};
}
/// Diagnose invalid operand for address of operations.
///
@@ -12540,6 +13292,9 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
} else if (op->getObjectKind() == OK_VectorComponent) {
// The operand cannot be an element of a vector
AddressOfError = AO_Vector_Element;
+ } else if (op->getObjectKind() == OK_MatrixComponent) {
+ // The operand cannot be an element of a matrix.
+ AddressOfError = AO_Matrix_Element;
} else if (dcl) { // C99 6.5.3.2p1
// We have an lvalue with a decl. Make sure the decl is not declared
// with the register storage-class specifier.
@@ -12581,7 +13336,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
}
}
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
- !isa<BindingDecl>(dcl))
+ !isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl))
llvm_unreachable("Unknown/unexpected decl type");
}
@@ -12845,7 +13600,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
BinaryOperatorKind Opc, QualType ResultTy,
ExprValueKind VK, ExprObjectKind OK,
bool IsCompAssign, SourceLocation OpLoc,
- FPOptions FPFeatures) {
+ FPOptionsOverride FPFeatures) {
auto &Context = S.getASTContext();
assert((isVector(ResultTy, Context.HalfTy) ||
isVector(ResultTy, Context.ShortTy)) &&
@@ -12863,13 +13618,13 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
BinOpResTy = S.GetSignedVectorType(BinOpResTy);
if (IsCompAssign)
- return new (Context) CompoundAssignOperator(
- LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy,
- OpLoc, FPFeatures);
+ return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc,
+ ResultTy, VK, OK, OpLoc, FPFeatures,
+ BinOpResTy, BinOpResTy);
LHS = convertVector(LHS.get(), Context.FloatTy, S);
- auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
- VK, OK, OpLoc, FPFeatures);
+ auto *BO = BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc,
+ BinOpResTy, VK, OK, OpLoc, FPFeatures);
return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
}
@@ -12882,13 +13637,15 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
// doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands.
LHS = S.CorrectDelayedTyposInExpr(LHS);
- RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) {
- if (Opc != BO_Assign)
- return ExprResult(E);
- // Avoid correcting the RHS to the same Expr as the LHS.
- Decl *D = getDeclFromExpr(E);
- return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
- });
+ RHS = S.CorrectDelayedTyposInExpr(
+ RHS, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false,
+ [Opc, LHS](Expr *E) {
+ if (Opc != BO_Assign)
+ return ExprResult(E);
+ // Avoid correcting the RHS to the same Expr as the LHS.
+ Decl *D = getDeclFromExpr(E);
+ return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E;
+ });
}
return std::make_pair(LHS, RHS);
}
@@ -12896,10 +13653,27 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr,
/// Returns true if conversion between vectors of halfs and vectors of floats
/// is needed.
static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
- QualType SrcType) {
- return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType &&
- !Ctx.getTargetInfo().useFP16ConversionIntrinsics() &&
- isVector(SrcType, Ctx.HalfTy);
+ Expr *E0, Expr *E1 = nullptr) {
+ if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType ||
+ Ctx.getTargetInfo().useFP16ConversionIntrinsics())
+ return false;
+
+ auto HasVectorOfHalfType = [&Ctx](Expr *E) {
+ QualType Ty = E->IgnoreImplicit()->getType();
+
+ // Don't promote half precision neon vectors like float16x4_t in arm_neon.h
+ // to vectors of floats. Although the element type of the vectors is __fp16,
+ // the vectors shouldn't be treated as storage-only types. See the
+ // discussion here: https://reviews.llvm.org/rG825235c140e7
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ if (VT->getVectorKind() == VectorType::NeonVector)
+ return false;
+ return VT->getElementType().getCanonicalType() == Ctx.HalfTy;
+ }
+ return false;
+ };
+
+ return HasVectorOfHalfType(E0) && (!E1 || HasVectorOfHalfType(E1));
}
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
@@ -12964,14 +13738,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
}
- // Diagnose operations on the unsupported types for OpenMP device compilation.
- if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) {
- if (Opc != BO_Assign && Opc != BO_Comma) {
- checkOpenMPDeviceExpr(LHSExpr);
- checkOpenMPDeviceExpr(RHSExpr);
- }
- }
-
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -13119,14 +13885,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
- if (ResultTy->isRealFloatingType() &&
- (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
- getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
- // Mark the current function as usng floating point constrained intrinsics
- if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
- F->setUsesFPIntrin(true);
- }
-
// Some of the binary operations require promoting operands of half vector to
// float vectors and truncating the result back to half vector. For now, we do
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
@@ -13134,8 +13892,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
assert(isVector(RHS.get()->getType(), Context.HalfTy) ==
isVector(LHS.get()->getType(), Context.HalfTy) &&
"both sides are half vectors or neither sides are");
- ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context,
- LHS.get()->getType());
+ ConvertHalfVec =
+ needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get(), RHS.get());
// Check for array bounds violations for both sides of the BinaryOperator
CheckArrayAccess(LHS.get());
@@ -13165,9 +13923,9 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (CompResultTy.isNull()) {
if (ConvertHalfVec)
return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false,
- OpLoc, FPFeatures);
- return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
- OK, OpLoc, FPFeatures);
+ OpLoc, CurFPFeatureOverrides());
+ return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy,
+ VK, OK, OpLoc, CurFPFeatureOverrides());
}
// Handle compound assignments.
@@ -13177,13 +13935,19 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
OK = LHS.get()->getObjectKind();
}
+ // The LHS is not converted to the result type for fixed-point compound
+ // assignment as the common type is computed on demand. Reset the CompLHSTy
+ // to the LHS type we would have gotten after unary conversions.
+ if (CompResultTy->isFixedPointType())
+ CompLHSTy = UsualUnaryConversions(LHS.get()).get()->getType();
+
if (ConvertHalfVec)
return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true,
- OpLoc, FPFeatures);
+ OpLoc, CurFPFeatureOverrides());
- return new (Context) CompoundAssignOperator(
- LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
- OpLoc, FPFeatures);
+ return CompoundAssignOperator::Create(
+ Context, LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc,
+ CurFPFeatureOverrides(), CompLHSTy, CompResultTy);
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -13436,7 +14200,7 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
RHS->getType(), Functions);
// In C++20 onwards, we may have a second operator to look up.
- if (S.getLangOpts().CPlusPlus2a) {
+ if (S.getLangOpts().CPlusPlus20) {
if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))
S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),
RHS->getType(), Functions);
@@ -13586,12 +14350,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< Input.get()->getSourceRange());
}
}
- // Diagnose operations on the unsupported types for OpenMP device compilation.
- if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) {
- if (UnaryOperator::isIncrementDecrementOp(Opc) ||
- UnaryOperator::isArithmeticOp(Opc))
- checkOpenMPDeviceExpr(InputExpr);
- }
switch (Opc) {
case UO_PreInc:
@@ -13627,8 +14385,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
// float vector and truncating the result back to a half vector. For now, we
// do this only when HalfArgsAndReturns is set (that is, when the target is
// arm or arm64).
- ConvertHalfVec =
- needsConversionOfHalfVec(true, Context, Input.get()->getType());
+ ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get());
// If the operand is a half vector, promote it to a float vector.
if (ConvertHalfVec)
@@ -13722,9 +14479,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
// Vector logical not returns the signed variant of the operand type.
resultType = GetSignedVectorType(resultType);
break;
+ } else if (Context.getLangOpts().CPlusPlus && resultType->isVectorType()) {
+ const VectorType *VTy = resultType->castAs<VectorType>();
+ if (VTy->getVectorKind() != VectorType::GenericVector)
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
+
+ // Vector logical not returns the signed variant of the operand type.
+ resultType = GetSignedVectorType(resultType);
+ break;
} else {
- // FIXME: GCC's vector extension permits the usage of '!' with a vector
- // type in C++. We should allow that here too.
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -13771,8 +14535,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Opc != UO_AddrOf && Opc != UO_Deref)
CheckArrayAccess(Input.get());
- auto *UO = new (Context)
- UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow);
+ auto *UO =
+ UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK, OK,
+ OpLoc, CanOverflow, CurFPFeatureOverrides());
if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
!isa<ArrayType>(UO->getType().getDesugaredType(Context)))
@@ -13898,9 +14663,13 @@ void Sema::ActOnStmtExprError() {
PopExpressionEvaluationContext();
}
-ExprResult
-Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
- SourceLocation RPLoc) { // "({..})"
+ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt,
+ SourceLocation RPLoc) {
+ return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S));
+}
+
+ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
+ SourceLocation RPLoc, unsigned TemplateDepth) {
assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
@@ -13931,7 +14700,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
// FIXME: Check that expression type is complete/non-abstract; statement
// expressions are not lvalues.
- Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
+ Expr *ResStmtExpr =
+ new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth);
if (StmtExprMayBindToTemp)
return MaybeBindToTemporary(ResStmtExpr);
return ResStmtExpr;
@@ -14159,11 +14929,9 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resType;
- bool ValueDependent = false;
bool CondIsTrue = false;
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
resType = Context.DependentTy;
- ValueDependent = true;
} else {
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
@@ -14179,14 +14947,12 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr;
resType = ActiveExpr->getType();
- ValueDependent = ActiveExpr->isValueDependent();
VK = ActiveExpr->getValueKind();
OK = ActiveExpr->getObjectKind();
}
- return new (Context)
- ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, VK, OK, RPLoc,
- CondIsTrue, resType->isDependentType(), ValueDependent);
+ return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
+ resType, VK, OK, RPLoc, CondIsTrue);
}
//===----------------------------------------------------------------------===//
@@ -14297,11 +15063,12 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
if (ExplicitSignature) {
for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) {
ParmVarDecl *Param = ExplicitSignature.getParam(I);
- if (Param->getIdentifier() == nullptr &&
- !Param->isImplicit() &&
- !Param->isInvalidDecl() &&
- !getLangOpts().CPlusPlus)
- Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ if (Param->getIdentifier() == nullptr && !Param->isImplicit() &&
+ !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) {
+ // Diagnose this as an extension in C17 and earlier.
+ if (!getLangOpts().C2x)
+ Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x);
+ }
Params.push_back(Param);
}
@@ -14690,21 +15457,15 @@ ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext);
}
-bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
- bool Diagnose) {
+bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp,
+ bool Diagnose) {
if (!getLangOpts().ObjC)
return false;
const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
if (!PT)
return false;
-
- if (!PT->isObjCIdType()) {
- // Check if the destination is the 'NSString' interface.
- const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
- if (!ID || !ID->getIdentifier()->isStr("NSString"))
- return false;
- }
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
// Ignore any parens, implicit casts (should only be
// array-to-pointer decays), and not-so-opaque values. The last is
@@ -14714,15 +15475,41 @@ bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
if (OV->getSourceExpr())
SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts();
- StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
- if (!SL || !SL->isAscii())
- return false;
- if (Diagnose) {
- Diag(SL->getBeginLoc(), diag::err_missing_atsign_prefix)
- << FixItHint::CreateInsertion(SL->getBeginLoc(), "@");
- Exp = BuildObjCStringLiteral(SL->getBeginLoc(), SL).get();
+ if (auto *SL = dyn_cast<StringLiteral>(SrcExpr)) {
+ if (!PT->isObjCIdType() &&
+ !(ID && ID->getIdentifier()->isStr("NSString")))
+ return false;
+ if (!SL->isAscii())
+ return false;
+
+ if (Diagnose) {
+ Diag(SL->getBeginLoc(), diag::err_missing_atsign_prefix)
+ << /*string*/0 << FixItHint::CreateInsertion(SL->getBeginLoc(), "@");
+ Exp = BuildObjCStringLiteral(SL->getBeginLoc(), SL).get();
+ }
+ return true;
}
- return true;
+
+ if ((isa<IntegerLiteral>(SrcExpr) || isa<CharacterLiteral>(SrcExpr) ||
+ isa<FloatingLiteral>(SrcExpr) || isa<ObjCBoolLiteralExpr>(SrcExpr) ||
+ isa<CXXBoolLiteralExpr>(SrcExpr)) &&
+ !SrcExpr->isNullPointerConstant(
+ getASTContext(), Expr::NPC_NeverValueDependent)) {
+ if (!ID || !ID->getIdentifier()->isStr("NSNumber"))
+ return false;
+ if (Diagnose) {
+ Diag(SrcExpr->getBeginLoc(), diag::err_missing_atsign_prefix)
+ << /*number*/1
+ << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), "@");
+ Expr *NumLit =
+ BuildObjCNumericLiteral(SrcExpr->getBeginLoc(), SrcExpr).get();
+ if (NumLit)
+ Exp = NumLit;
+ }
+ return true;
+ }
+
+ return false;
}
static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType,
@@ -14769,24 +15556,44 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
return false;
case PointerToInt:
- DiagKind = diag::ext_typecheck_convert_pointer_int;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_pointer_int;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_pointer_int;
+ }
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
break;
case IntToPointer:
- DiagKind = diag::ext_typecheck_convert_int_pointer;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_int_pointer;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_int_pointer;
+ }
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
+ break;
+ case IncompatibleFunctionPointer:
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_incompatible_function_pointer;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer;
+ }
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
break;
case IncompatiblePointer:
- if (Action == AA_Passing_CFAudited)
+ if (Action == AA_Passing_CFAudited) {
DiagKind = diag::err_arc_typecheck_convert_incompatible_pointer;
- else if (SrcType->isFunctionPointerType() &&
- DstType->isFunctionPointerType())
- DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer;
- else
+ } else if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_incompatible_pointer;
+ isInvalid = true;
+ } else {
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
-
+ }
CheckInferredResultType = DstType->isObjCObjectPointerType() &&
SrcType->isObjCObjectPointerType();
if (Hint.isNull() && !CheckInferredResultType) {
@@ -14799,15 +15606,27 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
MayHaveConvFixit = true;
break;
case IncompatiblePointerSign:
- DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_incompatible_pointer_sign;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
+ }
break;
case FunctionVoidPointer:
- DiagKind = diag::ext_typecheck_convert_pointer_void_func;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_pointer_void_func;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_pointer_void_func;
+ }
break;
case IncompatiblePointerDiscardsQualifiers: {
// Perform array-to-pointer decay if necessary.
if (SrcType->isArrayType()) SrcType = Context.getArrayDecayedType(SrcType);
+ isInvalid = true;
+
Qualifiers lhq = SrcType->getPointeeType().getQualifiers();
Qualifiers rhq = DstType->getPointeeType().getQualifiers();
if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
@@ -14835,19 +15654,33 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (getLangOpts().CPlusPlus &&
IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType))
return false;
- DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_typecheck_convert_discards_qualifiers;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
+ }
+
break;
case IncompatibleNestedPointerQualifiers:
- DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
+ if (getLangOpts().CPlusPlus) {
+ isInvalid = true;
+ DiagKind = diag::err_nested_pointer_qualifier_mismatch;
+ } else {
+ DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
+ }
break;
case IncompatibleNestedPointerAddressSpaceMismatch:
DiagKind = diag::err_typecheck_incompatible_nested_address_space;
+ isInvalid = true;
break;
case IntToBlockPointer:
DiagKind = diag::err_int_to_block_pointer;
+ isInvalid = true;
break;
case IncompatibleBlockPointer:
DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
+ isInvalid = true;
break;
case IncompatibleObjCQualifiedId: {
if (SrcType->isObjCQualifiedIdType()) {
@@ -14872,14 +15705,25 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
- DiagKind = diag::warn_incompatible_qualified_id;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_incompatible_qualified_id;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::warn_incompatible_qualified_id;
+ }
break;
}
case IncompatibleVectors:
- DiagKind = diag::warn_incompatible_vectors;
+ if (getLangOpts().CPlusPlus) {
+ DiagKind = diag::err_incompatible_vectors;
+ isInvalid = true;
+ } else {
+ DiagKind = diag::warn_incompatible_vectors;
+ }
break;
case IncompatibleObjCWeakRef:
DiagKind = diag::err_arc_weak_unavailable_assign;
+ isInvalid = true;
break;
case Incompatible:
if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) {
@@ -14937,9 +15781,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
HandleFunctionTypeMismatch(FDiag, SecondType, FirstType);
Diag(Loc, FDiag);
- if (DiagKind == diag::warn_incompatible_qualified_id &&
+ if ((DiagKind == diag::warn_incompatible_qualified_id ||
+ DiagKind == diag::err_incompatible_qualified_id) &&
PDecl && IFace && !IFace->hasDefinition())
- Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id)
+ Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id)
<< IFace << PDecl;
if (SecondType == Context.OverloadTy)
@@ -15064,6 +15909,12 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
return ExprError();
}
+ ExprResult RValueExpr = DefaultLvalueConversion(E);
+ if (RValueExpr.isInvalid())
+ return ExprError();
+
+ E = RValueExpr.get();
+
// Circumvent ICE checking in C++11 to avoid evaluating the expression twice
// in the non-ICE case.
if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) {
@@ -15251,7 +16102,7 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
/// and if so, remove it from the list of volatile-qualified assignments that
/// we are going to warn are deprecated.
void Sema::CheckUnusedVolatileAssignment(Expr *E) {
- if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a)
+ if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus20)
return;
// Note: ignoring parens here is not justified by the standard rules, but
@@ -15266,6 +16117,186 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
}
}
+ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
+ if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() ||
+ RebuildingImmediateInvocation)
+ return E;
+
+ /// Opportunistically remove the callee from ReferencesToConsteval if we can.
+ /// It's OK if this fails; we'll also remove this in
+ /// HandleImmediateInvocations, but catching it here allows us to avoid
+ /// walking the AST looking for it in simple cases.
+ if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit()))
+ if (auto *DeclRef =
+ dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit()))
+ ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef);
+
+ E = MaybeCreateExprWithCleanups(E);
+
+ ConstantExpr *Res = ConstantExpr::Create(
+ getASTContext(), E.get(),
+ ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
+ getASTContext()),
+ /*IsImmediateInvocation*/ true);
+ ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+ return Res;
+}
+
+static void EvaluateAndDiagnoseImmediateInvocation(
+ Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ Expr::EvalResult Eval;
+ Eval.Diag = &Notes;
+ ConstantExpr *CE = Candidate.getPointer();
+ bool Result = CE->EvaluateAsConstantExpr(Eval, Expr::EvaluateForCodeGen,
+ SemaRef.getASTContext(), true);
+ if (!Result || !Notes.empty()) {
+ Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit();
+ if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr))
+ InnerExpr = FunctionalCast->getSubExpr();
+ FunctionDecl *FD = nullptr;
+ if (auto *Call = dyn_cast<CallExpr>(InnerExpr))
+ FD = cast<FunctionDecl>(Call->getCalleeDecl());
+ else if (auto *Call = dyn_cast<CXXConstructExpr>(InnerExpr))
+ FD = Call->getConstructor();
+ else
+ llvm_unreachable("unhandled decl kind");
+ assert(FD->isConsteval());
+ SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD;
+ for (auto &Note : Notes)
+ SemaRef.Diag(Note.first, Note.second);
+ return;
+ }
+ CE->MoveIntoResult(Eval.Val, SemaRef.getASTContext());
+}
+
+static void RemoveNestedImmediateInvocation(
+ Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec,
+ SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator It) {
+ struct ComplexRemove : TreeTransform<ComplexRemove> {
+ using Base = TreeTransform<ComplexRemove>;
+ llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet;
+ SmallVector<Sema::ImmediateInvocationCandidate, 4> &IISet;
+ SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator
+ CurrentII;
+ ComplexRemove(Sema &SemaRef, llvm::SmallPtrSetImpl<DeclRefExpr *> &DR,
+ SmallVector<Sema::ImmediateInvocationCandidate, 4> &II,
+ SmallVector<Sema::ImmediateInvocationCandidate,
+ 4>::reverse_iterator Current)
+ : Base(SemaRef), DRSet(DR), IISet(II), CurrentII(Current) {}
+ void RemoveImmediateInvocation(ConstantExpr* E) {
+ auto It = std::find_if(CurrentII, IISet.rend(),
+ [E](Sema::ImmediateInvocationCandidate Elem) {
+ return Elem.getPointer() == E;
+ });
+ assert(It != IISet.rend() &&
+ "ConstantExpr marked IsImmediateInvocation should "
+ "be present");
+ It->setInt(1); // Mark as deleted
+ }
+ ExprResult TransformConstantExpr(ConstantExpr *E) {
+ if (!E->isImmediateInvocation())
+ return Base::TransformConstantExpr(E);
+ RemoveImmediateInvocation(E);
+ return Base::TransformExpr(E->getSubExpr());
+ }
+ /// Base::TransfromCXXOperatorCallExpr doesn't traverse the callee so
+ /// we need to remove its DeclRefExpr from the DRSet.
+ ExprResult TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ DRSet.erase(cast<DeclRefExpr>(E->getCallee()->IgnoreImplicit()));
+ return Base::TransformCXXOperatorCallExpr(E);
+ }
+ /// Base::TransformInitializer skip ConstantExpr so we need to visit them
+ /// here.
+ ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
+ if (!Init)
+ return Init;
+ /// ConstantExpr are the first layer of implicit node to be removed so if
+ /// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
+ if (auto *CE = dyn_cast<ConstantExpr>(Init))
+ if (CE->isImmediateInvocation())
+ RemoveImmediateInvocation(CE);
+ return Base::TransformInitializer(Init, NotCopyInit);
+ }
+ ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
+ DRSet.erase(E);
+ return E;
+ }
+ bool AlwaysRebuild() { return false; }
+ bool ReplacingOriginal() { return true; }
+ bool AllowSkippingCXXConstructExpr() {
+ bool Res = AllowSkippingFirstCXXConstructExpr;
+ AllowSkippingFirstCXXConstructExpr = true;
+ return Res;
+ }
+ bool AllowSkippingFirstCXXConstructExpr = true;
+ } Transformer(SemaRef, Rec.ReferenceToConsteval,
+ Rec.ImmediateInvocationCandidates, It);
+
+ /// CXXConstructExpr with a single argument are getting skipped by
+ /// TreeTransform in some situtation because they could be implicit. This
+ /// can only occur for the top-level CXXConstructExpr because it is used
+ /// nowhere in the expression being transformed therefore will not be rebuilt.
+ /// Setting AllowSkippingFirstCXXConstructExpr to false will prevent from
+ /// skipping the first CXXConstructExpr.
+ if (isa<CXXConstructExpr>(It->getPointer()->IgnoreImplicit()))
+ Transformer.AllowSkippingFirstCXXConstructExpr = false;
+
+ ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr());
+ assert(Res.isUsable());
+ Res = SemaRef.MaybeCreateExprWithCleanups(Res);
+ It->getPointer()->setSubExpr(Res.get());
+}
+
+static void
+HandleImmediateInvocations(Sema &SemaRef,
+ Sema::ExpressionEvaluationContextRecord &Rec) {
+ if ((Rec.ImmediateInvocationCandidates.size() == 0 &&
+ Rec.ReferenceToConsteval.size() == 0) ||
+ SemaRef.RebuildingImmediateInvocation)
+ return;
+
+ /// When we have more then 1 ImmediateInvocationCandidates we need to check
+ /// for nested ImmediateInvocationCandidates. when we have only 1 we only
+ /// need to remove ReferenceToConsteval in the immediate invocation.
+ if (Rec.ImmediateInvocationCandidates.size() > 1) {
+
+ /// Prevent sema calls during the tree transform from adding pointers that
+ /// are already in the sets.
+ llvm::SaveAndRestore<bool> DisableIITracking(
+ SemaRef.RebuildingImmediateInvocation, true);
+
+ /// Prevent diagnostic during tree transfrom as they are duplicates
+ Sema::TentativeAnalysisScope DisableDiag(SemaRef);
+
+ for (auto It = Rec.ImmediateInvocationCandidates.rbegin();
+ It != Rec.ImmediateInvocationCandidates.rend(); It++)
+ if (!It->getInt())
+ RemoveNestedImmediateInvocation(SemaRef, Rec, It);
+ } else if (Rec.ImmediateInvocationCandidates.size() == 1 &&
+ Rec.ReferenceToConsteval.size()) {
+ struct SimpleRemove : RecursiveASTVisitor<SimpleRemove> {
+ llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet;
+ SimpleRemove(llvm::SmallPtrSetImpl<DeclRefExpr *> &S) : DRSet(S) {}
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ DRSet.erase(E);
+ return DRSet.size();
+ }
+ } Visitor(Rec.ReferenceToConsteval);
+ Visitor.TraverseStmt(
+ Rec.ImmediateInvocationCandidates.front().getPointer()->getSubExpr());
+ }
+ for (auto CE : Rec.ImmediateInvocationCandidates)
+ if (!CE.getInt())
+ EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
+ for (auto DR : Rec.ReferenceToConsteval) {
+ auto *FD = cast<FunctionDecl>(DR->getDecl());
+ SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
+ << FD;
+ SemaRef.Diag(FD->getLocation(), diag::note_declared_at);
+ }
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
unsigned NumTypos = Rec.NumTypos;
@@ -15299,6 +16330,7 @@ void Sema::PopExpressionEvaluationContext() {
}
WarnOnPendingNoDerefs(Rec);
+ HandleImmediateInvocations(*this, Rec);
// Warn on any volatile-qualified simple-assignments that are not discarded-
// value expressions nor unevaluated operands (those cases get removed from
@@ -15584,6 +16616,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
+ if (getLangOpts().SYCLIsDevice)
+ checkSYCLDeviceFunction(Loc, Func);
+
// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
runWithSufficientStackSpace(Loc, [&] {
@@ -15722,15 +16757,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (funcHasParameterSizeMangling(*this, Func))
CheckCompleteParameterTypesForMangler(*this, Func, Loc);
- Func->markUsed(Context);
- }
+ // In the MS C++ ABI, the compiler emits destructor variants where they are
+ // used. If the destructor is used here but defined elsewhere, mark the
+ // virtual base destructors referenced. If those virtual base destructors
+ // are inline, this will ensure they are defined when emitting the complete
+ // destructor variant. This checking may be redundant if the destructor is
+ // provided later in this TU.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (auto *Dtor = dyn_cast<CXXDestructorDecl>(Func)) {
+ CXXRecordDecl *Parent = Dtor->getParent();
+ if (Parent->getNumVBases() > 0 && !Dtor->getBody())
+ CheckCompleteDestructorVariant(Loc, Dtor);
+ }
+ }
- if (LangOpts.OpenMP) {
- markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse);
- if (LangOpts.OpenMPIsDevice)
- checkOpenMPDeviceFunction(Loc, Func);
- else
- checkOpenMPHostFunction(Loc, Func);
+ Func->markUsed(Context);
}
}
@@ -16022,6 +17063,10 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
if (HasConst)
DeclRefType.addConst();
}
+ // Do not capture firstprivates in tasks.
+ if (S.isOpenMPPrivateDecl(Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel) !=
+ OMPC_unknown)
+ return true;
ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel,
RSI->OpenMPCaptureLevel);
}
@@ -16106,9 +17151,10 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
// Make sure that by-copy captures are of a complete and non-abstract type.
if (!Invalid && BuildAndDiagnose) {
if (!CaptureType->isDependentType() &&
- S.RequireCompleteType(Loc, CaptureType,
- diag::err_capture_of_incomplete_type,
- Var->getDeclName()))
+ S.RequireCompleteSizedType(
+ Loc, CaptureType,
+ diag::err_capture_of_incomplete_or_sizeless_type,
+ Var->getDeclName()))
Invalid = true;
else if (S.RequireNonAbstractType(Loc, CaptureType,
diag::err_capture_of_abstract_type))
@@ -16250,12 +17296,14 @@ bool Sema::tryCaptureVariable(
// just break here. Similarly, global variables that are captured in a
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
- bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel);
+ OpenMPClauseKind IsOpenMPPrivateDecl = isOpenMPPrivateDecl(
+ Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
// If the variable is private (i.e. not captured) and has variably
// modified type, we still need to capture the type for correct
// codegen in all regions, associated with the construct. Currently,
// it is captured in the innermost captured region only.
- if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) {
+ if (IsOpenMPPrivateDecl != OMPC_unknown &&
+ Var->getType()->isVariablyModifiedType()) {
QualType QTy = Var->getType();
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
QTy = PVD->getOriginalType();
@@ -16269,15 +17317,23 @@ bool Sema::tryCaptureVariable(
captureVariablyModifiedType(Context, QTy, OuterRSI);
}
}
- bool IsTargetCap = !IsOpenMPPrivateDecl &&
- isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
+ bool IsTargetCap =
+ IsOpenMPPrivateDecl != OMPC_private &&
+ isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
+ // Do not capture global if it is not privatized in outer regions.
+ bool IsGlobalCap =
+ IsGlobal && isOpenMPGlobalCapturedDecl(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
+
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
// enclosing region. Therefore, the capture is not initially nested.
if (IsTargetCap)
adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel);
- if (IsTargetCap || IsOpenMPPrivateDecl) {
+ if (IsTargetCap || IsOpenMPPrivateDecl == OMPC_private ||
+ (IsGlobal && !IsGlobalCap)) {
Nested = !IsTargetCap;
DeclRefType = DeclRefType.getUnqualifiedType();
CaptureType = Context.getLValueReferenceType(DeclRefType);
@@ -16493,7 +17549,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// Mark that this expression does not constitute an odr-use.
auto MarkNotOdrUsed = [&] {
- S.MaybeODRUseExprs.erase(E);
+ S.MaybeODRUseExprs.remove(E);
if (LambdaScopeInfo *LSI = S.getCurLambda())
LSI->markVariableExprAsNonODRUsed(E);
};
@@ -17025,6 +18081,11 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
if (Method->isVirtual() &&
!Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext))
OdrUse = false;
+
+ if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
+ if (!isConstantEvaluated() && FD->isConsteval() &&
+ !RebuildingImmediateInvocation)
+ ExprEvalContexts.back().ReferenceToConsteval.insert(E);
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
@@ -17116,71 +18177,36 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) {
}
namespace {
- /// Helper class that marks all of the declarations referenced by
- /// potentially-evaluated subexpressions as "referenced".
- class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> {
- Sema &S;
- bool SkipLocalVariables;
-
- public:
- typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited;
-
- EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
- : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { }
-
- void VisitDeclRefExpr(DeclRefExpr *E) {
- // If we were asked not to visit local variables, don't.
- if (SkipLocalVariables) {
- if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
- if (VD->hasLocalStorage())
- return;
- }
-
- S.MarkDeclRefReferenced(E);
- }
-
- void VisitMemberExpr(MemberExpr *E) {
- S.MarkMemberReferenced(E);
- Inherited::VisitMemberExpr(E);
- }
-
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
- S.MarkFunctionReferenced(
- E->getBeginLoc(),
- const_cast<CXXDestructorDecl *>(E->getTemporary()->getDestructor()));
- Visit(E->getSubExpr());
- }
-
- void VisitCXXNewExpr(CXXNewExpr *E) {
- if (E->getOperatorNew())
- S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew());
- if (E->getOperatorDelete())
- S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete());
- Inherited::VisitCXXNewExpr(E);
- }
+/// Helper class that marks all of the declarations referenced by
+/// potentially-evaluated subexpressions as "referenced".
+class EvaluatedExprMarker : public UsedDeclVisitor<EvaluatedExprMarker> {
+public:
+ typedef UsedDeclVisitor<EvaluatedExprMarker> Inherited;
+ bool SkipLocalVariables;
- void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
- if (E->getOperatorDelete())
- S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete());
- QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
- if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
- S.MarkFunctionReferenced(E->getBeginLoc(), S.LookupDestructor(Record));
- }
+ EvaluatedExprMarker(Sema &S, bool SkipLocalVariables)
+ : Inherited(S), SkipLocalVariables(SkipLocalVariables) {}
- Inherited::VisitCXXDeleteExpr(E);
- }
+ void visitUsedDecl(SourceLocation Loc, Decl *D) {
+ S.MarkFunctionReferenced(Loc, cast<FunctionDecl>(D));
+ }
- void VisitCXXConstructExpr(CXXConstructExpr *E) {
- S.MarkFunctionReferenced(E->getBeginLoc(), E->getConstructor());
- Inherited::VisitCXXConstructExpr(E);
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ // If we were asked not to visit local variables, don't.
+ if (SkipLocalVariables) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (VD->hasLocalStorage())
+ return;
}
+ S.MarkDeclRefReferenced(E);
+ }
- void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
- Visit(E->getExpr());
- }
- };
-}
+ void VisitMemberExpr(MemberExpr *E) {
+ S.MarkMemberReferenced(E);
+ Visit(E->getBase());
+ }
+};
+} // namespace
/// Mark any declarations that appear within this expression or any
/// potentially-evaluated subexpressions as "referenced".
@@ -18060,11 +19086,25 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
return ExprError();
}
+ case BuiltinType::IncompleteMatrixIdx:
+ Diag(cast<MatrixSubscriptExpr>(E->IgnoreParens())
+ ->getRowIdx()
+ ->getBeginLoc(),
+ diag::err_matrix_incomplete_index);
+ return ExprError();
+
// Expressions of unknown type.
case BuiltinType::OMPArraySection:
Diag(E->getBeginLoc(), diag::err_omp_array_section_use);
return ExprError();
+ // Expressions of unknown type.
+ case BuiltinType::OMPArrayShaping:
+ return ExprError(Diag(E->getBeginLoc(), diag::err_omp_array_shaping_use));
+
+ case BuiltinType::OMPIterator:
+ return ExprError(Diag(E->getBeginLoc(), diag::err_omp_iterator_use));
+
// Everything else should be impossible.
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
@@ -18138,7 +19178,16 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
}
-bool Sema::IsDependentFunctionNameExpr(Expr *E) {
- assert(E->isTypeDependent());
- return isa<UnresolvedLookupExpr>(E);
+ExprResult Sema::CreateRecoveryExpr(SourceLocation Begin, SourceLocation End,
+ ArrayRef<Expr *> SubExprs, QualType T) {
+ if (!Context.getLangOpts().RecoveryAST)
+ return ExprError();
+
+ if (isSFINAEContext())
+ return ExprError();
+
+ if (T.isNull() || !Context.getLangOpts().RecoveryASTType)
+ // We don't know the concrete type, fallback to dependent type.
+ T = Context.DependentTy;
+ return RecoveryExpr::Create(Context, T, Begin, End, SubExprs);
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index a73e6906fceb..d885920b6c14 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -11,6 +11,7 @@
///
//===----------------------------------------------------------------------===//
+#include "clang/Sema/Template.h"
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "TypeLocBuilder.h"
@@ -155,196 +156,203 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// }
//
// See also PR6358 and PR6359.
- // For this reason, we're currently only doing the C++03 version of this
- // code; the C++0x version has to wait until we get a proper spec.
- QualType SearchType;
- DeclContext *LookupCtx = nullptr;
- bool isDependent = false;
- bool LookInScope = false;
+ //
+ // For now, we accept all the cases in which the name given could plausibly
+ // be interpreted as a correct destructor name, issuing off-by-default
+ // extension diagnostics on the cases that don't strictly conform to the
+ // C++20 rules. This basically means we always consider looking in the
+ // nested-name-specifier prefix, the complete nested-name-specifier, and
+ // the scope, and accept if we find the expected type in any of the three
+ // places.
if (SS.isInvalid())
return nullptr;
+ // Whether we've failed with a diagnostic already.
+ bool Failed = false;
+
+ llvm::SmallVector<NamedDecl*, 8> FoundDecls;
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 8> FoundDeclSet;
+
// If we have an object type, it's because we are in a
// pseudo-destructor-expression or a member access expression, and
// we know what type we're looking for.
- if (ObjectTypePtr)
- SearchType = GetTypeFromParser(ObjectTypePtr);
+ QualType SearchType =
+ ObjectTypePtr ? GetTypeFromParser(ObjectTypePtr) : QualType();
- if (SS.isSet()) {
- NestedNameSpecifier *NNS = SS.getScopeRep();
-
- bool AlreadySearched = false;
- bool LookAtPrefix = true;
- // C++11 [basic.lookup.qual]p6:
- // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
- // the type-names are looked up as types in the scope designated by the
- // nested-name-specifier. Similarly, in a qualified-id of the form:
- //
- // nested-name-specifier[opt] class-name :: ~ class-name
- //
- // the second class-name is looked up in the same scope as the first.
- //
- // Here, we determine whether the code below is permitted to look at the
- // prefix of the nested-name-specifier.
- DeclContext *DC = computeDeclContext(SS, EnteringContext);
- if (DC && DC->isFileContext()) {
- AlreadySearched = true;
- LookupCtx = DC;
- isDependent = false;
- } else if (DC && isa<CXXRecordDecl>(DC)) {
- LookAtPrefix = false;
- LookInScope = true;
- }
-
- // The second case from the C++03 rules quoted further above.
- NestedNameSpecifier *Prefix = nullptr;
- if (AlreadySearched) {
- // Nothing left to do.
- } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) {
- CXXScopeSpec PrefixSS;
- PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data()));
- LookupCtx = computeDeclContext(PrefixSS, EnteringContext);
- isDependent = isDependentScopeSpecifier(PrefixSS);
- } else if (ObjectTypePtr) {
- LookupCtx = computeDeclContext(SearchType);
- isDependent = SearchType->isDependentType();
- } else {
- LookupCtx = computeDeclContext(SS, EnteringContext);
- isDependent = LookupCtx && LookupCtx->isDependentContext();
- }
- } else if (ObjectTypePtr) {
- // C++ [basic.lookup.classref]p3:
- // If the unqualified-id is ~type-name, the type-name is looked up
- // in the context of the entire postfix-expression. If the type T
- // of the object expression is of a class type C, the type-name is
- // also looked up in the scope of class C. At least one of the
- // lookups shall find a name that refers to (possibly
- // cv-qualified) T.
- LookupCtx = computeDeclContext(SearchType);
- isDependent = SearchType->isDependentType();
- assert((isDependent || !SearchType->isIncompleteType()) &&
- "Caller should have completed object type");
-
- LookInScope = true;
- } else {
- // Perform lookup into the current scope (only).
- LookInScope = true;
- }
-
- TypeDecl *NonMatchingTypeDecl = nullptr;
- LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
- for (unsigned Step = 0; Step != 2; ++Step) {
- // Look for the name first in the computed lookup context (if we
- // have one) and, if that fails to find a match, in the scope (if
- // we're allowed to look there).
- Found.clear();
- if (Step == 0 && LookupCtx) {
- if (RequireCompleteDeclContext(SS, LookupCtx))
- return nullptr;
- LookupQualifiedName(Found, LookupCtx);
- } else if (Step == 1 && LookInScope && S) {
- LookupName(Found, S);
- } else {
- continue;
- }
+ auto CheckLookupResult = [&](LookupResult &Found) -> ParsedType {
+ auto IsAcceptableResult = [&](NamedDecl *D) -> bool {
+ auto *Type = dyn_cast<TypeDecl>(D->getUnderlyingDecl());
+ if (!Type)
+ return false;
- // FIXME: Should we be suppressing ambiguities here?
- if (Found.isAmbiguous())
- return nullptr;
+ if (SearchType.isNull() || SearchType->isDependentType())
+ return true;
- if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
QualType T = Context.getTypeDeclType(Type);
- MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
+ return Context.hasSameUnqualifiedType(T, SearchType);
+ };
- if (SearchType.isNull() || SearchType->isDependentType() ||
- Context.hasSameUnqualifiedType(T, SearchType)) {
- // We found our type!
+ unsigned NumAcceptableResults = 0;
+ for (NamedDecl *D : Found) {
+ if (IsAcceptableResult(D))
+ ++NumAcceptableResults;
+
+ // Don't list a class twice in the lookup failure diagnostic if it's
+ // found by both its injected-class-name and by the name in the enclosing
+ // scope.
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ if (RD->isInjectedClassName())
+ D = cast<NamedDecl>(RD->getParent());
+
+ if (FoundDeclSet.insert(D).second)
+ FoundDecls.push_back(D);
+ }
+
+ // As an extension, attempt to "fix" an ambiguity by erasing all non-type
+ // results, and all non-matching results if we have a search type. It's not
+ // clear what the right behavior is if destructor lookup hits an ambiguity,
+ // but other compilers do generally accept at least some kinds of
+ // ambiguity.
+ if (Found.isAmbiguous() && NumAcceptableResults == 1) {
+ Diag(NameLoc, diag::ext_dtor_name_ambiguous);
+ LookupResult::Filter F = Found.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
+ Diag(D->getLocation(), diag::note_destructor_type_here)
+ << Context.getTypeDeclType(TD);
+ else
+ Diag(D->getLocation(), diag::note_destructor_nontype_here);
+
+ if (!IsAcceptableResult(D))
+ F.erase();
+ }
+ F.done();
+ }
+
+ if (Found.isAmbiguous())
+ Failed = true;
+ if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
+ if (IsAcceptableResult(Type)) {
+ QualType T = Context.getTypeDeclType(Type);
+ MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
return CreateParsedType(T,
Context.getTrivialTypeSourceInfo(T, NameLoc));
}
+ }
- if (!SearchType.isNull())
- NonMatchingTypeDecl = Type;
- }
-
- // If the name that we found is a class template name, and it is
- // the same name as the template name in the last part of the
- // nested-name-specifier (if present) or the object type, then
- // this is the destructor for that class.
- // FIXME: This is a workaround until we get real drafting for core
- // issue 399, for which there isn't even an obvious direction.
- if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) {
- QualType MemberOfType;
- if (SS.isSet()) {
- if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) {
- // Figure out the type of the context, if it has one.
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx))
- MemberOfType = Context.getTypeDeclType(Record);
- }
- }
- if (MemberOfType.isNull())
- MemberOfType = SearchType;
+ return nullptr;
+ };
- if (MemberOfType.isNull())
- continue;
+ bool IsDependent = false;
- // We're referring into a class template specialization. If the
- // class template we found is the same as the template being
- // specialized, we found what we are looking for.
- if (const RecordType *Record = MemberOfType->getAs<RecordType>()) {
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
- if (Spec->getSpecializedTemplate()->getCanonicalDecl() ==
- Template->getCanonicalDecl())
- return CreateParsedType(
- MemberOfType,
- Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
- }
+ auto LookupInObjectType = [&]() -> ParsedType {
+ if (Failed || SearchType.isNull())
+ return nullptr;
- continue;
- }
+ IsDependent |= SearchType->isDependentType();
- // We're referring to an unresolved class template
- // specialization. Determine whether we class template we found
- // is the same as the template being specialized or, if we don't
- // know which template is being specialized, that it at least
- // has the same name.
- if (const TemplateSpecializationType *SpecType
- = MemberOfType->getAs<TemplateSpecializationType>()) {
- TemplateName SpecName = SpecType->getTemplateName();
-
- // The class template we found is the same template being
- // specialized.
- if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) {
- if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl())
- return CreateParsedType(
- MemberOfType,
- Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
+ LookupResult Found(*this, &II, NameLoc, LookupDestructorName);
+ DeclContext *LookupCtx = computeDeclContext(SearchType);
+ if (!LookupCtx)
+ return nullptr;
+ LookupQualifiedName(Found, LookupCtx);
+ return CheckLookupResult(Found);
+ };
- continue;
- }
+ auto LookupInNestedNameSpec = [&](CXXScopeSpec &LookupSS) -> ParsedType {
+ if (Failed)
+ return nullptr;
- // The class template we found has the same name as the
- // (dependent) template name being specialized.
- if (DependentTemplateName *DepTemplate
- = SpecName.getAsDependentTemplateName()) {
- if (DepTemplate->isIdentifier() &&
- DepTemplate->getIdentifier() == Template->getIdentifier())
- return CreateParsedType(
- MemberOfType,
- Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
+ IsDependent |= isDependentScopeSpecifier(LookupSS);
+ DeclContext *LookupCtx = computeDeclContext(LookupSS, EnteringContext);
+ if (!LookupCtx)
+ return nullptr;
- continue;
- }
- }
+ LookupResult Found(*this, &II, NameLoc, LookupDestructorName);
+ if (RequireCompleteDeclContext(LookupSS, LookupCtx)) {
+ Failed = true;
+ return nullptr;
}
+ LookupQualifiedName(Found, LookupCtx);
+ return CheckLookupResult(Found);
+ };
+
+ auto LookupInScope = [&]() -> ParsedType {
+ if (Failed || !S)
+ return nullptr;
+
+ LookupResult Found(*this, &II, NameLoc, LookupDestructorName);
+ LookupName(Found, S);
+ return CheckLookupResult(Found);
+ };
+
+ // C++2a [basic.lookup.qual]p6:
+ // In a qualified-id of the form
+ //
+ // nested-name-specifier[opt] type-name :: ~ type-name
+ //
+ // the second type-name is looked up in the same scope as the first.
+ //
+ // We interpret this as meaning that if you do a dual-scope lookup for the
+ // first name, you also do a dual-scope lookup for the second name, per
+ // C++ [basic.lookup.classref]p4:
+ //
+ // If the id-expression in a class member access is a qualified-id of the
+ // form
+ //
+ // class-name-or-namespace-name :: ...
+ //
+ // the class-name-or-namespace-name following the . or -> is first looked
+ // up in the class of the object expression and the name, if found, is used.
+ // Otherwise, it is looked up in the context of the entire
+ // postfix-expression.
+ //
+ // This looks in the same scopes as for an unqualified destructor name:
+ //
+ // C++ [basic.lookup.classref]p3:
+ // If the unqualified-id is ~ type-name, the type-name is looked up
+ // in the context of the entire postfix-expression. If the type T
+ // of the object expression is of a class type C, the type-name is
+ // also looked up in the scope of class C. At least one of the
+ // lookups shall find a name that refers to cv T.
+ //
+ // FIXME: The intent is unclear here. Should type-name::~type-name look in
+ // the scope anyway if it finds a non-matching name declared in the class?
+ // If both lookups succeed and find a dependent result, which result should
+ // we retain? (Same question for p->~type-name().)
+
+ if (NestedNameSpecifier *Prefix =
+ SS.isSet() ? SS.getScopeRep()->getPrefix() : nullptr) {
+ // This is
+ //
+ // nested-name-specifier type-name :: ~ type-name
+ //
+ // Look for the second type-name in the nested-name-specifier.
+ CXXScopeSpec PrefixSS;
+ PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data()));
+ if (ParsedType T = LookupInNestedNameSpec(PrefixSS))
+ return T;
+ } else {
+ // This is one of
+ //
+ // type-name :: ~ type-name
+ // ~ type-name
+ //
+ // Look in the scope and (if any) the object type.
+ if (ParsedType T = LookupInScope())
+ return T;
+ if (ParsedType T = LookupInObjectType())
+ return T;
}
- if (isDependent) {
- // We didn't find our type, but that's okay: it's dependent
- // anyway.
+ if (Failed)
+ return nullptr;
+
+ if (IsDependent) {
+ // We didn't find our type, but that's OK: it's dependent anyway.
// FIXME: What if we have no nested-name-specifier?
QualType T = CheckTypenameType(ETK_None, SourceLocation(),
@@ -353,26 +361,98 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
return ParsedType::make(T);
}
- if (NonMatchingTypeDecl) {
- QualType T = Context.getTypeDeclType(NonMatchingTypeDecl);
- Diag(NameLoc, diag::err_destructor_expr_type_mismatch)
- << T << SearchType;
- Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here)
- << T;
- } else if (ObjectTypePtr)
- Diag(NameLoc, diag::err_ident_in_dtor_not_a_type)
- << &II;
- else {
- SemaDiagnosticBuilder DtorDiag = Diag(NameLoc,
- diag::err_destructor_class_name);
- if (S) {
- const DeclContext *Ctx = S->getEntity();
- if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx))
- DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc),
- Class->getNameAsString());
+ // The remaining cases are all non-standard extensions imitating the behavior
+ // of various other compilers.
+ unsigned NumNonExtensionDecls = FoundDecls.size();
+
+ if (SS.isSet()) {
+ // For compatibility with older broken C++ rules and existing code,
+ //
+ // nested-name-specifier :: ~ type-name
+ //
+ // also looks for type-name within the nested-name-specifier.
+ if (ParsedType T = LookupInNestedNameSpec(SS)) {
+ Diag(SS.getEndLoc(), diag::ext_dtor_named_in_wrong_scope)
+ << SS.getRange()
+ << FixItHint::CreateInsertion(SS.getEndLoc(),
+ ("::" + II.getName()).str());
+ return T;
+ }
+
+ // For compatibility with other compilers and older versions of Clang,
+ //
+ // nested-name-specifier type-name :: ~ type-name
+ //
+ // also looks for type-name in the scope. Unfortunately, we can't
+ // reasonably apply this fallback for dependent nested-name-specifiers.
+ if (SS.getScopeRep()->getPrefix()) {
+ if (ParsedType T = LookupInScope()) {
+ Diag(SS.getEndLoc(), diag::ext_qualified_dtor_named_in_lexical_scope)
+ << FixItHint::CreateRemoval(SS.getRange());
+ Diag(FoundDecls.back()->getLocation(), diag::note_destructor_type_here)
+ << GetTypeFromParser(T);
+ return T;
+ }
}
}
+ // We didn't find anything matching; tell the user what we did find (if
+ // anything).
+
+ // Don't tell the user about declarations we shouldn't have found.
+ FoundDecls.resize(NumNonExtensionDecls);
+
+ // List types before non-types.
+ std::stable_sort(FoundDecls.begin(), FoundDecls.end(),
+ [](NamedDecl *A, NamedDecl *B) {
+ return isa<TypeDecl>(A->getUnderlyingDecl()) >
+ isa<TypeDecl>(B->getUnderlyingDecl());
+ });
+
+ // Suggest a fixit to properly name the destroyed type.
+ auto MakeFixItHint = [&]{
+ const CXXRecordDecl *Destroyed = nullptr;
+ // FIXME: If we have a scope specifier, suggest its last component?
+ if (!SearchType.isNull())
+ Destroyed = SearchType->getAsCXXRecordDecl();
+ else if (S)
+ Destroyed = dyn_cast_or_null<CXXRecordDecl>(S->getEntity());
+ if (Destroyed)
+ return FixItHint::CreateReplacement(SourceRange(NameLoc),
+ Destroyed->getNameAsString());
+ return FixItHint();
+ };
+
+ if (FoundDecls.empty()) {
+ // FIXME: Attempt typo-correction?
+ Diag(NameLoc, diag::err_undeclared_destructor_name)
+ << &II << MakeFixItHint();
+ } else if (!SearchType.isNull() && FoundDecls.size() == 1) {
+ if (auto *TD = dyn_cast<TypeDecl>(FoundDecls[0]->getUnderlyingDecl())) {
+ assert(!SearchType.isNull() &&
+ "should only reject a type result if we have a search type");
+ QualType T = Context.getTypeDeclType(TD);
+ Diag(NameLoc, diag::err_destructor_expr_type_mismatch)
+ << T << SearchType << MakeFixItHint();
+ } else {
+ Diag(NameLoc, diag::err_destructor_expr_nontype)
+ << &II << MakeFixItHint();
+ }
+ } else {
+ Diag(NameLoc, SearchType.isNull() ? diag::err_destructor_name_nontype
+ : diag::err_destructor_expr_mismatch)
+ << &II << SearchType << MakeFixItHint();
+ }
+
+ for (NamedDecl *FoundD : FoundDecls) {
+ if (auto *TD = dyn_cast<TypeDecl>(FoundD->getUnderlyingDecl()))
+ Diag(FoundD->getLocation(), diag::note_destructor_type_here)
+ << Context.getTypeDeclType(TD);
+ else
+ Diag(FoundD->getLocation(), diag::note_destructor_nontype_here)
+ << FoundD;
+ }
+
return nullptr;
}
@@ -624,11 +704,11 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT,
}
/// Build a Microsoft __uuidof expression with a type operand.
-ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
+ExprResult Sema::BuildCXXUuidof(QualType Type,
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
- StringRef UuidStr;
+ MSGuidDecl *Guid = nullptr;
if (!Operand->getType()->isDependentType()) {
llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs;
getUuidAttrOfType(*this, Operand->getType(), UuidAttrs);
@@ -636,22 +716,21 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
if (UuidAttrs.size() > 1)
return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
- UuidStr = UuidAttrs.back()->getGuid();
+ Guid = UuidAttrs.back()->getGuidDecl();
}
- return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr,
- SourceRange(TypeidLoc, RParenLoc));
+ return new (Context)
+ CXXUuidofExpr(Type, Operand, Guid, SourceRange(TypeidLoc, RParenLoc));
}
/// Build a Microsoft __uuidof expression with an expression operand.
-ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
- SourceLocation TypeidLoc,
- Expr *E,
- SourceLocation RParenLoc) {
- StringRef UuidStr;
+ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc,
+ Expr *E, SourceLocation RParenLoc) {
+ MSGuidDecl *Guid = nullptr;
if (!E->getType()->isDependentType()) {
if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- UuidStr = "00000000-0000-0000-0000-000000000000";
+ // A null pointer results in {00000000-0000-0000-0000-000000000000}.
+ Guid = Context.getMSGuidDecl(MSGuidDecl::Parts{});
} else {
llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs;
getUuidAttrOfType(*this, E->getType(), UuidAttrs);
@@ -659,29 +738,20 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
if (UuidAttrs.size() > 1)
return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
- UuidStr = UuidAttrs.back()->getGuid();
+ Guid = UuidAttrs.back()->getGuidDecl();
}
}
- return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr,
- SourceRange(TypeidLoc, RParenLoc));
+ return new (Context)
+ CXXUuidofExpr(Type, E, Guid, SourceRange(TypeidLoc, RParenLoc));
}
/// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression);
ExprResult
Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc,
bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
- // If MSVCGuidDecl has not been cached, do the lookup.
- if (!MSVCGuidDecl) {
- IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID");
- LookupResult R(*this, GuidII, SourceLocation(), LookupTagName);
- LookupQualifiedName(R, Context.getTranslationUnitDecl());
- MSVCGuidDecl = R.getAsSingle<RecordDecl>();
- if (!MSVCGuidDecl)
- return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof));
- }
-
- QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl);
+ QualType GuidType = Context.getMSGuidType();
+ GuidType.addConst();
if (isType) {
// The operand is a type; handle it as such.
@@ -876,6 +946,11 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
E->getSourceRange()))
return true;
+ if (!isPointer && Ty->isSizelessType()) {
+ Diag(ThrowLoc, diag::err_throw_sizeless) << Ty << E->getSourceRange();
+ return true;
+ }
+
if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy,
diag::err_throw_abstract_type, E))
return true;
@@ -1742,8 +1817,9 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const {
return false;
if (FD.isDefined())
return false;
- bool IsAligned = false;
- if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned)
+ Optional<unsigned> AlignmentParam;
+ if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) &&
+ AlignmentParam.hasValue())
return true;
return false;
}
@@ -2061,8 +2137,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SmallVector<Expr *, 8> AllPlaceArgs;
if (OperatorNew) {
- const FunctionProtoType *Proto =
- OperatorNew->getType()->getAs<FunctionProtoType>();
+ auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>();
VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction
: VariadicDoesNotApply;
@@ -2070,18 +2145,80 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// arguments. Skip the first parameter because we don't have a corresponding
// argument. Skip the second parameter too if we're passing in the
// alignment; we've already filled it in.
+ unsigned NumImplicitArgs = PassAlignment ? 2 : 1;
if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto,
- PassAlignment ? 2 : 1, PlacementArgs,
- AllPlaceArgs, CallType))
+ NumImplicitArgs, PlacementArgs, AllPlaceArgs,
+ CallType))
return ExprError();
if (!AllPlaceArgs.empty())
PlacementArgs = AllPlaceArgs;
- // FIXME: This is wrong: PlacementArgs misses out the first (size) argument.
- DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs);
-
- // FIXME: Missing call to CheckFunctionCall or equivalent
+ // We would like to perform some checking on the given `operator new` call,
+ // but the PlacementArgs does not contain the implicit arguments,
+ // namely allocation size and maybe allocation alignment,
+ // so we need to conjure them.
+
+ QualType SizeTy = Context.getSizeType();
+ unsigned SizeTyWidth = Context.getTypeSize(SizeTy);
+
+ llvm::APInt SingleEltSize(
+ SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity());
+
+ // How many bytes do we want to allocate here?
+ llvm::Optional<llvm::APInt> AllocationSize;
+ if (!ArraySize.hasValue() && !AllocType->isDependentType()) {
+ // For non-array operator new, we only want to allocate one element.
+ AllocationSize = SingleEltSize;
+ } else if (KnownArraySize.hasValue() && !AllocType->isDependentType()) {
+ // For array operator new, only deal with static array size case.
+ bool Overflow;
+ AllocationSize = llvm::APInt(SizeTyWidth, *KnownArraySize)
+ .umul_ov(SingleEltSize, Overflow);
+ (void)Overflow;
+ assert(
+ !Overflow &&
+ "Expected that all the overflows would have been handled already.");
+ }
+
+ IntegerLiteral AllocationSizeLiteral(
+ Context,
+ AllocationSize.getValueOr(llvm::APInt::getNullValue(SizeTyWidth)),
+ SizeTy, SourceLocation());
+ // Otherwise, if we failed to constant-fold the allocation size, we'll
+ // just give up and pass-in something opaque, that isn't a null pointer.
+ OpaqueValueExpr OpaqueAllocationSize(SourceLocation(), SizeTy, VK_RValue,
+ OK_Ordinary, /*SourceExpr=*/nullptr);
+
+ // Let's synthesize the alignment argument in case we will need it.
+ // Since we *really* want to allocate these on stack, this is slightly ugly
+ // because there might not be a `std::align_val_t` type.
+ EnumDecl *StdAlignValT = getStdAlignValT();
+ QualType AlignValT =
+ StdAlignValT ? Context.getTypeDeclType(StdAlignValT) : SizeTy;
+ IntegerLiteral AlignmentLiteral(
+ Context,
+ llvm::APInt(Context.getTypeSize(SizeTy),
+ Alignment / Context.getCharWidth()),
+ SizeTy, SourceLocation());
+ ImplicitCastExpr DesiredAlignment(ImplicitCastExpr::OnStack, AlignValT,
+ CK_IntegralCast, &AlignmentLiteral,
+ VK_RValue);
+
+ // Adjust placement args by prepending conjured size and alignment exprs.
+ llvm::SmallVector<Expr *, 8> CallArgs;
+ CallArgs.reserve(NumImplicitArgs + PlacementArgs.size());
+ CallArgs.emplace_back(AllocationSize.hasValue()
+ ? static_cast<Expr *>(&AllocationSizeLiteral)
+ : &OpaqueAllocationSize);
+ if (PassAlignment)
+ CallArgs.emplace_back(&DesiredAlignment);
+ CallArgs.insert(CallArgs.end(), PlacementArgs.begin(), PlacementArgs.end());
+
+ DiagnoseSentinelCalls(OperatorNew, PlacementLParen, CallArgs);
+
+ checkCall(OperatorNew, Proto, /*ThisArg=*/nullptr, CallArgs,
+ /*IsMemberFunction=*/false, StartLoc, Range, CallType);
// Warn if the type is over-aligned and is being allocated by (unaligned)
// global operator new.
@@ -2193,7 +2330,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
return Diag(Loc, diag::err_bad_new_type)
<< AllocType << 1 << R;
else if (!AllocType->isDependentType() &&
- RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R))
+ RequireCompleteSizedType(
+ Loc, AllocType, diag::err_new_incomplete_or_sizeless_type, R))
return true;
else if (RequireNonAbstractType(Loc, AllocType,
diag::err_allocation_of_abstract_type))
@@ -2515,8 +2653,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// for template argument deduction and for comparison purposes.
QualType ExpectedFunctionType;
{
- const FunctionProtoType *Proto
- = OperatorNew->getType()->getAs<FunctionProtoType>();
+ auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>();
SmallVector<QualType, 4> ArgTypes;
ArgTypes.push_back(Context.VoidPtrTy);
@@ -2835,6 +2972,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->setParams(ParamDecls);
if (ExtraAttr)
Alloc->addAttr(ExtraAttr);
+ AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(Alloc);
Context.getTranslationUnitDecl()->addDecl(Alloc);
IdResolver.tryAddTopLevelDecl(Alloc, Name);
};
@@ -3319,7 +3457,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// this, so we treat it as a warning unless we're in a SFINAE context.
Diag(StartLoc, diag::ext_delete_void_ptr_operand)
<< Type << Ex.get()->getSourceRange();
- } else if (Pointee->isFunctionType() || Pointee->isVoidType()) {
+ } else if (Pointee->isFunctionType() || Pointee->isVoidType() ||
+ Pointee->isSizelessType()) {
return ExprError(Diag(StartLoc, diag::err_delete_operand)
<< Type << Ex.get()->getSourceRange());
} else if (!Pointee->isDependentType()) {
@@ -3865,15 +4004,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(),
PDiag(diag::err_typecheck_ambiguous_condition)
<< From->getSourceRange());
- return ExprError();
+ return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
llvm_unreachable("Cannot perform an ellipsis conversion");
case ImplicitConversionSequence::BadConversion:
- bool Diagnosed =
- DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType,
- From->getType(), From, Action);
+ Sema::AssignConvertType ConvTy =
+ CheckAssignmentConstraints(From->getExprLoc(), ToType, From->getType());
+ bool Diagnosed = DiagnoseAssignmentResult(
+ ConvTy == Compatible ? Incompatible : ConvTy, From->getExprLoc(),
+ ToType, From->getType(), From, Action);
assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed;
return ExprError();
}
@@ -4062,8 +4203,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
case ICK_Compatible_Conversion:
- From = ImpCastExprToType(From, ToType, CK_NoOp,
- VK_RValue, /*BasePath=*/nullptr, CCK).get();
+ From = ImpCastExprToType(From, ToType, CK_NoOp, From->getValueKind(),
+ /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Writeback_Conversion:
@@ -4213,9 +4354,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// Case 2. _Complex x -> y
} else {
- const ComplexType *FromComplex = From->getType()->getAs<ComplexType>();
- assert(FromComplex);
-
+ auto *FromComplex = From->getType()->castAs<ComplexType>();
QualType ElType = FromComplex->getElementType();
bool isFloatingComplex = ElType->isRealFloatingType();
@@ -4302,11 +4441,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
case ICK_Qualification: {
- // The qualification keeps the category of the inner expression, unless the
- // target type isn't a reference.
- ExprValueKind VK =
- ToType->isReferenceType() ? From->getValueKind() : VK_RValue;
-
+ ExprValueKind VK = From->getValueKind();
CastKind CK = CK_NoOp;
if (ToType->isReferenceType() &&
@@ -4348,6 +4483,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
VK_RValue, nullptr, CCK).get();
}
+ // Materialize a temporary if we're implicitly converting to a reference
+ // type. This is not required by the C++ rules but is necessary to maintain
+ // AST invariants.
+ if (ToType->isReferenceType() && From->isRValue()) {
+ ExprResult Res = TemporaryMaterializationConversion(From);
+ if (Res.isInvalid())
+ return ExprError();
+ From = Res.get();
+ }
+
// If this conversion sequence succeeded and involved implicitly converting a
// _Nullable type to a _Nonnull one, complain.
if (!isCast(CCK))
@@ -4504,8 +4649,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
if((Operator->*IsDesiredOp)()) {
FoundOperator = true;
- const FunctionProtoType *CPT =
- Operator->getType()->getAs<FunctionProtoType>();
+ auto *CPT = Operator->getType()->castAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT || !CPT->isNothrow())
return false;
@@ -4534,7 +4678,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
case UTT_IsArray:
return T->isArrayType();
case UTT_IsPointer:
- return T->isPointerType();
+ return T->isAnyPointerType();
case UTT_IsLvalueReference:
return T->isLValueReferenceType();
case UTT_IsRvalueReference:
@@ -4754,8 +4898,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public)
return false;
if (UTT == UTT_IsNothrowDestructible) {
- const FunctionProtoType *CPT =
- Destructor->getType()->getAs<FunctionProtoType>();
+ auto *CPT = Destructor->getType()->castAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT || !CPT->isNothrow())
return false;
@@ -4843,8 +4986,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
if (Constructor->isCopyConstructor(FoundTQs)) {
FoundConstructor = true;
- const FunctionProtoType *CPT
- = Constructor->getType()->getAs<FunctionProtoType>();
+ auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
@@ -4882,8 +5024,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl());
if (Constructor->isDefaultConstructor()) {
FoundConstructor = true;
- const FunctionProtoType *CPT
- = Constructor->getType()->getAs<FunctionProtoType>();
+ auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
@@ -4976,20 +5117,19 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (RD && RD->isAbstract())
return false;
- SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
+ llvm::BumpPtrAllocator OpaqueExprAllocator;
SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
for (unsigned I = 1, N = Args.size(); I != N; ++I) {
QualType ArgTy = Args[I]->getType();
if (ArgTy->isObjectType() || ArgTy->isFunctionType())
ArgTy = S.Context.getRValueReferenceType(ArgTy);
- OpaqueArgExprs.push_back(
- OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
- ArgTy.getNonLValueExprType(S.Context),
- Expr::getValueKindForType(ArgTy)));
+ ArgExprs.push_back(
+ new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+ OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(),
+ ArgTy.getNonLValueExprType(S.Context),
+ Expr::getValueKindForType(ArgTy)));
}
- for (Expr &E : OpaqueArgExprs)
- ArgExprs.push_back(&E);
// Perform the initialization in an unevaluated context within a SFINAE
// trap at translation unit scope.
@@ -5539,7 +5679,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
// C++2a allows functions with ref-qualifier & if their cv-qualifier-seq
// is (exactly) 'const'.
if (Proto->isConst() && !Proto->isVolatile())
- Diag(Loc, getLangOpts().CPlusPlus2a
+ Diag(Loc, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue
: diag::ext_pointer_to_const_ref_member_on_rvalue);
else
@@ -5768,7 +5908,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
QualType CondType = Cond.get()->getType();
- const auto *CondVT = CondType->getAs<VectorType>();
+ const auto *CondVT = CondType->castAs<VectorType>();
QualType CondElementTy = CondVT->getElementType();
unsigned CondElementCount = CondVT->getNumElements();
QualType LHSType = LHS.get()->getType();
@@ -5824,7 +5964,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
return {};
}
ResultType = Context.getVectorType(
- ResultElementTy, CondType->getAs<VectorType>()->getNumElements(),
+ ResultElementTy, CondType->castAs<VectorType>()->getNumElements(),
VectorType::GenericVector);
LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
@@ -5833,9 +5973,9 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
assert(!ResultType.isNull() && ResultType->isVectorType() &&
"Result should have been a vector type");
- QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType();
- unsigned ResultElementCount =
- ResultType->getAs<VectorType>()->getNumElements();
+ auto *ResultVectorTy = ResultType->castAs<VectorType>();
+ QualType ResultElementTy = ResultVectorTy->getElementType();
+ unsigned ResultElementCount = ResultVectorTy->getNumElements();
if (ResultElementCount != CondElementCount) {
Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType
@@ -6632,8 +6772,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>())
T = MemPtr->getPointeeType();
- const FunctionType *FTy = T->getAs<FunctionType>();
- assert(FTy && "call to value not of function type?");
+ auto *FTy = T->castAs<FunctionType>();
ReturnsRetained = FTy->getExtInfo().getProducesResult();
// ActOnStmtExpr arranges things so that StmtExprs of retainable
@@ -6697,6 +6836,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
VK_RValue);
}
+ if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+ Cleanup.setExprNeedsCleanups(true);
+
if (!getLangOpts().CPlusPlus)
return E;
@@ -6799,8 +6941,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
// a new AsmStmtWithTemporaries.
CompoundStmt *CompStmt = CompoundStmt::Create(
Context, SubStmt, SourceLocation(), SourceLocation());
- Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
- SourceLocation());
+ Expr *E = new (Context)
+ StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(),
+ /*FIXME TemplateDepth=*/0);
return MaybeCreateExprWithCleanups(E);
}
@@ -6843,9 +6986,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return ExprError();
if (RHS.get() == BO->getRHS())
return E;
- return new (Context) BinaryOperator(
- BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
- BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures());
+ return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma,
+ BO->getType(), BO->getValueKind(),
+ BO->getObjectKind(), BO->getOperatorLoc(),
+ BO->getFPFeatures(getLangOpts()));
}
}
@@ -7317,7 +7461,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(S,
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -7370,7 +7514,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(S,
- TemplateId->SS,
+ SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
TemplateId->Name,
@@ -7447,13 +7591,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
// a difference in ARC, but outside of ARC the resulting block literal
// follows the normal lifetime rules for block literals instead of being
// autoreleased.
- DiagnosticErrorTrap Trap(Diags);
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult BlockExp = BuildBlockForLambdaConversion(
Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get());
PopExpressionEvaluationContext();
+ // FIXME: This note should be produced by a CodeSynthesisContext.
if (BlockExp.isInvalid())
Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv);
return BlockExp;
@@ -7512,61 +7656,6 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen);
}
-static bool IsSpecialDiscardedValue(Expr *E) {
- // In C++11, discarded-value expressions of a certain form are special,
- // according to [expr]p10:
- // The lvalue-to-rvalue conversion (4.1) is applied only if the
- // expression is an lvalue of volatile-qualified type and it has
- // one of the following forms:
- E = E->IgnoreParens();
-
- // - id-expression (5.1.1),
- if (isa<DeclRefExpr>(E))
- return true;
-
- // - subscripting (5.2.1),
- if (isa<ArraySubscriptExpr>(E))
- return true;
-
- // - class member access (5.2.5),
- if (isa<MemberExpr>(E))
- return true;
-
- // - indirection (5.3.1),
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
- if (UO->getOpcode() == UO_Deref)
- return true;
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
- // - pointer-to-member operation (5.5),
- if (BO->isPtrMemOp())
- return true;
-
- // - comma expression (5.18) where the right operand is one of the above.
- if (BO->getOpcode() == BO_Comma)
- return IsSpecialDiscardedValue(BO->getRHS());
- }
-
- // - conditional expression (5.16) where both the second and the third
- // operands are one of the above, or
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
- return IsSpecialDiscardedValue(CO->getTrueExpr()) &&
- IsSpecialDiscardedValue(CO->getFalseExpr());
- // The related edge case of "*x ?: *x".
- if (BinaryConditionalOperator *BCO =
- dyn_cast<BinaryConditionalOperator>(E)) {
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(BCO->getTrueExpr()))
- return IsSpecialDiscardedValue(OVE->getSourceExpr()) &&
- IsSpecialDiscardedValue(BCO->getFalseExpr());
- }
-
- // Objective-C++ extensions to the rule.
- if (isa<PseudoObjectExpr>(E) || isa<ObjCIvarRefExpr>(E))
- return true;
-
- return false;
-}
-
/// Perform the conversions required for an expression used in a
/// context that ignores the result.
ExprResult Sema::IgnoredValueConversions(Expr *E) {
@@ -7591,23 +7680,20 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return E;
}
- if (getLangOpts().CPlusPlus) {
+ if (getLangOpts().CPlusPlus) {
// The C++11 standard defines the notion of a discarded-value expression;
// normally, we don't need to do anything to handle it, but if it is a
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
// conversion.
- if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
- E->getType().isVolatileQualified()) {
- if (IsSpecialDiscardedValue(E)) {
- ExprResult Res = DefaultLvalueConversion(E);
- if (Res.isInvalid())
- return E;
- E = Res.get();
- } else {
- // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
- // it occurs as a discarded-value expression.
- CheckUnusedVolatileAssignment(E);
- }
+ if (getLangOpts().CPlusPlus11 && E->isReadIfDiscardedInCPlusPlus11()) {
+ ExprResult Res = DefaultLvalueConversion(E);
+ if (Res.isInvalid())
+ return E;
+ E = Res.get();
+ } else {
+ // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
+ // it occurs as a discarded-value expression.
+ CheckUnusedVolatileAssignment(E);
}
// C++1z:
@@ -8163,6 +8249,7 @@ public:
ExprResult
Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl,
+ bool RecoverUncorrectedTypos,
llvm::function_ref<ExprResult(Expr *)> Filter) {
// If the current evaluation context indicates there are uncorrected typos
// and the current expression isn't guaranteed to not have typos, try to
@@ -8175,6 +8262,16 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl,
TyposResolved -= DelayedTypos.size();
if (Result.isInvalid() || Result.get() != E) {
ExprEvalContexts.back().NumTypos -= TyposResolved;
+ if (Result.isInvalid() && RecoverUncorrectedTypos) {
+ struct TyposReplace : TreeTransform<TyposReplace> {
+ TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {}
+ ExprResult TransformTypoExpr(clang::TypoExpr *E) {
+ return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(),
+ E->getEndLoc(), {});
+ }
+ } TT(*this);
+ return TT.TransformExpr(E);
+ }
return Result;
}
assert(TyposResolved == 0 && "Corrected typo but got same Expr back?");
@@ -8213,7 +8310,8 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
DiagnoseUnusedExprResult(FullExpr.get());
}
- FullExpr = CorrectDelayedTyposInExpr(FullExpr.get());
+ FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr,
+ /*RecoverUncorrectedTypos=*/true);
if (FullExpr.isInvalid())
return ExprError();
@@ -8331,3 +8429,216 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc,
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
+
+concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) {
+ return BuildExprRequirement(E, /*IsSimple=*/true,
+ /*NoexceptLoc=*/SourceLocation(),
+ /*ReturnTypeRequirement=*/{});
+}
+
+concepts::Requirement *
+Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS,
+ SourceLocation NameLoc, IdentifierInfo *TypeName,
+ TemplateIdAnnotation *TemplateId) {
+ assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) &&
+ "Exactly one of TypeName and TemplateId must be specified.");
+ TypeSourceInfo *TSI = nullptr;
+ if (TypeName) {
+ QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc,
+ SS.getWithLocInContext(Context), *TypeName,
+ NameLoc, &TSI, /*DeducedTypeContext=*/false);
+ if (T.isNull())
+ return nullptr;
+ } else {
+ ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS,
+ TemplateId->TemplateKWLoc,
+ TemplateId->Template, TemplateId->Name,
+ TemplateId->TemplateNameLoc,
+ TemplateId->LAngleLoc, ArgsPtr,
+ TemplateId->RAngleLoc);
+ if (T.isInvalid())
+ return nullptr;
+ if (GetTypeFromParser(T.get(), &TSI).isNull())
+ return nullptr;
+ }
+ return BuildTypeRequirement(TSI);
+}
+
+concepts::Requirement *
+Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) {
+ return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc,
+ /*ReturnTypeRequirement=*/{});
+}
+
+concepts::Requirement *
+Sema::ActOnCompoundRequirement(
+ Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstraint, unsigned Depth) {
+ // C++2a [expr.prim.req.compound] p1.3.3
+ // [..] the expression is deduced against an invented function template
+ // F [...] F is a void function template with a single type template
+ // parameter T declared with the constrained-parameter. Form a new
+ // cv-qualifier-seq cv by taking the union of const and volatile specifiers
+ // around the constrained-parameter. F has a single parameter whose
+ // type-specifier is cv T followed by the abstract-declarator. [...]
+ //
+ // The cv part is done in the calling function - we get the concept with
+ // arguments and the abstract declarator with the correct CV qualification and
+ // have to synthesize T and the single parameter of F.
+ auto &II = Context.Idents.get("expr-type");
+ auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext,
+ SourceLocation(),
+ SourceLocation(), Depth,
+ /*Index=*/0, &II,
+ /*Typename=*/true,
+ /*ParameterPack=*/false,
+ /*HasTypeConstraint=*/true);
+
+ if (ActOnTypeConstraint(SS, TypeConstraint, TParam,
+ /*EllpsisLoc=*/SourceLocation()))
+ // Just produce a requirement with no type requirements.
+ return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {});
+
+ auto *TPL = TemplateParameterList::Create(Context, SourceLocation(),
+ SourceLocation(),
+ ArrayRef<NamedDecl *>(TParam),
+ SourceLocation(),
+ /*RequiresClause=*/nullptr);
+ return BuildExprRequirement(
+ E, /*IsSimple=*/false, NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement(TPL));
+}
+
+concepts::ExprRequirement *
+Sema::BuildExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) {
+ auto Status = concepts::ExprRequirement::SS_Satisfied;
+ ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr;
+ if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent())
+ Status = concepts::ExprRequirement::SS_Dependent;
+ else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can)
+ Status = concepts::ExprRequirement::SS_NoexceptNotMet;
+ else if (ReturnTypeRequirement.isSubstitutionFailure())
+ Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure;
+ else if (ReturnTypeRequirement.isTypeConstraint()) {
+ // C++2a [expr.prim.req]p1.3.3
+ // The immediately-declared constraint ([temp]) of decltype((E)) shall
+ // be satisfied.
+ TemplateParameterList *TPL =
+ ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
+ QualType MatchedType =
+ BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType();
+ llvm::SmallVector<TemplateArgument, 1> Args;
+ Args.push_back(TemplateArgument(MatchedType));
+ 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();
+ ExprResult Constraint = SubstExpr(IDC, MLTAL);
+ assert(!Constraint.isInvalid() &&
+ "Substitution cannot fail as it is simply putting a type template "
+ "argument into a concept specialization expression's parameter.");
+
+ SubstitutedConstraintExpr =
+ cast<ConceptSpecializationExpr>(Constraint.get());
+ if (!SubstitutedConstraintExpr->isSatisfied())
+ Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied;
+ }
+ return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc,
+ ReturnTypeRequirement, Status,
+ SubstitutedConstraintExpr);
+}
+
+concepts::ExprRequirement *
+Sema::BuildExprRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic,
+ bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) {
+ return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic,
+ IsSimple, NoexceptLoc,
+ ReturnTypeRequirement);
+}
+
+concepts::TypeRequirement *
+Sema::BuildTypeRequirement(TypeSourceInfo *Type) {
+ return new (Context) concepts::TypeRequirement(Type);
+}
+
+concepts::TypeRequirement *
+Sema::BuildTypeRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return new (Context) concepts::TypeRequirement(SubstDiag);
+}
+
+concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) {
+ return BuildNestedRequirement(Constraint);
+}
+
+concepts::NestedRequirement *
+Sema::BuildNestedRequirement(Expr *Constraint) {
+ ConstraintSatisfaction Satisfaction;
+ if (!Constraint->isInstantiationDependent() &&
+ CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{},
+ Constraint->getSourceRange(), Satisfaction))
+ return nullptr;
+ return new (Context) concepts::NestedRequirement(Context, Constraint,
+ Satisfaction);
+}
+
+concepts::NestedRequirement *
+Sema::BuildNestedRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return new (Context) concepts::NestedRequirement(SubstDiag);
+}
+
+RequiresExprBodyDecl *
+Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ Scope *BodyScope) {
+ assert(BodyScope);
+
+ RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext,
+ RequiresKWLoc);
+
+ PushDeclContext(BodyScope, Body);
+
+ for (ParmVarDecl *Param : LocalParameters) {
+ if (Param->hasDefaultArg())
+ // C++2a [expr.prim.req] p4
+ // [...] A local parameter of a requires-expression shall not have a
+ // default argument. [...]
+ Diag(Param->getDefaultArgRange().getBegin(),
+ diag::err_requires_expr_local_parameter_default_argument);
+ // Ignore default argument and move on
+
+ Param->setDeclContext(Body);
+ // If this has an identifier, add it to the scope stack.
+ if (Param->getIdentifier()) {
+ CheckShadow(BodyScope, Param);
+ PushOnScopeChains(Param, BodyScope);
+ }
+ }
+ return Body;
+}
+
+void Sema::ActOnFinishRequiresExpr() {
+ assert(CurContext && "DeclContext imbalance!");
+ CurContext = CurContext->getLexicalParent();
+ assert(CurContext && "Popped translation unit!");
+}
+
+ExprResult
+Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc) {
+ return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters,
+ Requirements, ClosingBraceLoc);
+}
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index c61b13cf5980..228a1ec3ba1f 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -894,6 +894,62 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ArrayWithObjectsMethod, SR));
}
+/// Check for duplicate keys in an ObjC dictionary literal. For instance:
+/// NSDictionary *nd = @{ @"foo" : @"bar", @"foo" : @"baz" };
+static void
+CheckObjCDictionaryLiteralDuplicateKeys(Sema &S,
+ ObjCDictionaryLiteral *Literal) {
+ if (Literal->isValueDependent() || Literal->isTypeDependent())
+ return;
+
+ // NSNumber has quite relaxed equality semantics (for instance, @YES is
+ // considered equal to @1.0). For now, ignore floating points and just do a
+ // bit-width and sign agnostic integer compare.
+ struct APSIntCompare {
+ bool operator()(const llvm::APSInt &LHS, const llvm::APSInt &RHS) const {
+ return llvm::APSInt::compareValues(LHS, RHS) < 0;
+ }
+ };
+
+ llvm::DenseMap<StringRef, SourceLocation> StringKeys;
+ std::map<llvm::APSInt, SourceLocation, APSIntCompare> IntegralKeys;
+
+ auto checkOneKey = [&](auto &Map, const auto &Key, SourceLocation Loc) {
+ auto Pair = Map.insert({Key, Loc});
+ if (!Pair.second) {
+ S.Diag(Loc, diag::warn_nsdictionary_duplicate_key);
+ S.Diag(Pair.first->second, diag::note_nsdictionary_duplicate_key_here);
+ }
+ };
+
+ for (unsigned Idx = 0, End = Literal->getNumElements(); Idx != End; ++Idx) {
+ Expr *Key = Literal->getKeyValueElement(Idx).Key->IgnoreParenImpCasts();
+
+ if (auto *StrLit = dyn_cast<ObjCStringLiteral>(Key)) {
+ StringRef Bytes = StrLit->getString()->getBytes();
+ SourceLocation Loc = StrLit->getExprLoc();
+ checkOneKey(StringKeys, Bytes, Loc);
+ }
+
+ if (auto *BE = dyn_cast<ObjCBoxedExpr>(Key)) {
+ Expr *Boxed = BE->getSubExpr();
+ SourceLocation Loc = BE->getExprLoc();
+
+ // Check for @("foo").
+ if (auto *Str = dyn_cast<StringLiteral>(Boxed->IgnoreParenImpCasts())) {
+ checkOneKey(StringKeys, Str->getBytes(), Loc);
+ continue;
+ }
+
+ Expr::EvalResult Result;
+ if (Boxed->EvaluateAsInt(Result, S.getASTContext(),
+ Expr::SE_AllowSideEffects)) {
+ checkOneKey(IntegralKeys, Result.Val.getInt(), Loc);
+ }
+ }
+ }
+}
+
ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
MutableArrayRef<ObjCDictionaryElement> Elements) {
SourceLocation Loc = SR.getBegin();
@@ -1061,12 +1117,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
HasPackExpansions = true;
}
- QualType Ty
- = Context.getObjCObjectPointerType(
- Context.getObjCInterfaceType(NSDictionaryDecl));
- return MaybeBindToTemporary(ObjCDictionaryLiteral::Create(
- Context, Elements, HasPackExpansions, Ty,
- DictionaryWithObjectsMethod, SR));
+ QualType Ty = Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(NSDictionaryDecl));
+
+ auto *Literal =
+ ObjCDictionaryLiteral::Create(Context, Elements, HasPackExpansions, Ty,
+ DictionaryWithObjectsMethod, SR);
+ CheckObjCDictionaryLiteralDuplicateKeys(*this, Literal);
+ return MaybeBindToTemporary(Literal);
}
ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
@@ -1170,33 +1228,66 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
}
}
-static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
- Selector Sel,
- ObjCMethodList &MethList,
- bool &onlyDirect) {
+static ObjCMethodDecl *LookupDirectMethodInMethodList(Sema &S, Selector Sel,
+ ObjCMethodList &MethList,
+ bool &onlyDirect,
+ bool &anyDirect) {
+ (void)Sel;
ObjCMethodList *M = &MethList;
- for (M = M->getNext(); M; M = M->getNext()) {
+ ObjCMethodDecl *DirectMethod = nullptr;
+ for (; M; M = M->getNext()) {
ObjCMethodDecl *Method = M->getMethod();
- if (Method->getSelector() != Sel)
+ if (!Method)
continue;
- if (!Method->isDirectMethod())
+ assert(Method->getSelector() == Sel && "Method with wrong selector in method list");
+ if (Method->isDirectMethod()) {
+ anyDirect = true;
+ DirectMethod = Method;
+ } else
onlyDirect = false;
}
+
+ return DirectMethod;
}
-static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
- Selector Sel, bool &onlyDirect) {
- for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
- e = S.MethodPool.end(); b != e; b++) {
- // first, instance methods
- ObjCMethodList &InstMethList = b->second.first;
- HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList,
- onlyDirect);
+// Search the global pool for (potentially) direct methods matching the given
+// selector. If a non-direct method is found, set \param onlyDirect to false. If
+// a direct method is found, set \param anyDirect to true. Returns a direct
+// method, if any.
+static ObjCMethodDecl *LookupDirectMethodInGlobalPool(Sema &S, Selector Sel,
+ bool &onlyDirect,
+ bool &anyDirect) {
+ auto Iter = S.MethodPool.find(Sel);
+ if (Iter == S.MethodPool.end())
+ return nullptr;
- // second, class methods
- ObjCMethodList &ClsMethList = b->second.second;
- HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect);
- }
+ ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList(
+ S, Sel, Iter->second.first, onlyDirect, anyDirect);
+ ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList(
+ S, Sel, Iter->second.second, onlyDirect, anyDirect);
+
+ return DirectInstance ? DirectInstance : DirectClass;
+}
+
+static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) {
+ auto *CurMD = S.getCurMethodDecl();
+ if (!CurMD)
+ return nullptr;
+ ObjCInterfaceDecl *IFace = CurMD->getClassInterface();
+
+ // The language enforce that only one direct method is present in a given
+ // class, so we just need to find one method in the current class to know
+ // whether Sel is potentially direct in this context.
+ if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true))
+ return MD;
+ if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/true))
+ return MD;
+ if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false))
+ return MD;
+ if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/false))
+ return MD;
+
+ return nullptr;
}
ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
@@ -1222,15 +1313,38 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
} else {
- bool onlyDirect = Method->isDirectMethod();
- DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect);
DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
WarnMultipleSelectors);
+
+ bool onlyDirect = true;
+ bool anyDirect = false;
+ ObjCMethodDecl *GlobalDirectMethod =
+ LookupDirectMethodInGlobalPool(*this, Sel, onlyDirect, anyDirect);
+
if (onlyDirect) {
Diag(AtLoc, diag::err_direct_selector_expression)
<< Method->getSelector();
Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName();
+ } else if (anyDirect) {
+ // If we saw any direct methods, see if we see a direct member of the
+ // current class. If so, the @selector will likely be used to refer to
+ // this direct method.
+ ObjCMethodDecl *LikelyTargetMethod = findMethodInCurrentClass(*this, Sel);
+ if (LikelyTargetMethod && LikelyTargetMethod->isDirectMethod()) {
+ Diag(AtLoc, diag::warn_potentially_direct_selector_expression) << Sel;
+ Diag(LikelyTargetMethod->getLocation(),
+ diag::note_direct_method_declared_at)
+ << LikelyTargetMethod->getDeclName();
+ } else if (!LikelyTargetMethod) {
+ // Otherwise, emit the "strict" variant of this diagnostic, unless
+ // LikelyTargetMethod is non-direct.
+ Diag(AtLoc, diag::warn_strict_potentially_direct_selector_expression)
+ << Sel;
+ Diag(GlobalDirectMethod->getLocation(),
+ diag::note_direct_method_declared_at)
+ << GlobalDirectMethod->getDeclName();
+ }
}
}
@@ -1953,7 +2067,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
// Do not warn if user is using property-dot syntax to make call to
// user named setter.
- if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter))
+ if (!(PDecl->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_setter))
Diag(MemberLoc,
diag::warn_property_access_suggest)
<< MemberName << QualType(OPT, 0) << PDecl->getName()
@@ -2570,6 +2685,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
+ if (Method && Method->isDirectMethod() && SuperLoc.isValid()) {
+ Diag(SuperLoc, diag::err_messaging_super_with_direct_method)
+ << FixItHint::CreateReplacement(
+ SuperLoc, getLangOpts().ObjCAutoRefCount
+ ? "self"
+ : Method->getClassInterface()->getName());
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+
// Warn about explicit call of +initialize on its own class. But not on 'super'.
if (Method && Method->getMethodFamily() == OMF_initialize) {
if (!SuperLoc.isValid()) {
@@ -2774,9 +2899,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ReceiverType->isIntegerType())) {
// Implicitly convert integers and pointers to 'id' but emit a warning.
// But not in ARC.
- Diag(Loc, diag::warn_bad_receiver_type)
- << ReceiverType
- << Receiver->getSourceRange();
+ Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << RecRange;
if (ReceiverType->isPointerType()) {
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
CK_CPointerToObjCPointerCast).get();
@@ -2927,11 +3050,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// definition is found in a module that's not visible.
const ObjCInterfaceDecl *forwardClass = nullptr;
if (RequireCompleteType(Loc, OCIType->getPointeeType(),
- getLangOpts().ObjCAutoRefCount
- ? diag::err_arc_receiver_forward_instance
- : diag::warn_receiver_forward_instance,
- Receiver? Receiver->getSourceRange()
- : SourceRange(SuperLoc))) {
+ getLangOpts().ObjCAutoRefCount
+ ? diag::err_arc_receiver_forward_instance
+ : diag::warn_receiver_forward_instance,
+ RecRange)) {
if (getLangOpts().ObjCAutoRefCount)
return ExprError();
@@ -2993,8 +3115,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError();
} else {
// Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type)
- << ReceiverType << Receiver->getSourceRange();
+ Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << RecRange;
return ExprError();
}
}
@@ -3012,15 +3133,35 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
<< Method->getDeclName();
}
- if (ReceiverType->isObjCClassType() && !isImplicit) {
- Diag(Receiver->getExprLoc(),
- diag::err_messaging_class_with_direct_method);
+ // Under ARC, self can't be assigned, and doing a direct call to `self`
+ // when it's a Class is hence safe. For other cases, we can't trust `self`
+ // is what we think it is, so we reject it.
+ if (ReceiverType->isObjCClassType() && !isImplicit &&
+ !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) {
+ {
+ DiagnosticBuilder Builder =
+ Diag(Receiver->getExprLoc(),
+ diag::err_messaging_class_with_direct_method);
+ if (Receiver->isObjCSelfExpr()) {
+ Builder.AddFixItHint(FixItHint::CreateReplacement(
+ RecRange, Method->getClassInterface()->getName()));
+ }
+ }
Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName();
}
if (SuperLoc.isValid()) {
- Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
+ {
+ DiagnosticBuilder Builder =
+ Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
+ if (ReceiverType->isObjCClassType()) {
+ Builder.AddFixItHint(FixItHint::CreateReplacement(
+ SuperLoc, Method->getClassInterface()->getName()));
+ } else {
+ Builder.AddFixItHint(FixItHint::CreateReplacement(SuperLoc, "self"));
+ }
+ }
Diag(Method->getLocation(), diag::note_direct_method_declared_at)
<< Method->getDeclName();
}
@@ -3232,7 +3373,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!isImplicit && Method) {
if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) {
bool IsWeak =
- Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak;
+ Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak;
if (!IsWeak && Sel.isUnarySelector())
IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
if (IsWeak && !isUnevaluatedContext() &&
@@ -4337,7 +4478,7 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType,
// to 'NSString *', instead of falling through to report a "bridge cast"
// diagnostic.
if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
- ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose))
+ CheckConversionToObjCLiteral(castType, castExpr, Diagnose))
return ACR_error;
// Do not issue "bridge cast" diagnostic when implicit casting
@@ -4400,9 +4541,10 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
} else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) {
assert(uo->getOpcode() == UO_Extension);
Expr *sub = stripARCUnbridgedCast(uo->getSubExpr());
- return new (Context)
- UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(),
- sub->getObjectKind(), uo->getOperatorLoc(), false);
+ return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(),
+ sub->getValueKind(), sub->getObjectKind(),
+ uo->getOperatorLoc(), false,
+ CurFPFeatureOverrides());
} else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
assert(!gse->isResultDependent());
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 785637761e71..eb07de65d266 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
@@ -1092,7 +1093,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
auto *CXXRD = T->getAsCXXRecordDecl();
if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
- diag::warn_cxx2a_compat_aggregate_init_with_ctors)
+ diag::warn_cxx20_compat_aggregate_init_with_ctors)
<< StructuredSubobjectInitList->getSourceRange() << T;
}
}
@@ -1118,14 +1119,14 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Result:
// Extra braces here are suspicious.
- DiagID = diag::warn_braces_around_scalar_init;
+ DiagID = diag::warn_braces_around_init;
break;
case InitializedEntity::EK_Member:
// Warn on aggregate initialization but not on ctor init list or
// default member initializer.
if (Entity.getParent())
- DiagID = diag::warn_braces_around_scalar_init;
+ DiagID = diag::warn_braces_around_init;
break;
case InitializedEntity::EK_Variable:
@@ -1156,9 +1157,9 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
if (DiagID) {
S.Diag(Braces.getBegin(), DiagID)
- << Braces
- << FixItHint::CreateRemoval(Braces.getBegin())
- << FixItHint::CreateRemoval(Braces.getEnd());
+ << Entity.getType()->isSizelessBuiltinType() << Braces
+ << FixItHint::CreateRemoval(Braces.getBegin())
+ << FixItHint::CreateRemoval(Braces.getEnd());
}
}
@@ -1202,6 +1203,12 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
: diag::ext_excess_initializers_in_char_array_initializer;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< IList->getInit(Index)->getSourceRange();
+ } else if (T->isSizelessBuiltinType()) {
+ unsigned DK = ExtraInitsIsError
+ ? diag::err_excess_initializers_for_sizeless_type
+ : diag::ext_excess_initializers_for_sizeless_type;
+ SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
+ << T << IList->getInit(Index)->getSourceRange();
} else {
int initKind = T->isArrayType() ? 0 :
T->isVectorType() ? 1 :
@@ -1235,7 +1242,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (!HasEquivCtor) {
SemaRef.Diag(IList->getBeginLoc(),
- diag::warn_cxx2a_compat_aggregate_init_with_ctors)
+ diag::warn_cxx20_compat_aggregate_init_with_ctors)
<< IList->getSourceRange() << T;
}
}
@@ -1294,7 +1301,8 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_init_objc_class) << DeclType;
hadError = true;
- } else if (DeclType->isOCLIntelSubgroupAVCType()) {
+ } else if (DeclType->isOCLIntelSubgroupAVCType() ||
+ DeclType->isSizelessBuiltinType()) {
// Checks for scalar type are sufficient for these types too.
CheckScalarType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
@@ -1507,12 +1515,20 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (Index >= IList->getNumInits()) {
- if (!VerifyOnly)
- SemaRef.Diag(IList->getBeginLoc(),
- SemaRef.getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_empty_scalar_initializer
- : diag::err_empty_scalar_initializer)
- << IList->getSourceRange();
+ if (!VerifyOnly) {
+ if (DeclType->isSizelessBuiltinType())
+ SemaRef.Diag(IList->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_empty_sizeless_initializer
+ : diag::err_empty_sizeless_initializer)
+ << DeclType << IList->getSourceRange();
+ else
+ SemaRef.Diag(IList->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_empty_scalar_initializer
+ : diag::err_empty_scalar_initializer)
+ << IList->getSourceRange();
+ }
hadError = !SemaRef.getLangOpts().CPlusPlus11;
++Index;
++StructuredIndex;
@@ -1524,17 +1540,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
// FIXME: This is invalid, and accepting it causes overload resolution
// to pick the wrong overload in some corner cases.
if (!VerifyOnly)
- SemaRef.Diag(SubIList->getBeginLoc(),
- diag::ext_many_braces_around_scalar_init)
- << SubIList->getSourceRange();
+ SemaRef.Diag(SubIList->getBeginLoc(), diag::ext_many_braces_around_init)
+ << DeclType->isSizelessBuiltinType() << SubIList->getSourceRange();
CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList,
StructuredIndex);
return;
} else if (isa<DesignatedInitExpr>(expr)) {
if (!VerifyOnly)
- SemaRef.Diag(expr->getBeginLoc(), diag::err_designator_for_scalar_init)
- << DeclType << expr->getSourceRange();
+ SemaRef.Diag(expr->getBeginLoc(),
+ diag::err_designator_for_scalar_or_sizeless_init)
+ << DeclType->isSizelessBuiltinType() << DeclType
+ << expr->getSourceRange();
hadError = true;
++Index;
++StructuredIndex;
@@ -1621,7 +1638,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
expr = Result.getAs<Expr>();
// FIXME: Why are we updating the syntactic init list?
- if (!VerifyOnly)
+ if (!VerifyOnly && expr)
IList->setInit(Index, expr);
if (hadError)
@@ -3477,6 +3494,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_NonConstLValueReferenceBindingToTemporary:
case FK_NonConstLValueReferenceBindingToBitfield:
case FK_NonConstLValueReferenceBindingToVectorElement:
+ case FK_NonConstLValueReferenceBindingToMatrixElement:
case FK_NonConstLValueReferenceBindingToUnrelated:
case FK_RValueReferenceBindingToLValue:
case FK_ReferenceAddrspaceMismatchTemporary:
@@ -4420,16 +4438,20 @@ static void TryListInitialization(Sema &S,
// direct-list-initialization and copy-initialization otherwise.
// We can't use InitListChecker for this, because it always performs
// copy-initialization. This only matters if we might use an 'explicit'
- // conversion operator, so we only need to handle the cases where the source
- // is of record type.
- if (InitList->getInit(0)->getType()->isRecordType()) {
+ // conversion operator, or for the special case conversion of nullptr_t to
+ // bool, so we only need to handle those cases.
+ //
+ // FIXME: Why not do this in all cases?
+ Expr *Init = InitList->getInit(0);
+ if (Init->getType()->isRecordType() ||
+ (Init->getType()->isNullPtrType() && DestType->isBooleanType())) {
InitializationKind SubKind =
Kind.getKind() == InitializationKind::IK_DirectList
? InitializationKind::CreateDirect(Kind.getLocation(),
InitList->getLBraceLoc(),
InitList->getRBraceLoc())
: Kind;
- Expr *SubInit[1] = { InitList->getInit(0) };
+ Expr *SubInit[1] = { Init };
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
/*TopLevelOfInitList*/true,
TreatUnavailableAsInvalid);
@@ -4666,10 +4688,14 @@ static void TryReferenceInitialization(Sema &S,
/// which a reference can never bind). Attempting to bind a reference to
/// such a glvalue will always create a temporary.
static bool isNonReferenceableGLValue(Expr *E) {
- return E->refersToBitField() || E->refersToVectorElement();
+ return E->refersToBitField() || E->refersToVectorElement() ||
+ E->refersToMatrixElement();
}
/// Reference initialization without resolving overloaded functions.
+///
+/// We also can get here in C if we call a builtin which is declared as
+/// a function with a parameter of reference type (such as __builtin_va_end()).
static void TryReferenceInitializationCore(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4746,15 +4772,20 @@ static void TryReferenceInitializationCore(Sema &S,
// an rvalue. DR1287 removed the "implicitly" here.
if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() &&
(isLValueRef || InitCategory.isRValue())) {
- ConvOvlResult = TryRefInitWithConversionFunction(
- S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef,
- /*IsLValueRef*/ isLValueRef, Sequence);
- if (ConvOvlResult == OR_Success)
- return;
- if (ConvOvlResult != OR_No_Viable_Function)
- Sequence.SetOverloadFailure(
- InitializationSequence::FK_ReferenceInitOverloadFailed,
- ConvOvlResult);
+ if (S.getLangOpts().CPlusPlus) {
+ // Try conversion functions only for C++.
+ ConvOvlResult = TryRefInitWithConversionFunction(
+ S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef,
+ /*IsLValueRef*/ isLValueRef, Sequence);
+ if (ConvOvlResult == OR_Success)
+ return;
+ if (ConvOvlResult != OR_No_Viable_Function)
+ Sequence.SetOverloadFailure(
+ InitializationSequence::FK_ReferenceInitOverloadFailed,
+ ConvOvlResult);
+ } else {
+ ConvOvlResult = OR_No_Viable_Function;
+ }
}
}
@@ -4787,6 +4818,9 @@ static void TryReferenceInitializationCore(Sema &S,
else if (Initializer->refersToVectorElement())
FK = InitializationSequence::
FK_NonConstLValueReferenceBindingToVectorElement;
+ else if (Initializer->refersToMatrixElement())
+ FK = InitializationSequence::
+ FK_NonConstLValueReferenceBindingToMatrixElement;
else
llvm_unreachable("unexpected kind of compatible initializer");
break;
@@ -4924,7 +4958,7 @@ static void TryReferenceInitializationCore(Sema &S,
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, TempEntity.getType(),
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
+ Sema::AllowedExplicit::None,
/*FIXME:InOverloadResolution=*/false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
/*AllowObjCWritebackConversion=*/false);
@@ -5620,7 +5654,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
if (S.CheckObjCBridgeRelatedConversions(Initializer->getBeginLoc(),
DestType, Initializer->getType(),
Initializer) ||
- S.ConversionToObjCStringLiteralCheck(DestType, Initializer))
+ S.CheckConversionToObjCLiteral(DestType, Initializer))
Args[0] = Initializer;
}
if (!isa<InitListExpr>(Initializer))
@@ -5854,6 +5888,19 @@ void InitializationSequence::InitializeFrom(Sema &S,
return;
}
+ // - Otherwise, if the initialization is direct-initialization, the source
+ // type is std::nullptr_t, and the destination type is bool, the initial
+ // value of the object being initialized is false.
+ if (!SourceType.isNull() && SourceType->isNullPtrType() &&
+ DestType->isBooleanType() &&
+ Kind.getKind() == InitializationKind::IK_Direct) {
+ AddConversionSequenceStep(
+ ImplicitConversionSequence::getNullptrToBool(SourceType, DestType,
+ Initializer->isGLValue()),
+ DestType);
+ return;
+ }
+
// - Otherwise, the initial value of the object being initialized is the
// (possibly converted) value of the initializer expression. Standard
// conversions (Clause 4) will be used, if necessary, to convert the
@@ -5863,7 +5910,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
ImplicitConversionSequence ICS
= S.TryImplicitConversion(Initializer, DestType,
/*SuppressUserConversions*/true,
- /*AllowExplicitConversions*/ false,
+ Sema::AllowedExplicit::None,
/*InOverloadResolution*/ false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
allowObjCWritebackConversion);
@@ -6416,12 +6463,14 @@ PerformConstructorInitialization(Sema &S,
}
S.MarkFunctionReferenced(Loc, Constructor);
- CurInit = CXXTemporaryObjectExpr::Create(
- S.Context, Constructor,
- Entity.getType().getNonLValueExprType(S.Context), TSInfo,
- ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
- IsListInitialization, IsStdInitListInitialization,
- ConstructorInitRequiresZeroInit);
+ CurInit = S.CheckForImmediateInvocation(
+ CXXTemporaryObjectExpr::Create(
+ S.Context, Constructor,
+ Entity.getType().getNonLValueExprType(S.Context), TSInfo,
+ ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
+ IsListInitialization, IsStdInitListInitialization,
+ ConstructorInitRequiresZeroInit),
+ Constructor);
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -8159,9 +8208,13 @@ ExprResult InitializationSequence::Perform(Sema &S,
if (const auto *ToPtrType = Step->Type->getAs<PointerType>()) {
if (FromPtrType->getPointeeType()->hasAttr(attr::NoDeref) &&
!ToPtrType->getPointeeType()->hasAttr(attr::NoDeref)) {
- S.Diag(CurInit.get()->getExprLoc(),
- diag::warn_noderef_to_dereferenceable_pointer)
- << CurInit.get()->getSourceRange();
+ // Do not check static casts here because they are checked earlier
+ // in Sema::ActOnCXXNamedCast()
+ if (!Kind.isStaticCast()) {
+ S.Diag(CurInit.get()->getExprLoc(),
+ diag::warn_noderef_to_dereferenceable_pointer)
+ << CurInit.get()->getSourceRange();
+ }
}
}
}
@@ -8762,7 +8815,7 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_UTF8StringIntoPlainChar:
S.Diag(Kind.getLocation(),
diag::err_array_init_utf8_string_into_char)
- << S.getLangOpts().CPlusPlus2a;
+ << S.getLangOpts().CPlusPlus20;
break;
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
@@ -8889,6 +8942,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
+ case FK_NonConstLValueReferenceBindingToMatrixElement:
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_to_matrix_element)
+ << DestType.isVolatileQualified() << Args[0]->getSourceRange();
+ break;
+
case FK_RValueReferenceBindingToLValue:
S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref)
<< DestType.getNonReferenceType() << OnlyArg->getType()
@@ -9234,6 +9292,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "non-const lvalue reference bound to vector element";
break;
+ case FK_NonConstLValueReferenceBindingToMatrixElement:
+ OS << "non-const lvalue reference bound to matrix element";
+ break;
+
case FK_NonConstLValueReferenceBindingToUnrelated:
OS << "non-const lvalue reference bound to unrelated type";
break;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c2d14a44f53d..657ed13f207a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization(
// deduce against.
QualType DeductType = Context.getAutoDeductType();
TypeLocBuilder TLB;
- TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
+ AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType);
+ TL.setNameLoc(Loc);
if (ByRef) {
DeductType = BuildReferenceType(DeductType, true, Loc, Id);
assert(!DeductType.isNull() && "can't build reference to auto");
@@ -799,7 +800,7 @@ QualType Sema::buildLambdaInitCaptureInitialization(
}
if (EllipsisLoc.isValid()) {
if (Init->containsUnexpandedParameterPack()) {
- Diag(EllipsisLoc, getLangOpts().CPlusPlus2a
+ Diag(EllipsisLoc, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_init_capture_pack
: diag::ext_init_capture_pack);
DeductType = Context.getPackExpansionType(DeductType, NumExpansions);
@@ -989,8 +990,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);
- // CUDA lambdas get implicit attributes based on the scope in which they're
- // declared.
+ // CUDA lambdas get implicit host and device attributes.
if (getLangOpts().CUDA)
CUDASetLambdaAttrs(Method);
@@ -1052,8 +1052,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// "&identifier", "this", or "* this". [ Note: The form [&,this] is
// redundant but accepted for compatibility with ISO C++14. --end note ]
if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis)
- Diag(C->Loc, !getLangOpts().CPlusPlus2a
- ? diag::ext_equals_this_lambda_capture_cxx2a
+ Diag(C->Loc, !getLangOpts().CPlusPlus20
+ ? diag::ext_equals_this_lambda_capture_cxx20
: diag::warn_cxx17_compat_equals_this_lambda_capture);
// C++11 [expr.prim.lambda]p12:
@@ -1233,7 +1233,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
PushExpressionEvaluationContext(
- ExpressionEvaluationContext::PotentiallyEvaluated);
+ LSI->CallOperator->isConsteval()
+ ? ExpressionEvaluationContext::ConstantEvaluated
+ : ExpressionEvaluationContext::PotentiallyEvaluated);
}
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
@@ -1626,7 +1628,8 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
// If the variable being captured has an invalid type, mark the class as
// invalid as well.
if (!FieldType->isDependentType()) {
- if (RequireCompleteType(Loc, FieldType, diag::err_field_incomplete)) {
+ if (RequireCompleteSizedType(Loc, FieldType,
+ diag::err_field_incomplete_or_sizeless)) {
RD->setInvalidDecl();
Field->setInvalidDecl();
} else {
@@ -1744,7 +1747,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// Capturing 'this' implicitly with a default of '[=]' is deprecated,
// because it results in a reference capture. Don't warn prior to
// C++2a; there's nothing that can be done about it before then.
- if (getLangOpts().CPlusPlus2a && IsImplicit &&
+ if (getLangOpts().CPlusPlus20 && IsImplicit &&
CaptureDefault == LCD_ByCopy) {
Diag(From.getLocation(), diag::warn_deprecated_this_capture);
Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
@@ -1776,8 +1779,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
BuildCaptureField(Class, From);
Captures.push_back(Capture);
CaptureInits.push_back(Init.get());
+
+ if (LangOpts.CUDA)
+ CUDACheckLambdaCapture(CallOperator, From);
}
+ Class->setCaptures(Captures);
+
// C++11 [expr.prim.lambda]p6:
// The closure type for a lambda-expression with no lambda-capture
// has a public non-virtual non-explicit const conversion function
@@ -1807,7 +1815,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
CaptureDefault, CaptureDefaultLoc,
- Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, EndLoc,
ContainsUnexpandedParameterPack);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 0ed51de0cc13..5757eaf3fac0 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -215,6 +215,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
case Sema::LookupOrdinaryName:
case Sema::LookupRedeclarationWithLinkage:
case Sema::LookupLocalFriendName:
+ case Sema::LookupDestructorName:
IDNS = Decl::IDNS_Ordinary;
if (CPlusPlus) {
IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace;
@@ -378,11 +379,14 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
// type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef
// might carry additional semantic information, such as an alignment override.
// However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag
- // declaration over a typedef.
+ // declaration over a typedef. Also prefer a tag over a typedef for
+ // destructor name lookup because in some contexts we only accept a
+ // class-name in a destructor declaration.
if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) {
assert(isa<TypeDecl>(DUnderlying) && isa<TypeDecl>(EUnderlying));
bool HaveTag = isa<TagDecl>(EUnderlying);
- bool WantTag = Kind == Sema::LookupTagName;
+ bool WantTag =
+ Kind == Sema::LookupTagName || Kind == Sema::LookupDestructorName;
return HaveTag != WantTag;
}
@@ -1149,73 +1153,14 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
return false;
}
-// Find the next outer declaration context from this scope. This
-// routine actually returns the semantic outer context, which may
-// differ from the lexical context (encoded directly in the Scope
-// stack) when we are parsing a member of a class template. In this
-// case, the second element of the pair will be true, to indicate that
-// name lookup should continue searching in this semantic context when
-// it leaves the current template parameter scope.
-static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
- DeclContext *DC = S->getEntity();
- DeclContext *Lexical = nullptr;
- for (Scope *OuterS = S->getParent(); OuterS;
- OuterS = OuterS->getParent()) {
- if (OuterS->getEntity()) {
- Lexical = OuterS->getEntity();
- break;
- }
- }
-
- // C++ [temp.local]p8:
- // In the definition of a member of a class template that appears
- // outside of the namespace containing the class template
- // definition, the name of a template-parameter hides the name of
- // a member of this namespace.
- //
- // Example:
- //
- // namespace N {
- // class C { };
- //
- // template<class T> class B {
- // void f(T);
- // };
- // }
- //
- // template<class C> void N::B<C>::f(C) {
- // C b; // C is the template parameter, not N::C
- // }
- //
- // In this example, the lexical context we return is the
- // TranslationUnit, while the semantic context is the namespace N.
- if (!Lexical || !DC || !S->getParent() ||
- !S->getParent()->isTemplateParamScope())
- return std::make_pair(Lexical, false);
-
- // Find the outermost template parameter scope.
- // For the example, this is the scope for the template parameters of
- // template<class C>.
- Scope *OutermostTemplateScope = S->getParent();
- while (OutermostTemplateScope->getParent() &&
- OutermostTemplateScope->getParent()->isTemplateParamScope())
- OutermostTemplateScope = OutermostTemplateScope->getParent();
-
- // Find the namespace context in which the original scope occurs. In
- // the example, this is namespace N.
- DeclContext *Semantic = DC;
- while (!Semantic->isFileContext())
- Semantic = Semantic->getParent();
-
- // Find the declaration context just outside of the template
- // parameter scope. This is the context in which the template is
- // being lexically declaration (a namespace context). In the
- // example, this is the global scope.
- if (Lexical->isFileContext() && !Lexical->Equals(Semantic) &&
- Lexical->Encloses(Semantic))
- return std::make_pair(Semantic, true);
-
- return std::make_pair(Lexical, false);
+/// Find the outer declaration context from this scope. This indicates the
+/// context that we should search up to (exclusive) before considering the
+/// parent of the specified scope.
+static DeclContext *findOuterContext(Scope *S) {
+ for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent())
+ if (DeclContext *DC = OuterS->getLookupEntity())
+ return DC;
+ return nullptr;
}
namespace {
@@ -1282,13 +1227,11 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
UnqualUsingDirectiveSet UDirs(*this);
bool VisitedUsingDirectives = false;
bool LeftStartingScope = false;
- DeclContext *OutsideOfTemplateParamDC = nullptr;
// When performing a scope lookup, we want to find local extern decls.
FindLocalExternScope FindLocals(R);
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
- DeclContext *Ctx = S->getEntity();
bool SearchNamespaceScope = true;
// Check whether the IdResolver has anything in this scope.
for (; I != IEnd && S->isDeclScope(*I); ++I) {
@@ -1320,7 +1263,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (!SearchNamespaceScope) {
R.resolveKind();
if (S->isClassScope())
- if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+ if (CXXRecordDecl *Record =
+ dyn_cast_or_null<CXXRecordDecl>(S->getEntity()))
R.setNamingClass(Record);
return true;
}
@@ -1334,24 +1278,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return false;
}
- if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
- S->getParent() && !S->getParent()->isTemplateParamScope()) {
- // We've just searched the last template parameter scope and
- // found nothing, so look into the contexts between the
- // lexical and semantic declaration contexts returned by
- // findOuterContext(). This implements the name lookup behavior
- // of C++ [temp.local]p8.
- Ctx = OutsideOfTemplateParamDC;
- OutsideOfTemplateParamDC = nullptr;
- }
-
- if (Ctx) {
- DeclContext *OuterCtx;
- bool SearchAfterTemplateScope;
- std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
- if (SearchAfterTemplateScope)
- OutsideOfTemplateParamDC = OuterCtx;
-
+ if (DeclContext *Ctx = S->getLookupEntity()) {
+ DeclContext *OuterCtx = findOuterContext(S);
for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
// We do not directly look into transparent contexts, since
// those entities will be found in the nearest enclosing
@@ -1476,25 +1404,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return true;
}
- DeclContext *Ctx = S->getEntity();
- if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
- S->getParent() && !S->getParent()->isTemplateParamScope()) {
- // We've just searched the last template parameter scope and
- // found nothing, so look into the contexts between the
- // lexical and semantic declaration contexts returned by
- // findOuterContext(). This implements the name lookup behavior
- // of C++ [temp.local]p8.
- Ctx = OutsideOfTemplateParamDC;
- OutsideOfTemplateParamDC = nullptr;
- }
-
+ DeclContext *Ctx = S->getLookupEntity();
if (Ctx) {
- DeclContext *OuterCtx;
- bool SearchAfterTemplateScope;
- std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
- if (SearchAfterTemplateScope)
- OutsideOfTemplateParamDC = OuterCtx;
-
+ DeclContext *OuterCtx = findOuterContext(S);
for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) {
// We do not directly look into transparent contexts, since
// those entities will be found in the nearest enclosing
@@ -1575,7 +1487,9 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
unsigned N = CodeSynthesisContexts.size();
for (unsigned I = CodeSynthesisContextLookupModules.size();
I != N; ++I) {
- Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity);
+ Module *M = CodeSynthesisContexts[I].Entity ?
+ getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
+ nullptr;
if (M && !LookupModulesCache.insert(M).second)
M = nullptr;
CodeSynthesisContextLookupModules.push_back(M);
@@ -1704,7 +1618,8 @@ bool Sema::hasVisibleMemberSpecialization(
/// path (by instantiating a template, you allow it to see the declarations that
/// your module can see, including those later on in your module).
bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
- assert(D->isHidden() && "should not call this: not in slow case");
+ assert(!D->isUnconditionallyVisible() &&
+ "should not call this: not in slow case");
Module *DeclModule = SemaRef.getOwningModule(D);
assert(DeclModule && "hidden decl has no owning module");
@@ -2295,6 +2210,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
case LookupMemberName:
case LookupRedeclarationWithLinkage:
case LookupLocalFriendName:
+ case LookupDestructorName:
BaseCallback = &CXXRecordDecl::FindOrdinaryMember;
break;
@@ -2959,7 +2875,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// These are fundamental types.
case Type::Vector:
case Type::ExtVector:
+ case Type::ConstantMatrix:
case Type::Complex:
+ case Type::ExtInt:
break;
// Non-deduced auto types only get here for error cases.
@@ -3985,14 +3903,12 @@ private:
}
}
- // FIXME: C++ [temp.local]p8
- DeclContext *Entity = nullptr;
- if (S->getEntity()) {
+ DeclContext *Entity = S->getLookupEntity();
+ if (Entity) {
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
// where we hit the context stored in the next outer scope.
- Entity = S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
+ DeclContext *OuterCtx = findOuterContext(S);
for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
Ctx = Ctx->getLookupParent()) {
@@ -5158,9 +5074,9 @@ TypoExpr *Sema::CorrectTypoDelayed(
IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3)
return nullptr;
-
ExprEvalContexts.back().NumTypos++;
- return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC));
+ return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC),
+ TypoName.getLoc());
}
void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
@@ -5342,9 +5258,8 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
/// Get a "quoted.h" or <angled.h> include path to use in a diagnostic
/// suggesting the addition of a #include of the specified file.
-static std::string getIncludeStringForHeader(Preprocessor &PP,
- const FileEntry *E,
- llvm::StringRef IncludingFile) {
+static std::string getHeaderNameForHeader(Preprocessor &PP, const FileEntry *E,
+ llvm::StringRef IncludingFile) {
bool IsSystem = false;
auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(
E, IncludingFile, &IsSystem);
@@ -5358,25 +5273,10 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
assert(!Modules.empty());
auto NotePrevious = [&] {
- unsigned DiagID;
- switch (MIK) {
- case MissingImportKind::Declaration:
- DiagID = diag::note_previous_declaration;
- break;
- case MissingImportKind::Definition:
- DiagID = diag::note_previous_definition;
- break;
- case MissingImportKind::DefaultArgument:
- DiagID = diag::note_default_argument_declared_here;
- break;
- case MissingImportKind::ExplicitSpecialization:
- DiagID = diag::note_explicit_specialization_declared_here;
- break;
- case MissingImportKind::PartialSpecialization:
- DiagID = diag::note_partial_specialization_declared_here;
- break;
- }
- Diag(DeclLoc, DiagID);
+ // FIXME: Suppress the note backtrace even under
+ // -fdiagnostics-show-note-include-stack. We don't care how this
+ // declaration was previously reached.
+ Diag(DeclLoc, diag::note_unreachable_entity) << (int)MIK;
};
// Weed out duplicates from module list.
@@ -5389,26 +5289,24 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
UniqueModules.push_back(M);
}
- llvm::StringRef IncludingFile;
- if (const FileEntry *FE =
- SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
- IncludingFile = FE->tryGetRealPathName();
+ // Try to find a suitable header-name to #include.
+ std::string HeaderName;
+ if (const FileEntry *Header =
+ PP.getHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) {
+ if (const FileEntry *FE =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
+ HeaderName = getHeaderNameForHeader(PP, Header, FE->tryGetRealPathName());
+ }
- if (UniqueModules.empty()) {
- // All candidates were global module fragments. Try to suggest a #include.
- const FileEntry *E =
- PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc);
+ // If we have a #include we should suggest, or if all definition locations
+ // were in global module fragments, don't suggest an import.
+ if (!HeaderName.empty() || UniqueModules.empty()) {
// FIXME: Find a smart place to suggest inserting a #include, and add
// a FixItHint there.
- Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment)
- << (int)MIK << Decl << !!E
- << (E ? getIncludeStringForHeader(PP, E, IncludingFile) : "");
- // Produce a "previous" note if it will point to a header rather than some
- // random global module fragment.
- // FIXME: Suppress the note backtrace even under
- // -fdiagnostics-show-note-include-stack.
- if (E)
- NotePrevious();
+ Diag(UseLoc, diag::err_module_unimported_use_header)
+ << (int)MIK << Decl << !HeaderName.empty() << HeaderName;
+ // Produce a note showing where the entity was declared.
+ NotePrevious();
if (Recover)
createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]);
return;
@@ -5430,16 +5328,6 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
Diag(UseLoc, diag::err_module_unimported_use_multiple)
<< (int)MIK << Decl << ModuleList;
- } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics(
- UseLoc, Modules[0], DeclLoc)) {
- // The right way to make the declaration visible is to include a header;
- // suggest doing so.
- //
- // FIXME: Find a smart place to suggest inserting a #include, and add
- // a FixItHint there.
- Diag(UseLoc, diag::err_module_unimported_use_header)
- << (int)MIK << Decl << Modules[0]->getFullModuleName()
- << getIncludeStringForHeader(PP, E, IncludingFile);
} else {
// FIXME: Add a FixItHint that imports the corresponding module.
Diag(UseLoc, diag::err_module_unimported_use)
@@ -5500,9 +5388,10 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
TypoDiagnosticGenerator TDG,
- TypoRecoveryCallback TRC) {
+ TypoRecoveryCallback TRC,
+ SourceLocation TypoLoc) {
assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer");
- auto TE = new (Context) TypoExpr(Context.DependentTy);
+ auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc);
auto &State = DelayedTypos[TE];
State.Consumer = std::move(TCC);
State.DiagHandler = std::move(TDG);
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index f6717f4cbe5e..e301c62dd2c0 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -35,24 +35,23 @@ using namespace clang;
///
/// Returns OCL_None if the attributes as stated do not imply an ownership.
/// Never returns OCL_Autoreleasing.
-static Qualifiers::ObjCLifetime getImpliedARCOwnership(
- ObjCPropertyDecl::PropertyAttributeKind attrs,
- QualType type) {
+static Qualifiers::ObjCLifetime
+getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) {
// retain, strong, copy, weak, and unsafe_unretained are only legal
// on properties of retainable pointer type.
- if (attrs & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy)) {
+ if (attrs &
+ (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong |
+ ObjCPropertyAttribute::kind_copy)) {
return Qualifiers::OCL_Strong;
- } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) {
+ } else if (attrs & ObjCPropertyAttribute::kind_weak) {
return Qualifiers::OCL_Weak;
- } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) {
+ } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) {
return Qualifiers::OCL_ExplicitNone;
}
// assign can appear on other types, so we have to check the
// property type.
- if (attrs & ObjCPropertyDecl::OBJC_PR_assign &&
+ if (attrs & ObjCPropertyAttribute::kind_assign &&
type->isObjCRetainableType()) {
return Qualifiers::OCL_ExplicitNone;
}
@@ -66,8 +65,7 @@ static void checkPropertyDeclWithOwnership(Sema &S,
ObjCPropertyDecl *property) {
if (property->isInvalidDecl()) return;
- ObjCPropertyDecl::PropertyAttributeKind propertyKind
- = property->getPropertyAttributes();
+ ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes();
Qualifiers::ObjCLifetime propertyLifetime
= property->getType().getObjCLifetime();
@@ -80,14 +78,14 @@ static void checkPropertyDeclWithOwnership(Sema &S,
// attribute. That's okay, but restore reasonable invariants by
// setting the property attribute according to the lifetime
// qualifier.
- ObjCPropertyDecl::PropertyAttributeKind attr;
+ ObjCPropertyAttribute::Kind attr;
if (propertyLifetime == Qualifiers::OCL_Strong) {
- attr = ObjCPropertyDecl::OBJC_PR_strong;
+ attr = ObjCPropertyAttribute::kind_strong;
} else if (propertyLifetime == Qualifiers::OCL_Weak) {
- attr = ObjCPropertyDecl::OBJC_PR_weak;
+ attr = ObjCPropertyAttribute::kind_weak;
} else {
assert(propertyLifetime == Qualifiers::OCL_ExplicitNone);
- attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ attr = ObjCPropertyAttribute::kind_unsafe_unretained;
}
property->setPropertyAttributes(attr);
return;
@@ -130,18 +128,19 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {
// In GC mode, just look for the __weak qualifier.
if (S.getLangOpts().getGC() != LangOptions::NonGC) {
- if (T.isObjCGCWeak()) return ObjCDeclSpec::DQ_PR_weak;
+ if (T.isObjCGCWeak())
+ return ObjCPropertyAttribute::kind_weak;
- // In ARC/MRC, look for an explicit ownership qualifier.
- // For some reason, this only applies to __weak.
+ // In ARC/MRC, look for an explicit ownership qualifier.
+ // For some reason, this only applies to __weak.
} else if (auto ownership = T.getObjCLifetime()) {
switch (ownership) {
case Qualifiers::OCL_Weak:
- return ObjCDeclSpec::DQ_PR_weak;
+ return ObjCPropertyAttribute::kind_weak;
case Qualifiers::OCL_Strong:
- return ObjCDeclSpec::DQ_PR_strong;
+ return ObjCPropertyAttribute::kind_strong;
case Qualifiers::OCL_ExplicitNone:
- return ObjCDeclSpec::DQ_PR_unsafe_unretained;
+ return ObjCPropertyAttribute::kind_unsafe_unretained;
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_None:
return 0;
@@ -153,22 +152,20 @@ static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) {
}
static const unsigned OwnershipMask =
- (ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_weak |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak |
+ ObjCPropertyAttribute::kind_strong |
+ ObjCPropertyAttribute::kind_unsafe_unretained);
static unsigned getOwnershipRule(unsigned attr) {
unsigned result = attr & OwnershipMask;
// From an ownership perspective, assign and unsafe_unretained are
// identical; make sure one also implies the other.
- if (result & (ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained)) {
- result |= ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
+ if (result & (ObjCPropertyAttribute::kind_assign |
+ ObjCPropertyAttribute::kind_unsafe_unretained)) {
+ result |= ObjCPropertyAttribute::kind_assign |
+ ObjCPropertyAttribute::kind_unsafe_unretained;
}
return result;
@@ -183,15 +180,16 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
tok::ObjCKeywordKind MethodImplKind,
DeclContext *lexicalDC) {
unsigned Attributes = ODS.getPropertyAttributes();
- FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0);
+ FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) !=
+ 0);
TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
QualType T = TSI->getType();
if (!getOwnershipRule(Attributes)) {
Attributes |= deducePropertyOwnershipFromType(*this, T);
}
- bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
+ bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) ||
// default is readwrite!
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
+ !(Attributes & ObjCPropertyAttribute::kind_readonly));
// Proceed with constructing the ObjCPropertyDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
@@ -277,39 +275,39 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
return Res;
}
-static ObjCPropertyDecl::PropertyAttributeKind
+static ObjCPropertyAttribute::Kind
makePropertyAttributesAsWritten(unsigned Attributes) {
unsigned attributesAsWritten = 0;
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly;
- if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite;
- if (Attributes & ObjCDeclSpec::DQ_PR_getter)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter;
- if (Attributes & ObjCDeclSpec::DQ_PR_setter)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter;
- if (Attributes & ObjCDeclSpec::DQ_PR_assign)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign;
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain;
- if (Attributes & ObjCDeclSpec::DQ_PR_strong)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong;
- if (Attributes & ObjCDeclSpec::DQ_PR_weak)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak;
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy;
- if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
- if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
- if (Attributes & ObjCDeclSpec::DQ_PR_class)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
- if (Attributes & ObjCDeclSpec::DQ_PR_direct)
- attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct;
-
- return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
+ if (Attributes & ObjCPropertyAttribute::kind_readonly)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_readonly;
+ if (Attributes & ObjCPropertyAttribute::kind_readwrite)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite;
+ if (Attributes & ObjCPropertyAttribute::kind_getter)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_getter;
+ if (Attributes & ObjCPropertyAttribute::kind_setter)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_setter;
+ if (Attributes & ObjCPropertyAttribute::kind_assign)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_assign;
+ if (Attributes & ObjCPropertyAttribute::kind_retain)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_retain;
+ if (Attributes & ObjCPropertyAttribute::kind_strong)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_strong;
+ if (Attributes & ObjCPropertyAttribute::kind_weak)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_weak;
+ if (Attributes & ObjCPropertyAttribute::kind_copy)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_copy;
+ if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained;
+ if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic;
+ if (Attributes & ObjCPropertyAttribute::kind_atomic)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_atomic;
+ if (Attributes & ObjCPropertyAttribute::kind_class)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_class;
+ if (Attributes & ObjCPropertyAttribute::kind_direct)
+ attributesAsWritten |= ObjCPropertyAttribute::kind_direct;
+
+ return (ObjCPropertyAttribute::Kind)attributesAsWritten;
}
static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
@@ -347,12 +345,10 @@ static void checkAtomicPropertyMismatch(Sema &S,
ObjCPropertyDecl *NewProperty,
bool PropagateAtomicity) {
// If the atomicity of both matches, we're done.
- bool OldIsAtomic =
- (OldProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
- == 0;
- bool NewIsAtomic =
- (NewProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
- == 0;
+ bool OldIsAtomic = (OldProperty->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_nonatomic) == 0;
+ bool NewIsAtomic = (NewProperty->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_nonatomic) == 0;
if (OldIsAtomic == NewIsAtomic) return;
// Determine whether the given property is readonly and implicitly
@@ -360,14 +356,16 @@ static void checkAtomicPropertyMismatch(Sema &S,
auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool {
// Is it readonly?
auto Attrs = Property->getPropertyAttributes();
- if ((Attrs & ObjCPropertyDecl::OBJC_PR_readonly) == 0) return false;
+ if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0)
+ return false;
// Is it nonatomic?
- if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) return false;
+ if (Attrs & ObjCPropertyAttribute::kind_nonatomic)
+ return false;
// Was 'atomic' specified directly?
if (Property->getPropertyAttributesAsWritten() &
- ObjCPropertyDecl::OBJC_PR_atomic)
+ ObjCPropertyAttribute::kind_atomic)
return false;
return true;
@@ -375,16 +373,16 @@ static void checkAtomicPropertyMismatch(Sema &S,
// If we're allowed to propagate atomicity, and the new property did
// not specify atomicity at all, propagate.
- const unsigned AtomicityMask =
- (ObjCPropertyDecl::OBJC_PR_atomic | ObjCPropertyDecl::OBJC_PR_nonatomic);
+ const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic |
+ ObjCPropertyAttribute::kind_nonatomic);
if (PropagateAtomicity &&
((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) {
unsigned Attrs = NewProperty->getPropertyAttributes();
Attrs = Attrs & ~AtomicityMask;
if (OldIsAtomic)
- Attrs |= ObjCPropertyDecl::OBJC_PR_atomic;
+ Attrs |= ObjCPropertyAttribute::kind_atomic;
else
- Attrs |= ObjCPropertyDecl::OBJC_PR_nonatomic;
+ Attrs |= ObjCPropertyAttribute::kind_nonatomic;
NewProperty->overwritePropertyAttributes(Attrs);
return;
@@ -438,8 +436,9 @@ Sema::HandlePropertyInClassExtension(Scope *S,
return nullptr;
}
- bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
- (Attributes & ObjCDeclSpec::DQ_PR_class);
+ bool isClassProperty =
+ (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
+ (Attributes & ObjCPropertyAttribute::kind_class);
// Find the property in the extended class's primary class or
// extensions.
@@ -464,11 +463,11 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// This is a common error where the user often intended the original
// declaration to be readonly.
unsigned diag =
- (Attributes & ObjCDeclSpec::DQ_PR_readwrite) &&
- (PIDecl->getPropertyAttributesAsWritten() &
- ObjCPropertyDecl::OBJC_PR_readwrite)
- ? diag::err_use_continuation_class_redeclaration_readwrite
- : diag::err_use_continuation_class;
+ (Attributes & ObjCPropertyAttribute::kind_readwrite) &&
+ (PIDecl->getPropertyAttributesAsWritten() &
+ ObjCPropertyAttribute::kind_readwrite)
+ ? diag::err_use_continuation_class_redeclaration_readwrite
+ : diag::err_use_continuation_class;
Diag(AtLoc, diag)
<< CCPrimary->getDeclName();
Diag(PIDecl->getLocation(), diag::note_property_declare);
@@ -478,15 +477,15 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// Check for consistency of getters.
if (PIDecl->getGetterName() != GetterSel) {
// If the getter was written explicitly, complain.
- if (AttributesAsWritten & ObjCDeclSpec::DQ_PR_getter) {
- Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
- << PIDecl->getGetterName() << GetterSel;
- Diag(PIDecl->getLocation(), diag::note_property_declare);
- }
+ if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) {
+ Diag(AtLoc, diag::warn_property_redecl_getter_mismatch)
+ << PIDecl->getGetterName() << GetterSel;
+ Diag(PIDecl->getLocation(), diag::note_property_declare);
+ }
// Always adopt the getter from the original declaration.
GetterSel = PIDecl->getGetterName();
- Attributes |= ObjCDeclSpec::DQ_PR_getter;
+ Attributes |= ObjCPropertyAttribute::kind_getter;
}
// Check consistency of ownership.
@@ -505,9 +504,9 @@ Sema::HandlePropertyInClassExtension(Scope *S,
}
// If the redeclaration is 'weak' but the original property is not,
- if ((Attributes & ObjCPropertyDecl::OBJC_PR_weak) &&
- !(PIDecl->getPropertyAttributesAsWritten()
- & ObjCPropertyDecl::OBJC_PR_weak) &&
+ if ((Attributes & ObjCPropertyAttribute::kind_weak) &&
+ !(PIDecl->getPropertyAttributesAsWritten() &
+ ObjCPropertyAttribute::kind_weak) &&
PIDecl->getType()->getAs<ObjCObjectPointerType>() &&
PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) {
Diag(AtLoc, diag::warn_property_implicitly_mismatched);
@@ -584,8 +583,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// Property defaults to 'assign' if it is readwrite, unless this is ARC
// and the type is retainable.
bool isAssign;
- if (Attributes & (ObjCDeclSpec::DQ_PR_assign |
- ObjCDeclSpec::DQ_PR_unsafe_unretained)) {
+ if (Attributes & (ObjCPropertyAttribute::kind_assign |
+ ObjCPropertyAttribute::kind_unsafe_unretained)) {
isAssign = true;
} else if (getOwnershipRule(Attributes) || !isReadWrite) {
isAssign = false;
@@ -596,8 +595,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
// Issue a warning if property is 'assign' as default and its
// object, which is gc'able conforms to NSCopying protocol
- if (getLangOpts().getGC() != LangOptions::NonGC &&
- isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) {
+ if (getLangOpts().getGC() != LangOptions::NonGC && isAssign &&
+ !(Attributes & ObjCPropertyAttribute::kind_assign)) {
if (const ObjCObjectPointerType *ObjPtrTy =
T->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
@@ -625,8 +624,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PropertyId, AtLoc,
LParenLoc, T, TInfo);
- bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
- (Attributes & ObjCDeclSpec::DQ_PR_class);
+ bool isClassProperty =
+ (AttributesAsWritten & ObjCPropertyAttribute::kind_class) ||
+ (Attributes & ObjCPropertyAttribute::kind_class);
// Class property and instance property can have the same name.
if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
@@ -654,68 +654,68 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PDecl->setPropertyAttributesAsWritten(
makePropertyAttributesAsWritten(AttributesAsWritten));
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+ if (Attributes & ObjCPropertyAttribute::kind_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly);
- if (Attributes & ObjCDeclSpec::DQ_PR_getter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+ if (Attributes & ObjCPropertyAttribute::kind_getter)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter);
- if (Attributes & ObjCDeclSpec::DQ_PR_setter)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+ if (Attributes & ObjCPropertyAttribute::kind_setter)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter);
if (isReadWrite)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite);
- if (Attributes & ObjCDeclSpec::DQ_PR_retain)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (Attributes & ObjCPropertyAttribute::kind_retain)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain);
- if (Attributes & ObjCDeclSpec::DQ_PR_strong)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ if (Attributes & ObjCPropertyAttribute::kind_strong)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
- if (Attributes & ObjCDeclSpec::DQ_PR_weak)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+ if (Attributes & ObjCPropertyAttribute::kind_weak)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
- if (Attributes & ObjCDeclSpec::DQ_PR_copy)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ if (Attributes & ObjCPropertyAttribute::kind_copy)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy);
- if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
// In the semantic attributes, one of nonatomic or atomic is always set.
- if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if (Attributes & ObjCPropertyAttribute::kind_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic);
else
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic);
// 'unsafe_unretained' is alias for 'assign'.
- if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign);
if (isAssign)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained);
if (MethodImplKind == tok::objc_required)
PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
else if (MethodImplKind == tok::objc_optional)
PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
- if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
+ if (Attributes & ObjCPropertyAttribute::kind_nullability)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability);
- if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
+ if (Attributes & ObjCPropertyAttribute::kind_null_resettable)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable);
- if (Attributes & ObjCDeclSpec::DQ_PR_class)
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+ if (Attributes & ObjCPropertyAttribute::kind_class)
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class);
- if ((Attributes & ObjCDeclSpec::DQ_PR_direct) ||
+ if ((Attributes & ObjCPropertyAttribute::kind_direct) ||
CDecl->hasAttr<ObjCDirectMembersAttr>()) {
if (isa<ObjCProtocolDecl>(CDecl)) {
Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
} else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
- PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct);
+ PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct);
} else {
Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
<< PDecl->getDeclName();
@@ -781,10 +781,9 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
case Qualifiers::OCL_ExplicitNone:
S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
- << property->getDeclName()
- << ivar->getDeclName()
- << ((property->getPropertyAttributesAsWritten()
- & ObjCPropertyDecl::OBJC_PR_assign) != 0);
+ << property->getDeclName() << ivar->getDeclName()
+ << ((property->getPropertyAttributesAsWritten() &
+ ObjCPropertyAttribute::kind_assign) != 0);
break;
case Qualifiers::OCL_Autoreleasing:
@@ -815,21 +814,20 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
if (!ivar) {
// if no backing ivar, make property 'strong'.
- property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
return;
}
// property assumes owenership of backing ivar.
QualType ivarType = ivar->getType();
Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
if (ivarLifetime == Qualifiers::OCL_Strong)
- property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
else if (ivarLifetime == Qualifiers::OCL_Weak)
- property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+ property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak);
}
-static bool
-isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
- ObjCPropertyDecl::PropertyAttributeKind Kind) {
+static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2,
+ ObjCPropertyAttribute::Kind Kind) {
return (Attr1 & Kind) != (Attr2 & Kind);
}
@@ -912,30 +910,31 @@ SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc,
};
// The ownership might be incompatible unless the property has no explicit
// ownership.
- bool HasOwnership = (Attr & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong |
- ObjCPropertyDecl::OBJC_PR_copy |
- ObjCPropertyDecl::OBJC_PR_assign |
- ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
- ObjCPropertyDecl::OBJC_PR_weak)) != 0;
+ bool HasOwnership =
+ (Attr & (ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong |
+ ObjCPropertyAttribute::kind_copy |
+ ObjCPropertyAttribute::kind_assign |
+ ObjCPropertyAttribute::kind_unsafe_unretained |
+ ObjCPropertyAttribute::kind_weak)) != 0;
if (HasOwnership &&
isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
- ObjCPropertyDecl::OBJC_PR_copy)) {
- Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_copy, "copy");
+ ObjCPropertyAttribute::kind_copy)) {
+ Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy");
continue;
}
if (HasOwnership && areIncompatiblePropertyAttributes(
OriginalAttributes, Attr,
- ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong)) {
- Diag(OriginalAttributes & (ObjCPropertyDecl::OBJC_PR_retain |
- ObjCPropertyDecl::OBJC_PR_strong),
+ ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong)) {
+ Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong),
"retain (or strong)");
continue;
}
if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr,
- ObjCPropertyDecl::OBJC_PR_atomic)) {
- Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_atomic, "atomic");
+ ObjCPropertyAttribute::kind_atomic)) {
+ Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic");
continue;
}
}
@@ -1126,8 +1125,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return nullptr;
}
unsigned PIkind = property->getPropertyAttributesAsWritten();
- if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic |
- ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) {
+ if ((PIkind & (ObjCPropertyAttribute::kind_atomic |
+ ObjCPropertyAttribute::kind_nonatomic)) == 0) {
if (AtLoc.isValid())
Diag(AtLoc, diag::warn_implicit_atomic_property);
else
@@ -1143,10 +1142,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return nullptr;
}
}
- if (Synthesize&&
- (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) &&
- property->hasAttr<IBOutletAttr>() &&
- !AtLoc.isValid()) {
+ if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) &&
+ property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) {
bool ReadWriteProperty = false;
// Search into the class extensions and see if 'readonly property is
// redeclared 'readwrite', then no warning is to be issued.
@@ -1155,7 +1152,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (!R.empty())
if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) {
PIkind = ExtProp->getPropertyAttributesAsWritten();
- if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) {
+ if (PIkind & ObjCPropertyAttribute::kind_readwrite) {
ReadWriteProperty = true;
break;
}
@@ -1232,16 +1229,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (getLangOpts().ObjCAutoRefCount &&
(property->getPropertyAttributesAsWritten() &
- ObjCPropertyDecl::OBJC_PR_readonly) &&
+ ObjCPropertyAttribute::kind_readonly) &&
PropertyIvarType->isObjCRetainableType()) {
setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar);
}
- ObjCPropertyDecl::PropertyAttributeKind kind
- = property->getPropertyAttributes();
+ ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes();
bool isARCWeak = false;
- if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
+ if (kind & ObjCPropertyAttribute::kind_weak) {
// Add GC __weak to the ivar type if the property is weak.
if (getLangOpts().getGC() != LangOptions::NonGC) {
assert(!getLangOpts().ObjCAutoRefCount);
@@ -1312,7 +1308,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// It's an error if we have to do this and the user didn't
// explicitly write an ownership attribute on the property.
if (!hasWrittenStorageAttribute(property, QueryKind) &&
- !(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
+ !(kind & ObjCPropertyAttribute::kind_strong)) {
Diag(PropertyDiagLoc,
diag::err_arc_objc_property_default_assign_on_object);
Diag(property->getLocation(), diag::note_property_declare);
@@ -1456,7 +1452,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
PropertyLoc);
PIDecl->setGetterMethodDecl(OMD);
}
-
+
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be
@@ -1551,7 +1547,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ExprResult Res = BuildBinOp(S, PropertyDiagLoc,
BO_Assign, lhs, rhs);
if (property->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_atomic) {
+ ObjCPropertyAttribute::kind_atomic) {
Expr *callExpr = Res.getAs<Expr>();
if (const CXXOperatorCallExpr *CXXCE =
dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
@@ -1627,6 +1623,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
CatImplClass->addPropertyImplementation(PIDecl);
}
+ if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic &&
+ PIDecl->getPropertyDecl() &&
+ PIDecl->getPropertyDecl()->isDirectProperty()) {
+ Diag(PropertyLoc, diag::err_objc_direct_dynamic_property);
+ Diag(PIDecl->getPropertyDecl()->getLocation(),
+ diag::note_previous_declaration);
+ return nullptr;
+ }
+
return PIDecl;
}
@@ -1642,10 +1647,8 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *inheritedName,
bool OverridingProtocolProperty) {
- ObjCPropertyDecl::PropertyAttributeKind CAttr =
- Property->getPropertyAttributes();
- ObjCPropertyDecl::PropertyAttributeKind SAttr =
- SuperProperty->getPropertyAttributes();
+ ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes();
+ ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes();
// We allow readonly properties without an explicit ownership
// (assign/unsafe_unretained/weak/retain/strong/copy) in super class
@@ -1654,21 +1657,19 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
!getOwnershipRule(SAttr) && getOwnershipRule(CAttr))
;
else {
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
- && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
+ if ((CAttr & ObjCPropertyAttribute::kind_readonly) &&
+ (SAttr & ObjCPropertyAttribute::kind_readwrite))
Diag(Property->getLocation(), diag::warn_readonly_property)
<< Property->getDeclName() << inheritedName;
- if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
+ if ((CAttr & ObjCPropertyAttribute::kind_copy) !=
+ (SAttr & ObjCPropertyAttribute::kind_copy))
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "copy" << inheritedName;
- else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){
- unsigned CAttrRetain =
- (CAttr &
- (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
- unsigned SAttrRetain =
- (SAttr &
- (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+ else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) {
+ unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong));
+ unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong));
bool CStrong = (CAttrRetain != 0);
bool SStrong = (SAttrRetain != 0);
if (CStrong != SStrong)
@@ -1876,7 +1877,7 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
ObjCPropertyDecl *Prop) {
bool SuperClassImplementsGetter = false;
bool SuperClassImplementsSetter = false;
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
+ if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
SuperClassImplementsSetter = true;
while (IDecl->getSuperClass()) {
@@ -1919,7 +1920,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
continue;
ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
if (ImpMethod && !ImpMethod->getBody()) {
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
+ if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly)
continue;
ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
if (ImpMethod && !ImpMethod->getBody())
@@ -1956,16 +1957,16 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
}
// If property to be implemented in the super class, ignore.
if (PropInSuperClass) {
- if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
+ if ((Prop->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_readwrite) &&
(PropInSuperClass->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_readonly) &&
+ ObjCPropertyAttribute::kind_readonly) &&
!IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
!IDecl->HasUserDeclaredSetterMethod(Prop)) {
Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
<< Prop->getIdentifier();
Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
- }
- else {
+ } else {
Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass)
<< Prop->getIdentifier();
Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
@@ -2152,12 +2153,11 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)
const auto *property = propertyImpl->getPropertyDecl();
// Warn about null_resettable properties with synthesized setters,
// because the setter won't properly handle nil.
- if (propertyImpl->getPropertyImplementation()
- == ObjCPropertyImplDecl::Synthesize &&
+ if (propertyImpl->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Synthesize &&
(property->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_null_resettable) &&
- property->getGetterMethodDecl() &&
- property->getSetterMethodDecl()) {
+ ObjCPropertyAttribute::kind_null_resettable) &&
+ property->getGetterMethodDecl() && property->getSetterMethodDecl()) {
auto *getterImpl = propertyImpl->getGetterMethodDecl();
auto *setterImpl = propertyImpl->getSetterMethodDecl();
if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
@@ -2195,8 +2195,8 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
unsigned Attributes = Property->getPropertyAttributes();
unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
- if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) &&
- !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
+ if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) &&
+ !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) {
GetterMethod = Property->isClassProperty() ?
IMPDecl->getClassMethod(Property->getGetterName()) :
IMPDecl->getInstanceMethod(Property->getGetterName());
@@ -2222,8 +2222,8 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
}
// We only care about readwrite atomic property.
- if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
- !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
+ if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) ||
+ !(Attributes & ObjCPropertyAttribute::kind_readwrite))
continue;
if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
Property->getIdentifier(), Property->getQueryKind())) {
@@ -2244,7 +2244,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
<< (SetterMethod != nullptr);
// fixit stuff.
if (Property->getLParenLoc().isValid() &&
- !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) {
+ !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) {
// @property () ... case.
SourceLocation AfterLParen =
getLocForEndOfToken(Property->getLParenLoc());
@@ -2260,8 +2260,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
Diag(Property->getLocation(),
diag::note_atomic_property_fixup_suggest)
<< FixItHint::CreateInsertion(startLoc, "(nonatomic) ");
- }
- else
+ } else
Diag(MethodLoc, diag::note_atomic_property_fixup_suggest);
Diag(Property->getLocation(), diag::note_property_declare);
}
@@ -2421,6 +2420,40 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
+ // synthesizing accessors must not result in a direct method that is not
+ // monomorphic
+ if (!GetterMethod) {
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
+ auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod(
+ property->getGetterName(), !IsClassProperty, true, false, CatDecl);
+ if (ExistingGetter) {
+ if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) {
+ Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
+ << property->isDirectProperty() << 1 /* property */
+ << ExistingGetter->isDirectMethod()
+ << ExistingGetter->getDeclName();
+ Diag(ExistingGetter->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+ }
+
+ if (!property->isReadOnly() && !SetterMethod) {
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) {
+ auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod(
+ property->getSetterName(), !IsClassProperty, true, false, CatDecl);
+ if (ExistingSetter) {
+ if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) {
+ Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl)
+ << property->isDirectProperty() << 1 /* property */
+ << ExistingSetter->isDirectMethod()
+ << ExistingSetter->getDeclName();
+ Diag(ExistingSetter->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+ }
+
if (!property->isReadOnly() && SetterMethod) {
if (Context.getCanonicalType(SetterMethod->getReturnType()) !=
Context.VoidTy)
@@ -2455,7 +2488,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// If the property is null_resettable, the getter returns nonnull.
if (property->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_null_resettable) {
+ ObjCPropertyAttribute::kind_null_resettable) {
QualType modifiedTy = resultTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
if (*nullability == NullabilityKind::Unspecified)
@@ -2534,7 +2567,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// If the property is null_resettable, the setter accepts a
// nullable value.
if (property->getPropertyAttributes() &
- ObjCPropertyDecl::OBJC_PR_null_resettable) {
+ ObjCPropertyAttribute::kind_null_resettable) {
QualType modifiedTy = paramTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
if (*nullability == NullabilityKind::Unspecified)
@@ -2622,8 +2655,8 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if (!PDecl || PDecl->isInvalidDecl())
return;
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+ if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
+ (Attributes & ObjCPropertyAttribute::kind_readwrite))
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "readonly" << "readwrite";
@@ -2631,104 +2664,109 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
QualType PropertyTy = PropertyDecl->getType();
// Check for copy or retain on non-object types.
- if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
+ if ((Attributes &
+ (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
+ ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong)) &&
!PropertyTy->isObjCRetainableType() &&
!PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
- << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
- Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
- Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
- ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
+ << (Attributes & ObjCPropertyAttribute::kind_weak
+ ? "weak"
+ : Attributes & ObjCPropertyAttribute::kind_copy
+ ? "copy"
+ : "retain (or strong)");
+ Attributes &=
+ ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy |
+ ObjCPropertyAttribute::kind_retain |
+ ObjCPropertyAttribute::kind_strong);
PropertyDecl->setInvalidDecl();
}
// Check for assign on object types.
- if ((Attributes & ObjCDeclSpec::DQ_PR_assign) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
+ if ((Attributes & ObjCPropertyAttribute::kind_assign) &&
+ !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) &&
PropertyTy->isObjCRetainableType() &&
!PropertyTy->isObjCARCImplicitlyUnretainedType()) {
Diag(Loc, diag::warn_objc_property_assign_on_object);
}
// Check for more than one of { assign, copy, retain }.
- if (Attributes & ObjCDeclSpec::DQ_PR_assign) {
- if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ if (Attributes & ObjCPropertyAttribute::kind_assign) {
+ if (Attributes & ObjCPropertyAttribute::kind_copy) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "copy";
- Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ Attributes &= ~ObjCPropertyAttribute::kind_copy;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ if (Attributes & ObjCPropertyAttribute::kind_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ Attributes &= ~ObjCPropertyAttribute::kind_retain;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ if (Attributes & ObjCPropertyAttribute::kind_strong) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "strong";
- Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ Attributes &= ~ObjCPropertyAttribute::kind_strong;
}
- if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ if (getLangOpts().ObjCAutoRefCount &&
+ (Attributes & ObjCPropertyAttribute::kind_weak)) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "assign" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ Attributes &= ~ObjCPropertyAttribute::kind_weak;
}
if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
Diag(Loc, diag::warn_iboutletcollection_property_assign);
- } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
- if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+ } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) {
+ if (Attributes & ObjCPropertyAttribute::kind_copy) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "unsafe_unretained" << "copy";
- Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+ Attributes &= ~ObjCPropertyAttribute::kind_copy;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ if (Attributes & ObjCPropertyAttribute::kind_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "unsafe_unretained" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ Attributes &= ~ObjCPropertyAttribute::kind_retain;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ if (Attributes & ObjCPropertyAttribute::kind_strong) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "unsafe_unretained" << "strong";
- Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ Attributes &= ~ObjCPropertyAttribute::kind_strong;
}
- if (getLangOpts().ObjCAutoRefCount &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+ if (getLangOpts().ObjCAutoRefCount &&
+ (Attributes & ObjCPropertyAttribute::kind_weak)) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "unsafe_unretained" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ Attributes &= ~ObjCPropertyAttribute::kind_weak;
}
- } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
- if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+ } else if (Attributes & ObjCPropertyAttribute::kind_copy) {
+ if (Attributes & ObjCPropertyAttribute::kind_retain) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "copy" << "retain";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+ Attributes &= ~ObjCPropertyAttribute::kind_retain;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+ if (Attributes & ObjCPropertyAttribute::kind_strong) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "copy" << "strong";
- Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+ Attributes &= ~ObjCPropertyAttribute::kind_strong;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
+ if (Attributes & ObjCPropertyAttribute::kind_weak) {
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "copy" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ Attributes &= ~ObjCPropertyAttribute::kind_weak;
}
- }
- else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "retain" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
- }
- else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
- (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "strong" << "weak";
- Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+ } else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
+ (Attributes & ObjCPropertyAttribute::kind_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain"
+ << "weak";
+ Attributes &= ~ObjCPropertyAttribute::kind_retain;
+ } else if ((Attributes & ObjCPropertyAttribute::kind_strong) &&
+ (Attributes & ObjCPropertyAttribute::kind_weak)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong"
+ << "weak";
+ Attributes &= ~ObjCPropertyAttribute::kind_weak;
}
- if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
+ if (Attributes & ObjCPropertyAttribute::kind_weak) {
// 'weak' and 'nonnull' are mutually exclusive.
if (auto nullability = PropertyTy->getNullability(Context)) {
if (*nullability == NullabilityKind::NonNull)
@@ -2737,41 +2775,40 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
}
}
- if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) &&
- (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) {
- Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
- << "atomic" << "nonatomic";
- Attributes &= ~ObjCDeclSpec::DQ_PR_atomic;
+ if ((Attributes & ObjCPropertyAttribute::kind_atomic) &&
+ (Attributes & ObjCPropertyAttribute::kind_nonatomic)) {
+ Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic"
+ << "nonatomic";
+ Attributes &= ~ObjCPropertyAttribute::kind_atomic;
}
// Warn if user supplied no assignment attribute, property is
// readwrite, and this is an object type.
if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) {
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
+ if (Attributes & ObjCPropertyAttribute::kind_readonly) {
// do nothing
} else if (getLangOpts().ObjCAutoRefCount) {
// With arc, @property definitions should default to strong when
// not specified.
- PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+ PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong);
} else if (PropertyTy->isObjCObjectPointerType()) {
- bool isAnyClassTy =
- (PropertyTy->isObjCClassType() ||
- PropertyTy->isObjCQualifiedClassType());
- // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
- // issue any warning.
- if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
- ;
- else if (propertyInPrimaryClass) {
- // Don't issue warning on property with no life time in class
- // extension as it is inherited from property in primary class.
- // Skip this warning in gc-only mode.
- if (getLangOpts().getGC() != LangOptions::GCOnly)
- Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
-
- // If non-gc code warn that this is likely inappropriate.
- if (getLangOpts().getGC() == LangOptions::NonGC)
- Diag(Loc, diag::warn_objc_property_default_assign_on_object);
- }
+ bool isAnyClassTy = (PropertyTy->isObjCClassType() ||
+ PropertyTy->isObjCQualifiedClassType());
+ // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to
+ // issue any warning.
+ if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC)
+ ;
+ else if (propertyInPrimaryClass) {
+ // Don't issue warning on property with no life time in class
+ // extension as it is inherited from property in primary class.
+ // Skip this warning in gc-only mode.
+ if (getLangOpts().getGC() != LangOptions::GCOnly)
+ Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+
+ // If non-gc code warn that this is likely inappropriate.
+ if (getLangOpts().getGC() == LangOptions::NonGC)
+ Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+ }
}
// FIXME: Implement warning dependent on NSCopying being
@@ -2780,18 +2817,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
// (please trim this list while you are at it).
}
- if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)
- &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly)
- && getLangOpts().getGC() == LangOptions::GCOnly
- && PropertyTy->isBlockPointerType())
+ if (!(Attributes & ObjCPropertyAttribute::kind_copy) &&
+ !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
+ getLangOpts().getGC() == LangOptions::GCOnly &&
+ PropertyTy->isBlockPointerType())
Diag(Loc, diag::warn_objc_property_copy_missing_on_block);
- else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+ else if ((Attributes & ObjCPropertyAttribute::kind_retain) &&
+ !(Attributes & ObjCPropertyAttribute::kind_readonly) &&
+ !(Attributes & ObjCPropertyAttribute::kind_strong) &&
PropertyTy->isBlockPointerType())
- Diag(Loc, diag::warn_objc_property_retain_of_block);
+ Diag(Loc, diag::warn_objc_property_retain_of_block);
- if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
- (Attributes & ObjCDeclSpec::DQ_PR_setter))
+ if ((Attributes & ObjCPropertyAttribute::kind_readonly) &&
+ (Attributes & ObjCPropertyAttribute::kind_setter))
Diag(Loc, diag::warn_objc_readonly_property_has_setter);
}
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 3fce0e27e9b3..920463da4027 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -18,12 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
@@ -31,7 +34,10 @@
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <set>
+
using namespace clang;
using namespace llvm::omp;
@@ -47,9 +53,10 @@ static const Expr *checkMapClauseExpressionBase(
namespace {
/// Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
- DSA_unspecified = 0, /// Data sharing attribute not specified.
- DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
- DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
+ DSA_unspecified = 0, /// Data sharing attribute not specified.
+ DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
+ DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
+ DSA_firstprivate = 1 << 2, /// Default data sharing attribute 'firstprivate'.
};
/// Stack for tracking declarations used in OpenMP directives and
@@ -59,24 +66,35 @@ public:
struct DSAVarData {
OpenMPDirectiveKind DKind = OMPD_unknown;
OpenMPClauseKind CKind = OMPC_unknown;
+ unsigned Modifier = 0;
const Expr *RefExpr = nullptr;
DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
DSAVarData() = default;
DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
const Expr *RefExpr, DeclRefExpr *PrivateCopy,
- SourceLocation ImplicitDSALoc)
- : DKind(DKind), CKind(CKind), RefExpr(RefExpr),
+ SourceLocation ImplicitDSALoc, unsigned Modifier)
+ : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr),
PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
};
using OperatorOffsetTy =
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
using DoacrossDependMapTy =
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
+ /// Kind of the declaration used in the uses_allocators clauses.
+ enum class UsesAllocatorsDeclKind {
+ /// Predefined allocator
+ PredefinedAllocator,
+ /// User-defined allocator
+ UserDefinedAllocator,
+ /// The declaration that represent allocator trait
+ AllocatorTrait,
+ };
private:
struct DSAInfo {
OpenMPClauseKind Attributes = OMPC_unknown;
+ unsigned Modifier = 0;
/// Pointer to a reference expression and a flag which shows that the
/// variable is marked as lastprivate(true) or not (false).
llvm::PointerIntPair<const Expr *, 1, bool> RefExpr;
@@ -151,13 +169,21 @@ private:
bool CancelRegion = false;
bool LoopStart = false;
bool BodyComplete = false;
+ SourceLocation PrevScanLocation;
+ SourceLocation PrevOrderedLocation;
SourceLocation InnerTeamsRegionLoc;
/// Reference to the taskgroup task_reduction reference expression.
Expr *TaskgroupReductionRef = nullptr;
llvm::DenseSet<QualType> MappedClassesQualTypes;
+ SmallVector<Expr *, 4> InnerUsedAllocators;
+ llvm::DenseSet<CanonicalDeclPtr<Decl>> ImplicitTaskFirstprivates;
/// List of globals marked as declare target link in this target region
/// (isOpenMPTargetExecutionDirective(Directive) == true).
llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
+ /// List of decls used in inclusive/exclusive clauses of the scan directive.
+ llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
+ llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind>
+ UsesAllocatorsDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -263,11 +289,18 @@ private:
SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
/// omp_allocator_handle_t type.
QualType OMPAllocatorHandleT;
+ /// omp_depend_t type.
+ QualType OMPDependT;
+ /// omp_event_handle_t type.
+ QualType OMPEventHandleT;
+ /// omp_alloctrait_t type.
+ QualType OMPAlloctraitT;
/// Expression for the predefined allocators.
Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = {
nullptr};
/// Vector of previously encountered target directives
SmallVector<SourceLocation, 2> TargetLocations;
+ SourceLocation AtomicLocation;
public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
@@ -276,6 +309,10 @@ public:
void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; }
/// Gets omp_allocator_handle_t type.
QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; }
+ /// Sets omp_alloctrait_t type.
+ void setOMPAlloctraitT(QualType Ty) { OMPAlloctraitT = Ty; }
+ /// Gets omp_alloctrait_t type.
+ QualType getOMPAlloctraitT() const { return OMPAlloctraitT; }
/// Sets the given default allocator.
void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
Expr *Allocator) {
@@ -285,6 +322,15 @@ public:
Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const {
return OMPPredefinedAllocators[AllocatorKind];
}
+ /// Sets omp_depend_t type.
+ void setOMPDependT(QualType Ty) { OMPDependT = Ty; }
+ /// Gets omp_depend_t type.
+ QualType getOMPDependT() const { return OMPDependT; }
+
+ /// Sets omp_event_handle_t type.
+ void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; }
+ /// Gets omp_event_handle_t type.
+ QualType getOMPEventHandleT() const { return OMPEventHandleT; }
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
OpenMPClauseKind getClauseParsingMode() const {
@@ -439,13 +485,32 @@ public:
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const;
+ /// Check if the specified variable is a loop control variable for
+ /// current region.
+ /// \return The index of the loop control variable in the list of associated
+ /// for-loops (from outer to inner).
+ const LCDeclInfo isLoopControlVariable(const ValueDecl *D,
+ unsigned Level) const;
/// Get the loop control variable for the I-th loop (or nullptr) in
/// parent directive.
const ValueDecl *getParentLoopControlVariable(unsigned I) const;
+ /// Marks the specified decl \p D as used in scan directive.
+ void markDeclAsUsedInScanDirective(ValueDecl *D) {
+ if (SharingMapTy *Stack = getSecondOnStackOrNull())
+ Stack->UsedInScanDirective.insert(D);
+ }
+
+ /// Checks if the specified declaration was used in the inner scan directive.
+ bool isUsedInScanDirective(ValueDecl *D) const {
+ if (const SharingMapTy *Stack = getTopOfStackOrNull())
+ return Stack->UsedInScanDirective.count(D) > 0;
+ return false;
+ }
+
/// Adds explicit data sharing attribute to the specified declaration.
void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
- DeclRefExpr *PrivateCopy = nullptr);
+ DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0);
/// Adds additional information for the reduction items with the reduction id
/// represented as an operator.
@@ -467,11 +532,15 @@ public:
getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
const Expr *&ReductionRef,
Expr *&TaskgroupDescriptor) const;
- /// Return reduction reference expression for the current taskgroup.
+ /// Return reduction reference expression for the current taskgroup or
+ /// parallel/worksharing directives with task reductions.
Expr *getTaskgroupReductionRef() const {
- assert(getTopOfStack().Directive == OMPD_taskgroup &&
- "taskgroup reference expression requested for non taskgroup "
- "directive.");
+ assert((getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
+ "taskgroup reference expression requested for non taskgroup or "
+ "parallel/worksharing directive.");
return getTopOfStack().TaskgroupReductionRef;
}
/// Checks if the given \p VD declaration is actually a taskgroup reduction
@@ -487,6 +556,8 @@ public:
const DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
/// Returns data-sharing attributes for the specified declaration.
const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const;
+ /// Returns data-sharing attributes for the specified declaration.
+ const DSAVarData getImplicitDSA(ValueDecl *D, unsigned Level) const;
/// Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any directive which matches \a DPred
/// predicate.
@@ -552,7 +623,7 @@ public:
/// Checks if the defined 'requires' directive has specified type of clause.
template <typename ClauseType>
- bool hasRequiresDeclWithClause() {
+ bool hasRequiresDeclWithClause() const {
return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) {
return llvm::any_of(D->clauselists(), [](const OMPClause *C) {
return isa<ClauseType>(C);
@@ -587,6 +658,18 @@ public:
TargetLocations.push_back(LocStart);
}
+ /// Add location for the first encountered atomicc directive.
+ void addAtomicDirectiveLoc(SourceLocation Loc) {
+ if (AtomicLocation.isInvalid())
+ AtomicLocation = Loc;
+ }
+
+ /// Returns the location of the first encountered atomic directive in the
+ /// module.
+ SourceLocation getAtomicDirectiveLoc() const {
+ return AtomicLocation;
+ }
+
// Return previously encountered target region locations.
ArrayRef<SourceLocation> getEncounteredTargetLocs() const {
return TargetLocations;
@@ -602,6 +685,11 @@ public:
getTopOfStack().DefaultAttr = DSA_shared;
getTopOfStack().DefaultAttrLoc = Loc;
}
+ /// Set default data sharing attribute to firstprivate.
+ void setDefaultDSAFirstPrivate(SourceLocation Loc) {
+ getTopOfStack().DefaultAttr = DSA_firstprivate;
+ getTopOfStack().DefaultAttrLoc = Loc;
+ }
/// Set default data mapping attribute to Modifier:Kind
void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M,
OpenMPDefaultmapClauseKind Kind,
@@ -612,10 +700,24 @@ public:
}
/// Check whether the implicit-behavior has been set in defaultmap
bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) {
+ if (VariableCategory == OMPC_DEFAULTMAP_unknown)
+ return getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_aggregate]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
+ getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_scalar]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
+ getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_pointer]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown;
return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior !=
OMPC_DEFAULTMAP_MODIFIER_unknown;
}
+ DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const {
+ return getStackSize() <= Level ? DSA_unspecified
+ : getStackElemAtLevel(Level).DefaultAttr;
+ }
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
: getTopOfStack().DefaultAttr;
@@ -738,6 +840,37 @@ public:
return Top ? Top->CancelRegion : false;
}
+ /// Mark that parent region already has scan directive.
+ void setParentHasScanDirective(SourceLocation Loc) {
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->PrevScanLocation = Loc;
+ }
+ /// Return true if current region has inner cancel construct.
+ bool doesParentHasScanDirective() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevScanLocation.isValid() : false;
+ }
+ /// Return true if current region has inner cancel construct.
+ SourceLocation getParentScanDirectiveLoc() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevScanLocation : SourceLocation();
+ }
+ /// Mark that parent region already has ordered directive.
+ void setParentHasOrderedDirective(SourceLocation Loc) {
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->PrevOrderedLocation = Loc;
+ }
+ /// Return true if current region has inner ordered construct.
+ bool doesParentHasOrderedDirective() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevOrderedLocation.isValid() : false;
+ }
+ /// Returns the location of the previously specified ordered directive.
+ SourceLocation getParentOrderedDirectiveLoc() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevOrderedLocation : SourceLocation();
+ }
+
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
getTopOfStack().AssociatedLoops = Val;
@@ -899,6 +1032,46 @@ public:
"Expected target executable directive.");
return getTopOfStack().DeclareTargetLinkVarDecls;
}
+
+ /// Adds list of allocators expressions.
+ void addInnerAllocatorExpr(Expr *E) {
+ getTopOfStack().InnerUsedAllocators.push_back(E);
+ }
+ /// Return list of used allocators.
+ ArrayRef<Expr *> getInnerAllocators() const {
+ return getTopOfStack().InnerUsedAllocators;
+ }
+ /// Marks the declaration as implicitly firstprivate nin the task-based
+ /// regions.
+ void addImplicitTaskFirstprivate(unsigned Level, Decl *D) {
+ getStackElemAtLevel(Level).ImplicitTaskFirstprivates.insert(D);
+ }
+ /// Checks if the decl is implicitly firstprivate in the task-based region.
+ bool isImplicitTaskFirstprivate(Decl *D) const {
+ return getTopOfStack().ImplicitTaskFirstprivates.count(D) > 0;
+ }
+
+ /// Marks decl as used in uses_allocators clause as the allocator.
+ void addUsesAllocatorsDecl(const Decl *D, UsesAllocatorsDeclKind Kind) {
+ getTopOfStack().UsesAllocatorsDecls.try_emplace(D, Kind);
+ }
+ /// Checks if specified decl is used in uses allocator clause as the
+ /// allocator.
+ 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 I->getSecond();
+ }
+ 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 I->getSecond();
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -1001,6 +1174,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
DVar.PrivateCopy = Data.PrivateCopy;
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ DVar.Modifier = Data.Modifier;
return DVar;
}
@@ -1015,6 +1189,15 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
return DVar;
case DSA_none:
return DVar;
+ case DSA_firstprivate:
+ if (VD->getStorageDuration() == SD_Static &&
+ VD->getDeclContext()->isFileContext()) {
+ DVar.CKind = OMPC_unknown;
+ } else {
+ DVar.CKind = OMPC_firstprivate;
+ }
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ return DVar;
case DSA_unspecified:
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.2]
@@ -1113,6 +1296,19 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
}
const DSAStackTy::LCDeclInfo
+DSAStackTy::isLoopControlVariable(const ValueDecl *D, unsigned Level) const {
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ D = getCanonicalDecl(D);
+ for (unsigned I = Level + 1; I > 0; --I) {
+ const SharingMapTy &StackElem = getStackElemAtLevel(I - 1);
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ }
+ return {0, nullptr};
+}
+
+const DSAStackTy::LCDeclInfo
DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
const SharingMapTy *Parent = getSecondOnStackOrNull();
assert(Parent && "Data-sharing attributes stack is empty");
@@ -1135,19 +1331,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
}
void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
- DeclRefExpr *PrivateCopy) {
+ DeclRefExpr *PrivateCopy, unsigned Modifier) {
D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
DSAInfo &Data = Threadprivates[D];
Data.Attributes = A;
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
+ Data.Modifier = Modifier;
} else {
DSAInfo &Data = getTopOfStack().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
(isLoopControlVariable(D).first && A == OMPC_private));
+ Data.Modifier = Modifier;
if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
Data.RefExpr.setInt(/*IntVal=*/true);
return;
@@ -1159,6 +1357,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
+ Data.Modifier = Modifier;
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -1207,7 +1406,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- getTopOfStack().Directive == OMPD_taskgroup &&
+ (getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(BOK, SR);
@@ -1230,7 +1432,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- getTopOfStack().Directive == OMPD_taskgroup &&
+ (getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(ReductionRef, SR);
@@ -1251,7 +1456,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
- if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ if (Data.Attributes != OMPC_reduction ||
+ Data.Modifier != OMPC_REDUCTION_task)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
@@ -1263,8 +1469,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
- return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
- Data.PrivateCopy, I->DefaultAttrLoc);
+ return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task);
}
return DSAVarData();
}
@@ -1276,7 +1482,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
- if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
+ if (Data.Attributes != OMPC_reduction ||
+ Data.Modifier != OMPC_REDUCTION_task)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
@@ -1288,8 +1495,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
- return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
- Data.PrivateCopy, I->DefaultAttrLoc);
+ return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task);
}
return DSAVarData();
}
@@ -1364,6 +1571,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
if (TI != Threadprivates.end()) {
DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
+ DVar.Modifier = TI->getSecond().Modifier;
return DVar;
}
if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
@@ -1447,15 +1655,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
const_iterator EndI = end();
if (FromParent && I != EndI)
++I;
- auto It = I->SharingMap.find(D);
- if (It != I->SharingMap.end()) {
- const DSAInfo &Data = It->getSecond();
- DVar.RefExpr = Data.RefExpr.getPointer();
- DVar.PrivateCopy = Data.PrivateCopy;
- DVar.CKind = Data.Attributes;
- DVar.ImplicitDSALoc = I->DefaultAttrLoc;
- DVar.DKind = I->Directive;
- return DVar;
+ if (I != EndI) {
+ auto It = I->SharingMap.find(D);
+ if (It != I->SharingMap.end()) {
+ const DSAInfo &Data = It->getSecond();
+ DVar.RefExpr = Data.RefExpr.getPointer();
+ DVar.PrivateCopy = Data.PrivateCopy;
+ DVar.CKind = Data.Attributes;
+ DVar.ImplicitDSALoc = I->DefaultAttrLoc;
+ DVar.DKind = I->Directive;
+ DVar.Modifier = Data.Modifier;
+ return DVar;
+ }
}
DVar.CKind = OMPC_shared;
@@ -1493,6 +1704,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
const_iterator EndI = end();
if (FromParent && I != EndI)
++I;
+ if (I == EndI)
+ return DVar;
auto It = I->SharingMap.find(D);
if (It != I->SharingMap.end()) {
const DSAInfo &Data = It->getSecond();
@@ -1501,6 +1714,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
DVar.DKind = I->Directive;
+ DVar.Modifier = Data.Modifier;
}
return DVar;
@@ -1520,6 +1734,15 @@ const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
return getDSA(StartI, D);
}
+const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
+ unsigned Level) const {
+ if (getStackSize() <= Level)
+ return DSAVarData();
+ D = getCanonicalDecl(D);
+ const_iterator StartI = std::next(begin(), getStackSize() - 1 - Level);
+ return getDSA(StartI, D);
+}
+
const DSAStackTy::DSAVarData
DSAStackTy::hasDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
@@ -1640,23 +1863,28 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
- FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+
+ FunctionDecl *FD = getCurFunctionDecl();
DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
- switch (FES) {
- case FunctionEmissionStatus::Emitted:
- Kind = DeviceDiagBuilder::K_Immediate;
- break;
- case FunctionEmissionStatus::Unknown:
- Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred
- : DeviceDiagBuilder::K_Immediate;
- break;
- case FunctionEmissionStatus::TemplateDiscarded:
- case FunctionEmissionStatus::OMPDiscarded:
- Kind = DeviceDiagBuilder::K_Nop;
- break;
- case FunctionEmissionStatus::CUDADiscarded:
- llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
- break;
+ if (FD) {
+ FunctionEmissionStatus FES = getEmissionStatus(FD);
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = isOpenMPDeviceDelayedContext(*this)
+ ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ case FunctionEmissionStatus::CUDADiscarded:
+ llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
+ break;
+ }
}
return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
@@ -1685,107 +1913,6 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
}
-void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
- bool CheckForDelayedContext) {
- assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
- "Expected OpenMP device compilation.");
- assert(Callee && "Callee may not be null.");
- Callee = Callee->getMostRecentDecl();
- FunctionDecl *Caller = getCurFunctionDecl();
-
- // host only function are not available on the device.
- if (Caller) {
- FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
- FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
- assert(CallerS != FunctionEmissionStatus::CUDADiscarded &&
- CalleeS != FunctionEmissionStatus::CUDADiscarded &&
- "CUDADiscarded unexpected in OpenMP device function check");
- if ((CallerS == FunctionEmissionStatus::Emitted ||
- (!isOpenMPDeviceDelayedContext(*this) &&
- CallerS == FunctionEmissionStatus::Unknown)) &&
- CalleeS == FunctionEmissionStatus::OMPDiscarded) {
- StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_host);
- Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
- Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << HostDevTy;
- return;
- }
- }
- // If the caller is known-emitted, mark the callee as known-emitted.
- // Otherwise, mark the call in our call graph so we can traverse it later.
- if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) ||
- (!Caller && !CheckForDelayedContext) ||
- (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
- markKnownEmitted(*this, Caller, Callee, Loc,
- [CheckForDelayedContext](Sema &S, FunctionDecl *FD) {
- return CheckForDelayedContext &&
- S.getEmissionStatus(FD) ==
- FunctionEmissionStatus::Emitted;
- });
- else if (Caller)
- DeviceCallGraph[Caller].insert({Callee, Loc});
-}
-
-void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
- bool CheckCaller) {
- assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
- "Expected OpenMP host compilation.");
- assert(Callee && "Callee may not be null.");
- Callee = Callee->getMostRecentDecl();
- FunctionDecl *Caller = getCurFunctionDecl();
-
- // device only function are not available on the host.
- if (Caller) {
- FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
- FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
- assert(
- (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded &&
- CalleeS != FunctionEmissionStatus::CUDADiscarded)) &&
- "CUDADiscarded unexpected in OpenMP host function check");
- if (CallerS == FunctionEmissionStatus::Emitted &&
- CalleeS == FunctionEmissionStatus::OMPDiscarded) {
- StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
- Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
- Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << NoHostDevTy;
- return;
- }
- }
- // If the caller is known-emitted, mark the callee as known-emitted.
- // Otherwise, mark the call in our call graph so we can traverse it later.
- if (!shouldIgnoreInHostDeviceCheck(Callee)) {
- if ((!CheckCaller && !Caller) ||
- (Caller &&
- getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
- markKnownEmitted(
- *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) {
- return CheckCaller &&
- S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
- });
- else if (Caller)
- DeviceCallGraph[Caller].insert({Callee, Loc});
- }
-}
-
-void Sema::checkOpenMPDeviceExpr(const Expr *E) {
- assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
- "OpenMP device compilation mode is expected.");
- QualType Ty = E->getType();
- if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) ||
- ((Ty->isFloat128Type() ||
- (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) &&
- !Context.getTargetInfo().hasFloat128Type()) ||
- (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
- !Context.getTargetInfo().hasInt128Type()))
- targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type)
- << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
- << Context.getTargetInfo().getTriple().str() << E->getSourceRange();
-}
-
static OpenMPDefaultmapClauseKind
getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) {
if (LO.OpenMP <= 45) {
@@ -1901,7 +2028,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) ||
isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) ||
- isa<MemberExpr>(EI->getAssociatedExpression())) {
+ isa<MemberExpr>(EI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(EI->getAssociatedExpression())) {
IsVariableAssociatedWithSection = true;
// There is nothing more we need to know about this variable.
return true;
@@ -1935,14 +2063,23 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
((IsVariableUsedInMapClause &&
DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
OMPD_target) ||
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true)) &&
+ !(DSAStack->hasExplicitDSA(
+ D,
+ [](OpenMPClauseKind K) -> bool {
+ return K == OMPC_firstprivate;
+ },
+ Level, /*NotLastprivate=*/true) ||
+ DSAStack->isUsesAllocatorsDecl(Level, D))) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
- !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue());
+ !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()) &&
+ // If the variable is implicitly firstprivate and scalar - capture by
+ // copy
+ !(DSAStack->getDefaultDSA() == DSA_firstprivate &&
+ !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K != OMPC_unknown; }, Level) &&
+ !DSAStack->isLoopControlVariable(D, Level).first);
}
// When passing data by copy, we need to make sure it fits the uintptr size
@@ -2010,7 +2147,23 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
//
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return nullptr;
- return VD;
+ CapturedRegionScopeInfo *CSI = nullptr;
+ for (FunctionScopeInfo *FSI : llvm::drop_begin(
+ llvm::reverse(FunctionScopes),
+ CheckScopeInfo ? (FunctionScopes.size() - (StopAt + 1)) : 0)) {
+ if (!isa<CapturingScopeInfo>(FSI))
+ return nullptr;
+ if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI))
+ if (RSI->CapRegionKind == CR_OpenMP) {
+ CSI = RSI;
+ break;
+ }
+ }
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions,
+ DSAStack->getDirective(CSI->OpenMPLevel));
+ if (Regions[CSI->OpenMPCaptureLevel] != OMPD_task)
+ return VD;
}
}
@@ -2039,20 +2192,27 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) ||
(VD && DSAStack->isForceVarCapturing()))
return VD ? VD : Info.second;
- DSAStackTy::DSAVarData DVarPrivate =
+ DSAStackTy::DSAVarData DVarTop =
DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
- if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
- return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
+ if (DVarTop.CKind != OMPC_unknown && isOpenMPPrivate(DVarTop.CKind))
+ return VD ? VD : cast<VarDecl>(DVarTop.PrivateCopy->getDecl());
// Threadprivate variables must not be captured.
- if (isOpenMPThreadPrivate(DVarPrivate.CKind))
+ if (isOpenMPThreadPrivate(DVarTop.CKind))
return nullptr;
// The variable is not private or it is the variable in the directive with
// default(none) clause and not used in any clause.
- DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate,
- [](OpenMPDirectiveKind) { return true; },
- DSAStack->isClauseParsingMode());
+ DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
+ D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; },
+ DSAStack->isClauseParsingMode());
+ // Global shared must not be captured.
+ if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown &&
+ ((DSAStack->getDefaultDSA() != DSA_none &&
+ DSAStack->getDefaultDSA() != DSA_firstprivate) ||
+ DVarTop.CKind == OMPC_shared))
+ return nullptr;
if (DVarPrivate.CKind != OMPC_unknown ||
- (VD && DSAStack->getDefaultDSA() == DSA_none))
+ (VD && (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate)))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
return nullptr;
@@ -2060,9 +2220,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
unsigned Level) const {
- SmallVector<OpenMPDirectiveKind, 4> Regions;
- getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
- FunctionScopesIndex -= Regions.size();
+ FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level));
}
void Sema::startOpenMPLoop() {
@@ -2079,39 +2237,77 @@ void Sema::startOpenMPCXXRangeFor() {
}
}
-bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
+OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level,
+ unsigned CapLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ if (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) { return isOpenMPTaskingDirective(K); },
+ Level)) {
+ bool IsTriviallyCopyable =
+ D->getType().getNonReferenceType().isTriviallyCopyableType(Context);
+ OpenMPDirectiveKind DKind = DSAStack->getDirective(Level);
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DKind);
+ if (isOpenMPTaskingDirective(CaptureRegions[CapLevel]) &&
+ (IsTriviallyCopyable ||
+ !isOpenMPTaskLoopDirective(CaptureRegions[CapLevel]))) {
+ if (DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true))
+ return OMPC_firstprivate;
+ DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level);
+ if (DVar.CKind != OMPC_shared &&
+ !DSAStack->isLoopControlVariable(D, Level).first && !DVar.RefExpr) {
+ DSAStack->addImplicitTaskFirstprivate(Level, D);
+ return OMPC_firstprivate;
+ }
+ }
+ }
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
if (DSAStack->getAssociatedLoops() > 0 &&
!DSAStack->isLoopStarted()) {
DSAStack->resetPossibleLoopCounter(D);
DSAStack->loopStart();
- return true;
+ return OMPC_private;
}
if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() ||
DSAStack->isLoopControlVariable(D).first) &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K != OMPC_private; }, Level) &&
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
- return true;
+ return OMPC_private;
}
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) &&
DSAStack->isForceVarCapturing() &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level))
- return true;
- }
- return DSAStack->hasExplicitDSA(
- D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
- (DSAStack->isClauseParsingMode() &&
- DSAStack->getClauseParsingMode() == OMPC_private) ||
- // Consider taskgroup reduction descriptor variable a private to avoid
- // possible capture in the region.
- (DSAStack->hasExplicitDirective(
- [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; },
- Level) &&
- DSAStack->isTaskgroupReductionRef(D, Level));
+ return OMPC_private;
+ }
+ // User-defined allocators are private since they must be defined in the
+ // context of target region.
+ if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level) &&
+ DSAStack->isUsesAllocatorsDecl(Level, D).getValueOr(
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
+ DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator)
+ return OMPC_private;
+ return (DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
+ (DSAStack->isClauseParsingMode() &&
+ DSAStack->getClauseParsingMode() == OMPC_private) ||
+ // Consider taskgroup reduction descriptor variable a private
+ // to avoid possible capture in the region.
+ (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) {
+ return K == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K)) &&
+ !isOpenMPSimdDirective(K));
+ },
+ Level) &&
+ DSAStack->isTaskgroupReductionRef(D, Level)))
+ ? OMPC_private
+ : OMPC_unknown;
}
void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
@@ -2148,68 +2344,101 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
}
}
if (OMPC != OMPC_unknown)
- FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC));
+ FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, unsigned(OMPC)));
}
-bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
- unsigned Level) const {
+bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level,
+ unsigned CaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
// Return true if the current level is no longer enclosed in a target region.
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
const auto *VD = dyn_cast<VarDecl>(D);
return VD && !VD->hasLocalStorage() &&
DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
- Level);
+ Level) &&
+ Regions[CaptureLevel] != OMPD_task;
+}
+
+bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level,
+ unsigned CaptureLevel) const {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ // Return true if the current level is no longer enclosed in a target region.
+
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->hasLocalStorage()) {
+ DSAStackTy::DSAVarData TopDVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ unsigned NumLevels =
+ getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+ if (Level == 0)
+ return (NumLevels == CaptureLevel + 1) && TopDVar.CKind != OMPC_shared;
+ DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level - 1);
+ return DVar.CKind != OMPC_shared ||
+ isOpenMPGlobalCapturedDecl(
+ D, Level - 1,
+ getOpenMPCaptureLevels(DSAStack->getDirective(Level - 1)) - 1);
+ }
+ }
+ return true;
}
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
-void Sema::finalizeOpenMPDelayedAnalysis() {
+void Sema::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc,
+ OMPTraitInfo &TI) {
+ if (!OMPDeclareVariantScopes.empty()) {
+ Diag(Loc, diag::warn_nested_declare_variant);
+ return;
+ }
+ OMPDeclareVariantScopes.push_back(OMPDeclareVariantScope(TI));
+}
+
+void Sema::ActOnOpenMPEndDeclareVariant() {
+ assert(isInOpenMPDeclareVariantScope() &&
+ "Not in OpenMP declare variant scope!");
+
+ OMPDeclareVariantScopes.pop_back();
+}
+
+void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
+ const FunctionDecl *Callee,
+ SourceLocation Loc) {
assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
- // Diagnose implicit declare target functions and their callees.
- for (const auto &CallerCallees : DeviceCallGraph) {
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(
- CallerCallees.getFirst()->getMostRecentDecl());
- // Ignore host functions during device analyzis.
- if (LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
- continue;
- // Ignore nohost functions during host analyzis.
- if (!LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
- continue;
- for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation>
- &Callee : CallerCallees.getSecond()) {
- const FunctionDecl *FD = Callee.first->getMostRecentDecl();
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- if (LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
- // Diagnose host function called during device codegen.
- StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_host);
- Diag(Callee.second, diag::err_omp_wrong_device_function_call)
- << HostDevTy << 0;
- Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << HostDevTy;
- continue;
- }
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl());
+ // Ignore host functions during device analyzis.
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return;
+ // Ignore nohost functions during host analyzis.
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ return;
+ const FunctionDecl *FD = Callee->getMostRecentDecl();
+ DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
+ // Diagnose host function called during device codegen.
+ StringRef HostDevTy =
+ getOpenMPSimpleClauseTypeName(OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ return;
+ }
if (!LangOpts.OpenMPIsDevice && DevTy &&
*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
// Diagnose nohost function called during host codegen.
StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
- Diag(Callee.second, diag::err_omp_wrong_device_function_call)
- << NoHostDevTy << 1;
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
diag::note_omp_marked_device_type_here)
<< NoHostDevTy;
- continue;
}
- }
- }
}
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
@@ -2228,14 +2457,86 @@ void Sema::EndOpenMPClause() {
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
}
-static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
- ArrayRef<OMPClause *> Clauses);
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
SourceRange &ERange, bool AllowArraySection = false);
+
+/// Check consistency of the reduction clauses.
+static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses) {
+ bool InscanFound = false;
+ SourceLocation InscanLoc;
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions.
+ // A reduction clause without the inscan reduction-modifier may not appear on
+ // a construct on which a reduction clause with the inscan reduction-modifier
+ // appears.
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() != OMPC_reduction)
+ continue;
+ auto *RC = cast<OMPReductionClause>(C);
+ if (RC->getModifier() == OMPC_REDUCTION_inscan) {
+ InscanFound = true;
+ InscanLoc = RC->getModifierLoc();
+ continue;
+ }
+ if (RC->getModifier() == OMPC_REDUCTION_task) {
+ // OpenMP 5.0, 2.19.5.4 reduction Clause.
+ // A reduction clause with the task reduction-modifier may only appear on
+ // a parallel construct, a worksharing construct or a combined or
+ // composite construct for which any of the aforementioned constructs is a
+ // constituent construct and simd or loop are not constituent constructs.
+ OpenMPDirectiveKind CurDir = Stack->getCurrentDirective();
+ if (!(isOpenMPParallelDirective(CurDir) ||
+ isOpenMPWorksharingDirective(CurDir)) ||
+ isOpenMPSimdDirective(CurDir))
+ S.Diag(RC->getModifierLoc(),
+ diag::err_omp_reduction_task_not_parallel_or_worksharing);
+ continue;
+ }
+ }
+ if (InscanFound) {
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() != OMPC_reduction)
+ continue;
+ auto *RC = cast<OMPReductionClause>(C);
+ if (RC->getModifier() != OMPC_REDUCTION_inscan) {
+ S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown
+ ? RC->getBeginLoc()
+ : RC->getModifierLoc(),
+ diag::err_omp_inscan_reduction_expected);
+ S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction);
+ continue;
+ }
+ for (Expr *Ref : RC->varlists()) {
+ assert(Ref && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = Ref;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+ if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) {
+ S.Diag(Ref->getExprLoc(),
+ diag::err_omp_reduction_not_inclusive_exclusive)
+ << Ref->getSourceRange();
+ }
+ }
+ }
+ }
+}
+
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses);
static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
bool WithInit);
+static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
+ const ValueDecl *D,
+ const DSAStackTy::DSAVarData &DVar,
+ bool IsLoopIterVar = false);
+
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a lastprivate
@@ -2305,10 +2606,56 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
Clause->setPrivateRefs(PrivateRefs);
continue;
}
+ if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I);
+ auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts());
+ if (!DRE)
+ continue;
+ ValueDecl *VD = DRE->getDecl();
+ if (!VD || !isa<VarDecl>(VD))
+ continue;
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ // OpenMP [2.12.5, target Construct]
+ // Memory allocators that appear in a uses_allocators clause cannot
+ // appear in other data-sharing attribute clauses or data-mapping
+ // attribute clauses in the same construct.
+ Expr *MapExpr = nullptr;
+ if (DVar.RefExpr ||
+ DSAStack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [VD, &MapExpr](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents,
+ OpenMPClauseKind C) {
+ auto MI = MapExprComponents.rbegin();
+ auto ME = MapExprComponents.rend();
+ if (MI != ME &&
+ MI->getAssociatedDeclaration()->getCanonicalDecl() ==
+ VD->getCanonicalDecl()) {
+ MapExpr = MI->getAssociatedExpression();
+ return true;
+ }
+ return false;
+ })) {
+ Diag(D.Allocator->getExprLoc(),
+ diag::err_omp_allocator_used_in_clauses)
+ << D.Allocator->getSourceRange();
+ if (DVar.RefExpr)
+ reportOriginalDsa(*this, DSAStack, VD, DVar);
+ else
+ Diag(MapExpr->getExprLoc(), diag::note_used_here)
+ << MapExpr->getSourceRange();
+ }
+ }
+ continue;
+ }
}
// Check allocate clauses.
if (!CurContext->isDependentContext())
checkAllocateClauses(*this, DSAStack, D->clauses());
+ checkReductionClauses(*this, DSAStack, D->clauses());
}
DSAStack->pop();
@@ -2618,15 +2965,14 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
static OMPAllocateDeclAttr::AllocatorTypeTy
getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
if (!Allocator)
- return OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ return OMPAllocateDeclAttr::OMPNullMemAlloc;
if (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
Allocator->isInstantiationDependent() ||
Allocator->containsUnexpandedParameterPack())
return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
const Expr *AE = Allocator->IgnoreParenImpCasts();
- for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
- I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ 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;
@@ -2799,18 +3145,26 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
/// current compilation unit.
ArrayRef<SourceLocation> TargetLocations =
DSAStack->getEncounteredTargetLocs();
- if (!TargetLocations.empty()) {
+ SourceLocation AtomicLoc = DSAStack->getAtomicDirectiveLoc();
+ if (!TargetLocations.empty() || !AtomicLoc.isInvalid()) {
for (const OMPClause *CNew : ClauseList) {
// Check if any of the requires clauses affect target regions.
if (isa<OMPUnifiedSharedMemoryClause>(CNew) ||
isa<OMPUnifiedAddressClause>(CNew) ||
isa<OMPReverseOffloadClause>(CNew) ||
isa<OMPDynamicAllocatorsClause>(CNew)) {
- Diag(Loc, diag::err_omp_target_before_requires)
- << getOpenMPClauseName(CNew->getClauseKind());
+ Diag(Loc, diag::err_omp_directive_before_requires)
+ << "target" << getOpenMPClauseName(CNew->getClauseKind());
for (SourceLocation TargetLoc : TargetLocations) {
- Diag(TargetLoc, diag::note_omp_requires_encountered_target);
+ Diag(TargetLoc, diag::note_omp_requires_encountered_directive)
+ << "target";
}
+ } else if (!AtomicLoc.isInvalid() &&
+ isa<OMPAtomicDefaultMemOrderClause>(CNew)) {
+ Diag(Loc, diag::err_omp_directive_before_requires)
+ << "atomic" << getOpenMPClauseName(CNew->getClauseKind());
+ Diag(AtomicLoc, diag::note_omp_requires_encountered_directive)
+ << "atomic";
}
}
}
@@ -2824,7 +3178,7 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
const ValueDecl *D,
const DSAStackTy::DSAVarData &DVar,
- bool IsLoopIterVar = false) {
+ bool IsLoopIterVar) {
if (DVar.RefExpr) {
SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
@@ -2944,6 +3298,16 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
Visit(S->getInnermostCapturedStmt()->getCapturedStmt());
TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
}
+ // In tasks firstprivates are not captured anymore, need to analyze them
+ // explicitly.
+ if (isOpenMPTaskingDirective(S->getDirectiveKind()) &&
+ !isOpenMPTaskLoopDirective(S->getDirectiveKind())) {
+ for (OMPClause *C : S->clauses())
+ if (auto *FC = dyn_cast<OMPFirstprivateClause>(C)) {
+ for (Expr *Ref : FC->varlists())
+ Visit(Ref);
+ }
+ }
}
public:
@@ -2966,7 +3330,11 @@ public:
return;
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) &&
+ !Stack->isImplicitTaskFirstprivate(VD))
+ return;
+ // Skip allocators in uses_allocators clauses.
+ if (Stack->isUsesAllocatorsDecl(VD).hasValue())
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
@@ -2979,7 +3347,8 @@ public:
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
- !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
+ !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) &&
+ !Stack->isImplicitTaskFirstprivate(VD))
return;
SourceLocation ELoc = E->getExprLoc();
@@ -2988,10 +3357,19 @@ public:
// in the construct, and does not have a predetermined data-sharing
// attribute, must have its data-sharing attribute explicitly determined
// by being listed in a data-sharing attribute clause.
- if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
+ if (DVar.CKind == OMPC_unknown &&
+ (Stack->getDefaultDSA() == DSA_none ||
+ Stack->getDefaultDSA() == DSA_firstprivate) &&
isImplicitOrExplicitTaskingRegion(DKind) &&
VarsWithInheritedDSA.count(VD) == 0) {
- VarsWithInheritedDSA[VD] = E;
+ bool InheritedDSA = Stack->getDefaultDSA() == DSA_none;
+ if (!InheritedDSA && Stack->getDefaultDSA() == DSA_firstprivate) {
+ DSAStackTy::DSAVarData DVar =
+ Stack->getImplicitDSA(VD, /*FromParent=*/false);
+ InheritedDSA = DVar.CKind == OMPC_unknown;
+ }
+ if (InheritedDSA)
+ VarsWithInheritedDSA[VD] = E;
return;
}
@@ -3036,7 +3414,7 @@ public:
StackComponents,
OpenMPClauseKind) {
// Variable is used if it has been marked as an array, array
- // section or the variable iself.
+ // section, array shaping or the variable iself.
return StackComponents.size() == 1 ||
std::all_of(
std::next(StackComponents.rbegin()),
@@ -3047,6 +3425,8 @@ public:
nullptr &&
(isa<OMPArraySectionExpr>(
MC.getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(
+ MC.getAssociatedExpression()) ||
isa<ArraySubscriptExpr>(
MC.getAssociatedExpression()));
});
@@ -3091,7 +3471,9 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ if (((isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared) ||
+ (Stack->getDefaultDSA() == DSA_firstprivate &&
+ DVar.CKind == OMPC_firstprivate && !DVar.RefExpr)) &&
!Stack->isLoopControlVariable(VD).first) {
ImplicitFirstprivate.push_back(E);
return;
@@ -3112,7 +3494,7 @@ public:
return;
auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
- if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParens())) {
+ if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParenCasts())) {
if (!FD)
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false);
@@ -3204,8 +3586,10 @@ public:
// Do both expressions have the same kind?
if (CCI->getAssociatedExpression()->getStmtClass() !=
SC.getAssociatedExpression()->getStmtClass())
- if (!(isa<OMPArraySectionExpr>(
- SC.getAssociatedExpression()) &&
+ if (!((isa<OMPArraySectionExpr>(
+ SC.getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(
+ SC.getAssociatedExpression())) &&
isa<ArraySubscriptExpr>(
CCI->getAssociatedExpression())))
return false;
@@ -3516,7 +3900,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'parallel'.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel, /*OpenMPCaptureLevel=*/1);
+ ParamsParallel, /*OpenMPCaptureLevel=*/0);
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
@@ -3537,7 +3921,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params, /*OpenMPCaptureLevel=*/2);
+ Params, /*OpenMPCaptureLevel=*/1);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
@@ -3688,6 +4072,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
@@ -3695,8 +4081,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_end_declare_target:
case OMPD_requires:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
}
@@ -3841,6 +4230,36 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
}
}
+static bool checkOrderedOrderSpecified(Sema &S,
+ const ArrayRef<OMPClause *> Clauses) {
+ const OMPOrderedClause *Ordered = nullptr;
+ const OMPOrderClause *Order = nullptr;
+
+ for (const OMPClause *Clause : Clauses) {
+ if (Clause->getClauseKind() == OMPC_ordered)
+ Ordered = cast<OMPOrderedClause>(Clause);
+ else if (Clause->getClauseKind() == OMPC_order) {
+ Order = cast<OMPOrderClause>(Clause);
+ if (Order->getKind() != OMPC_ORDER_concurrent)
+ Order = nullptr;
+ }
+ if (Ordered && Order)
+ break;
+ }
+
+ if (Ordered && Order) {
+ S.Diag(Order->getKindKwLoc(),
+ diag::err_omp_simple_clause_incompatible_with_ordered)
+ << getOpenMPClauseName(OMPC_order)
+ << getOpenMPSimpleClauseTypeName(OMPC_order, OMPC_ORDER_concurrent)
+ << SourceRange(Order->getBeginLoc(), Order->getEndLoc());
+ S.Diag(Ordered->getBeginLoc(), diag::note_omp_ordered_param)
+ << 0 << SourceRange(Ordered->getBeginLoc(), Ordered->getEndLoc());
+ return true;
+ }
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
bool ErrorFound = false;
@@ -3859,7 +4278,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
SmallVector<const OMPClauseWithPreInit *, 4> PICs;
// This is required for proper codegen.
for (OMPClause *Clause : Clauses) {
- if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ if (!LangOpts.OpenMPSimd &&
+ isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
Clause->getClauseKind() == OMPC_in_reduction) {
// Capture taskgroup task_reduction descriptors inside the tasking regions
// with the corresponding in_reduction items.
@@ -3897,6 +4317,9 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
else if (Clause->getClauseKind() == OMPC_linear)
LCs.push_back(cast<OMPLinearClause>(Clause));
}
+ // Capture allocator expressions if used.
+ for (Expr *E : DSAStack->getInnerAllocators())
+ MarkDeclarationsReferencedInExpr(E);
// OpenMP, 2.7.1 Loop Construct, Restrictions
// The nonmonotonic modifier cannot be specified if an ordered clause is
// specified.
@@ -3908,10 +4331,18 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
? SC->getFirstScheduleModifierLoc()
: SC->getSecondScheduleModifierLoc(),
- diag::err_omp_schedule_nonmonotonic_ordered)
+ diag::err_omp_simple_clause_incompatible_with_ordered)
+ << getOpenMPClauseName(OMPC_schedule)
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule,
+ OMPC_SCHEDULE_MODIFIER_nonmonotonic)
<< SourceRange(OC->getBeginLoc(), OC->getEndLoc());
ErrorFound = true;
}
+ // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions.
+ // If an order(concurrent) clause is present, an ordered clause may not appear
+ // on the same directive.
+ if (checkOrderedOrderSpecified(*this, Clauses))
+ ErrorFound = true;
if (!LCs.empty() && OC && OC->getNumForLoops()) {
for (const OMPLinearClause *C : LCs) {
Diag(C->getBeginLoc(), diag::err_omp_linear_ordered)
@@ -3952,6 +4383,21 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
}
+ if (ThisCaptureRegion == OMPD_target) {
+ // Capture allocator traits in the target region. They are used implicitly
+ // and, thus, are not captured by default.
+ for (OMPClause *C : Clauses) {
+ if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End;
+ ++I) {
+ OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I);
+ if (Expr *E = D.AllocatorTraits)
+ MarkDeclarationsReferencedInExpr(E);
+ }
+ continue;
+ }
+ }
+ }
if (++CompletedRegions == CaptureRegions.size())
DSAStack->setBodyComplete();
SR = ActOnCapturedRegionEnd(SR.get());
@@ -3991,12 +4437,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInParallelRegion,
ShouldBeInOrderedRegion,
ShouldBeInTargetRegion,
- ShouldBeInTeamsRegion
+ ShouldBeInTeamsRegion,
+ ShouldBeInLoopSimdRegion,
} Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion) &&
((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
(SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
- CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) {
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic &&
+ CurrentRegion != OMPD_scan))) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
@@ -4041,7 +4489,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
if (ParentRegion == OMPD_unknown &&
!isOpenMPNestingTeamsDirective(CurrentRegion) &&
CurrentRegion != OMPD_cancellation_point &&
- CurrentRegion != OMPD_cancel)
+ CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan)
return false;
if (CurrentRegion == OMPD_cancellation_point ||
CurrentRegion == OMPD_cancel) {
@@ -4066,7 +4514,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ParentRegion == OMPD_distribute_parallel_for ||
ParentRegion == OMPD_teams_distribute_parallel_for ||
ParentRegion == OMPD_target_teams_distribute_parallel_for)) ||
- (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) ||
+ (CancelRegion == OMPD_taskgroup &&
+ (ParentRegion == OMPD_task ||
+ (SemaRef.getLangOpts().OpenMP >= 50 &&
+ (ParentRegion == OMPD_taskloop ||
+ ParentRegion == OMPD_master_taskloop ||
+ ParentRegion == OMPD_parallel_master_taskloop)))) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
ParentRegion == OMPD_parallel_sections)));
@@ -4150,6 +4603,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ParentRegion != OMPD_target);
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
+ } else if (CurrentRegion == OMPD_scan) {
+ // OpenMP [2.16, Nesting of Regions]
+ // If specified, a teams construct must be contained within a target
+ // construct.
+ NestingProhibited =
+ SemaRef.LangOpts.OpenMP < 50 ||
+ (ParentRegion != OMPD_simd && ParentRegion != OMPD_for &&
+ ParentRegion != OMPD_for_simd && ParentRegion != OMPD_parallel_for &&
+ ParentRegion != OMPD_parallel_for_simd);
+ OrphanSeen = ParentRegion == OMPD_unknown;
+ Recommend = ShouldBeInLoopSimdRegion;
}
if (!NestingProhibited &&
!isOpenMPTargetExecutionDirective(CurrentRegion) &&
@@ -4216,7 +4680,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
bool ErrorFound = false;
unsigned NamedModifiersNumber = 0;
llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers;
- FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1);
+ FoundNameModifiers.resize(llvm::omp::Directive_enumSize + 1);
SmallVector<SourceLocation, 4> NameModifierLoc;
for (const OMPClause *C : Clauses) {
if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) {
@@ -4353,6 +4817,30 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
}
+namespace {
+/// Checks if the allocator is used in uses_allocators clause to be allowed in
+/// target regions.
+class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> {
+ DSAStackTy *S = nullptr;
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ return S->isUsesAllocatorsDecl(E->getDecl())
+ .getValueOr(
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait;
+ }
+ bool VisitStmt(const Stmt *S) {
+ for (const Stmt *Child : S->children()) {
+ if (Child && Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit AllocatorChecker(DSAStackTy *S) : S(S) {}
+};
+} // namespace
+
static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
ArrayRef<OMPClause *> Clauses) {
assert(!S.CurContext->isDependentContext() &&
@@ -4421,6 +4909,22 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
}
for (OMPClause *C : AllocateRange) {
auto *AC = cast<OMPAllocateClause>(C);
+ if (S.getLangOpts().OpenMP >= 50 &&
+ !Stack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>() &&
+ isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ AC->getAllocator()) {
+ Expr *Allocator = AC->getAllocator();
+ // OpenMP, 2.12.5 target Construct
+ // Memory allocators that do not appear in a uses_allocators clause cannot
+ // appear as an allocator in an allocate clause or be used in the target
+ // region unless a requires directive with the dynamic_allocators clause
+ // is present in the same compilation unit.
+ AllocatorChecker Checker(Stack);
+ if (Checker.Visit(Allocator))
+ S.Diag(Allocator->getExprLoc(),
+ diag::err_omp_allocator_not_in_uses_allocators)
+ << Allocator->getSourceRange();
+ }
OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
getAllocatorKind(S, Stack, AC->getAllocator());
// OpenMP, 2.11.4 allocate Clause, Restrictions.
@@ -4513,6 +5017,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (E)
ImplicitFirstprivates.emplace_back(E);
}
+ // OpenMP 5.0, 2.10.1 task Construct
+ // [detach clause]... The event-handle will be considered as if it was
+ // specified on a firstprivate clause.
+ if (auto *DC = dyn_cast<OMPDetachClause>(C))
+ ImplicitFirstprivates.push_back(DC->getEventHandler());
}
if (!ImplicitFirstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
@@ -4648,6 +5157,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
"No associated statement allowed for 'omp flush' directive");
Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
+ case OMPD_depobj:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp depobj' directive");
+ Res = ActOnOpenMPDepobjDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
+ case OMPD_scan:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp scan' directive");
+ Res = ActOnOpenMPScanDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
case OMPD_ordered:
Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
@@ -4848,15 +5367,20 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_simd:
case OMPD_requires:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
ErrorFound = Res.isInvalid() || ErrorFound;
- // Check variables in the clauses if default(none) was specified.
- if (DSAStack->getDefaultDSA() == DSA_none) {
+ // Check variables in the clauses if default(none) or
+ // default(firstprivate) was specified.
+ if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate) {
DSAAttrChecker DSAChecker(DSAStack, *this, nullptr);
for (OMPClause *C : Clauses) {
switch (C->getClauseKind()) {
@@ -4876,6 +5400,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
break;
continue;
case OMPC_schedule:
+ case OMPC_detach:
break;
case OMPC_grainsize:
case OMPC_num_tasks:
@@ -4915,6 +5440,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -4924,11 +5453,19 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
continue;
case OMPC_allocator:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_threadprivate:
case OMPC_uniform:
case OMPC_unknown:
@@ -4939,6 +5476,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ default:
llvm_unreachable("Unexpected clause");
}
for (Stmt *CC : C->children()) {
@@ -4946,14 +5484,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
DSAChecker.Visit(CC);
}
}
- for (auto &P : DSAChecker.getVarsWithInheritedDSA())
+ for (const auto &P : DSAChecker.getVarsWithInheritedDSA())
VarsWithInheritedDSA[P.getFirst()] = P.getSecond();
}
for (const auto &P : VarsWithInheritedDSA) {
if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst()))
continue;
ErrorFound = true;
- if (DSAStack->getDefaultDSA() == DSA_none) {
+ if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate) {
Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
<< P.first << P.second->getSourceRange();
Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
@@ -4973,12 +5512,6 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (ErrorFound)
return StmtError();
- if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) {
- Res.getAs<OMPExecutableDirective>()
- ->getStructuredBlock()
- ->setIsOMPStructuredBlock(true);
- }
-
if (!CurContext->isDependentContext() &&
isOpenMPTargetExecutionDirective(Kind) &&
!(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
@@ -5166,7 +5699,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
- PVD->getOriginalType());
+ PVD->getOriginalType(),
+ /*IsDeclareSimd=*/true);
continue;
}
}
@@ -5186,7 +5720,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
- E->getType());
+ E->getType(), /*IsDeclareSimd=*/true);
continue;
}
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
@@ -5264,9 +5798,170 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
FD->setParams(Params);
}
+Sema::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI)
+ : TI(&TI), NameSuffix(TI.getMangledName()) {}
+
+FunctionDecl *
+Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S,
+ Declarator &D) {
+ IdentifierInfo *BaseII = D.getIdentifier();
+ LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(),
+ LookupOrdinaryName);
+ LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+ QualType FType = TInfo->getType();
+
+ bool IsConstexpr = D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr;
+ bool IsConsteval = D.getDeclSpec().getConstexprSpecifier() == CSK_consteval;
+
+ FunctionDecl *BaseFD = nullptr;
+ for (auto *Candidate : Lookup) {
+ auto *UDecl = dyn_cast<FunctionDecl>(Candidate->getUnderlyingDecl());
+ if (!UDecl)
+ continue;
+
+ // Don't specialize constexpr/consteval functions with
+ // non-constexpr/consteval functions.
+ if (UDecl->isConstexpr() && !IsConstexpr)
+ continue;
+ if (UDecl->isConsteval() && !IsConsteval)
+ continue;
+
+ QualType NewType = Context.mergeFunctionTypes(
+ FType, UDecl->getType(), /* OfBlockPointer */ false,
+ /* Unqualified */ false, /* AllowCXX */ true);
+ if (NewType.isNull())
+ continue;
+
+ // Found a base!
+ BaseFD = UDecl;
+ break;
+ }
+ if (!BaseFD) {
+ BaseFD = cast<FunctionDecl>(ActOnDeclarator(S, D));
+ BaseFD->setImplicit(true);
+ }
+
+ OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
+ std::string MangledName;
+ MangledName += D.getIdentifier()->getName();
+ MangledName += getOpenMPVariantManglingSeparatorStr();
+ MangledName += DVScope.NameSuffix;
+ IdentifierInfo &VariantII = Context.Idents.get(MangledName);
+
+ VariantII.setMangledOpenMPVariantName(true);
+ D.SetIdentifier(&VariantII, D.getBeginLoc());
+ return BaseFD;
+}
+
+void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
+ FunctionDecl *FD, FunctionDecl *BaseFD) {
+ // Do not mark function as is used to prevent its emission if this is the
+ // only place where it is used.
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ Expr *VariantFuncRef = DeclRefExpr::Create(
+ Context, NestedNameSpecifierLoc(), SourceLocation(), FD,
+ /* RefersToEnclosingVariableOrCapture */ false,
+ /* NameLoc */ FD->getLocation(), FD->getType(), ExprValueKind::VK_RValue);
+
+ OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
+ auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantFuncRef, DVScope.TI);
+ BaseFD->addAttr(OMPDeclareVariantA);
+}
+
+ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
+ SourceLocation LParenLoc,
+ MultiExprArg ArgExprs,
+ SourceLocation RParenLoc, Expr *ExecConfig) {
+ // The common case is a regular call we do not want to specialize at all. Try
+ // to make that case fast by bailing early.
+ CallExpr *CE = dyn_cast<CallExpr>(Call.get());
+ if (!CE)
+ return Call;
+
+ FunctionDecl *CalleeFnDecl = CE->getDirectCallee();
+ if (!CalleeFnDecl)
+ return Call;
+
+ if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>())
+ return Call;
+
+ ASTContext &Context = getASTContext();
+ OMPContext OMPCtx(getLangOpts().OpenMPIsDevice,
+ Context.getTargetInfo().getTriple());
+
+ SmallVector<Expr *, 4> Exprs;
+ SmallVector<VariantMatchInfo, 4> VMIs;
+ while (CalleeFnDecl) {
+ for (OMPDeclareVariantAttr *A :
+ CalleeFnDecl->specific_attrs<OMPDeclareVariantAttr>()) {
+ Expr *VariantRef = A->getVariantFuncRef();
+
+ VariantMatchInfo VMI;
+ OMPTraitInfo &TI = A->getTraitInfo();
+ TI.getAsVariantMatchInfo(Context, VMI);
+ if (!isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ false))
+ continue;
+
+ VMIs.push_back(VMI);
+ Exprs.push_back(VariantRef);
+ }
+
+ CalleeFnDecl = CalleeFnDecl->getPreviousDecl();
+ }
+
+ ExprResult NewCall;
+ do {
+ int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
+ if (BestIdx < 0)
+ return Call;
+ Expr *BestExpr = cast<DeclRefExpr>(Exprs[BestIdx]);
+ Decl *BestDecl = cast<DeclRefExpr>(BestExpr)->getDecl();
+
+ {
+ // Try to build a (member) call expression for the current best applicable
+ // variant expression. We allow this to fail in which case we continue
+ // with the next best variant expression. The fail case is part of the
+ // implementation defined behavior in the OpenMP standard when it talks
+ // about what differences in the function prototypes: "Any differences
+ // that the specific OpenMP context requires in the prototype of the
+ // variant from the base function prototype are implementation defined."
+ // This wording is there to allow the specialized variant to have a
+ // different type than the base function. This is intended and OK but if
+ // we cannot create a call the difference is not in the "implementation
+ // defined range" we allow.
+ Sema::TentativeAnalysisScope Trap(*this);
+
+ if (auto *SpecializedMethod = dyn_cast<CXXMethodDecl>(BestDecl)) {
+ auto *MemberCall = dyn_cast<CXXMemberCallExpr>(CE);
+ BestExpr = MemberExpr::CreateImplicit(
+ Context, MemberCall->getImplicitObjectArgument(),
+ /* IsArrow */ false, SpecializedMethod, Context.BoundMemberTy,
+ MemberCall->getValueKind(), MemberCall->getObjectKind());
+ }
+ NewCall = BuildCallExpr(Scope, BestExpr, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig);
+ if (NewCall.isUsable())
+ break;
+ }
+
+ VMIs.erase(VMIs.begin() + BestIdx);
+ Exprs.erase(Exprs.begin() + BestIdx);
+ } while (!VMIs.empty());
+
+ if (!NewCall.isUsable())
+ return Call;
+ return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0);
+}
+
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
- Expr *VariantRef, SourceRange SR) {
+ Expr *VariantRef, OMPTraitInfo &TI,
+ SourceRange SR) {
if (!DG || DG.get().isNull())
return None;
@@ -5319,12 +6014,41 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return None;
}
+ auto ShouldDelayChecks = [](Expr *&E, bool) {
+ return E && (E->isTypeDependent() || E->isValueDependent() ||
+ E->containsUnexpandedParameterPack() ||
+ E->isInstantiationDependent());
+ };
// Do not check templates, wait until instantiation.
- if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
- VariantRef->containsUnexpandedParameterPack() ||
- VariantRef->isInstantiationDependent() || FD->isDependentContext())
+ if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) ||
+ TI.anyScoreOrCondition(ShouldDelayChecks))
return std::make_pair(FD, VariantRef);
+ // Deal with non-constant score and user condition expressions.
+ auto HandleNonConstantScoresAndConditions = [this](Expr *&E,
+ bool IsScore) -> bool {
+ llvm::APSInt Result;
+ if (!E || E->isIntegerConstantExpr(Result, Context))
+ return false;
+
+ if (IsScore) {
+ // We warn on non-constant scores and pretend they were not present.
+ Diag(E->getExprLoc(), diag::warn_omp_declare_variant_score_not_constant)
+ << E;
+ E = nullptr;
+ } else {
+ // We could replace a non-constant user condition with "false" but we
+ // will soon need to handle these anyway for the dynamic version of
+ // OpenMP context selectors.
+ Diag(E->getExprLoc(),
+ diag::err_omp_declare_variant_user_condition_not_constant)
+ << E;
+ }
+ return true;
+ };
+ if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions))
+ return None;
+
// Convert VariantRef expression to the type of the original function to
// resolve possible conflicts.
ExprResult VariantRefCast;
@@ -5355,7 +6079,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
ImplicitConversionSequence ICS =
TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(),
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false);
@@ -5497,94 +6221,13 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return std::make_pair(FD, cast<Expr>(DRE));
}
-void Sema::ActOnOpenMPDeclareVariantDirective(
- FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
- ArrayRef<OMPCtxSelectorData> Data) {
- if (Data.empty())
- return;
- SmallVector<Expr *, 4> CtxScores;
- SmallVector<unsigned, 4> CtxSets;
- SmallVector<unsigned, 4> Ctxs;
- SmallVector<StringRef, 4> ImplVendors, DeviceKinds;
- bool IsError = false;
- for (const OMPCtxSelectorData &D : Data) {
- OpenMPContextSelectorSetKind CtxSet = D.CtxSet;
- OpenMPContextSelectorKind Ctx = D.Ctx;
- if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown)
- return;
- Expr *Score = nullptr;
- if (D.Score.isUsable()) {
- Score = D.Score.get();
- if (!Score->isTypeDependent() && !Score->isValueDependent() &&
- !Score->isInstantiationDependent() &&
- !Score->containsUnexpandedParameterPack()) {
- Score =
- PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score)
- .get();
- if (Score)
- Score = VerifyIntegerConstantExpression(Score).get();
- }
- } else {
- // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors.
- // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and
- // 2^(l+2), respectively, where l is the number of traits in the construct
- // set.
- // TODO: implement correct logic for isa and arch traits.
- // TODO: take the construct context set into account when it is
- // implemented.
- int L = 0; // Currently set the number of traits in construct set to 0,
- // since the construct trait set in not supported yet.
- if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind)
- Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get();
- else
- Score = ActOnIntegerConstant(SourceLocation(), 0).get();
- }
- switch (Ctx) {
- case OMP_CTX_vendor:
- assert(CtxSet == OMP_CTX_SET_implementation &&
- "Expected implementation context selector set.");
- ImplVendors.append(D.Names.begin(), D.Names.end());
- break;
- case OMP_CTX_kind:
- assert(CtxSet == OMP_CTX_SET_device &&
- "Expected device context selector set.");
- DeviceKinds.append(D.Names.begin(), D.Names.end());
- break;
- case OMP_CTX_unknown:
- llvm_unreachable("Unknown context selector kind.");
- }
- IsError = IsError || !Score;
- CtxSets.push_back(CtxSet);
- Ctxs.push_back(Ctx);
- CtxScores.push_back(Score);
- }
- if (!IsError) {
- auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
- Context, VariantRef, CtxScores.begin(), CtxScores.size(),
- CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(),
- ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(),
- DeviceKinds.size(), SR);
- FD->addAttr(NewAttr);
- }
-}
-
-void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
- FunctionDecl *Func,
- bool MightBeOdrUse) {
- assert(LangOpts.OpenMP && "Expected OpenMP mode.");
-
- if (!Func->isDependentContext() && Func->hasAttrs()) {
- for (OMPDeclareVariantAttr *A :
- Func->specific_attrs<OMPDeclareVariantAttr>()) {
- // TODO: add checks for active OpenMP context where possible.
- Expr *VariantRef = A->getVariantFuncRef();
- auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
- auto *F = cast<FunctionDecl>(DRE->getDecl());
- if (!F->isDefined() && F->isTemplateInstantiation())
- InstantiateFunctionDefinition(Loc, F->getFirstDecl());
- MarkFunctionReferenced(Loc, F, MightBeOdrUse);
- }
- }
+void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD,
+ Expr *VariantRef,
+ OMPTraitInfo &TI,
+ SourceRange SR) {
+ auto *NewAttr =
+ OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR);
+ FD->addAttr(NewAttr);
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -5605,6 +6248,7 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(),
DSAStack->isCancelRegion());
}
@@ -6300,8 +6944,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) {
static ExprResult
tryBuildCapture(Sema &SemaRef, Expr *Capture,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- if (SemaRef.CurContext->isDependentContext())
- return ExprResult(Capture);
+ if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors())
+ return Capture;
if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects))
return SemaRef.PerformImplicitConversion(
Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting,
@@ -6315,221 +6959,344 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
return Res;
}
-/// Build the expression to calculate the number of iterations.
-Expr *OpenMPIterationSpaceChecker::buildNumIterations(
- Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
- llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
- ExprResult Diff;
- QualType VarType = LCDecl->getType().getNonReferenceType();
- if (VarType->isIntegerType() || VarType->isPointerType() ||
- SemaRef.getLangOpts().CPlusPlus) {
- Expr *LBVal = LB;
- Expr *UBVal = UB;
- // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
- // max(LB(MinVal), LB(MaxVal))
- if (InitDependOnLC) {
- const LoopIterationSpace &IS =
- ResultIterSpaces[ResultIterSpaces.size() - 1 -
- InitDependOnLC.getValueOr(
- CondDependOnLC.getValueOr(0))];
- if (!IS.MinValue || !IS.MaxValue)
- return nullptr;
- // OuterVar = Min
- ExprResult MinValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
- if (!MinValue.isUsable())
- return nullptr;
-
- ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MinValue.get());
- if (!LBMinVal.isUsable())
- return nullptr;
- // OuterVar = Min, LBVal
- LBMinVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
- if (!LBMinVal.isUsable())
- return nullptr;
- // (OuterVar = Min, LBVal)
- LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
- if (!LBMinVal.isUsable())
- return nullptr;
-
- // OuterVar = Max
- ExprResult MaxValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
- if (!MaxValue.isUsable())
- return nullptr;
-
- ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MaxValue.get());
- if (!LBMaxVal.isUsable())
- return nullptr;
- // OuterVar = Max, LBVal
- LBMaxVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
- if (!LBMaxVal.isUsable())
- return nullptr;
- // (OuterVar = Max, LBVal)
- LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
- if (!LBMaxVal.isUsable())
- return nullptr;
-
- Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
- Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
- if (!LBMin || !LBMax)
- return nullptr;
- // LB(MinVal) < LB(MaxVal)
- ExprResult MinLessMaxRes =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
- if (!MinLessMaxRes.isUsable())
- return nullptr;
- Expr *MinLessMax =
- tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
- if (!MinLessMax)
- return nullptr;
- if (TestIsLessOp.getValue()) {
- // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
- // LB(MaxVal))
- ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
- MinLessMax, LBMin, LBMax);
- if (!MinLB.isUsable())
- return nullptr;
- LBVal = MinLB.get();
- } else {
- // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
- // LB(MaxVal))
- ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
- MinLessMax, LBMax, LBMin);
- if (!MaxLB.isUsable())
- return nullptr;
- LBVal = MaxLB.get();
- }
+/// Calculate number of iterations, transforming to unsigned, if number of
+/// iterations may be larger than the original type.
+static Expr *
+calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
+ Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy,
+ bool TestIsStrictOp, bool RoundToStep,
+ llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
+ ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
+ return nullptr;
+ llvm::APSInt LRes, URes, SRes;
+ bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context);
+ bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context);
+ bool NoNeedToConvert = IsLowerConst && !RoundToStep &&
+ ((!TestIsStrictOp && LRes.isNonNegative()) ||
+ (TestIsStrictOp && LRes.isStrictlyPositive()));
+ bool NeedToReorganize = false;
+ // Check if any subexpressions in Lower -Step [+ 1] lead to overflow.
+ if (!NoNeedToConvert && IsLowerConst &&
+ (TestIsStrictOp || (RoundToStep && IsStepConst))) {
+ NoNeedToConvert = true;
+ if (RoundToStep) {
+ unsigned BW = LRes.getBitWidth() > SRes.getBitWidth()
+ ? LRes.getBitWidth()
+ : SRes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ SRes = SRes.extend(BW + 1);
+ SRes.setIsSigned(true);
+ LRes -= SRes;
+ NoNeedToConvert = LRes.trunc(BW).extend(BW + 1) == LRes;
+ LRes = LRes.trunc(BW);
+ }
+ if (TestIsStrictOp) {
+ unsigned BW = LRes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ ++LRes;
+ NoNeedToConvert =
+ NoNeedToConvert && LRes.trunc(BW).extend(BW + 1) == LRes;
+ // truncate to the original bitwidth.
+ LRes = LRes.trunc(BW);
+ }
+ NeedToReorganize = NoNeedToConvert;
+ }
+ bool IsUpperConst = Upper->isIntegerConstantExpr(URes, SemaRef.Context);
+ if (NoNeedToConvert && IsLowerConst && IsUpperConst &&
+ (!RoundToStep || IsStepConst)) {
+ unsigned BW = LRes.getBitWidth() > URes.getBitWidth() ? LRes.getBitWidth()
+ : URes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ URes = URes.extend(BW + 1);
+ URes.setIsSigned(true);
+ URes -= LRes;
+ NoNeedToConvert = URes.trunc(BW).extend(BW + 1) == URes;
+ NeedToReorganize = NoNeedToConvert;
+ }
+ // If the boundaries are not constant or (Lower - Step [+ 1]) is not constant
+ // or less than zero (Upper - (Lower - Step [+ 1]) may overflow) - promote to
+ // unsigned.
+ if ((!NoNeedToConvert || (LRes.isNegative() && !IsUpperConst)) &&
+ !LCTy->isDependentType() && LCTy->isIntegerType()) {
+ QualType LowerTy = Lower->getType();
+ QualType UpperTy = Upper->getType();
+ uint64_t LowerSize = SemaRef.Context.getTypeSize(LowerTy);
+ uint64_t UpperSize = SemaRef.Context.getTypeSize(UpperTy);
+ if ((LowerSize <= UpperSize && UpperTy->hasSignedIntegerRepresentation()) ||
+ (LowerSize > UpperSize && LowerTy->hasSignedIntegerRepresentation())) {
+ QualType CastType = SemaRef.Context.getIntTypeForBitwidth(
+ LowerSize > UpperSize ? LowerSize : UpperSize, /*Signed=*/0);
+ Upper =
+ SemaRef
+ .PerformImplicitConversion(
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(),
+ CastType, Sema::AA_Converting)
+ .get();
+ Lower = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get();
+ NewStep = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, NewStep.get());
}
- // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
- // min(UB(MinVal), UB(MaxVal))
- if (CondDependOnLC) {
- const LoopIterationSpace &IS =
- ResultIterSpaces[ResultIterSpaces.size() - 1 -
- InitDependOnLC.getValueOr(
- CondDependOnLC.getValueOr(0))];
- if (!IS.MinValue || !IS.MaxValue)
- return nullptr;
- // OuterVar = Min
- ExprResult MinValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
- if (!MinValue.isUsable())
- return nullptr;
-
- ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MinValue.get());
- if (!UBMinVal.isUsable())
- return nullptr;
- // OuterVar = Min, UBVal
- UBMinVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
- if (!UBMinVal.isUsable())
- return nullptr;
- // (OuterVar = Min, UBVal)
- UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
- if (!UBMinVal.isUsable())
- return nullptr;
+ }
+ if (!Lower || !Upper || NewStep.isInvalid())
+ return nullptr;
- // OuterVar = Max
- ExprResult MaxValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
- if (!MaxValue.isUsable())
+ ExprResult Diff;
+ // If need to reorganize, then calculate the form as Upper - (Lower - Step [+
+ // 1]).
+ if (NeedToReorganize) {
+ Diff = Lower;
+
+ if (RoundToStep) {
+ // Lower - Step
+ Diff =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
return nullptr;
+ }
- ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MaxValue.get());
- if (!UBMaxVal.isUsable())
- return nullptr;
- // OuterVar = Max, UBVal
- UBMaxVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
- if (!UBMaxVal.isUsable())
- return nullptr;
- // (OuterVar = Max, UBVal)
- UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
- if (!UBMaxVal.isUsable())
- return nullptr;
+ // Lower - Step [+ 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Add, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return nullptr;
- Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
- Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
- if (!UBMin || !UBMax)
- return nullptr;
- // UB(MinVal) > UB(MaxVal)
- ExprResult MinGreaterMaxRes =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
- if (!MinGreaterMaxRes.isUsable())
- return nullptr;
- Expr *MinGreaterMax =
- tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
- if (!MinGreaterMax)
- return nullptr;
- if (TestIsLessOp.getValue()) {
- // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
- // UB(MaxVal))
- ExprResult MaxUB = SemaRef.ActOnConditionalOp(
- DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
- if (!MaxUB.isUsable())
- return nullptr;
- UBVal = MaxUB.get();
- } else {
- // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
- // UB(MaxVal))
- ExprResult MinUB = SemaRef.ActOnConditionalOp(
- DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
- if (!MinUB.isUsable())
- return nullptr;
- UBVal = MinUB.get();
- }
- }
- // Upper - Lower
- Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
- Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
- Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
- if (!Upper || !Lower)
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
return nullptr;
+ // Upper - (Lower - Step [+ 1]).
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
+ if (!Diff.isUsable())
+ return nullptr;
+ } else {
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
- if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
+ if (!Diff.isUsable() && LCTy->getAsCXXRecordDecl()) {
// BuildBinOp already emitted error, this one is to point user to upper
// and lower bound, and to tell what is passed to 'operator-'.
SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
<< Upper->getSourceRange() << Lower->getSourceRange();
return nullptr;
}
+
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ if (RoundToStep) {
+ // Upper - Lower [- 1] + Step
+ Diff =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return nullptr;
+ }
}
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return nullptr;
- // Upper - Lower [- 1]
- if (TestIsStrictOp)
- Diff = SemaRef.BuildBinOp(
- S, DefaultLoc, BO_Sub, Diff.get(),
- SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ // (Upper - Lower [- 1] + Step) / Step or (Upper - Lower) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
- // Upper - Lower [- 1] + Step
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
- if (!NewStep.isUsable())
- return nullptr;
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
- if (!Diff.isUsable())
+ return Diff.get();
+}
+
+/// Build the expression to calculate the number of iterations.
+Expr *OpenMPIterationSpaceChecker::buildNumIterations(
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
+ llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ QualType VarType = LCDecl->getType().getNonReferenceType();
+ if (!VarType->isIntegerType() && !VarType->isPointerType() &&
+ !SemaRef.getLangOpts().CPlusPlus)
return nullptr;
+ Expr *LBVal = LB;
+ Expr *UBVal = UB;
+ // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
+ // max(LB(MinVal), LB(MaxVal))
+ if (InitDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
+ ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, LBVal
+ LBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, LBVal)
+ LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, LBVal
+ LBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, LBVal)
+ LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
+ if (!LBMin || !LBMax)
+ return nullptr;
+ // LB(MinVal) < LB(MaxVal)
+ ExprResult MinLessMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
+ if (!MinLessMaxRes.isUsable())
+ return nullptr;
+ Expr *MinLessMax =
+ tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
+ if (!MinLessMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMin, LBMax);
+ if (!MinLB.isUsable())
+ return nullptr;
+ LBVal = MinLB.get();
+ } else {
+ // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMax, LBMin);
+ if (!MaxLB.isUsable())
+ return nullptr;
+ LBVal = MaxLB.get();
+ }
+ }
+ // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
+ // min(UB(MinVal), UB(MaxVal))
+ if (CondDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, UBVal
+ UBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, UBVal)
+ UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, UBVal
+ UBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, UBVal)
+ UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
+ if (!UBMin || !UBMax)
+ return nullptr;
+ // UB(MinVal) > UB(MaxVal)
+ ExprResult MinGreaterMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
+ if (!MinGreaterMaxRes.isUsable())
+ return nullptr;
+ Expr *MinGreaterMax =
+ tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
+ if (!MinGreaterMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MaxUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
+ if (!MaxUB.isUsable())
+ return nullptr;
+ UBVal = MaxUB.get();
+ } else {
+ // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MinUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
+ if (!MinUB.isUsable())
+ return nullptr;
+ UBVal = MinUB.get();
+ }
+ }
+ Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
+ Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
+ if (!Upper || !Lower)
return nullptr;
- // (Upper - Lower [- 1] + Step) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ ExprResult Diff =
+ calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType,
+ TestIsStrictOp, /*RoundToStep=*/true, Captures);
if (!Diff.isUsable())
return nullptr;
@@ -6603,55 +7370,37 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
MaxExpr = Upper;
// Build minimum/maximum value based on number of iterations.
- ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+ ExprResult Diff =
+ calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType,
+ TestIsStrictOp, /*RoundToStep=*/false, Captures);
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Upper - Lower [- 1]
- if (TestIsStrictOp)
- Diff = SemaRef.BuildBinOp(
- S, DefaultLoc, BO_Sub, Diff.get(),
- SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ // ((Upper - Lower [- 1]) / Step) * Step
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Upper - Lower [- 1] + Step
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
if (!NewStep.isUsable())
return std::make_pair(nullptr, nullptr);
-
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
- // (Upper - Lower [- 1]) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // ((Upper - Lower [- 1]) / Step) * Step
// Parentheses (for dumping/debugging purposes only).
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
- // Convert to the original type or ptrdiff_t, if original type is pointer.
- if (!VarType->isAnyPointerType() &&
- !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) {
- Diff = SemaRef.PerformImplicitConversion(
- Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true);
- } else if (VarType->isAnyPointerType() &&
- !SemaRef.Context.hasSameType(
- Diff.get()->getType(),
- SemaRef.Context.getUnsignedPointerDiffType())) {
+ // Convert to the ptrdiff_t, if original type is pointer.
+ if (VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(
+ Diff.get()->getType(),
+ SemaRef.Context.getUnsignedPointerDiffType())) {
Diff = SemaRef.PerformImplicitConversion(
Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(),
Sema::AA_Converting, /*AllowExplicit=*/true);
@@ -6659,33 +7408,43 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
if (TestIsLessOp.getValue()) {
// MinExpr = Lower;
// MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Add,
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(),
+ Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- MaxExpr = Diff.get();
} else {
// MaxExpr = Upper;
// MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub,
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(),
+ Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- MinExpr = Diff.get();
}
+ // Convert to the original type.
+ if (SemaRef.Context.hasSameType(Diff.get()->getType(), VarType))
+ Diff = SemaRef.PerformImplicitConversion(Diff.get(), VarType,
+ Sema::AA_Converting,
+ /*AllowExplicit=*/true);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue=*/false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue())
+ MaxExpr = Diff.get();
+ else
+ MinExpr = Diff.get();
+
return std::make_pair(MinExpr, MaxExpr);
}
@@ -6791,44 +7550,23 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
if (!Cnt)
return nullptr;
}
- ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
- if (VarType->isIntegerType() || VarType->isPointerType() ||
- SemaRef.getLangOpts().CPlusPlus) {
- // Upper - Lower
- Expr *Upper = TestIsLessOp.getValue()
- ? Cnt
- : tryBuildCapture(SemaRef, UB, Captures).get();
- Expr *Lower = TestIsLessOp.getValue()
- ? tryBuildCapture(SemaRef, LB, Captures).get()
- : Cnt;
- if (!Upper || !Lower)
- return nullptr;
-
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
-
- if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
- // BuildBinOp already emitted error, this one is to point user to upper
- // and lower bound, and to tell what is passed to 'operator-'.
- SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
- << Upper->getSourceRange() << Lower->getSourceRange();
- return nullptr;
- }
- }
-
- if (!Diff.isUsable())
+ if (!VarType->isIntegerType() && !VarType->isPointerType() &&
+ !SemaRef.getLangOpts().CPlusPlus)
return nullptr;
-
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
+ // Upper - Lower
+ Expr *Upper = TestIsLessOp.getValue()
+ ? Cnt
+ : tryBuildCapture(SemaRef, LB, Captures).get();
+ Expr *Lower = TestIsLessOp.getValue()
+ ? tryBuildCapture(SemaRef, LB, Captures).get()
+ : Cnt;
+ if (!Upper || !Lower)
return nullptr;
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
- if (!NewStep.isUsable())
- return nullptr;
- // (Upper - Lower) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ ExprResult Diff = calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper,
+ Step, VarType, /*TestIsStrictOp=*/false,
+ /*RoundToStep=*/false, Captures);
if (!Diff.isUsable())
return nullptr;
@@ -8088,8 +8826,9 @@ Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
}
setFunctionHasBranchProtectedScope();
- return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
- Clauses, AStmt, B, DSAStack->isCancelRegion());
+ return OMPForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPForSimdDirective(
@@ -8166,6 +8905,7 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(),
DSAStack->isCancelRegion());
}
@@ -8326,9 +9066,9 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
}
setFunctionHasBranchProtectedScope();
- return OMPParallelForDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ return OMPParallelForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
@@ -8392,8 +9132,9 @@ Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
- return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses,
- AStmt);
+ return OMPParallelMasterDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef());
}
StmtResult
@@ -8432,7 +9173,31 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPParallelSectionsDirective::Create(
- Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion());
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
+}
+
+/// detach and mergeable clauses are mutially exclusive, check for it.
+static bool checkDetachMergeableClauses(Sema &S,
+ ArrayRef<OMPClause *> Clauses) {
+ const OMPClause *PrevClause = nullptr;
+ bool ErrorFound = false;
+ for (const OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_detach ||
+ C->getClauseKind() == OMPC_mergeable) {
+ if (!PrevClause) {
+ PrevClause = C;
+ } else if (PrevClause->getClauseKind() != C->getClauseKind()) {
+ S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive)
+ << getOpenMPClauseName(C->getClauseKind())
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause)
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ ErrorFound = true;
+ }
+ }
+ }
+ return ErrorFound;
}
StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
@@ -8441,6 +9206,12 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
if (!AStmt)
return StmtError();
+ // OpenMP 5.0, 2.10.1 task Construct
+ // If a detach clause appears on the directive, then a mergeable clause cannot
+ // appear on the same directive.
+ if (checkDetachMergeableClauses(*this, Clauses))
+ return StmtError();
+
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
@@ -8489,10 +9260,94 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- assert(Clauses.size() <= 1 && "Extra clauses in flush directive");
+ OMPFlushClause *FC = nullptr;
+ OMPClause *OrderClause = nullptr;
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_flush)
+ FC = cast<OMPFlushClause>(C);
+ else
+ OrderClause = C;
+ }
+ OpenMPClauseKind MemOrderKind = OMPC_unknown;
+ SourceLocation MemOrderLoc;
+ for (const OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_acq_rel ||
+ C->getClauseKind() == OMPC_acquire ||
+ C->getClauseKind() == OMPC_release) {
+ if (MemOrderKind != OMPC_unknown) {
+ Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses)
+ << getOpenMPDirectiveName(OMPD_flush) << 1
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
+ } else {
+ MemOrderKind = C->getClauseKind();
+ MemOrderLoc = C->getBeginLoc();
+ }
+ }
+ }
+ if (FC && OrderClause) {
+ Diag(FC->getLParenLoc(), diag::err_omp_flush_order_clause_and_list)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ Diag(OrderClause->getBeginLoc(), diag::note_omp_flush_order_clause_here)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ return StmtError();
+ }
return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
+StmtResult Sema::ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (Clauses.empty()) {
+ Diag(StartLoc, diag::err_omp_depobj_expected);
+ return StmtError();
+ } else if (Clauses[0]->getClauseKind() != OMPC_depobj) {
+ Diag(Clauses[0]->getBeginLoc(), diag::err_omp_depobj_expected);
+ return StmtError();
+ }
+ // Only depobj expression and another single clause is allowed.
+ if (Clauses.size() > 2) {
+ Diag(Clauses[2]->getBeginLoc(),
+ diag::err_omp_depobj_single_clause_expected);
+ return StmtError();
+ } else if (Clauses.size() < 1) {
+ Diag(Clauses[0]->getEndLoc(), diag::err_omp_depobj_single_clause_expected);
+ return StmtError();
+ }
+ return OMPDepobjDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
+StmtResult Sema::ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // Check that exactly one clause is specified.
+ if (Clauses.size() != 1) {
+ Diag(Clauses.empty() ? EndLoc : Clauses[1]->getBeginLoc(),
+ diag::err_omp_scan_single_clause_expected);
+ return StmtError();
+ }
+ // Check that scan directive is used in the scopeof the OpenMP loop body.
+ if (Scope *S = DSAStack->getCurScope()) {
+ Scope *ParentS = S->getParent();
+ if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() ||
+ !ParentS->getBreakParent()->isOpenMPLoopScope())
+ return StmtError(Diag(StartLoc, diag::err_omp_orphaned_device_directive)
+ << getOpenMPDirectiveName(OMPD_scan) << 5);
+ }
+ // Check that only one instance of scan directives is used in the same outer
+ // region.
+ if (DSAStack->doesParentHasScanDirective()) {
+ Diag(StartLoc, diag::err_omp_several_directives_in_region) << "scan";
+ Diag(DSAStack->getParentScanDirectiveLoc(),
+ diag::note_omp_previous_directive)
+ << "scan";
+ return StmtError();
+ }
+ DSAStack->setParentHasScanDirective(StartLoc);
+ return OMPScanDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -8555,13 +9410,29 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
<< (TC != nullptr);
- Diag(Param->getBeginLoc(), diag::note_omp_ordered_param);
+ Diag(Param->getBeginLoc(), diag::note_omp_ordered_param) << 1;
ErrorFound = true;
}
}
if ((!AStmt && !DependFound) || ErrorFound)
return StmtError();
+ // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions.
+ // During execution of an iteration of a worksharing-loop or a loop nest
+ // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread
+ // must not execute more than one ordered region corresponding to an ordered
+ // construct without a depend clause.
+ if (!DependFound) {
+ if (DSAStack->doesParentHasOrderedDirective()) {
+ Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered";
+ Diag(DSAStack->getParentOrderedDirectiveLoc(),
+ diag::note_omp_previous_directive)
+ << "ordered";
+ return StmtError();
+ }
+ DSAStack->setParentHasOrderedDirective(StartLoc);
+ }
+
if (AStmt) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
@@ -8817,6 +9688,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
+ // Register location of the first atomic directive.
+ DSAStack->addAtomicDirectiveLoc(StartLoc);
if (!AStmt)
return StmtError();
@@ -8828,6 +9701,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
// longjmp() and throw() must not violate the entry/exit criteria.
OpenMPClauseKind AtomicKind = OMPC_unknown;
SourceLocation AtomicKindLoc;
+ OpenMPClauseKind MemOrderKind = OMPC_unknown;
+ SourceLocation MemOrderLoc;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
C->getClauseKind() == OMPC_update ||
@@ -8835,13 +9710,51 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
if (AtomicKind != OMPC_unknown) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses)
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
- Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause)
+ Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause)
<< getOpenMPClauseName(AtomicKind);
} else {
AtomicKind = C->getClauseKind();
AtomicKindLoc = C->getBeginLoc();
}
}
+ if (C->getClauseKind() == OMPC_seq_cst ||
+ C->getClauseKind() == OMPC_acq_rel ||
+ C->getClauseKind() == OMPC_acquire ||
+ C->getClauseKind() == OMPC_release ||
+ C->getClauseKind() == OMPC_relaxed) {
+ if (MemOrderKind != OMPC_unknown) {
+ Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses)
+ << getOpenMPDirectiveName(OMPD_atomic) << 0
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
+ } else {
+ MemOrderKind = C->getClauseKind();
+ MemOrderLoc = C->getBeginLoc();
+ }
+ }
+ }
+ // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions
+ // If atomic-clause is read then memory-order-clause must not be acq_rel or
+ // release.
+ // If atomic-clause is write then memory-order-clause must not be acq_rel or
+ // acquire.
+ // If atomic-clause is update or not present then memory-order-clause must not
+ // be acq_rel or acquire.
+ if ((AtomicKind == OMPC_read &&
+ (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_release)) ||
+ ((AtomicKind == OMPC_write || AtomicKind == OMPC_update ||
+ AtomicKind == OMPC_unknown) &&
+ (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_acquire))) {
+ SourceLocation Loc = AtomicKindLoc;
+ if (AtomicKind == OMPC_unknown)
+ Loc = StartLoc;
+ Diag(Loc, diag::err_omp_atomic_incompatible_mem_order_clause)
+ << getOpenMPClauseName(AtomicKind)
+ << (AtomicKind == OMPC_unknown ? 1 : 0)
+ << getOpenMPClauseName(MemOrderKind);
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
}
Stmt *Body = CS->getCapturedStmt();
@@ -9338,8 +10251,9 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
- return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses,
- AStmt);
+ return OMPTargetParallelDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
@@ -9391,9 +10305,9 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
}
setFunctionHasBranchProtectedScope();
- return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt,
- B, DSAStack->isCancelRegion());
+ return OMPTargetParallelForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
/// Check for existence of a map clause in the list of clauses.
@@ -9418,12 +10332,18 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
- // OpenMP [2.10.1, Restrictions, p. 97]
- // At least one map clause must appear on the directive.
- if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) {
+ // OpenMP [2.12.2, target data Construct, Restrictions]
+ // At least one map, use_device_addr or use_device_ptr clause must appear on
+ // the directive.
+ if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr) &&
+ (LangOpts.OpenMP < 50 || !hasClauses(Clauses, OMPC_use_device_addr))) {
+ StringRef Expected;
+ if (LangOpts.OpenMP < 50)
+ Expected = "'map' or 'use_device_ptr'";
+ else
+ Expected = "'map', 'use_device_ptr', or 'use_device_addr'";
Diag(StartLoc, diag::err_omp_no_clause_for_directive)
- << "'map' or 'use_device_ptr'"
- << getOpenMPDirectiveName(OMPD_target_data);
+ << Expected << getOpenMPDirectiveName(OMPD_target_data);
return StmtError();
}
@@ -9604,12 +10524,10 @@ static bool checkGrainsizeNumTasksClauses(Sema &S,
if (!PrevClause)
PrevClause = C;
else if (PrevClause->getClauseKind() != C->getClauseKind()) {
- S.Diag(C->getBeginLoc(),
- diag::err_omp_grainsize_num_tasks_mutually_exclusive)
+ S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive)
<< getOpenMPClauseName(C->getClauseKind())
<< getOpenMPClauseName(PrevClause->getClauseKind());
- S.Diag(PrevClause->getBeginLoc(),
- diag::note_omp_previous_grainsize_num_tasks)
+ S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause)
<< getOpenMPClauseName(PrevClause->getClauseKind());
ErrorFound = true;
}
@@ -9678,7 +10596,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B);
+ NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
@@ -9763,7 +10682,8 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B);
+ NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
@@ -9867,7 +10787,8 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPParallelMasterTaskLoopDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
@@ -10004,7 +10925,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
setFunctionHasBranchProtectedScope();
return OMPDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
@@ -10301,7 +11222,6 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective(
CS->getCapturedDecl()->setNothrow();
}
-
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
@@ -10446,7 +11366,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective(
return OMPTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
@@ -10575,7 +11495,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
@@ -10721,9 +11641,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
- case OMPC_device:
- Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_num_teams:
Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -10742,6 +11659,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_hint:
Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_depobj:
+ Res = ActOnOpenMPDepobjClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_detach:
+ Res = ActOnOpenMPDetachClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_device:
case OMPC_if:
case OMPC_default:
case OMPC_proc_bind:
@@ -10768,6 +11692,10 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -10780,6 +11708,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -10789,6 +11718,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10918,10 +11854,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -10939,6 +11879,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with if-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -10988,10 +11929,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -11013,6 +11958,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11063,10 +12009,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11085,6 +12035,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11135,10 +12086,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11157,6 +12112,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11208,10 +12164,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11229,6 +12189,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11280,10 +12241,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11301,6 +12266,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11351,10 +12317,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11373,6 +12343,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11425,10 +12396,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11447,6 +12422,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11474,11 +12450,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -11491,6 +12472,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -11500,6 +12482,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -11747,8 +12737,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
return true;
// Build the predefined allocator expressions.
bool ErrorFound = false;
- for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
- I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
StringRef Allocator =
OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
@@ -11775,7 +12764,8 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
Stack->setAllocator(AllocatorKind, Res.get());
}
if (ErrorFound) {
- S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found);
+ S.Diag(Loc, diag::err_omp_implied_type_not_found)
+ << "omp_allocator_handle_t";
return false;
}
OMPAllocatorHandleT.addConst();
@@ -11852,9 +12842,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_default:
- Res =
- ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
- ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPDefaultClause(static_cast<DefaultKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_proc_bind:
Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument),
@@ -11865,6 +12854,14 @@ 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);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -11891,11 +12888,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
- case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
@@ -11915,6 +12916,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -11923,6 +12925,13 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11946,34 +12955,36 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
else if (I + Skipped + 1 != Last)
Out << ", ";
}
- return Out.str();
+ return std::string(Out.str());
}
-OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
+OMPClause *Sema::ActOnOpenMPDefaultClause(DefaultKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- if (Kind == OMPC_DEFAULT_unknown) {
- static_assert(OMPC_DEFAULT_unknown > 0,
- "OMPC_DEFAULT_unknown not greater than 0");
+ if (Kind == OMP_DEFAULT_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_default, /*First=*/0,
- /*Last=*/OMPC_DEFAULT_unknown)
+ /*Last=*/unsigned(OMP_DEFAULT_unknown))
<< getOpenMPClauseName(OMPC_default);
return nullptr;
}
+
switch (Kind) {
- case OMPC_DEFAULT_none:
+ case OMP_DEFAULT_none:
DSAStack->setDefaultDSANone(KindKwLoc);
break;
- case OMPC_DEFAULT_shared:
+ case OMP_DEFAULT_shared:
DSAStack->setDefaultDSAShared(KindKwLoc);
break;
- case OMPC_DEFAULT_unknown:
- llvm_unreachable("Clause kind is not allowed.");
+ case OMP_DEFAULT_firstprivate:
+ DSAStack->setDefaultDSAFirstPrivate(KindKwLoc);
break;
+ default:
+ llvm_unreachable("DSA unexpected in OpenMP default clause");
}
+
return new (Context)
OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
@@ -12010,6 +13021,43 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
LParenLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_ORDER_unknown) {
+ 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,
+ /*Last=*/OMPC_ORDER_unknown)
+ << getOpenMPClauseName(OMPC_order);
+ return nullptr;
+ }
+ return new (Context)
+ OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source ||
+ Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) {
+ unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink,
+ OMPC_DEPEND_depobj};
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_depend, /*First=*/0,
+ /*Last=*/OMPC_DEPEND_unknown, Except)
+ << getOpenMPClauseName(OMPC_update);
+ return nullptr;
+ }
+ return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind,
+ EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,
@@ -12047,6 +13095,12 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind],
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_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -12073,13 +13127,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
- case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
@@ -12095,6 +13153,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -12104,6 +13163,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12170,7 +13237,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
// OpenMP, 2.7.1, Loop Construct, Restrictions
// The nonmonotonic modifier can only be specified with schedule(dynamic) or
// schedule(guided).
- if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
+ // OpenMP 5.0 does not have this restriction.
+ if (LangOpts.OpenMP < 50 &&
+ (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) {
Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc,
@@ -12250,6 +13319,18 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_seq_cst:
Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
break;
+ case OMPC_acq_rel:
+ Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc);
+ break;
+ case OMPC_acquire:
+ Res = ActOnOpenMPAcquireClause(StartLoc, EndLoc);
+ break;
+ case OMPC_release:
+ Res = ActOnOpenMPReleaseClause(StartLoc, EndLoc);
+ break;
+ case OMPC_relaxed:
+ Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc);
+ break;
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
@@ -12271,6 +13352,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_dynamic_allocators:
Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc);
break;
+ case OMPC_destroy:
+ Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -12295,6 +13379,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_depend:
case OMPC_device:
case OMPC_map:
@@ -12311,11 +13396,19 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12349,7 +13442,7 @@ OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc,
OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
- return new (Context) OMPUpdateClause(StartLoc, EndLoc);
+ return OMPUpdateClause::Create(Context, StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
@@ -12362,6 +13455,26 @@ OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
return new (Context) OMPSeqCstClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPAcqRelClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPAcqRelClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPAcquireClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPAcquireClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPReleaseClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPReleaseClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPRelaxedClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
@@ -12397,14 +13510,19 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
return new (Context) OMPDynamicAllocatorsClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPDestroyClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPVarListClause(
- OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
+ OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr,
const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
CXXScopeSpec &ReductionOrMapperIdScopeSpec,
DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit,
- SourceLocation DepLinMapLastLoc) {
+ SourceLocation ExtraModifierLoc) {
SourceLocation StartLoc = Locs.StartLoc;
SourceLocation LParenLoc = Locs.LParenLoc;
SourceLocation EndLoc = Locs.EndLoc;
@@ -12421,15 +13539,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
"Unexpected lastprivate modifier.");
Res = ActOnOpenMPLastprivateClause(
VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier),
- DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
+ ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_reduction:
- Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown &&
+ "Unexpected lastprivate modifier.");
+ Res = ActOnOpenMPReductionClause(
+ VarList, static_cast<OpenMPReductionClauseModifier>(ExtraModifier),
+ StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc,
+ ReductionOrMapperIdScopeSpec, ReductionOrMapperId);
break;
case OMPC_task_reduction:
Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
@@ -12445,13 +13566,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
"Unexpected linear modifier.");
Res = ActOnOpenMPLinearClause(
- VarList, TailExpr, StartLoc, LParenLoc,
- static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ VarList, DepModOrTailExpr, StartLoc, LParenLoc,
+ static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc,
ColonLoc, EndLoc);
break;
case OMPC_aligned:
- Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
- ColonLoc, EndLoc);
+ Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -12466,8 +13587,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
"Unexpected depend modifier.");
Res = ActOnOpenMPDependClause(
- static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc,
- ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
+ DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier),
+ ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
@@ -12475,7 +13596,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPMapClause(
MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec,
ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier),
- IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs);
+ IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
@@ -12488,17 +13609,31 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_use_device_ptr:
Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs);
break;
+ case OMPC_use_device_addr:
+ Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs);
+ break;
case OMPC_is_device_ptr:
Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
break;
case OMPC_allocate:
- Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
- ColonLoc, EndLoc);
+ Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_nontemporal:
Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_inclusive:
+ Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_exclusive:
+ Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_affinity:
+ Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
+ DepModOrTailExpr, VarList);
+ break;
case OMPC_if:
+ case OMPC_depobj:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -12518,6 +13653,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
@@ -12539,6 +13678,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_uses_allocators:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12985,7 +14129,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
ExprCaptures.push_back(Ref->getDecl());
}
}
- DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
+ if (!IsImplicitClause)
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
@@ -13518,6 +14663,12 @@ struct ReductionData {
SmallVector<Expr *, 8> RHSs;
/// Reduction operation expression.
SmallVector<Expr *, 8> ReductionOps;
+ /// inscan copy operation expressions.
+ SmallVector<Expr *, 8> InscanCopyOps;
+ /// inscan copy temp array expressions for prefix sums.
+ SmallVector<Expr *, 8> InscanCopyArrayTemps;
+ /// inscan copy temp array element expressions for prefix sums.
+ SmallVector<Expr *, 8> InscanCopyArrayElems;
/// Taskgroup descriptors for the corresponding reduction items in
/// in_reduction clauses.
SmallVector<Expr *, 8> TaskgroupDescriptors;
@@ -13525,14 +14676,21 @@ struct ReductionData {
SmallVector<Decl *, 4> ExprCaptures;
/// List of postupdate expressions.
SmallVector<Expr *, 4> ExprPostUpdates;
+ /// Reduction modifier.
+ unsigned RedModifier = 0;
ReductionData() = delete;
/// Reserves required memory for the reduction data.
- ReductionData(unsigned Size) {
+ ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier) {
Vars.reserve(Size);
Privates.reserve(Size);
LHSs.reserve(Size);
RHSs.reserve(Size);
ReductionOps.reserve(Size);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.reserve(Size);
+ InscanCopyArrayTemps.reserve(Size);
+ InscanCopyArrayElems.reserve(Size);
+ }
TaskgroupDescriptors.reserve(Size);
ExprCaptures.reserve(Size);
ExprPostUpdates.reserve(Size);
@@ -13546,16 +14704,31 @@ struct ReductionData {
RHSs.emplace_back(nullptr);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(nullptr);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.push_back(nullptr);
+ InscanCopyArrayTemps.push_back(nullptr);
+ InscanCopyArrayElems.push_back(nullptr);
+ }
}
/// Stores reduction data.
void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
- Expr *TaskgroupDescriptor) {
+ Expr *TaskgroupDescriptor, Expr *CopyOp, Expr *CopyArrayTemp,
+ Expr *CopyArrayElem) {
Vars.emplace_back(Item);
Privates.emplace_back(Private);
LHSs.emplace_back(LHS);
RHSs.emplace_back(RHS);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(TaskgroupDescriptor);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.push_back(CopyOp);
+ InscanCopyArrayTemps.push_back(CopyArrayTemp);
+ InscanCopyArrayElems.push_back(CopyArrayElem);
+ } else {
+ assert(CopyOp == nullptr && CopyArrayTemp == nullptr &&
+ CopyArrayElem == nullptr &&
+ "Copy operation must be used for inscan reductions only.");
+ }
}
};
} // namespace
@@ -13567,7 +14740,7 @@ static bool checkOMPArraySectionConstantForReduction(
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
- if (OASE->getColonLoc().isValid())
+ if (OASE->getColonLocFirst().isValid())
return false;
// This is an array subscript which has implicit length 1!
@@ -13593,7 +14766,7 @@ static bool checkOMPArraySectionConstantForReduction(
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
- if (OASE->getColonLoc().isValid())
+ if (OASE->getColonLocFirst().isValid())
return false;
// This is an array subscript which has implicit length 1!
@@ -13948,11 +15121,11 @@ static bool actOnOMPReductionKindClause(
if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) {
S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
S.Diag(ELoc, diag::note_vla_unsupported);
+ continue;
} else {
S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
S.targetDiag(ELoc, diag::note_vla_unsupported);
}
- continue;
}
// For arrays/array sections only:
// Create pseudo array type for private copy. The size for this array will
@@ -14007,9 +15180,9 @@ static bool actOnOMPReductionKindClause(
if (auto *ComplexTy = OrigType->getAs<ComplexType>())
Type = ComplexTy->getElementType();
if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue =
- llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
- /*isIEEE=*/true);
+ llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue(
+ Context.getFloatTypeSemantics(Type),
+ Context.getTypeSize(Type));
Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
Type, ELoc);
} else if (Type->isScalarType()) {
@@ -14157,6 +15330,53 @@ static bool actOnOMPReductionKindClause(
continue;
}
+ // Add copy operations for inscan reductions.
+ // LHS = RHS;
+ ExprResult CopyOpRes, TempArrayRes, TempArrayElem;
+ if (ClauseKind == OMPC_reduction &&
+ RD.RedModifier == OMPC_REDUCTION_inscan) {
+ ExprResult RHS = S.DefaultLvalueConversion(RHSDRE);
+ CopyOpRes = S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, LHSDRE,
+ RHS.get());
+ if (!CopyOpRes.isUsable())
+ continue;
+ CopyOpRes =
+ S.ActOnFinishFullExpr(CopyOpRes.get(), /*DiscardedValue=*/true);
+ if (!CopyOpRes.isUsable())
+ continue;
+ // For simd directive and simd-based directives in simd mode no need to
+ // construct temp array, need just a single temp element.
+ if (Stack->getCurrentDirective() == OMPD_simd ||
+ (S.getLangOpts().OpenMPSimd &&
+ isOpenMPSimdDirective(Stack->getCurrentDirective()))) {
+ VarDecl *TempArrayVD =
+ buildVarDecl(S, ELoc, PrivateTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ // Add a constructor to the temp decl.
+ S.ActOnUninitializedDecl(TempArrayVD);
+ TempArrayRes = buildDeclRefExpr(S, TempArrayVD, PrivateTy, ELoc);
+ } else {
+ // Build temp array for prefix sum.
+ auto *Dim = new (S.Context)
+ OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue);
+ QualType ArrayTy =
+ S.Context.getVariableArrayType(PrivateTy, Dim, ArrayType::Normal,
+ /*IndexTypeQuals=*/0, {ELoc, ELoc});
+ VarDecl *TempArrayVD =
+ buildVarDecl(S, ELoc, ArrayTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ // Add a constructor to the temp decl.
+ S.ActOnUninitializedDecl(TempArrayVD);
+ TempArrayRes = buildDeclRefExpr(S, TempArrayVD, ArrayTy, ELoc);
+ TempArrayElem =
+ S.DefaultFunctionArrayLvalueConversion(TempArrayRes.get());
+ auto *Idx = new (S.Context)
+ OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue);
+ TempArrayElem = S.CreateBuiltinArraySubscriptExpr(TempArrayElem.get(),
+ ELoc, Idx, ELoc);
+ }
+ }
+
// OpenMP [2.15.4.6, Restrictions, p.2]
// A list item that appears in an in_reduction clause of a task construct
// must appear in a task_reduction clause of a construct associated with a
@@ -14167,8 +15387,8 @@ static bool actOnOMPReductionKindClause(
if (ClauseKind == OMPC_in_reduction) {
SourceRange ParentSR;
BinaryOperatorKind ParentBOK;
- const Expr *ParentReductionOp;
- Expr *ParentBOKTD, *ParentReductionOpTD;
+ const Expr *ParentReductionOp = nullptr;
+ Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr;
DSAStackTy::DSAVarData ParentBOKDSA =
Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK,
ParentBOKTD);
@@ -14177,13 +15397,9 @@ static bool actOnOMPReductionKindClause(
D, ParentSR, ParentReductionOp, ParentReductionOpTD);
bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
- if (!IsParentBOK && !IsParentReductionOp) {
- S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction);
- continue;
- }
if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
- (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK ||
- IsParentReductionOp) {
+ (DeclareReductionRef.isUsable() && IsParentBOK) ||
+ (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) {
bool EmitError = true;
if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
llvm::FoldingSetNodeID RedId, ParentRedId;
@@ -14206,7 +15422,6 @@ static bool actOnOMPReductionKindClause(
}
}
TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
- assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined.");
}
DeclRefExpr *Ref = nullptr;
@@ -14245,8 +15460,17 @@ static bool actOnOMPReductionKindClause(
}
// All reduction items are still marked as reduction (to do not increase
// code base size).
- Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
- if (CurrDir == OMPD_taskgroup) {
+ unsigned Modifier = RD.RedModifier;
+ // Consider task_reductions as reductions with task modifier. Required for
+ // correct analysis of in_reduction clauses.
+ if (CurrDir == OMPD_taskgroup && ClauseKind == OMPC_task_reduction)
+ Modifier = OMPC_REDUCTION_task;
+ Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref, Modifier);
+ if (Modifier == OMPC_REDUCTION_task &&
+ (CurrDir == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(CurrDir) ||
+ isOpenMPWorksharingDirective(CurrDir)) &&
+ !isOpenMPSimdDirective(CurrDir)))) {
if (DeclareReductionRef.isUsable())
Stack->addTaskgroupReductionData(D, ReductionIdRange,
DeclareReductionRef.get());
@@ -14254,17 +15478,41 @@ static bool actOnOMPReductionKindClause(
Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK);
}
RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(),
- TaskgroupDescriptor);
+ TaskgroupDescriptor, CopyOpRes.get(), TempArrayRes.get(),
+ TempArrayElem.get());
}
return RD.Vars.empty();
}
OMPClause *Sema::ActOnOpenMPReductionClause(
- ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ColonLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions) {
- ReductionData RD(VarList.size());
+ if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) {
+ Diag(LParenLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_reduction, /*First=*/0,
+ /*Last=*/OMPC_REDUCTION_unknown)
+ << getOpenMPClauseName(OMPC_reduction);
+ return nullptr;
+ }
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions
+ // A reduction clause with the inscan reduction-modifier may only appear on a
+ // worksharing-loop construct, a worksharing-loop SIMD construct, a simd
+ // construct, a parallel worksharing-loop construct or a parallel
+ // worksharing-loop SIMD construct.
+ if (Modifier == OMPC_REDUCTION_inscan &&
+ (DSAStack->getCurrentDirective() != OMPD_for &&
+ DSAStack->getCurrentDirective() != OMPD_for_simd &&
+ DSAStack->getCurrentDirective() != OMPD_simd &&
+ DSAStack->getCurrentDirective() != OMPD_parallel_for &&
+ DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) {
+ Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction);
+ return nullptr;
+ }
+
+ ReductionData RD(VarList.size(), Modifier);
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
StartLoc, LParenLoc, ColonLoc, EndLoc,
ReductionIdScopeSpec, ReductionId,
@@ -14272,9 +15520,10 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
return nullptr;
return OMPReductionClause::Create(
- Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
- ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
- RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier,
+ RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.InscanCopyOps,
+ RD.InscanCopyArrayTemps, RD.InscanCopyArrayElems,
buildPreInits(Context, RD.ExprCaptures),
buildPostUpdate(*this, RD.ExprPostUpdates));
}
@@ -14330,8 +15579,8 @@ bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
}
bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
- OpenMPLinearClauseKind LinKind,
- QualType Type) {
+ OpenMPLinearClauseKind LinKind, QualType Type,
+ bool IsDeclareSimd) {
const auto *VD = dyn_cast_or_null<VarDecl>(D);
// A variable must not have an incomplete type or a reference type.
if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
@@ -14347,8 +15596,10 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
// OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
// A variable that is privatized must not have a const-qualified type
// unless it is of class type with a mutable member. This restriction does
- // not apply to the firstprivate clause.
- if (rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc))
+ // not apply to the firstprivate clause, nor to the linear clause on
+ // declarative directives (like declare simd).
+ if (!IsDeclareSimd &&
+ rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc))
return true;
// A list item must be of integral or pointer type.
@@ -14900,8 +16151,53 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList);
}
+/// Tries to find omp_depend_t. type.
+static bool findOMPDependT(Sema &S, SourceLocation Loc, DSAStackTy *Stack,
+ bool Diagnose = true) {
+ QualType OMPDependT = Stack->getOMPDependT();
+ if (!OMPDependT.isNull())
+ return true;
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_depend_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ if (Diagnose)
+ S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_depend_t";
+ return false;
+ }
+ Stack->setOMPDependT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (!Depobj)
+ return nullptr;
+
+ bool OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack);
+
+ // OpenMP 5.0, 2.17.10.1 depobj Construct
+ // depobj is an lvalue expression of type omp_depend_t.
+ if (!Depobj->isTypeDependent() && !Depobj->isValueDependent() &&
+ !Depobj->isInstantiationDependent() &&
+ !Depobj->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ !Context.typesAreCompatible(DSAStack->getOMPDependT(), Depobj->getType(),
+ /*CompareUnqualified=*/true))) {
+ Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue)
+ << 0 << Depobj->getType() << Depobj->getSourceRange();
+ }
+
+ if (!Depobj->isLValue()) {
+ Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue)
+ << 1 << Depobj->getSourceRange();
+ }
+
+ return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj);
+}
+
OMPClause *
-Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
+Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
@@ -14911,16 +16207,38 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
<< "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend);
return nullptr;
}
- if (DSAStack->getCurrentDirective() != OMPD_ordered &&
+ if ((DSAStack->getCurrentDirective() != OMPD_ordered ||
+ DSAStack->getCurrentDirective() == OMPD_depobj) &&
(DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source ||
- DepKind == OMPC_DEPEND_sink)) {
- unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink};
+ DepKind == OMPC_DEPEND_sink ||
+ ((LangOpts.OpenMP < 50 ||
+ DSAStack->getCurrentDirective() == OMPD_depobj) &&
+ DepKind == OMPC_DEPEND_depobj))) {
+ SmallVector<unsigned, 3> Except;
+ Except.push_back(OMPC_DEPEND_source);
+ Except.push_back(OMPC_DEPEND_sink);
+ if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj)
+ Except.push_back(OMPC_DEPEND_depobj);
+ std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier)
+ ? "depend modifier(iterator) or "
+ : "";
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_depend, /*First=*/0,
- /*Last=*/OMPC_DEPEND_unknown, Except)
+ << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0,
+ /*Last=*/OMPC_DEPEND_unknown,
+ Except)
<< getOpenMPClauseName(OMPC_depend);
return nullptr;
}
+ if (DepModifier &&
+ (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) {
+ Diag(DepModifier->getExprLoc(),
+ diag::err_omp_depend_sink_source_with_modifier);
+ return nullptr;
+ }
+ if (DepModifier &&
+ !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator))
+ Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator);
+
SmallVector<Expr *, 8> Vars;
DSAStackTy::OperatorOffsetTy OpsOffs;
llvm::APSInt DepCounter(/*BitWidth=*/32);
@@ -15021,42 +16339,97 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
}
OpsOffs.emplace_back(RHS, OOK);
} else {
- // OpenMP 5.0 [2.17.11, Restrictions]
- // List items used in depend clauses cannot be zero-length array sections.
- const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
- if (OASE) {
- const Expr *Length = OASE->getLength();
- Expr::EvalResult Result;
- if (Length && !Length->isValueDependent() &&
- Length->EvaluateAsInt(Result, Context) &&
- Result.Val.getInt().isNullValue()) {
- Diag(ELoc,
- diag::err_omp_depend_zero_length_array_section_not_allowed)
- << SimpleExpr->getSourceRange();
+ bool OMPDependTFound = LangOpts.OpenMP >= 50;
+ if (OMPDependTFound)
+ OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack,
+ DepKind == OMPC_DEPEND_depobj);
+ if (DepKind == OMPC_DEPEND_depobj) {
+ // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
+ // List items used in depend clauses with the depobj dependence type
+ // must be expressions of the omp_depend_t type.
+ if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
+ !RefExpr->isInstantiationDependent() &&
+ !RefExpr->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
+ RefExpr->getType()))) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 0 << RefExpr->getType() << RefExpr->getSourceRange();
continue;
}
- }
+ if (!RefExpr->isLValue()) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 1 << RefExpr->getType() << RefExpr->getSourceRange();
+ continue;
+ }
+ } else {
+ // OpenMP 5.0 [2.17.11, Restrictions]
+ // List items used in depend clauses cannot be zero-length array
+ // sections.
+ QualType ExprTy = RefExpr->getType().getNonReferenceType();
+ const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (OASE) {
+ QualType BaseType =
+ OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ ExprTy = ATy->getElementType();
+ else
+ ExprTy = BaseType->getPointeeType();
+ ExprTy = ExprTy.getNonReferenceType();
+ const Expr *Length = OASE->getLength();
+ Expr::EvalResult Result;
+ if (Length && !Length->isValueDependent() &&
+ Length->EvaluateAsInt(Result, Context) &&
+ Result.Val.getInt().isNullValue()) {
+ Diag(ELoc,
+ diag::err_omp_depend_zero_length_array_section_not_allowed)
+ << SimpleExpr->getSourceRange();
+ continue;
+ }
+ }
- auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
- (ASE &&
- !ASE->getBase()->getType().getNonReferenceType()->isPointerType() &&
- !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
- << RefExpr->getSourceRange();
- continue;
- }
+ // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
+ // List items used in depend clauses with the in, out, inout or
+ // mutexinoutset dependence types cannot be expressions of the
+ // omp_depend_t type.
+ if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
+ !RefExpr->isInstantiationDependent() &&
+ !RefExpr->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << 1
+ << RefExpr->getSourceRange();
+ continue;
+ }
- ExprResult Res;
- {
- Sema::TentativeAnalysisScope Trap(*this);
- Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
- RefExpr->IgnoreParenImpCasts());
- }
- if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
- Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
- << RefExpr->getSourceRange();
- continue;
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
+ if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
+ (ASE && !ASE->getBase()->isTypeDependent() &&
+ !ASE->getBase()
+ ->getType()
+ .getNonReferenceType()
+ ->isPointerType() &&
+ !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+ !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
+ continue;
+ }
}
}
Vars.push_back(RefExpr->IgnoreParenImpCasts());
@@ -15074,24 +16447,40 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
return nullptr;
auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- DepKind, DepLoc, ColonLoc, Vars,
- TotalDepCount.getZExtValue());
+ DepModifier, DepKind, DepLoc, ColonLoc,
+ Vars, TotalDepCount.getZExtValue());
if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
DSAStack->isParentOrderedRegion())
DSAStack->addDoacrossDependClause(C, OpsOffs);
return C;
}
-OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
+OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier,
+ Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 50) &&
+ "Unexpected device modifier in OpenMP < 50.");
+
+ bool ErrorFound = false;
+ if (ModifierLoc.isValid() && Modifier == OMPC_DEVICE_unknown) {
+ std::string Values =
+ getListOfPossibleValues(OMPC_device, /*First=*/0, OMPC_DEVICE_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_device);
+ ErrorFound = true;
+ }
+
Expr *ValExpr = Device;
Stmt *HelperValStmt = nullptr;
// OpenMP [2.9.1, Restrictions]
// The device expression must evaluate to a non-negative integer value.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
- /*StrictlyPositive=*/false))
+ ErrorFound = !isNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
+ /*StrictlyPositive=*/false) ||
+ ErrorFound;
+ if (ErrorFound)
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
@@ -15104,8 +16493,9 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
HelperValStmt = buildPreInits(Context, Captures);
}
- return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
@@ -15133,7 +16523,8 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
// If this is an array subscript, it refers to the whole size if the size of
// the dimension is constant and equals 1. Also, an array section assumes the
// format of an array subscript if no colon is used.
- if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
+ if (isa<ArraySubscriptExpr>(E) ||
+ (OASE && OASE->getColonLocFirst().isInvalid())) {
if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
return ATy->getSize().getSExtValue() != 1;
// Size can't be evaluated statically.
@@ -15189,7 +16580,8 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
// An array subscript always refer to a single element. Also, an array section
// assumes the format of an array subscript if no colon is used.
- if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
+ if (isa<ArraySubscriptExpr>(E) ||
+ (OASE && OASE->getColonLocFirst().isInvalid()))
return false;
assert(OASE && "Expecting array section if not an array subscript.");
@@ -15214,256 +16606,338 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
return ConstLength.getSExtValue() != 1;
}
-// Return the expression of the base of the mappable expression or null if it
-// cannot be determined and do all the necessary checks to see if the expression
-// is valid as a standalone mappable expression. In the process, record all the
-// components of the expression.
-static const Expr *checkMapClauseExpressionBase(
- Sema &SemaRef, Expr *E,
- OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
- OpenMPClauseKind CKind, bool NoDiagnose) {
- SourceLocation ELoc = E->getExprLoc();
- SourceRange ERange = E->getSourceRange();
-
- // The base of elements of list in a map clause have to be either:
- // - a reference to variable or field.
- // - a member expression.
- // - an array expression.
- //
- // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
- // reference to 'r'.
- //
- // If we have:
- //
- // struct SS {
- // Bla S;
- // foo() {
- // #pragma omp target map (S.Arr[:12]);
- // }
- // }
- //
- // We want to retrieve the member expression 'this->S';
+// The base of elements of list in a map clause have to be either:
+// - a reference to variable or field.
+// - a member expression.
+// - an array expression.
+//
+// E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
+// reference to 'r'.
+//
+// If we have:
+//
+// struct SS {
+// Bla S;
+// foo() {
+// #pragma omp target map (S.Arr[:12]);
+// }
+// }
+//
+// We want to retrieve the member expression 'this->S';
+// OpenMP 5.0 [2.19.7.1, map Clause, Restrictions, p.2]
+// If a list item is an array section, it must specify contiguous storage.
+//
+// For this restriction it is sufficient that we make sure only references
+// to variables or fields and array expressions, and that no array sections
+// exist except in the rightmost expression (unless they cover the whole
+// dimension of the array). E.g. these would be invalid:
+//
+// r.ArrS[3:5].Arr[6:7]
+//
+// r.ArrS[3:5].x
+//
+// but these would be valid:
+// r.ArrS[3].Arr[6:7]
+//
+// r.ArrS[3].x
+namespace {
+class MapBaseChecker final : public StmtVisitor<MapBaseChecker, bool> {
+ Sema &SemaRef;
+ OpenMPClauseKind CKind = OMPC_unknown;
+ OMPClauseMappableExprCommon::MappableExprComponentList &Components;
+ bool NoDiagnose = false;
const Expr *RelevantExpr = nullptr;
-
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
- // If a list item is an array section, it must specify contiguous storage.
- //
- // For this restriction it is sufficient that we make sure only references
- // to variables or fields and array expressions, and that no array sections
- // exist except in the rightmost expression (unless they cover the whole
- // dimension of the array). E.g. these would be invalid:
- //
- // r.ArrS[3:5].Arr[6:7]
- //
- // r.ArrS[3:5].x
- //
- // but these would be valid:
- // r.ArrS[3].Arr[6:7]
- //
- // r.ArrS[3].x
-
bool AllowUnitySizeArraySection = true;
bool AllowWholeSizeArraySection = true;
+ SourceLocation ELoc;
+ SourceRange ERange;
- while (!RelevantExpr) {
- E = E->IgnoreParenImpCasts();
+ void emitErrorMsg() {
+ // If nothing else worked, this is not a valid map clause expression.
+ if (SemaRef.getLangOpts().OpenMP < 50) {
+ SemaRef.Diag(ELoc,
+ diag::err_omp_expected_named_var_member_or_array_expression)
+ << ERange;
+ } else {
+ SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses)
+ << getOpenMPClauseName(CKind) << ERange;
+ }
+ }
- if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
- if (!isa<VarDecl>(CurE->getDecl()))
- return nullptr;
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ if (!isa<VarDecl>(DRE->getDecl())) {
+ emitErrorMsg();
+ return false;
+ }
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = DRE;
+ // Record the component.
+ Components.emplace_back(DRE, DRE->getDecl());
+ return true;
+ }
- RelevantExpr = CurE;
+ bool VisitMemberExpr(MemberExpr *ME) {
+ Expr *E = ME;
+ Expr *BaseE = ME->getBase()->IgnoreParenCasts();
- // If we got a reference to a declaration, we should not expect any array
- // section before that.
- AllowUnitySizeArraySection = false;
- AllowWholeSizeArraySection = false;
+ if (isa<CXXThisExpr>(BaseE)) {
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ // We found a base expression: this->Val.
+ RelevantExpr = ME;
+ } else {
+ E = BaseE;
+ }
- // Record the component.
- CurComponents.emplace_back(CurE, CurE->getDecl());
- } else if (auto *CurE = dyn_cast<MemberExpr>(E)) {
- Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts();
+ if (!isa<FieldDecl>(ME->getMemberDecl())) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
+ << ME->getSourceRange();
+ return false;
+ }
+ if (RelevantExpr)
+ return false;
+ return Visit(E);
+ }
- if (isa<CXXThisExpr>(BaseE))
- // We found a base expression: this->Val.
- RelevantExpr = CurE;
- else
- E = BaseE;
+ auto *FD = cast<FieldDecl>(ME->getMemberDecl());
- if (!isa<FieldDecl>(CurE->getMemberDecl())) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
- << CurE->getSourceRange();
- return nullptr;
- }
- if (RelevantExpr)
- return nullptr;
- continue;
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
+ // A bit-field cannot appear in a map clause.
+ //
+ if (FD->isBitField()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
+ << ME->getSourceRange() << getOpenMPClauseName(CKind);
+ return false;
}
+ if (RelevantExpr)
+ return false;
+ return Visit(E);
+ }
- auto *FD = cast<FieldDecl>(CurE->getMemberDecl());
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ QualType CurType = BaseE->getType().getNonReferenceType();
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
- // A bit-field cannot appear in a map clause.
- //
- if (FD->isBitField()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
- << CurE->getSourceRange() << getOpenMPClauseName(CKind);
- return nullptr;
- }
- if (RelevantExpr)
- return nullptr;
- continue;
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
+ // A list item cannot be a variable that is a member of a structure with
+ // a union type.
+ //
+ if (CurType->isUnionType()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
+ << ME->getSourceRange();
+ return false;
}
+ return RelevantExpr || Visit(E);
+ }
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
- // If the type of a list item is a reference to a type T then the type
- // will be considered to be T for all purposes of this clause.
- QualType CurType = BaseE->getType().getNonReferenceType();
+ // If we got a member expression, we should not expect any array section
+ // before that:
+ //
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
+ // If a list item is an element of a structure, only the rightmost symbol
+ // of the variable reference can be an array section.
+ //
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
- // A list item cannot be a variable that is a member of a structure with
- // a union type.
- //
- if (CurType->isUnionType()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
- << CurE->getSourceRange();
- return nullptr;
- }
- continue;
+ // Record the component.
+ Components.emplace_back(ME, FD);
+ return RelevantExpr || Visit(E);
+ }
+
+ bool VisitArraySubscriptExpr(ArraySubscriptExpr *AE) {
+ Expr *E = AE->getBase()->IgnoreParenImpCasts();
+
+ if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << AE->getSourceRange();
+ return false;
}
+ return RelevantExpr || Visit(E);
+ }
- // If we got a member expression, we should not expect any array section
- // before that:
- //
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
- // If a list item is an element of a structure, only the rightmost symbol
- // of the variable reference can be an array section.
- //
- AllowUnitySizeArraySection = false;
+ // If we got an array subscript that express the whole dimension we
+ // can have any array expressions before. If it only expressing part of
+ // the dimension, we can only have unitary-size array expressions.
+ if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, AE,
+ E->getType()))
AllowWholeSizeArraySection = false;
- // Record the component.
- CurComponents.emplace_back(CurE, FD);
- } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
- E = CurE->getBase()->IgnoreParenImpCasts();
-
- if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
- << 0 << CurE->getSourceRange();
- return nullptr;
- }
- continue;
+ if (const auto *TE = dyn_cast<CXXThisExpr>(E->IgnoreParenCasts())) {
+ Expr::EvalResult Result;
+ if (!AE->getIdx()->isValueDependent() &&
+ AE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext()) &&
+ !Result.Val.getInt().isNullValue()) {
+ SemaRef.Diag(AE->getIdx()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(AE->getIdx()->getExprLoc(),
+ diag::note_omp_invalid_subscript_on_this_ptr_map);
}
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = TE;
+ }
- // If we got an array subscript that express the whole dimension we
- // can have any array expressions before. If it only expressing part of
- // the dimension, we can only have unitary-size array expressions.
- if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE,
- E->getType()))
- AllowWholeSizeArraySection = false;
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(AE, nullptr);
- if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
- Expr::EvalResult Result;
- if (CurE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext())) {
- if (!Result.Val.getInt().isNullValue()) {
- SemaRef.Diag(CurE->getIdx()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getIdx()->getExprLoc(),
- diag::note_omp_invalid_subscript_on_this_ptr_map);
- }
- }
- RelevantExpr = TE;
- }
+ return RelevantExpr || Visit(E);
+ }
- // Record the component - we don't have any declaration associated.
- CurComponents.emplace_back(CurE, nullptr);
- } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
- assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
- E = CurE->getBase()->IgnoreParenImpCasts();
+ bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) {
+ assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
+ Expr *E = OASE->getBase()->IgnoreParenImpCasts();
+ QualType CurType =
+ OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
- QualType CurType =
- OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ if (CurType->isReferenceType())
+ CurType = CurType->getPointeeType();
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
- // If the type of a list item is a reference to a type T then the type
- // will be considered to be T for all purposes of this clause.
- if (CurType->isReferenceType())
- CurType = CurType->getPointeeType();
+ bool IsPointer = CurType->isAnyPointerType();
- bool IsPointer = CurType->isAnyPointerType();
+ if (!IsPointer && !CurType->isArrayType()) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << OASE->getSourceRange();
+ return false;
+ }
- if (!IsPointer && !CurType->isArrayType()) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
- << 0 << CurE->getSourceRange();
- return nullptr;
- }
+ bool NotWhole =
+ checkArrayExpressionDoesNotReferToWholeSize(SemaRef, OASE, CurType);
+ bool NotUnity =
+ checkArrayExpressionDoesNotReferToUnitySize(SemaRef, OASE, CurType);
- bool NotWhole =
- checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType);
- bool NotUnity =
- checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType);
+ if (AllowWholeSizeArraySection) {
+ // Any array section is currently allowed. Allowing a whole size array
+ // section implies allowing a unity array section as well.
+ //
+ // If this array section refers to the whole dimension we can still
+ // accept other array sections before this one, except if the base is a
+ // pointer. Otherwise, only unitary sections are accepted.
+ if (NotWhole || IsPointer)
+ AllowWholeSizeArraySection = false;
+ } else if (AllowUnitySizeArraySection && NotUnity) {
+ // A unity or whole array section is not allowed and that is not
+ // compatible with the properties of the current array section.
+ SemaRef.Diag(
+ ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
+ << OASE->getSourceRange();
+ return false;
+ }
- if (AllowWholeSizeArraySection) {
- // Any array section is currently allowed. Allowing a whole size array
- // section implies allowing a unity array section as well.
- //
- // If this array section refers to the whole dimension we can still
- // accept other array sections before this one, except if the base is a
- // pointer. Otherwise, only unitary sections are accepted.
- if (NotWhole || IsPointer)
- AllowWholeSizeArraySection = false;
- } else if (AllowUnitySizeArraySection && NotUnity) {
- // A unity or whole array section is not allowed and that is not
- // compatible with the properties of the current array section.
- SemaRef.Diag(
- ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
- << CurE->getSourceRange();
- return nullptr;
+ if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
+ Expr::EvalResult ResultR;
+ Expr::EvalResult ResultL;
+ if (!OASE->getLength()->isValueDependent() &&
+ OASE->getLength()->EvaluateAsInt(ResultR, SemaRef.getASTContext()) &&
+ !ResultR.Val.getInt().isOneValue()) {
+ SemaRef.Diag(OASE->getLength()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(OASE->getLength()->getExprLoc(),
+ diag::note_omp_invalid_length_on_this_ptr_mapping);
}
-
- if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
- Expr::EvalResult ResultR;
- Expr::EvalResult ResultL;
- if (CurE->getLength()->EvaluateAsInt(ResultR,
- SemaRef.getASTContext())) {
- if (!ResultR.Val.getInt().isOneValue()) {
- SemaRef.Diag(CurE->getLength()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getLength()->getExprLoc(),
- diag::note_omp_invalid_length_on_this_ptr_mapping);
- }
- }
- if (CurE->getLowerBound() && CurE->getLowerBound()->EvaluateAsInt(
- ResultL, SemaRef.getASTContext())) {
- if (!ResultL.Val.getInt().isNullValue()) {
- SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
- diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
- }
- }
- RelevantExpr = TE;
+ if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() &&
+ OASE->getLowerBound()->EvaluateAsInt(ResultL,
+ SemaRef.getASTContext()) &&
+ !ResultL.Val.getInt().isNullValue()) {
+ SemaRef.Diag(OASE->getLowerBound()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(OASE->getLowerBound()->getExprLoc(),
+ diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
}
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = TE;
+ }
- // Record the component - we don't have any declaration associated.
- CurComponents.emplace_back(CurE, nullptr);
- } else {
- if (!NoDiagnose) {
- // If nothing else worked, this is not a valid map clause expression.
- SemaRef.Diag(
- ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
- << ERange;
- }
- return nullptr;
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(OASE, nullptr);
+ return RelevantExpr || Visit(E);
+ }
+ bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
+ Expr *Base = E->getBase();
+
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(E, nullptr);
+
+ return Visit(Base->IgnoreParenImpCasts());
+ }
+
+ bool VisitUnaryOperator(UnaryOperator *UO) {
+ if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() ||
+ UO->getOpcode() != UO_Deref) {
+ emitErrorMsg();
+ return false;
}
+ if (!RelevantExpr) {
+ // Record the component if haven't found base decl.
+ Components.emplace_back(UO, nullptr);
+ }
+ return RelevantExpr || Visit(UO->getSubExpr()->IgnoreParenImpCasts());
}
+ bool VisitBinaryOperator(BinaryOperator *BO) {
+ if (SemaRef.getLangOpts().OpenMP < 50 || !BO->getType()->isPointerType()) {
+ emitErrorMsg();
+ return false;
+ }
+
+ // 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
+ // know the other subtree is just an offset)
+ Expr *LE = BO->getLHS()->IgnoreParenImpCasts();
+ Expr *RE = BO->getRHS()->IgnoreParenImpCasts();
+ Components.emplace_back(BO, nullptr);
+ assert((LE->getType().getTypePtr() == BO->getType().getTypePtr() ||
+ RE->getType().getTypePtr() == BO->getType().getTypePtr()) &&
+ "Either LHS or RHS have base decl inside");
+ if (BO->getType().getTypePtr() == LE->getType().getTypePtr())
+ return RelevantExpr || Visit(LE);
+ return RelevantExpr || Visit(RE);
+ }
+ bool VisitCXXThisExpr(CXXThisExpr *CTE) {
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = CTE;
+ Components.emplace_back(CTE, nullptr);
+ return true;
+ }
+ bool VisitStmt(Stmt *) {
+ emitErrorMsg();
+ return false;
+ }
+ const Expr *getFoundBase() const {
+ return RelevantExpr;
+ }
+ explicit MapBaseChecker(
+ Sema &SemaRef, OpenMPClauseKind CKind,
+ OMPClauseMappableExprCommon::MappableExprComponentList &Components,
+ bool NoDiagnose, SourceLocation &ELoc, SourceRange &ERange)
+ : SemaRef(SemaRef), CKind(CKind), Components(Components),
+ NoDiagnose(NoDiagnose), ELoc(ELoc), ERange(ERange) {}
+};
+} // namespace
- return RelevantExpr;
+/// Return the expression of the base of the mappable expression or null if it
+/// cannot be determined and do all the necessary checks to see if the expression
+/// is valid as a standalone mappable expression. In the process, record all the
+/// components of the expression.
+static const Expr *checkMapClauseExpressionBase(
+ Sema &SemaRef, Expr *E,
+ OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
+ OpenMPClauseKind CKind, bool NoDiagnose) {
+ SourceLocation ELoc = E->getExprLoc();
+ SourceRange ERange = E->getSourceRange();
+ MapBaseChecker Checker(SemaRef, CKind, CurComponents, NoDiagnose, ELoc,
+ ERange);
+ if (Checker.Visit(E->IgnoreParens()))
+ return Checker.getFoundBase();
+ return nullptr;
}
// Return true if expression E associated with value VD has conflicts with other
@@ -15520,9 +16994,11 @@ static bool checkMapConflicts(
// variable in map clauses of the same construct.
if (CurrentRegionOnly &&
(isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) ||
- isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) &&
+ isa<OMPArraySectionExpr>(CI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(CI->getAssociatedExpression())) &&
(isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) ||
- isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) {
+ isa<OMPArraySectionExpr>(SI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(SI->getAssociatedExpression()))) {
SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(),
diag::err_omp_multiple_array_items_in_map_clause)
<< CI->getAssociatedExpression()->getSourceRange();
@@ -15554,6 +17030,9 @@ static bool checkMapConflicts(
const Expr *E = OASE->getBase()->IgnoreParenImpCasts();
Type =
OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+ } else if (const auto *OASE = dyn_cast<OMPArrayShapingExpr>(
+ SI->getAssociatedExpression())) {
+ Type = OASE->getBase()->getType()->getPointeeType();
}
if (Type.isNull() || Type->isAnyPointerType() ||
checkArrayExpressionDoesNotReferToWholeSize(
@@ -15916,10 +17395,15 @@ static void checkMappableExpressionList(
Expr *SimpleExpr = RE->IgnoreParenCasts();
- if (!RE->IgnoreParenImpCasts()->isLValue()) {
- SemaRef.Diag(ELoc,
- diag::err_omp_expected_named_var_member_or_array_expression)
- << RE->getSourceRange();
+ if (!RE->isLValue()) {
+ if (SemaRef.getLangOpts().OpenMP < 50) {
+ SemaRef.Diag(
+ ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
+ << RE->getSourceRange();
+ } else {
+ SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses)
+ << getOpenMPClauseName(CKind) << RE->getSourceRange();
+ }
continue;
}
@@ -16011,6 +17495,7 @@ static void checkMappableExpressionList(
QualType Type;
auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens());
auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens());
+ auto *OAShE = dyn_cast<OMPArrayShapingExpr>(VE->IgnoreParens());
if (ASE) {
Type = ASE->getType().getNonReferenceType();
} else if (OASE) {
@@ -16021,6 +17506,8 @@ static void checkMappableExpressionList(
else
Type = BaseType->getPointeeType();
Type = Type.getNonReferenceType();
+ } else if (OAShE) {
+ Type = OAShE->getBase()->getType()->getPointeeType();
} else {
Type = VE->getType();
}
@@ -16064,6 +17551,21 @@ static void checkMappableExpressionList(
continue;
}
+ // target, target data
+ // OpenMP 5.0 [2.12.2, Restrictions, p. 163]
+ // OpenMP 5.0 [2.12.5, Restrictions, p. 174]
+ // A map-type in a map clause must be to, from, tofrom or alloc
+ if ((DKind == OMPD_target_data ||
+ isOpenMPTargetExecutionDirective(DKind)) &&
+ !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||
+ MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
+ << (IsMapTypeImplicit ? 1 : 0)
+ << getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
+ << getOpenMPDirectiveName(DKind);
+ continue;
+ }
+
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
@@ -16124,7 +17626,7 @@ OMPClause *Sema::ActOnOpenMPMapClause(
OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown};
- SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers];
+ SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers];
// Process map-type-modifiers, flag errors for duplicate modifiers.
unsigned Count = 0;
@@ -16134,7 +17636,7 @@ OMPClause *Sema::ActOnOpenMPMapClause(
Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier);
continue;
}
- assert(Count < OMPMapClause::NumberOfModifiers &&
+ assert(Count < NumberOfOMPMapClauseModifiers &&
"Modifiers exceed the allowed number of map type modifiers");
Modifiers[Count] = MapTypeModifiers[I];
ModifiersLoc[Count] = MapTypeModifiersLoc[I];
@@ -16678,6 +18180,69 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
}
+/// Tries to find omp_event_handle_t type.
+static bool findOMPEventHandleT(Sema &S, SourceLocation Loc,
+ DSAStackTy *Stack) {
+ QualType OMPEventHandleT = Stack->getOMPEventHandleT();
+ if (!OMPEventHandleT.isNull())
+ return true;
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_event_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_event_handle_t";
+ return false;
+ }
+ Stack->setOMPEventHandleT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (!Evt->isValueDependent() && !Evt->isTypeDependent() &&
+ !Evt->isInstantiationDependent() &&
+ !Evt->containsUnexpandedParameterPack()) {
+ if (!findOMPEventHandleT(*this, Evt->getExprLoc(), DSAStack))
+ return nullptr;
+ // OpenMP 5.0, 2.10.1 task Construct.
+ // event-handle is a variable of the omp_event_handle_t type.
+ auto *Ref = dyn_cast<DeclRefExpr>(Evt->IgnoreParenImpCasts());
+ if (!Ref) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 0 << Evt->getSourceRange();
+ return nullptr;
+ }
+ auto *VD = dyn_cast_or_null<VarDecl>(Ref->getDecl());
+ if (!VD) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 0 << Evt->getSourceRange();
+ return nullptr;
+ }
+ if (!Context.hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(),
+ VD->getType()) ||
+ VD->getType().isConstant(Context)) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 1 << VD->getType()
+ << Evt->getSourceRange();
+ return nullptr;
+ }
+ // OpenMP 5.0, 2.10.1 task Construct
+ // [detach clause]... The event-handle will be considered as if it was
+ // specified on a firstprivate clause.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
+ DVar.RefExpr) {
+ Diag(Evt->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ reportOriginalDsa(*this, DSAStack, VD, DVar);
+ return nullptr;
+ }
+ }
+
+ return new (Context) OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPDistScheduleClause(
OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
@@ -16758,7 +18323,8 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
}
} else {
bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown);
- bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown);
+ bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) ||
+ (LangOpts.OpenMP >= 50 && KindLoc.isInvalid());
if (!isDefaultmapKind || !isDefaultmapModifier) {
std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', "
"'firstprivate', 'none', 'default'";
@@ -16786,7 +18352,14 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
return nullptr;
}
}
- DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
+ if (Kind == OMPC_DEFAULTMAP_unknown) {
+ // Variable category is not specified - mark all categories.
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_aggregate, StartLoc);
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_scalar, StartLoc);
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_pointer, StartLoc);
+ } else {
+ DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
+ }
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -16955,15 +18528,6 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
- // Mark the function as must be emitted for the device.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
- *DevTy != OMPDeclareTargetDeclAttr::DT_Host)
- checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false);
- if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
- *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost)
- checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false);
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
@@ -17109,6 +18673,58 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
+OMPClause *Sema::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs) {
+ MappableVarListInfo MVLI(VarList);
+
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP use_device_addr clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second) {
+ // It will be analyzed later.
+ MVLI.ProcessedVarList.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+ auto *VD = dyn_cast<VarDecl>(D);
+
+ // If required, build a capture to implement the privatization initialized
+ // with the current list item value.
+ DeclRefExpr *Ref = nullptr;
+ if (!VD)
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref);
+
+ // We need to add a data sharing attribute for this variable to make sure it
+ // is correctly captured. A variable that shows up in a use_device_addr has
+ // similar properties of a first private variable.
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
+
+ // Create a mappable component for the list item. List items in this clause
+ // only need a component.
+ MVLI.VarBaseDeclarations.push_back(D);
+ MVLI.VarComponents.emplace_back();
+ Expr *Component = SimpleRefExpr;
+ if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) ||
+ isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts())))
+ Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get();
+ MVLI.VarComponents.back().push_back(
+ OMPClauseMappableExprCommon::MappableComponent(Component, D));
+ }
+
+ if (MVLI.ProcessedVarList.empty())
+ return nullptr;
+
+ return OMPUseDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
@@ -17248,6 +18864,8 @@ OMPClause *Sema::ActOnOpenMPAllocateClause(
if (Vars.empty())
return nullptr;
+ if (Allocator)
+ DSAStack->addInnerAllocatorExpr(Allocator);
return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
ColonLoc, EndLoc, Vars);
}
@@ -17290,3 +18908,266 @@ OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList,
return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars);
}
+
+OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/true);
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
+ // A list item that appears in the inclusive or exclusive clause must appear
+ // in a reduction clause with the inscan modifier on the enclosing
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
+ if (DVar.CKind != OMPC_reduction ||
+ DVar.Modifier != OMPC_REDUCTION_inscan)
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
+ << RefExpr->getSourceRange();
+
+ if (DSAStack->getParentDirective() != OMPD_unknown)
+ DSAStack->markDeclAsUsedInScanDirective(D);
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
+ DSAStackTy::DSAVarData DVar;
+ if (ParentDirective != OMPD_unknown)
+ DVar = DSAStack->getTopDSA(D, /*FromParent=*/true);
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
+ // A list item that appears in the inclusive or exclusive clause must appear
+ // in a reduction clause with the inscan modifier on the enclosing
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
+ if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction ||
+ DVar.Modifier != OMPC_REDUCTION_inscan) {
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
+ << RefExpr->getSourceRange();
+ } else {
+ DSAStack->markDeclAsUsedInScanDirective(D);
+ }
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+/// Tries to find omp_alloctrait_t type.
+static bool findOMPAlloctraitT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) {
+ QualType OMPAlloctraitT = Stack->getOMPAlloctraitT();
+ if (!OMPAlloctraitT.isNull())
+ return true;
+ IdentifierInfo &II = S.PP.getIdentifierTable().get("omp_alloctrait_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_alloctrait_t";
+ return false;
+ }
+ Stack->setOMPAlloctraitT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPUsesAllocatorClause(
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<UsesAllocatorsData> Data) {
+ // OpenMP [2.12.5, target Construct]
+ // allocator is an identifier of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, StartLoc, DSAStack))
+ return nullptr;
+ // OpenMP [2.12.5, target Construct]
+ // allocator-traits-array is an identifier of const omp_alloctrait_t * type.
+ if (llvm::any_of(
+ Data,
+ [](const UsesAllocatorsData &D) { return D.AllocatorTraits; }) &&
+ !findOMPAlloctraitT(*this, StartLoc, DSAStack))
+ return nullptr;
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> PredefinedAllocators;
+ for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ StringRef Allocator =
+ OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
+ DeclarationName AllocatorName = &Context.Idents.get(Allocator);
+ PredefinedAllocators.insert(LookupSingleName(
+ TUScope, AllocatorName, StartLoc, Sema::LookupAnyName));
+ }
+
+ SmallVector<OMPUsesAllocatorsClause::Data, 4> NewData;
+ for (const UsesAllocatorsData &D : Data) {
+ Expr *AllocatorExpr = nullptr;
+ // Check allocator expression.
+ if (D.Allocator->isTypeDependent()) {
+ AllocatorExpr = D.Allocator;
+ } else {
+ // Traits were specified - need to assign new allocator to the specified
+ // allocator, so it must be an lvalue.
+ 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()))) {
+ Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_allocator_handle_t" << (DRE ? 1 : 0)
+ << AllocatorExpr->getType() << D.Allocator->getSourceRange();
+ continue;
+ }
+ // OpenMP [2.12.5, target Construct]
+ // Predefined allocators appearing in a uses_allocators clause cannot have
+ // traits specified.
+ if (IsPredefinedAllocator && D.AllocatorTraits) {
+ Diag(D.AllocatorTraits->getExprLoc(),
+ diag::err_omp_predefined_allocator_with_traits)
+ << D.AllocatorTraits->getSourceRange();
+ Diag(D.Allocator->getExprLoc(), diag::note_omp_predefined_allocator)
+ << cast<NamedDecl>(DRE->getDecl())->getName()
+ << D.Allocator->getSourceRange();
+ continue;
+ }
+ // OpenMP [2.12.5, target Construct]
+ // Non-predefined allocators appearing in a uses_allocators clause must
+ // have traits specified.
+ if (!IsPredefinedAllocator && !D.AllocatorTraits) {
+ Diag(D.Allocator->getExprLoc(),
+ diag::err_omp_nonpredefined_allocator_without_traits);
+ continue;
+ }
+ // No allocator traits - just convert it to rvalue.
+ if (!D.AllocatorTraits)
+ AllocatorExpr = DefaultLvalueConversion(AllocatorExpr).get();
+ DSAStack->addUsesAllocatorsDecl(
+ DRE->getDecl(),
+ IsPredefinedAllocator
+ ? DSAStackTy::UsesAllocatorsDeclKind::PredefinedAllocator
+ : DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator);
+ }
+ Expr *AllocatorTraitsExpr = nullptr;
+ if (D.AllocatorTraits) {
+ if (D.AllocatorTraits->isTypeDependent()) {
+ AllocatorTraitsExpr = D.AllocatorTraits;
+ } else {
+ // OpenMP [2.12.5, target Construct]
+ // Arrays that contain allocator traits that appear in a uses_allocators
+ // clause must be constant arrays, have constant values and be defined
+ // in the same scope as the construct in which the clause appears.
+ AllocatorTraitsExpr = D.AllocatorTraits->IgnoreParenImpCasts();
+ // Check that traits expr is a constant array.
+ QualType TraitTy;
+ if (const ArrayType *Ty =
+ AllocatorTraitsExpr->getType()->getAsArrayTypeUnsafe())
+ if (const auto *ConstArrayTy = dyn_cast<ConstantArrayType>(Ty))
+ TraitTy = ConstArrayTy->getElementType();
+ if (TraitTy.isNull() ||
+ !(Context.hasSameUnqualifiedType(TraitTy,
+ DSAStack->getOMPAlloctraitT()) ||
+ Context.typesAreCompatible(TraitTy, DSAStack->getOMPAlloctraitT(),
+ /*CompareUnqualified=*/true))) {
+ Diag(D.AllocatorTraits->getExprLoc(),
+ diag::err_omp_expected_array_alloctraits)
+ << AllocatorTraitsExpr->getType();
+ continue;
+ }
+ // Do not map by default allocator traits if it is a standalone
+ // variable.
+ if (auto *DRE = dyn_cast<DeclRefExpr>(AllocatorTraitsExpr))
+ DSAStack->addUsesAllocatorsDecl(
+ DRE->getDecl(),
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait);
+ }
+ }
+ OMPUsesAllocatorsClause::Data &NewD = NewData.emplace_back();
+ NewD.Allocator = AllocatorExpr;
+ NewD.AllocatorTraits = AllocatorTraitsExpr;
+ NewD.LParenLoc = D.LParenLoc;
+ NewD.RParenLoc = D.RParenLoc;
+ }
+ return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ NewData);
+}
+
+OMPClause *Sema::ActOnOpenMPAffinityClause(
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : Locators) {
+ assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts();
+
+ if (!SimpleExpr->isLValue()) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << 1 << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr);
+ }
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+ !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << 1 << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+ Vars.push_back(SimpleExpr);
+ }
+
+ return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, Modifier, Vars);
+}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0fd932fac970..8635397f4806 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10,10 +10,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Overload.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.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"
@@ -21,9 +21,11 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -38,6 +40,8 @@
using namespace clang;
using namespace sema;
+using AllowedExplicit = Sema::AllowedExplicit;
+
static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
return llvm::any_of(FD->parameters(), [](const ParmVarDecl *P) {
return P->hasAttr<PassObjectSizeAttr>();
@@ -91,10 +95,9 @@ static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence& User,
OverloadCandidateSet& Conversions,
- bool AllowExplicit,
+ AllowedExplicit AllowExplicit,
bool AllowObjCConversionOnExplicit);
-
static ImplicitConversionSequence::CompareKind
CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
const StandardConversionSequence& SCS1,
@@ -229,7 +232,6 @@ bool StandardConversionSequence::isPointerConversionToBool() const {
getFromType()->isMemberPointerType() ||
getFromType()->isObjCObjectPointerType() ||
getFromType()->isBlockPointerType() ||
- getFromType()->isNullPtrType() ||
First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer))
return true;
@@ -327,9 +329,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
goto FloatingIntegralConversion;
if (FromType->isIntegralOrUnscopedEnumerationType())
goto IntegralConversion;
- // Boolean conversions can be from pointers and pointers to members
- // [conv.bool], and those aren't considered narrowing conversions.
- return NK_Not_Narrowing;
+ // -- from a pointer type or pointer-to-member type to bool, or
+ return NK_Type_Narrowing;
// -- from a floating-point type to an integer type, or
//
@@ -1317,7 +1318,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
static ImplicitConversionSequence
TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit,
+ AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion,
@@ -1420,7 +1421,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
static ImplicitConversionSequence
TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit,
+ AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion,
@@ -1475,13 +1476,12 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr *From, QualType ToType,
bool SuppressUserConversions,
- bool AllowExplicit,
+ AllowedExplicit AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion) {
- return ::TryImplicitConversion(*this, From, ToType,
- SuppressUserConversions, AllowExplicit,
- InOverloadResolution, CStyle,
+ return ::TryImplicitConversion(*this, From, ToType, SuppressUserConversions,
+ AllowExplicit, InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
/*AllowObjCConversionOnExplicit=*/false);
}
@@ -1514,10 +1514,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From->getType(), From);
ICS = ::TryImplicitConversion(*this, From, ToType,
/*SuppressUserConversions=*/false,
- AllowExplicit,
+ AllowExplicit ? AllowedExplicit::All
+ : AllowedExplicit::None,
/*InOverloadResolution=*/false,
- /*CStyle=*/false,
- AllowObjCWritebackConversion,
+ /*CStyle=*/false, AllowObjCWritebackConversion,
/*AllowObjCConversionOnExplicit=*/false);
return PerformImplicitConversion(From, ToType, ICS, Action);
}
@@ -1653,9 +1653,13 @@ static bool IsVectorConversion(Sema &S, QualType FromType,
// 1)vector types are equivalent AltiVec and GCC vector types
// 2)lax vector conversions are permitted and the vector types are of the
// same size
+ // 3)the destination type does not have the ARM MVE strict-polymorphism
+ // attribute, which inhibits lax vector conversion for overload resolution
+ // only
if (ToType->isVectorType() && FromType->isVectorType()) {
if (S.Context.areCompatibleVectorTypes(FromType, ToType) ||
- S.isLaxVectorConversion(FromType, ToType)) {
+ (S.isLaxVectorConversion(FromType, ToType) &&
+ !ToType->hasAttr(attr::ArmMveStrictPolymorphism))) {
ICK = ICK_Vector_Conversion;
return true;
}
@@ -1844,8 +1848,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
(FromType->isArithmeticType() ||
FromType->isAnyPointerType() ||
FromType->isBlockPointerType() ||
- FromType->isMemberPointerType() ||
- FromType->isNullPtrType())) {
+ FromType->isMemberPointerType())) {
// Boolean conversions (C++ 4.12).
SCS.Second = ICK_Boolean_Conversion;
FromType = S.Context.BoolTy;
@@ -1867,6 +1870,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// FIXME: disable conversions between long double and __float128 if
// their representation is different until there is back end support
// We of course allow this conversion if long double is really double.
+
+ // Conversions between bfloat and other floats are not permitted.
+ if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty)
+ return false;
if (&S.Context.getFloatTypeSemantics(FromType) !=
&S.Context.getFloatTypeSemantics(ToType)) {
bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty &&
@@ -1885,6 +1892,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
ToType->isIntegralType(S.Context)) ||
(FromType->isIntegralOrUnscopedEnumerationType() &&
ToType->isRealFloatingType())) {
+ // Conversions between bfloat and int are not permitted.
+ if (FromType->isBFloat16Type() || ToType->isBFloat16Type())
+ return false;
+
// Floating-integral conversions (C++ 4.9).
SCS.Second = ICK_Floating_Integral;
FromType = ToType.getUnqualifiedType();
@@ -3000,13 +3011,13 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType,
// We must have a derived-to-base conversion. Check an
// ambiguous or inaccessible conversion.
unsigned InaccessibleID = 0;
- unsigned AmbigiousID = 0;
+ unsigned AmbiguousID = 0;
if (Diagnose) {
InaccessibleID = diag::err_upcast_to_inaccessible_base;
- AmbigiousID = diag::err_ambiguous_derived_to_base_conv;
+ AmbiguousID = diag::err_ambiguous_derived_to_base_conv;
}
if (CheckDerivedToBaseConversion(
- FromPointeeType, ToPointeeType, InaccessibleID, AmbigiousID,
+ FromPointeeType, ToPointeeType, InaccessibleID, AmbiguousID,
From->getExprLoc(), From->getSourceRange(), DeclarationName(),
&BasePath, IgnoreBaseAccess))
return true;
@@ -3176,7 +3187,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
/// FromType and \p ToType is permissible, given knowledge about whether every
/// outer layer is const-qualified.
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
- bool CStyle,
+ bool CStyle, bool IsTopLevel,
bool &PreviousToQualsIncludeConst,
bool &ObjCLifetimeConversion) {
Qualifiers FromQuals = FromType.getQualifiers();
@@ -3213,11 +3224,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
return false;
- // For a C-style cast, just require the address spaces to overlap.
- // FIXME: Does "superset" also imply the representation of a pointer is the
- // same? We're assuming that it does here and in compatiblyIncludes.
- if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
- !FromQuals.isAddressSpaceSupersetOf(ToQuals))
+ // If address spaces mismatch:
+ // - in top level it is only valid to convert to addr space that is a
+ // superset in all cases apart from C-style casts where we allow
+ // conversions between overlapping address spaces.
+ // - in non-top levels it is not a valid conversion.
+ if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
+ (!IsTopLevel ||
+ !(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
+ (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
return false;
// -- if the cv 1,j and cv 2,j are different, then const is in
@@ -3258,9 +3273,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
- if (!isQualificationConversionStep(FromType, ToType, CStyle,
- PreviousToQualsIncludeConst,
- ObjCLifetimeConversion))
+ if (!isQualificationConversionStep(
+ FromType, ToType, CStyle, !UnwrappedAnyPointer,
+ PreviousToQualsIncludeConst, ObjCLifetimeConversion))
return false;
UnwrappedAnyPointer = true;
}
@@ -3393,9 +3408,10 @@ static OverloadingResult
IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
- bool AllowExplicit,
+ AllowedExplicit AllowExplicit,
bool AllowObjCConversionOnExplicit) {
- assert(AllowExplicit || !AllowObjCConversionOnExplicit);
+ assert(AllowExplicit != AllowedExplicit::None ||
+ !AllowObjCConversionOnExplicit);
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
// Whether we will only visit constructors.
@@ -3428,7 +3444,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
// But first, see if there is an init-list-constructor that will work.
OverloadingResult Result = IsInitializerListConstructorConversion(
- S, From, ToType, ToRecordDecl, User, CandidateSet, AllowExplicit);
+ S, From, ToType, ToRecordDecl, User, CandidateSet,
+ AllowExplicit == AllowedExplicit::All);
if (Result != OR_No_Viable_Function)
return Result;
// Never mind.
@@ -3467,14 +3484,16 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions,
- /*PartialOverloading*/ false, AllowExplicit);
+ /*PartialOverloading*/ false,
+ AllowExplicit == AllowedExplicit::All);
else
// 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,
- /*PartialOverloading*/ false, AllowExplicit);
+ /*PartialOverloading*/ false,
+ AllowExplicit == AllowedExplicit::All);
}
}
}
@@ -3507,11 +3526,12 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (ConvTemplate)
S.AddTemplateConversionCandidate(
ConvTemplate, FoundDecl, ActingContext, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
+ CandidateSet, AllowObjCConversionOnExplicit,
+ AllowExplicit != AllowedExplicit::None);
else
- S.AddConversionCandidate(
- Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
- AllowObjCConversionOnExplicit, AllowExplicit);
+ S.AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType,
+ CandidateSet, AllowObjCConversionOnExplicit,
+ AllowExplicit != AllowedExplicit::None);
}
}
}
@@ -3597,7 +3617,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
- CandidateSet, false, false);
+ CandidateSet, AllowedExplicit::None, false);
if (!(OvResult == OR_Ambiguous ||
(OvResult == OR_No_Viable_Function && !CandidateSet.empty())))
@@ -4499,7 +4519,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// If we find a qualifier mismatch, the types are not reference-compatible,
// but are still be reference-related if they're similar.
bool ObjCLifetimeConversion = false;
- if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
+ if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
PreviousToQualsIncludeConst,
ObjCLifetimeConversion))
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
@@ -4689,7 +4709,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
Sema::ReferenceConversions::NestedQualification)
? ICK_Qualification
: ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setFromType(T2);
ICS.Standard.setToType(0, T2);
ICS.Standard.setToType(1, T1);
ICS.Standard.setToType(2, T1);
@@ -4858,7 +4878,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// cv-qualification is subsumed by the initialization itself
// and does not constitute a conversion.
ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false,
@@ -5027,7 +5047,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
if (ToType->isRecordType() && !ToType->isAggregateType()) {
// This function can deal with initializer lists.
return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
InOverloadResolution, /*CStyle=*/false,
AllowObjCWritebackConversion,
/*AllowObjCConversionOnExplicit=*/false);
@@ -5179,7 +5199,7 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
return TryImplicitConversion(S, From, ToType,
SuppressUserConversions,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
InOverloadResolution,
/*CStyle=*/false,
AllowObjCWritebackConversion,
@@ -5425,9 +5445,20 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
/// expression From to bool (C++0x [conv]p3).
static ImplicitConversionSequence
TryContextuallyConvertToBool(Sema &S, Expr *From) {
+ // C++ [dcl.init]/17.8:
+ // - Otherwise, if the initialization is direct-initialization, the source
+ // type is std::nullptr_t, and the destination type is bool, the initial
+ // value of the object being initialized is false.
+ if (From->getType()->isNullPtrType())
+ return ImplicitConversionSequence::getNullptrToBool(From->getType(),
+ S.Context.BoolTy,
+ From->isGLValue());
+
+ // All other direct-initialization of bool is equivalent to an implicit
+ // conversion to bool in which explicit conversions are permitted.
return TryImplicitConversion(S, From, S.Context.BoolTy,
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/true,
+ AllowedExplicit::Conversions,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false,
@@ -5699,7 +5730,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
= TryImplicitConversion(S, From, Ty,
// FIXME: Are these flags correct?
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/true,
+ AllowedExplicit::Conversions,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false,
@@ -6291,9 +6322,9 @@ void Sema::AddOverloadCandidate(
return;
}
- if (Expr *RequiresClause = Function->getTrailingRequiresClause()) {
+ if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Function, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -6333,7 +6364,8 @@ void Sema::AddOverloadCandidate(
}
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
+ if (EnableIfAttr *FailedAttr =
+ CheckEnableIf(Function, CandidateSet.getLocation(), Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -6439,11 +6471,10 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
return nullptr;
}
-static bool
-convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
- ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap,
- bool MissingImplicitThis, Expr *&ConvertedThis,
- SmallVectorImpl<Expr *> &ConvertedArgs) {
+static bool convertArgsForAvailabilityChecks(
+ Sema &S, FunctionDecl *Function, Expr *ThisArg, SourceLocation CallLoc,
+ ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap, bool MissingImplicitThis,
+ Expr *&ConvertedThis, SmallVectorImpl<Expr *> &ConvertedArgs) {
if (ThisArg) {
CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
assert(!isa<CXXConstructorDecl>(Method) &&
@@ -6488,17 +6519,9 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
if (!Function->isVariadic() && Args.size() < Function->getNumParams()) {
for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) {
ParmVarDecl *P = Function->getParamDecl(i);
- Expr *DefArg = P->hasUninstantiatedDefaultArg()
- ? P->getUninstantiatedDefaultArg()
- : P->getDefaultArg();
- // This can only happen in code completion, i.e. when PartialOverloading
- // is true.
- if (!DefArg)
+ if (!P->hasDefaultArg())
return false;
- ExprResult R =
- S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
- S.Context, Function->getParamDecl(i)),
- SourceLocation(), DefArg);
+ ExprResult R = S.BuildCXXDefaultArgExpr(CallLoc, Function, P);
if (R.isInvalid())
return false;
ConvertedArgs.push_back(R.get());
@@ -6510,7 +6533,9 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
return true;
}
-EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
+EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function,
+ SourceLocation CallLoc,
+ ArrayRef<Expr *> Args,
bool MissingImplicitThis) {
auto EnableIfAttrs = Function->specific_attrs<EnableIfAttr>();
if (EnableIfAttrs.begin() == EnableIfAttrs.end())
@@ -6521,7 +6546,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
// FIXME: We should look into making enable_if late-parsed.
Expr *DiscardedThis;
if (!convertArgsForAvailabilityChecks(
- *this, Function, /*ThisArg=*/nullptr, Args, Trap,
+ *this, Function, /*ThisArg=*/nullptr, CallLoc, Args, Trap,
/*MissingImplicitThis=*/true, DiscardedThis, ConvertedArgs))
return *EnableIfAttrs.begin();
@@ -6808,9 +6833,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
- if (Expr *RequiresClause = Method->getTrailingRequiresClause()) {
+ if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Method, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -6851,7 +6876,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
}
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Method, Args, true)) {
+ if (EnableIfAttr *FailedAttr =
+ CheckEnableIf(Method, CandidateSet.getLocation(), Args, true)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -7204,10 +7230,9 @@ void Sema::AddConversionCandidate(
return;
}
- Expr *RequiresClause = Conversion->getTrailingRequiresClause();
- if (RequiresClause) {
+ if (Conversion->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Conversion, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7305,7 +7330,8 @@ void Sema::AddConversionCandidate(
"Can only end up with a standard conversion sequence or failure");
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
+ if (EnableIfAttr *FailedAttr =
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -7475,7 +7501,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
- if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
+ if (EnableIfAttr *FailedAttr =
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -7665,6 +7692,10 @@ class BuiltinCandidateTypeSet {
/// candidates.
TypeSet VectorTypes;
+ /// The set of matrix types that will be used in the built-in
+ /// candidates.
+ TypeSet MatrixTypes;
+
/// A flag indicating non-record types are viable candidates
bool HasNonRecordTypes;
@@ -7722,9 +7753,11 @@ public:
/// enumeration_end - Past the last enumeration type found;
iterator enumeration_end() { return EnumerationTypes.end(); }
- iterator vector_begin() { return VectorTypes.begin(); }
- iterator vector_end() { return VectorTypes.end(); }
+ llvm::iterator_range<iterator> vector_types() { return VectorTypes; }
+
+ llvm::iterator_range<iterator> matrix_types() { return MatrixTypes; }
+ bool containsMatrixType(QualType Ty) const { return MatrixTypes.count(Ty); }
bool hasNonRecordTypes() { return HasNonRecordTypes; }
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
bool hasNullPtrType() const { return HasNullPtrType; }
@@ -7899,6 +7932,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// extension.
HasArithmeticOrEnumeralTypes = true;
VectorTypes.insert(Ty);
+ } else if (Ty->isMatrixType()) {
+ // Similar to vector types, we treat vector types as arithmetic types in
+ // many contexts as an extension.
+ HasArithmeticOrEnumeralTypes = true;
+ MatrixTypes.insert(Ty);
} else if (Ty->isNullPtrType()) {
HasNullPtrType = true;
} else if (AllowUserConversions && TyRec) {
@@ -8127,6 +8165,13 @@ class BuiltinOperatorOverloadBuilder {
}
+ /// Helper to add an overload candidate for a binary builtin with types \p L
+ /// and \p R.
+ void AddCandidate(QualType L, QualType R) {
+ QualType LandR[2] = {L, R};
+ S.AddBuiltinCandidate(LandR, Args, CandidateSet);
+ }
+
public:
BuiltinOperatorOverloadBuilder(
Sema &S, ArrayRef<Expr *> Args,
@@ -8254,13 +8299,8 @@ public:
}
// Extension: We also add these operators for vector types.
- for (BuiltinCandidateTypeSet::iterator
- Vec = CandidateTypes[0].vector_begin(),
- VecEnd = CandidateTypes[0].vector_end();
- Vec != VecEnd; ++Vec) {
- QualType VecTy = *Vec;
+ for (QualType VecTy : CandidateTypes[0].vector_types())
S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
- }
}
// C++ [over.built]p8:
@@ -8294,13 +8334,8 @@ public:
}
// Extension: We also add this operator for vector types.
- for (BuiltinCandidateTypeSet::iterator
- Vec = CandidateTypes[0].vector_begin(),
- VecEnd = CandidateTypes[0].vector_end();
- Vec != VecEnd; ++Vec) {
- QualType VecTy = *Vec;
+ for (QualType VecTy : CandidateTypes[0].vector_types())
S.AddBuiltinCandidate(&VecTy, Args, CandidateSet);
- }
}
// C++ [over.match.oper]p16:
@@ -8380,7 +8415,7 @@ public:
// We interpret "same parameter-type-list" as applying to the
// "synthesized candidate, with the order of the two parameters
// reversed", not to the original function.
- bool Reversed = C->RewriteKind & CRK_Reversed;
+ bool Reversed = C->isReversed();
QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)
->getType()
.getUnqualifiedType();
@@ -8531,17 +8566,31 @@ public:
// Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the
// conditional operator for vector types.
- for (BuiltinCandidateTypeSet::iterator
- Vec1 = CandidateTypes[0].vector_begin(),
- Vec1End = CandidateTypes[0].vector_end();
- Vec1 != Vec1End; ++Vec1) {
- for (BuiltinCandidateTypeSet::iterator
- Vec2 = CandidateTypes[1].vector_begin(),
- Vec2End = CandidateTypes[1].vector_end();
- Vec2 != Vec2End; ++Vec2) {
- QualType LandR[2] = { *Vec1, *Vec2 };
+ for (QualType Vec1Ty : CandidateTypes[0].vector_types())
+ for (QualType Vec2Ty : CandidateTypes[1].vector_types()) {
+ QualType LandR[2] = {Vec1Ty, Vec2Ty};
S.AddBuiltinCandidate(LandR, Args, CandidateSet);
}
+ }
+
+ /// Add binary operator overloads for each candidate matrix type M1, M2:
+ /// * (M1, M1) -> M1
+ /// * (M1, M1.getElementType()) -> M1
+ /// * (M2.getElementType(), M2) -> M2
+ /// * (M2, M2) -> M2 // Only if M2 is not part of CandidateTypes[0].
+ void addMatrixBinaryArithmeticOverloads() {
+ if (!HasArithmeticOrEnumeralCandidateType)
+ return;
+
+ for (QualType M1 : CandidateTypes[0].matrix_types()) {
+ AddCandidate(M1, cast<MatrixType>(M1)->getElementType());
+ AddCandidate(M1, M1);
+ }
+
+ for (QualType M2 : CandidateTypes[1].matrix_types()) {
+ AddCandidate(cast<MatrixType>(M2)->getElementType(), M2);
+ if (!CandidateTypes[0].containsMatrixType(M2))
+ AddCandidate(M2, M2);
}
}
@@ -8802,30 +8851,23 @@ public:
}
// Extension: Add the binary operators =, +=, -=, *=, /= for vector types.
- for (BuiltinCandidateTypeSet::iterator
- Vec1 = CandidateTypes[0].vector_begin(),
- Vec1End = CandidateTypes[0].vector_end();
- Vec1 != Vec1End; ++Vec1) {
- for (BuiltinCandidateTypeSet::iterator
- Vec2 = CandidateTypes[1].vector_begin(),
- Vec2End = CandidateTypes[1].vector_end();
- Vec2 != Vec2End; ++Vec2) {
+ for (QualType Vec1Ty : CandidateTypes[0].vector_types())
+ for (QualType Vec2Ty : CandidateTypes[0].vector_types()) {
QualType ParamTypes[2];
- ParamTypes[1] = *Vec2;
+ ParamTypes[1] = Vec2Ty;
// Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1);
+ ParamTypes[0] = S.Context.getLValueReferenceType(Vec1Ty);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/isEqualOp);
// Add this built-in operator as a candidate (VQ is 'volatile').
if (VisibleTypeConversionsQuals.hasVolatile()) {
- ParamTypes[0] = S.Context.getVolatileType(*Vec1);
+ ParamTypes[0] = S.Context.getVolatileType(Vec1Ty);
ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
/*IsAssignmentOperator=*/isEqualOp);
}
}
- }
}
// C++ [over.built]p22:
@@ -9118,14 +9160,17 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
} else {
OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op);
OpBuilder.addGenericBinaryArithmeticOverloads();
+ OpBuilder.addMatrixBinaryArithmeticOverloads();
}
break;
case OO_Star: // '*' is either unary or binary
if (Args.size() == 1)
OpBuilder.addUnaryStarPointerOverloads();
- else
+ else {
OpBuilder.addGenericBinaryArithmeticOverloads();
+ OpBuilder.addMatrixBinaryArithmeticOverloads();
+ }
break;
case OO_Slash:
@@ -9270,17 +9315,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
- /*SuppressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit*/ true,
- /*AllowExplicitConversions*/ false,
- ADLCallKind::UsesADL);
+ AddOverloadCandidate(
+ FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
+ PartialOverloading, /*AllowExplicit=*/true,
+ /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
+ AddOverloadCandidate(
+ FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
+ /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false,
+ ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
+ }
} else {
+ auto *FTD = cast<FunctionTemplateDecl>(*I);
AddTemplateOverloadCandidate(
- cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
- CandidateSet,
+ FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet,
/*SuppressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit*/true, ADLCallKind::UsesADL);
+ /*AllowExplicit=*/true, ADLCallKind::UsesADL);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(
+ Context, FTD->getTemplatedDecl())) {
+ AddTemplateOverloadCandidate(
+ FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
+ CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit=*/true, ADLCallKind::UsesADL,
+ OverloadCandidateParamOrder::Reversed);
+ }
}
}
}
@@ -9338,16 +9397,22 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
return Comparison::Equal;
}
-static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
- const OverloadCandidate &Cand2) {
+static Comparison
+isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
+ const OverloadCandidate &Cand2) {
if (!Cand1.Function || !Cand1.Function->isMultiVersion() || !Cand2.Function ||
!Cand2.Function->isMultiVersion())
- return false;
+ return Comparison::Equal;
- // If Cand1 is invalid, it cannot be a better match, if Cand2 is invalid, this
- // is obviously better.
- if (Cand1.Function->isInvalidDecl()) return false;
- if (Cand2.Function->isInvalidDecl()) return true;
+ // If both are invalid, they are equal. If one of them is invalid, the other
+ // is better.
+ if (Cand1.Function->isInvalidDecl()) {
+ if (Cand2.Function->isInvalidDecl())
+ return Comparison::Equal;
+ return Comparison::Worse;
+ }
+ if (Cand2.Function->isInvalidDecl())
+ return Comparison::Better;
// If this is a cpu_dispatch/cpu_specific multiversion situation, prefer
// cpu_dispatch, else arbitrarily based on the identifiers.
@@ -9357,16 +9422,18 @@ static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
const auto *Cand2CPUSpec = Cand2.Function->getAttr<CPUSpecificAttr>();
if (!Cand1CPUDisp && !Cand2CPUDisp && !Cand1CPUSpec && !Cand2CPUSpec)
- return false;
+ return Comparison::Equal;
if (Cand1CPUDisp && !Cand2CPUDisp)
- return true;
+ return Comparison::Better;
if (Cand2CPUDisp && !Cand1CPUDisp)
- return false;
+ return Comparison::Worse;
if (Cand1CPUSpec && Cand2CPUSpec) {
if (Cand1CPUSpec->cpus_size() != Cand2CPUSpec->cpus_size())
- return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size();
+ return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size()
+ ? Comparison::Better
+ : Comparison::Worse;
std::pair<CPUSpecificAttr::cpus_iterator, CPUSpecificAttr::cpus_iterator>
FirstDiff = std::mismatch(
@@ -9379,11 +9446,56 @@ static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
assert(FirstDiff.first != Cand1CPUSpec->cpus_end() &&
"Two different cpu-specific versions should not have the same "
"identifier list, otherwise they'd be the same decl!");
- return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName();
+ return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName()
+ ? Comparison::Better
+ : Comparison::Worse;
}
llvm_unreachable("No way to get here unless both had cpu_dispatch");
}
+/// 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 (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F))
+ return llvm::None;
+
+ auto *M = cast<CXXMethodDecl>(F);
+ // Static member functions' object parameters match all types.
+ if (M->isStatic())
+ return QualType();
+
+ QualType T = M->getThisObjectType();
+ if (M->getRefQualifier() == RQ_RValue)
+ return Context.getRValueReferenceType(T);
+ return Context.getLValueReferenceType(T);
+}
+
+static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
+ const FunctionDecl *F2, unsigned NumParams) {
+ if (declaresSameEntity(F1, F2))
+ return true;
+
+ auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) {
+ if (First) {
+ if (Optional<QualType> T = getImplicitObjectParamType(Context, F))
+ return *T;
+ }
+ assert(I < F->getNumParams());
+ return F->getParamDecl(I++)->getType();
+ };
+
+ unsigned I1 = 0, I2 = 0;
+ for (unsigned I = 0; I != NumParams; ++I) {
+ QualType T1 = NextParam(F1, I1, I == 0);
+ QualType T2 = NextParam(F2, I2, I == 0);
+ if (!T1.isNull() && !T1.isNull() && !Context.hasSameUnqualifiedType(T1, T2))
+ return false;
+ }
+ return true;
+}
+
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
bool clang::isBetterOverloadCandidate(
@@ -9451,18 +9563,20 @@ bool clang::isBetterOverloadCandidate(
break;
case ImplicitConversionSequence::Worse:
- if (Cand1.Function && Cand1.Function == Cand2.Function &&
- (Cand2.RewriteKind & CRK_Reversed) != 0) {
+ if (Cand1.Function && Cand2.Function &&
+ Cand1.isReversed() != Cand2.isReversed() &&
+ haveSameParameterTypes(S.Context, Cand1.Function, Cand2.Function,
+ NumArgs)) {
// Work around large-scale breakage caused by considering reversed
// forms of operator== in C++20:
//
- // When comparing a function against its reversed form, if we have a
- // better conversion for one argument and a worse conversion for the
- // other, we prefer the non-reversed form.
+ // When comparing a function against a reversed function with the same
+ // parameter types, if we have a better conversion for one argument and
+ // a worse conversion for the other, the implicit conversion sequences
+ // are treated as being equally good.
//
- // This prevents a conversion function from being considered ambiguous
- // with its own reversed form in various where it's only incidentally
- // heterogeneous.
+ // This prevents a comparison function from being considered ambiguous
+ // with a reversed form that is written in the same way.
//
// We diagnose this as an extension from CreateOverloadedBinOp.
HasWorseConversion = true;
@@ -9480,10 +9594,8 @@ bool clang::isBetterOverloadCandidate(
// -- for some argument j, ICSj(F1) is a better conversion sequence than
// ICSj(F2), or, if not that,
- if (HasBetterConversion)
+ if (HasBetterConversion && !HasWorseConversion)
return true;
- if (HasWorseConversion)
- return false;
// -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence
@@ -9540,14 +9652,13 @@ bool clang::isBetterOverloadCandidate(
// according to the partial ordering rules described in 14.5.5.2, or,
// if not that,
if (Cand1IsSpecialization && Cand2IsSpecialization) {
- if (FunctionTemplateDecl *BetterTemplate
- = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
- Cand2.Function->getPrimaryTemplate(),
- Loc,
- isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion
- : TPOC_Call,
- Cand1.ExplicitCallArguments,
- Cand2.ExplicitCallArguments))
+ if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(
+ Cand1.Function->getPrimaryTemplate(),
+ Cand2.Function->getPrimaryTemplate(), Loc,
+ isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
+ : TPOC_Call,
+ Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
+ Cand1.isReversed() ^ Cand2.isReversed()))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
@@ -9566,17 +9677,15 @@ bool clang::isBetterOverloadCandidate(
if (RC1 && RC2) {
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function,
- {RC2}, AtLeastAsConstrained1))
- return false;
- if (!AtLeastAsConstrained1)
- return false;
- if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
+ {RC2}, AtLeastAsConstrained1) ||
+ S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
{RC1}, AtLeastAsConstrained2))
return false;
- if (!AtLeastAsConstrained2)
- return true;
- } else if (RC1 || RC2)
+ if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
+ return AtLeastAsConstrained1;
+ } else if (RC1 || RC2) {
return RC1 != nullptr;
+ }
}
}
@@ -9646,7 +9755,8 @@ bool clang::isBetterOverloadCandidate(
if (HasPS1 != HasPS2 && HasPS1)
return true;
- return isBetterMultiversionCandidate(Cand1, Cand2);
+ Comparison MV = isBetterMultiversionCandidate(Cand1, Cand2);
+ return MV == Comparison::Better;
}
/// Determine whether two declarations are "equivalent" for the purposes of
@@ -9947,9 +10057,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
}
- if (const Expr *RC = FD->getTrailingRequiresClause()) {
+ if (FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (S.CheckConstraintSatisfaction(RC, Satisfaction))
+ if (S.CheckFunctionConstraints(FD, Satisfaction, Loc))
return false;
if (!Satisfaction.IsSatisfied) {
if (Complain) {
@@ -10974,8 +11084,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
<< FnDesc /* Ignored */;
ConstraintSatisfaction Satisfaction;
- if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(),
- Satisfaction))
+ if (S.CheckFunctionConstraints(Fn, Satisfaction))
break;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
}
@@ -11275,7 +11384,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
unsigned ConvIdx = 0;
unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
- bool Reversed = Cand->RewriteKind & CRK_Reversed;
+ bool Reversed = Cand->isReversed();
if (Cand->IsSurrogate) {
QualType ConvType
@@ -12688,9 +12797,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// base classes.
CallExpr *CE = CallExpr::Create(Context, Fn, Args, Context.DependentTy,
VK_RValue, RParenLoc);
- CE->setTypeDependent(true);
- CE->setValueDependent(true);
- CE->setInstantiationDependent(true);
+ CE->markDependentForPostponedNameLookup();
*Result = CE;
return true;
}
@@ -12703,6 +12810,42 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
return false;
}
+// Guess at what the return type for an unresolvable overload should be.
+static QualType chooseRecoveryType(OverloadCandidateSet &CS,
+ OverloadCandidateSet::iterator *Best) {
+ llvm::Optional<QualType> Result;
+ // Adjust Type after seeing a candidate.
+ auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
+ if (!Candidate.Function)
+ return;
+ QualType T = Candidate.Function->getReturnType();
+ if (T.isNull())
+ return;
+ if (!Result)
+ Result = T;
+ else if (Result != T)
+ Result = QualType();
+ };
+
+ // Look for an unambiguous type from a progressively larger subset.
+ // e.g. if types disagree, but all *viable* overloads return int, choose int.
+ //
+ // First, consider only the best candidate.
+ if (Best && *Best != CS.end())
+ ConsiderCandidate(**Best);
+ // Next, consider only viable candidates.
+ if (!Result)
+ for (const auto &C : CS)
+ if (C.Viable)
+ ConsiderCandidate(C);
+ // Finally, consider all candidates.
+ if (!Result)
+ for (const auto &C : CS)
+ ConsiderCandidate(C);
+
+ return Result.getValueOr(QualType());
+}
+
/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns
/// the completed call expression. If overload resolution fails, emits
/// diagnostics and returns ExprError()
@@ -12792,8 +12935,11 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
}
}
- // Overload resolution failed.
- return ExprError();
+ // Overload resolution failed, try to recover.
+ SmallVector<Expr *, 8> SubExprs = {Fn};
+ SubExprs.append(Args.begin(), Args.end());
+ return SemaRef.CreateRecoveryExpr(Fn->getBeginLoc(), RParenLoc, SubExprs,
+ chooseRecoveryType(*CandidateSet, Best));
}
static void markUnaddressableCandidatesUnviable(Sema &S,
@@ -12893,8 +13039,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (Input->isTypeDependent()) {
if (Fns.empty())
- return new (Context) UnaryOperator(Input, Opc, Context.DependentTy,
- VK_RValue, OK_Ordinary, OpLoc, false);
+ return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy,
+ VK_RValue, OK_Ordinary, OpLoc, false,
+ CurFPFeatureOverrides());
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
@@ -12902,7 +13049,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
/*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end());
return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray,
Context.DependentTy, VK_RValue, OpLoc,
- FPOptions());
+ CurFPFeatureOverrides());
}
// Build an empty overload set.
@@ -12976,7 +13123,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Args[0] = Input;
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
- FPOptions(), Best->IsADLCandidate);
+ CurFPFeatureOverrides(), Best->IsADLCandidate);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
@@ -12984,8 +13131,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (CheckFunctionCall(FnDecl, TheCall,
FnDecl->getType()->castAs<FunctionProtoType>()))
return ExprError();
-
- return MaybeBindToTemporary(TheCall);
+ return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FnDecl);
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -13134,7 +13280,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
- if (!getLangOpts().CPlusPlus2a)
+ if (!getLangOpts().CPlusPlus20)
AllowRewrittenCandidates = false;
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
@@ -13146,14 +13292,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If there are no functions to store, just build a dependent
// BinaryOperator or CompoundAssignment.
if (Opc <= BO_Assign || Opc > BO_OrAssign)
- return new (Context) BinaryOperator(
- Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
- OpLoc, FPFeatures);
-
- return new (Context) CompoundAssignOperator(
- Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
- Context.DependentTy, Context.DependentTy, OpLoc,
- FPFeatures);
+ return BinaryOperator::Create(
+ Context, Args[0], Args[1], Opc, Context.DependentTy, VK_RValue,
+ OK_Ordinary, OpLoc, CurFPFeatureOverrides());
+ return CompoundAssignOperator::Create(
+ Context, Args[0], Args[1], Opc, Context.DependentTy, VK_LValue,
+ OK_Ordinary, OpLoc, CurFPFeatureOverrides(), Context.DependentTy,
+ Context.DependentTy);
}
// FIXME: save results of ADL from here?
@@ -13166,7 +13311,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
/*ADL*/ PerformADL, IsOverloaded(Fns), Fns.begin(), Fns.end());
return CXXOperatorCallExpr::Create(Context, Op, Fn, Args,
Context.DependentTy, VK_RValue, OpLoc,
- FPFeatures);
+ CurFPFeatureOverrides());
}
// Always do placeholder-like conversions on the RHS.
@@ -13210,7 +13355,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
- bool IsReversed = (Best->RewriteKind & CRK_Reversed);
+ bool IsReversed = Best->isReversed();
if (IsReversed)
std::swap(Args[0], Args[1]);
@@ -13227,36 +13372,56 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// resolution for an operator@, its return type shall be cv bool
if (Best->RewriteKind && ChosenOp == OO_EqualEqual &&
!FnDecl->getReturnType()->isBooleanType()) {
- Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool)
+ bool IsExtension =
+ FnDecl->getReturnType()->isIntegralOrUnscopedEnumerationType();
+ Diag(OpLoc, IsExtension ? diag::ext_ovl_rewrite_equalequal_not_bool
+ : diag::err_ovl_rewrite_equalequal_not_bool)
<< FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
Diag(FnDecl->getLocation(), diag::note_declared_at);
- return ExprError();
+ if (!IsExtension)
+ return ExprError();
}
if (AllowRewrittenCandidates && !IsReversed &&
- CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) {
- // We could have reversed this operator, but didn't. Check if the
+ CandidateSet.getRewriteInfo().isReversible()) {
+ // We could have reversed this operator, but didn't. Check if some
// reversed form was a viable candidate, and if so, if it had a
// better conversion for either parameter. If so, this call is
// formally ambiguous, and allowing it is an extension.
+ llvm::SmallVector<FunctionDecl*, 4> AmbiguousWith;
for (OverloadCandidate &Cand : CandidateSet) {
- if (Cand.Viable && Cand.Function == FnDecl &&
- Cand.RewriteKind & CRK_Reversed) {
+ if (Cand.Viable && Cand.Function && Cand.isReversed() &&
+ haveSameParameterTypes(Context, Cand.Function, FnDecl, 2)) {
for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
if (CompareImplicitConversionSequences(
*this, OpLoc, Cand.Conversions[ArgIdx],
Best->Conversions[ArgIdx]) ==
ImplicitConversionSequence::Better) {
- Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)
- << BinaryOperator::getOpcodeStr(Opc)
- << Args[0]->getType() << Args[1]->getType()
- << Args[0]->getSourceRange() << Args[1]->getSourceRange();
- Diag(FnDecl->getLocation(),
- diag::note_ovl_ambiguous_oper_binary_reversed_candidate);
+ AmbiguousWith.push_back(Cand.Function);
+ break;
}
}
- break;
+ }
+ }
+
+ if (!AmbiguousWith.empty()) {
+ bool AmbiguousWithSelf =
+ AmbiguousWith.size() == 1 &&
+ declaresSameEntity(AmbiguousWith.front(), FnDecl);
+ Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getType() << Args[1]->getType() << AmbiguousWithSelf
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ if (AmbiguousWithSelf) {
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_oper_binary_reversed_self);
+ } else {
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_oper_binary_selected_candidate);
+ for (auto *F : AmbiguousWith)
+ Diag(F->getLocation(),
+ diag::note_ovl_ambiguous_oper_binary_reversed_candidate);
}
}
}
@@ -13315,7 +13480,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
- FPFeatures, Best->IsADLCandidate);
+ CurFPFeatureOverrides(), Best->IsADLCandidate);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
@@ -13341,6 +13506,10 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (R.isInvalid())
return ExprError();
+ R = CheckForImmediateInvocation(R, FnDecl);
+ if (R.isInvalid())
+ return ExprError();
+
// For a rewritten candidate, we've already reversed the arguments
// if needed. Perform the rest of the rewrite now.
if ((Best->RewriteKind & CRK_DifferentOperator) ||
@@ -13580,10 +13749,10 @@ ExprResult Sema::BuildSynthesizedThreeWayComparison(
// Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to
// bind the OpaqueValueExprs before they're (repeatedly) used.
- Expr *SyntacticForm = new (Context)
- BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(),
- Result.get()->getValueKind(),
- Result.get()->getObjectKind(), OpLoc, FPFeatures);
+ Expr *SyntacticForm = BinaryOperator::Create(
+ Context, OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(),
+ Result.get()->getValueKind(), Result.get()->getObjectKind(), OpLoc,
+ CurFPFeatureOverrides());
Expr *SemanticForm[] = {LHS, RHS, Result.get()};
return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
}
@@ -13614,7 +13783,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args,
Context.DependentTy, VK_RValue, RLoc,
- FPOptions());
+ CurFPFeatureOverrides());
}
// Handle placeholders on both operands.
@@ -13687,10 +13856,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall =
- CXXOperatorCallExpr::Create(Context, OO_Subscript, FnExpr.get(),
- Args, ResultTy, VK, RLoc, FPOptions());
-
+ CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
+ Context, OO_Subscript, FnExpr.get(), Args, ResultTy, VK, RLoc,
+ CurFPFeatureOverrides());
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -14000,7 +14168,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// resolution process, we still need to handle the enable_if attribute. Do
// that here, so it will not hide previous -- and more relevant -- errors.
if (auto *MemE = dyn_cast<MemberExpr>(NakedMemExpr)) {
- if (const EnableIfAttr *Attr = CheckEnableIf(Method, Args, true)) {
+ if (const EnableIfAttr *Attr =
+ CheckEnableIf(Method, LParenLoc, Args, true)) {
Diag(MemE->getMemberLoc(),
diag::err_ovl_no_viable_member_function_in_call)
<< Method << Method->getSourceRange();
@@ -14039,7 +14208,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemExpr->getMemberLoc());
}
- return MaybeBindToTemporary(TheCall);
+ return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall),
+ TheCall->getMethodDecl());
}
/// BuildCallToObjectOfClassType - Build a call to an object of class
@@ -14310,9 +14480,9 @@ 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, FPOptions());
+ CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
+ Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
+ CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
@@ -14320,7 +14490,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (CheckFunctionCall(Method, TheCall, Proto))
return true;
- return MaybeBindToTemporary(TheCall);
+ return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
}
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
@@ -14428,8 +14598,9 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
QualType ResultTy = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPOptions());
+ CXXOperatorCallExpr *TheCall =
+ CXXOperatorCallExpr::Create(Context, OO_Arrow, FnExpr.get(), Base,
+ ResultTy, VK, OpLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
return ExprError();
@@ -14515,7 +14686,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
if (CheckFunctionCall(FD, UDL, nullptr))
return ExprError();
- return MaybeBindToTemporary(UDL);
+ return CheckForImmediateInvocation(MaybeBindToTemporary(UDL), FD);
}
/// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the
@@ -14676,9 +14847,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (Context.getTargetInfo().getCXXABI().isMicrosoft())
(void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
- return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
- VK_RValue, OK_Ordinary,
- UnOp->getOperatorLoc(), false);
+ return UnaryOperator::Create(
+ Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary,
+ UnOp->getOperatorLoc(), false, CurFPFeatureOverrides());
}
}
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
@@ -14686,10 +14857,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (SubExpr == UnOp->getSubExpr())
return UnOp;
- return new (Context) UnaryOperator(SubExpr, UO_AddrOf,
- Context.getPointerType(SubExpr->getType()),
- VK_RValue, OK_Ordinary,
- UnOp->getOperatorLoc(), false);
+ return UnaryOperator::Create(Context, SubExpr, UO_AddrOf,
+ Context.getPointerType(SubExpr->getType()),
+ VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(),
+ false, CurFPFeatureOverrides());
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 5587e0d24c7f..d17599a6ed14 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -127,12 +127,10 @@ namespace {
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
assert(uop->getOpcode() == UO_Extension);
e = rebuild(uop->getSubExpr());
- return new (S.Context) UnaryOperator(e, uop->getOpcode(),
- uop->getType(),
- uop->getValueKind(),
- uop->getObjectKind(),
- uop->getOperatorLoc(),
- uop->canOverflow());
+ return UnaryOperator::Create(
+ S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(),
+ uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(),
+ S.CurFPFeatureOverrides());
}
if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
@@ -167,16 +165,11 @@ namespace {
Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS : RHS;
rebuiltExpr = rebuild(rebuiltExpr);
- return new (S.Context) ChooseExpr(ce->getBuiltinLoc(),
- ce->getCond(),
- LHS, RHS,
- rebuiltExpr->getType(),
- rebuiltExpr->getValueKind(),
- rebuiltExpr->getObjectKind(),
- ce->getRParenLoc(),
- ce->isConditionTrue(),
- rebuiltExpr->isTypeDependent(),
- rebuiltExpr->isValueDependent());
+ return new (S.Context)
+ ChooseExpr(ce->getBuiltinLoc(), ce->getCond(), LHS, RHS,
+ rebuiltExpr->getType(), rebuiltExpr->getValueKind(),
+ rebuiltExpr->getObjectKind(), ce->getRParenLoc(),
+ ce->isConditionTrue());
}
llvm_unreachable("bad expression to rebuild!");
@@ -453,11 +446,11 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
ExprResult result;
if (opcode == BO_Assign) {
result = semanticRHS;
- syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
- opcode, capturedRHS->getType(),
- capturedRHS->getValueKind(),
- OK_Ordinary, opcLoc,
- FPOptions());
+ syntactic = BinaryOperator::Create(S.Context, syntacticLHS, capturedRHS,
+ opcode, capturedRHS->getType(),
+ capturedRHS->getValueKind(), OK_Ordinary,
+ opcLoc, S.CurFPFeatureOverrides());
+
} else {
ExprResult opLHS = buildGet();
if (opLHS.isInvalid()) return ExprError();
@@ -468,14 +461,11 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
result = S.BuildBinOp(Sc, opcLoc, nonCompound, opLHS.get(), semanticRHS);
if (result.isInvalid()) return ExprError();
- syntactic =
- new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode,
- result.get()->getType(),
- result.get()->getValueKind(),
- OK_Ordinary,
- opLHS.get()->getType(),
- result.get()->getType(),
- opcLoc, FPOptions());
+ syntactic = CompoundAssignOperator::Create(
+ S.Context, syntacticLHS, capturedRHS, opcode, result.get()->getType(),
+ result.get()->getValueKind(), OK_Ordinary, opcLoc,
+ S.CurFPFeatureOverrides(), opLHS.get()->getType(),
+ result.get()->getType());
}
// The result of the assignment, if not void, is the value set into
@@ -536,12 +526,14 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
(result.get()->isTypeDependent() || CanCaptureValue(result.get())))
setResultToLastSemantic();
- UnaryOperator *syntactic = new (S.Context) UnaryOperator(
- syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc,
- !resultType->isDependentType()
- ? S.Context.getTypeSize(resultType) >=
- S.Context.getTypeSize(S.Context.IntTy)
- : false);
+ UnaryOperator *syntactic =
+ UnaryOperator::Create(S.Context, syntacticOp, opcode, resultType,
+ VK_LValue, OK_Ordinary, opcLoc,
+ !resultType->isDependentType()
+ ? S.Context.getTypeSize(resultType) >=
+ S.Context.getTypeSize(S.Context.IntTy)
+ : false,
+ S.CurFPFeatureOverrides());
return complete(syntactic);
}
@@ -590,7 +582,7 @@ bool ObjCPropertyOpBuilder::isWeakProperty() const {
QualType T;
if (RefExpr->isExplicitProperty()) {
const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
- if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)
return true;
T = Prop->getType();
@@ -1561,8 +1553,9 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
UnaryOperatorKind opcode, Expr *op) {
// Do nothing if the operand is dependent.
if (op->isTypeDependent())
- return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc, false);
+ return UnaryOperator::Create(Context, op, opcode, Context.DependentTy,
+ VK_RValue, OK_Ordinary, opcLoc, false,
+ CurFPFeatureOverrides());
assert(UnaryOperator::isIncrementDecrementOp(opcode));
Expr *opaqueRef = op->IgnoreParens();
@@ -1591,9 +1584,9 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
Expr *LHS, Expr *RHS) {
// Do nothing if either argument is dependent.
if (LHS->isTypeDependent() || RHS->isTypeDependent())
- return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
- VK_RValue, OK_Ordinary, opcLoc,
- FPOptions());
+ return BinaryOperator::Create(Context, LHS, RHS, opcode,
+ Context.DependentTy, VK_RValue, OK_Ordinary,
+ opcLoc, CurFPFeatureOverrides());
// Filter out non-overload placeholder types in the RHS.
if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1646,28 +1639,30 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
Expr *syntax = E->getSyntacticForm();
if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
- return new (Context) UnaryOperator(
- op, uop->getOpcode(), uop->getType(), uop->getValueKind(),
- uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());
+ return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(),
+ uop->getValueKind(), uop->getObjectKind(),
+ uop->getOperatorLoc(), uop->canOverflow(),
+ CurFPFeatureOverrides());
} else if (CompoundAssignOperator *cop
= dyn_cast<CompoundAssignOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
- return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(),
- cop->getType(),
- cop->getValueKind(),
- cop->getObjectKind(),
- cop->getComputationLHSType(),
- cop->getComputationResultType(),
- cop->getOperatorLoc(),
- FPOptions());
+ return CompoundAssignOperator::Create(
+ Context, lhs, rhs, cop->getOpcode(), cop->getType(),
+ cop->getValueKind(), cop->getObjectKind(), cop->getOperatorLoc(),
+ CurFPFeatureOverrides(), cop->getComputationLHSType(),
+ cop->getComputationResultType());
+
} else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
- return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
- bop->getType(), bop->getValueKind(),
- bop->getObjectKind(),
- bop->getOperatorLoc(), FPOptions());
+ return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(),
+ bop->getType(), bop->getValueKind(),
+ bop->getObjectKind(), bop->getOperatorLoc(),
+ CurFPFeatureOverrides());
+
+ } else if (isa<CallExpr>(syntax)) {
+ return syntax;
} else {
assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
new file mode 100644
index 000000000000..db7603b42f7b
--- /dev/null
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -0,0 +1,49 @@
+//===- SemaSYCL.cpp - Semantic Analysis for SYCL 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 SYCL constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+
+// -----------------------------------------------------------------------------
+// SYCL device specific diagnostics implementation
+// -----------------------------------------------------------------------------
+
+Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(getLangOpts().SYCLIsDevice &&
+ "Should only be called during SYCL compilation");
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
+ DeviceDiagBuilder::Kind DiagKind = [this, FD] {
+ if (!FD)
+ return DeviceDiagBuilder::K_Nop;
+ if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
+ return DeviceDiagBuilder::K_ImmediateWithCallStack;
+ return DeviceDiagBuilder::K_Deferred;
+ }();
+ return DeviceDiagBuilder(DiagKind, Loc, DiagID, FD, *this);
+}
+
+bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+ assert(getLangOpts().SYCLIsDevice &&
+ "Should only be called during SYCL compilation");
+ assert(Callee && "Callee may not be null.");
+
+ // Errors in unevaluated context don't need to be generated,
+ // so we can safely skip them.
+ if (isUnevaluatedContext() || isConstantEvaluated())
+ return true;
+
+ DeviceDiagBuilder::Kind DiagKind = DeviceDiagBuilder::K_Nop;
+
+ return DiagKind != DeviceDiagBuilder::K_Immediate &&
+ DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack;
+}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d6c3af9e84c8..73f3183c163f 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -334,6 +334,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
const Expr *Source = POE->getSyntacticForm();
+ // Handle the actually selected call of an OpenMP specialized call.
+ if (LangOpts.OpenMP && isa<CallExpr>(Source) &&
+ POE->getNumSemanticExprs() == 1 &&
+ isa<CallExpr>(POE->getSemanticExpr(0)))
+ return DiagnoseUnusedExprResult(POE->getSemanticExpr(0));
if (isa<ObjCSubscriptRefExpr>(Source))
DiagID = diag::warn_unused_container_subscript_expr;
else
@@ -365,7 +370,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
}
- if (E->isGLValue() && E->getType().isVolatileQualified()) {
+ // Tell the user to assign it into a variable to force a volatile load if this
+ // isn't an array.
+ if (E->isGLValue() && E->getType().isVolatileQualified() &&
+ !E->getType()->isArrayType()) {
Diag(Loc, diag::warn_unused_volatile) << R1 << R2;
return;
}
@@ -389,6 +397,11 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
ArrayRef<Stmt *> Elts, bool isStmtExpr) {
const unsigned NumElts = Elts.size();
+ // Mark the current function as usng floating point constrained intrinsics
+ if (getCurFPFeatures().isFPConstrained())
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext))
+ F->setUsesFPIntrin(true);
+
// If we're in C89 mode, check that we don't have any decls after stmts. If
// so, emit an extension diagnostic.
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) {
@@ -464,7 +477,9 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
return ER;
};
- ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
+ ExprResult Converted = CorrectDelayedTyposInExpr(
+ Val, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false,
+ CheckAndFinish);
if (Converted.get() == Val.get())
Converted = CheckAndFinish(Val.get());
return Converted;
@@ -730,11 +745,11 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
if (CondExpr && !CondExpr->isTypeDependent()) {
// We have already converted the expression to an integral or enumeration
- // type, when we parsed the switch condition. If we don't have an
- // appropriate type now, enter the switch scope but remember that it's
- // invalid.
- assert(CondExpr->getType()->isIntegralOrEnumerationType() &&
- "invalid condition type");
+ // type, when we parsed the switch condition. There are cases where we don't
+ // have an appropriate type, e.g. a typo-expr Cond was corrected to an
+ // inappropriate-type expr, we just return an error.
+ if (!CondExpr->getType()->isIntegralOrEnumerationType())
+ return StmtError();
if (CondExpr->isKnownToHaveBooleanValue()) {
// switch(bool_expr) {...} is often a programmer error, e.g.
// switch(n && mask) { ... } // Doh - should be "n & mask".
@@ -1313,8 +1328,9 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
}
}
-StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
- Stmt *Body) {
+StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc,
+ SourceLocation LParenLoc, ConditionResult Cond,
+ SourceLocation RParenLoc, Stmt *Body) {
if (Cond.isInvalid())
return StmtError();
@@ -1329,7 +1345,7 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
getCurCompoundScope().setHasEmptyLoopBodies();
return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body,
- WhileLoc);
+ WhileLoc, LParenLoc, RParenLoc);
}
StmtResult
@@ -1387,10 +1403,9 @@ namespace {
Simple = false;
}
- // Any Stmt not whitelisted will cause the condition to be marked complex.
- void VisitStmt(Stmt *S) {
- Simple = false;
- }
+ // Any Stmt not explicitly listed will cause the condition to be marked
+ // complex.
+ void VisitStmt(Stmt *S) { Simple = false; }
void VisitBinaryOperator(BinaryOperator *E) {
Visit(E->getLHS());
@@ -2114,18 +2129,22 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
return StmtError();
}
+ // This function is responsible for attaching an initializer to LoopVar. We
+ // must call ActOnInitializerError if we fail to do so.
Decl *LoopVar = DS->getSingleDecl();
if (LoopVar->isInvalidDecl() || !Range ||
DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) {
- LoopVar->setInvalidDecl();
+ ActOnInitializerError(LoopVar);
return StmtError();
}
// Build the coroutine state immediately and not later during template
// instantiation
if (!CoawaitLoc.isInvalid()) {
- if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await"))
+ if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) {
+ ActOnInitializerError(LoopVar);
return StmtError();
+ }
}
// Build auto && __range = range-init
@@ -2137,7 +2156,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
std::string("__range") + DepthStr);
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
diag::err_for_range_deduction_failure)) {
- LoopVar->setInvalidDecl();
+ ActOnInitializerError(LoopVar);
return StmtError();
}
@@ -2146,14 +2165,20 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
if (RangeDecl.isInvalid()) {
- LoopVar->setInvalidDecl();
+ ActOnInitializerError(LoopVar);
return StmtError();
}
- return BuildCXXForRangeStmt(
+ StmtResult R = BuildCXXForRangeStmt(
ForLoc, CoawaitLoc, InitStmt, ColonLoc, RangeDecl.get(),
/*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
/*Cond=*/nullptr, /*Inc=*/nullptr, DS, RParenLoc, Kind);
+ if (R.isInvalid()) {
+ ActOnInitializerError(LoopVar);
+ return StmtError();
+ }
+
+ return R;
}
/// Create the initialization, compare, and increment steps for
@@ -2336,22 +2361,6 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild);
}
-namespace {
-/// RAII object to automatically invalidate a declaration if an error occurs.
-struct InvalidateOnErrorScope {
- InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled)
- : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {}
- ~InvalidateOnErrorScope() {
- if (Enabled && Trap.hasErrorOccurred())
- D->setInvalidDecl();
- }
-
- DiagnosticErrorTrap Trap;
- Decl *D;
- bool Enabled;
-};
-}
-
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation CoawaitLoc, Stmt *InitStmt,
@@ -2378,11 +2387,6 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
- // If we hit any errors, mark the loop variable as invalid if its type
- // contains 'auto'.
- InvalidateOnErrorScope Invalidate(*this, LoopVar,
- LoopVar->getType()->isUndeducedType());
-
StmtResult BeginDeclStmt = Begin;
StmtResult EndDeclStmt = End;
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
@@ -2664,7 +2668,8 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
// trying to determine whether this would be a valid range.
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false);
- if (LoopVar->isInvalidDecl())
+ if (LoopVar->isInvalidDecl() ||
+ (LoopVar->getInit() && LoopVar->getInit()->containsErrors()))
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
}
}
@@ -2741,22 +2746,24 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
E = E->IgnoreImpCasts();
}
- bool ReturnsReference = false;
+ QualType ReferenceReturnType;
if (isa<UnaryOperator>(E)) {
- ReturnsReference = true;
+ ReferenceReturnType = SemaRef.Context.getLValueReferenceType(E->getType());
} else {
const CXXOperatorCallExpr *Call = cast<CXXOperatorCallExpr>(E);
const FunctionDecl *FD = Call->getDirectCallee();
QualType ReturnType = FD->getReturnType();
- ReturnsReference = ReturnType->isReferenceType();
+ if (ReturnType->isReferenceType())
+ ReferenceReturnType = ReturnType;
}
- if (ReturnsReference) {
+ if (!ReferenceReturnType.isNull()) {
// Loop variable creates a temporary. Suggest either to go with
// non-reference loop variable to indicate a copy is made, or
- // the correct time to bind a const reference.
- SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy)
- << VD << VariableType << E->getType();
+ // the correct type to bind a const reference.
+ SemaRef.Diag(VD->getLocation(),
+ diag::warn_for_range_const_ref_binds_temp_built_from_ref)
+ << VD << VariableType << ReferenceReturnType;
QualType NonReferenceType = VariableType.getNonReferenceType();
NonReferenceType.removeLocalConst();
QualType NewReferenceType =
@@ -2769,7 +2776,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
// Suggest removing the reference from the loop variable.
// If the type is a rvalue reference do not warn since that changes the
// semantic of the code.
- SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
+ SemaRef.Diag(VD->getLocation(), diag::warn_for_range_ref_binds_ret_temp)
<< VD << RangeInitType;
QualType NonReferenceType = VariableType.getNonReferenceType();
NonReferenceType.removeLocalConst();
@@ -2821,7 +2828,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
// Suggest changing from a const variable to a const reference variable
// if doing so will prevent a copy.
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_copy)
- << VD << VariableType << InitExpr->getType();
+ << VD << VariableType;
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type)
<< SemaRef.Context.getLValueReferenceType(VariableType)
<< VD->getSourceRange()
@@ -2838,9 +2845,13 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
/// Suggest "const foo &x" to prevent the copy.
static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
const CXXForRangeStmt *ForStmt) {
- if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,
- ForStmt->getBeginLoc()) &&
- SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy,
+ if (SemaRef.inTemplateInstantiation())
+ return;
+
+ if (SemaRef.Diags.isIgnored(
+ diag::warn_for_range_const_ref_binds_temp_built_from_ref,
+ ForStmt->getBeginLoc()) &&
+ SemaRef.Diags.isIgnored(diag::warn_for_range_ref_binds_ret_temp,
ForStmt->getBeginLoc()) &&
SemaRef.Diags.isIgnored(diag::warn_for_range_copy,
ForStmt->getBeginLoc())) {
@@ -2860,6 +2871,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
if (!InitExpr)
return;
+ if (InitExpr->getExprLoc().isMacroID())
+ return;
+
if (VariableType->isReferenceType()) {
DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,
ForStmt->getRangeInit()->getType());
@@ -3286,6 +3300,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
assert(AT && "lost auto type from lambda return type");
if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
FD->setInvalidDecl();
+ // FIXME: preserve the ill-formed return expression.
return StmtError();
}
CurCap->ReturnType = FnRetType = FD->getReturnType();
@@ -3616,6 +3631,12 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (isa<CXXBoolLiteralExpr>(RetValExp))
Diag(ReturnLoc, diag::warn_main_returns_bool_literal)
<< RetValExp->getSourceRange();
+ if (FD->hasAttr<CmseNSEntryAttr>() && RetValExp) {
+ if (const auto *RT = dyn_cast<RecordType>(FnRetType.getCanonicalType())) {
+ if (RT->getDecl()->isOrContainsUnion())
+ Diag(RetValExp->getBeginLoc(), diag::warn_cmse_nonsecure_union) << 1;
+ }
+ }
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
FnRetType = MD->getReturnType();
isObjCMethod = true;
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 93faf2d151f9..10fa24682f9c 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -296,6 +296,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false))
return StmtError();
+ // Disallow _ExtInt, since the backends tend to have difficulties with
+ // non-normal sizes.
+ if (OutputExpr->getType()->isExtIntType())
+ return StmtError(
+ Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_type)
+ << OutputExpr->getType() << 0 /*Input*/
+ << OutputExpr->getSourceRange());
+
OutputConstraintInfos.push_back(Info);
// If this is dependent, just continue.
@@ -420,6 +428,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
}
+ if (InputExpr->getType()->isExtIntType())
+ return StmtError(
+ Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type)
+ << InputExpr->getType() << 1 /*Output*/
+ << InputExpr->getSourceRange());
+
InputConstraintInfos.push_back(Info);
const Type *Ty = Exprs[i]->getType().getTypePtr();
@@ -478,10 +492,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Look for the correct constraint index.
unsigned ConstraintIdx = Piece.getOperandNo();
+ unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
// Labels are the last in the Exprs list.
- if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs())
+ if (NS->isAsmGoto() && ConstraintIdx >= NumOperands)
continue;
- unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs();
// Look for the (ConstraintIdx - NumOperands + 1)th constraint with
// modifier '+'.
if (ConstraintIdx >= NumOperands) {
@@ -892,6 +906,15 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
SourceLocation EndLoc) {
bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
setFunctionHasBranchProtectedScope();
+
+ for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) {
+ if (Exprs[I]->getType()->isExtIntType())
+ return StmtError(
+ Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type)
+ << Exprs[I]->getType() << (I < NumOutputs)
+ << Exprs[I]->getSourceRange());
+ }
+
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
/*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 3d91893b4065..e9d3c755eb23 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
@@ -170,6 +171,44 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
}
+namespace {
+class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> {
+ bool FoundCallExpr = false;
+
+public:
+ typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited;
+
+ CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); }
+
+ bool foundCallExpr() { return FoundCallExpr; }
+
+ void VisitCallExpr(const CallExpr *E) { FoundCallExpr = true; }
+
+ void Visit(const Stmt *St) {
+ if (!St)
+ return;
+ ConstEvaluatedExprVisitor<CallExprFinder>::Visit(St);
+ }
+};
+} // namespace
+
+static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+ SourceRange Range) {
+ NoMergeAttr NMA(S.Context, A);
+ if (S.CheckAttrNoArgs(A))
+ return nullptr;
+
+ CallExprFinder CEF(S, St);
+
+ if (!CEF.foundCallExpr()) {
+ S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt)
+ << NMA.getSpelling();
+ return nullptr;
+ }
+
+ return ::new (S.Context) NoMergeAttr(S.Context, A);
+}
+
static void
CheckForIncompatibleAttributes(Sema &S,
const SmallVectorImpl<const Attr *> &Attrs) {
@@ -335,6 +374,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
return handleOpenCLUnrollHint(S, St, A, Range);
case ParsedAttr::AT_Suppress:
return handleSuppressAttr(S, St, A, Range);
+ case ParsedAttr::AT_NoMerge:
+ return handleNoMergeAttr(S, St, A, Range);
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1184446796eb..c05ed0b14e3e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -46,6 +46,47 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
+unsigned Sema::getTemplateDepth(Scope *S) const {
+ unsigned Depth = 0;
+
+ // Each template parameter scope represents one level of template parameter
+ // depth.
+ for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope;
+ TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) {
+ ++Depth;
+ }
+
+ // Note that there are template parameters with the given depth.
+ auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); };
+
+ // Look for parameters of an enclosing generic lambda. We don't create a
+ // template parameter scope for these.
+ for (FunctionScopeInfo *FSI : getFunctionScopes()) {
+ if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) {
+ if (!LSI->TemplateParams.empty()) {
+ ParamsAtDepth(LSI->AutoTemplateParameterDepth);
+ break;
+ }
+ if (LSI->GLTemplateParameterList) {
+ ParamsAtDepth(LSI->GLTemplateParameterList->getDepth());
+ break;
+ }
+ }
+ }
+
+ // Look for parameters of an enclosing terse function template. We don't
+ // create a template parameter scope for these either.
+ for (const InventedTemplateParameterInfo &Info :
+ getInventedParameterInfos()) {
+ if (!Info.TemplateParams.empty()) {
+ ParamsAtDepth(Info.AutoTemplateParameterDepth);
+ break;
+ }
+ }
+
+ return Depth;
+}
+
/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns null.
@@ -132,7 +173,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
ParsedType ObjectTypePtr,
bool EnteringContext,
TemplateTy &TemplateResult,
- bool &MemberOfUnknownSpecialization) {
+ bool &MemberOfUnknownSpecialization,
+ bool Disambiguation) {
assert(getLangOpts().CPlusPlus && "No template names in C!");
DeclarationName TName;
@@ -162,7 +204,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName);
if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
MemberOfUnknownSpecialization, SourceLocation(),
- &AssumedTemplate))
+ &AssumedTemplate,
+ /*AllowTypoCorrection=*/!Disambiguation))
return TNK_Non_template;
if (AssumedTemplate != AssumedTemplateKind::None) {
@@ -328,11 +371,15 @@ bool Sema::LookupTemplateName(LookupResult &Found,
QualType ObjectType,
bool EnteringContext,
bool &MemberOfUnknownSpecialization,
- SourceLocation TemplateKWLoc,
- AssumedTemplateKind *ATK) {
+ RequiredTemplateKind RequiredTemplate,
+ AssumedTemplateKind *ATK,
+ bool AllowTypoCorrection) {
if (ATK)
*ATK = AssumedTemplateKind::None;
+ if (SS.isInvalid())
+ return true;
+
Found.setTemplateNameLookup(true);
// Determine where to perform name lookup
@@ -342,7 +389,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
- assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+ assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
@@ -368,11 +415,11 @@ bool Sema::LookupTemplateName(LookupResult &Found,
Found.clear();
return false;
}
- } else if (SS.isSet()) {
+ } else if (SS.isNotEmpty()) {
// This nested-name-specifier occurs after another nested-name-specifier,
// so long into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
- IsDependent = !LookupCtx;
+ IsDependent = !LookupCtx && isDependentScopeSpecifier(SS);
// The declaration context must be complete.
if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx))
@@ -399,7 +446,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
IsDependent |= Found.wasNotFoundInCurrentInstantiation();
}
- if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) {
+ if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) {
// C++ [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
// immediately followed by an identifier followed by a <, the
@@ -426,7 +473,8 @@ bool Sema::LookupTemplateName(LookupResult &Found,
if (Found.isAmbiguous())
return false;
- if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) {
+ if (ATK && SS.isEmpty() && ObjectType.isNull() &&
+ !RequiredTemplate.hasTemplateKeyword()) {
// C++2a [temp.names]p2:
// A name is also considered to refer to a template if it is an
// unqualified-id followed by a < and name lookup finds either one or more
@@ -436,7 +484,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// all language modes, and diagnose the empty lookup in ActOnCallExpr if we
// successfully form a call to an undeclared template-id.
bool AllFunctions =
- getLangOpts().CPlusPlus2a &&
+ getLangOpts().CPlusPlus20 &&
std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) {
return isa<FunctionDecl>(ND->getUnderlyingDecl());
});
@@ -452,8 +500,9 @@ bool Sema::LookupTemplateName(LookupResult &Found,
}
}
- if (Found.empty() && !IsDependent) {
- // If we did not find any names, attempt to correct any typos.
+ if (Found.empty() && !IsDependent && AllowTypoCorrection) {
+ // If we did not find any names, and this is not a disambiguation, attempt
+ // to correct any typos.
DeclarationName Name = Found.getLookupName();
Found.clear();
// Simple filter callback that, for keywords, only accepts the C++ *_cast
@@ -497,9 +546,11 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// If a 'template' keyword was used, a lookup that finds only non-template
// names is an error.
- if (ExampleLookupResult && TemplateKWLoc.isValid()) {
+ if (ExampleLookupResult && RequiredTemplate) {
Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template)
- << Found.getLookupName() << SS.getRange();
+ << Found.getLookupName() << SS.getRange()
+ << RequiredTemplate.hasTemplateKeyword()
+ << RequiredTemplate.getTemplateKeywordLoc();
Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(),
diag::note_template_kw_refers_to_non_template)
<< Found.getLookupName();
@@ -1050,7 +1101,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
return TemplateArgs;
}
-bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
+bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS,
+ TemplateIdAnnotation *TypeConstr,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc) {
ConceptDecl *CD =
@@ -1080,14 +1132,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
makeTemplateArgumentListInfo(*this, *TypeConstr);
}
return AttachTypeConstraint(
- TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) :
- NestedNameSpecifierLoc(),
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(),
DeclarationNameInfo(DeclarationName(TypeConstr->Name),
TypeConstr->TemplateNameLoc), CD,
TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
ConstrainedParameter, EllipsisLoc);
}
+template<typename ArgumentLocAppender>
+static ExprResult formImmediatelyDeclaredConstraint(
+ Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
+ ConceptDecl *NamedConcept, SourceLocation LAngleLoc,
+ SourceLocation RAngleLoc, QualType ConstrainedType,
+ SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo ConstraintArgs;
+ ConstraintArgs.addArgument(
+ S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType),
+ /*NTTPType=*/QualType(), ParamNameLoc));
+
+ ConstraintArgs.setRAngleLoc(RAngleLoc);
+ ConstraintArgs.setLAngleLoc(LAngleLoc);
+ Appender(ConstraintArgs);
+
+ // C++2a [temp.param]p4:
+ // [...] This constraint-expression E is called the immediately-declared
+ // constraint of T. [...]
+ CXXScopeSpec SS;
+ SS.Adopt(NS);
+ ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
+
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ //
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ ImmediatelyDeclaredConstraint.get(), BO_LAnd,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation(),
+ /*NumExpansions=*/None);
+}
+
/// Attach a type-constraint to a template parameter.
/// \returns true if an error occured. This can happen if the
/// immediately-declared constraint could not be formed (e.g. incorrect number
@@ -1106,51 +1201,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
*TemplateArgs) : nullptr;
QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
- TemplateArgumentListInfo ConstraintArgs;
- ConstraintArgs.addArgument(
- TemplateArgumentLoc(
- TemplateArgument(ParamAsArgument),
- TemplateArgumentLocInfo(
- Context.getTrivialTypeSourceInfo(ParamAsArgument,
- ConstrainedParameter->getLocation()))));
- if (TemplateArgs) {
- ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
- ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
- for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
- ConstraintArgs.addArgument(ArgLoc);
- }
- // C++2a [temp.param]p4:
- // [...] This constraint-expression E is called the immediately-declared
- // constraint of T. [...]
- CXXScopeSpec SS;
- SS.Adopt(NS);
- ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
- /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
- NamedConcept, &ConstraintArgs);
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, NS, NameInfo, NamedConcept,
+ TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
+ TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
+ ParamAsArgument, ConstrainedParameter->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ if (TemplateArgs)
+ for (const auto &ArgLoc : TemplateArgs->arguments())
+ ConstraintArgs.addArgument(ArgLoc);
+ }, EllipsisLoc);
if (ImmediatelyDeclaredConstraint.isInvalid())
return true;
- if (ConstrainedParameter->isParameterPack()) {
- // C++2a [temp.param]p4:
- // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
- //
- // We have the following case:
- //
- // template<typename T> concept C1 = true;
- // template<C1... T> struct s1;
- //
- // The constraint: (C1<T> && ...)
- ImmediatelyDeclaredConstraint =
- BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
- ImmediatelyDeclaredConstraint.get(), BO_LAnd,
- EllipsisLoc, /*RHS=*/nullptr,
- /*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None).get();
- if (ImmediatelyDeclaredConstraint.isInvalid())
- return true;
- }
-
ConstrainedParameter->setTypeConstraint(NS, NameInfo,
/*FoundDecl=*/NamedConcept,
NamedConcept, ArgsAsWritten,
@@ -1158,6 +1223,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
return false;
}
+bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
+ SourceLocation EllipsisLoc) {
+ if (NTTP->getType() != TL.getType() ||
+ TL.getAutoKeyword() != AutoTypeKeyword::Auto) {
+ Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_unsupported_placeholder_constraint)
+ << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange();
+ return true;
+ }
+ // FIXME: Concepts: This should be the type of the placeholder, but this is
+ // unclear in the wording right now.
+ DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue,
+ NTTP->getLocation());
+ if (!Ref)
+ return true;
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
+ TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
+ BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
+ ConstraintArgs.addArgument(TL.getArgLoc(I));
+ }, EllipsisLoc);
+ if (ImmediatelyDeclaredConstraint.isInvalid() ||
+ !ImmediatelyDeclaredConstraint.isUsable())
+ return true;
+
+ NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get());
+ return false;
+}
+
/// Check that the type of a non-type template parameter is
/// well-formed.
///
@@ -1242,11 +1339,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// Check that we have valid decl-specifiers specified.
auto CheckValidDeclSpecifiers = [this, &D] {
// C++ [temp.param]
- // p1
+ // p1
// template-parameter:
// ...
// parameter-declaration
- // p2
+ // p2
// ... A storage class shall not be specified in a template-parameter
// declaration.
// [dcl.typedef]p1:
@@ -1319,6 +1416,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
TInfo);
Param->setAccess(AS_public);
+ if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc())
+ if (TL.isConstrained())
+ if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc()))
+ Invalid = true;
+
if (Invalid)
Param->setInvalidDecl();
@@ -1844,16 +1946,46 @@ namespace {
/// constructor to a deduction guide.
class ExtractTypeForDeductionGuide
: public TreeTransform<ExtractTypeForDeductionGuide> {
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs;
+
public:
typedef TreeTransform<ExtractTypeForDeductionGuide> Base;
- ExtractTypeForDeductionGuide(Sema &SemaRef) : Base(SemaRef) {}
+ ExtractTypeForDeductionGuide(
+ Sema &SemaRef,
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs)
+ : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {}
TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); }
QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) {
- return TransformType(
- TLB,
- TL.getTypedefNameDecl()->getTypeSourceInfo()->getTypeLoc());
+ ASTContext &Context = SemaRef.getASTContext();
+ TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl();
+ TypeLocBuilder InnerTLB;
+ QualType Transformed =
+ TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc());
+ TypeSourceInfo *TSI =
+ TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed));
+
+ TypedefNameDecl *Decl = nullptr;
+
+ if (isa<TypeAliasDecl>(OrigDecl))
+ Decl = TypeAliasDecl::Create(
+ Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
+ OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
+ else {
+ assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef");
+ Decl = TypedefDecl::Create(
+ Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(),
+ OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI);
+ }
+
+ MaterializedTypedefs.push_back(Decl);
+
+ QualType TDTy = Context.getTypedefType(Decl);
+ TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy);
+ TypedefTL.setNameLoc(TL.getNameLoc());
+
+ return TDTy;
}
};
@@ -1905,6 +2037,7 @@ struct ConvertConstructorToDeductionGuideTransform {
// a list of substituted template arguments as we go.
for (NamedDecl *Param : *InnerParams) {
MultiLevelTemplateArgumentList Args;
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(SubstArgs);
Args.addOuterRetainedLevel();
NamedDecl *NewParam = transformTemplateParameter(Param, Args);
@@ -1924,6 +2057,7 @@ struct ConvertConstructorToDeductionGuideTransform {
// substitute references to the old parameters into references to the
// new ones.
MultiLevelTemplateArgumentList Args;
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
if (FTD) {
Args.addOuterTemplateArguments(SubstArgs);
Args.addOuterRetainedLevel();
@@ -1938,14 +2072,16 @@ struct ConvertConstructorToDeductionGuideTransform {
// new ones.
TypeLocBuilder TLB;
SmallVector<ParmVarDecl*, 8> Params;
- QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args);
+ SmallVector<TypedefNameDecl *, 4> MaterializedTypedefs;
+ QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args,
+ MaterializedTypedefs);
if (NewType.isNull())
return nullptr;
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
NewTInfo, CD->getBeginLoc(), CD->getLocation(),
- CD->getEndLoc());
+ CD->getEndLoc(), MaterializedTypedefs);
}
/// Build a deduction guide with the specified parameter types.
@@ -1996,12 +2132,14 @@ private:
if (const auto *TC = TTP->getTypeConstraint()) {
TemplateArgumentListInfo TransformedArgs;
const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten();
- if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
+ if (!ArgsAsWritten ||
+ SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
ArgsAsWritten->NumTemplateArgs, TransformedArgs,
Args))
SemaRef.AttachTypeConstraint(
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &TransformedArgs, NewTTP,
+ TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr,
+ NewTTP,
NewTTP->isParameterPack()
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
->getEllipsisLoc()
@@ -2038,16 +2176,18 @@ private:
return NewParam;
}
- QualType transformFunctionProtoType(TypeLocBuilder &TLB,
- FunctionProtoTypeLoc TL,
- SmallVectorImpl<ParmVarDecl*> &Params,
- MultiLevelTemplateArgumentList &Args) {
+ QualType transformFunctionProtoType(
+ TypeLocBuilder &TLB, FunctionProtoTypeLoc TL,
+ SmallVectorImpl<ParmVarDecl *> &Params,
+ MultiLevelTemplateArgumentList &Args,
+ SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
SmallVector<QualType, 4> ParamTypes;
const FunctionProtoType *T = TL.getTypePtr();
// -- The types of the function parameters are those of the constructor.
for (auto *OldParam : TL.getParams()) {
- ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args);
+ ParmVarDecl *NewParam =
+ transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
if (!NewParam)
return QualType();
ParamTypes.push_back(NewParam->getType());
@@ -2089,9 +2229,9 @@ private:
return Result;
}
- ParmVarDecl *
- transformFunctionTypeParam(ParmVarDecl *OldParam,
- MultiLevelTemplateArgumentList &Args) {
+ ParmVarDecl *transformFunctionTypeParam(
+ ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args,
+ llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) {
TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
TypeSourceInfo *NewDI;
if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
@@ -2114,15 +2254,22 @@ private:
// members of the current instantiations with the definitions of those
// typedefs, avoiding triggering instantiation of the deduced type during
// deduction.
- NewDI = ExtractTypeForDeductionGuide(SemaRef).transform(NewDI);
+ NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs)
+ .transform(NewDI);
// Resolving a wording defect, we also inherit default arguments from the
// constructor.
ExprResult NewDefArg;
if (OldParam->hasDefaultArg()) {
- NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args);
- if (NewDefArg.isInvalid())
- return nullptr;
+ // We don't care what the value is (we won't use it); just create a
+ // placeholder to indicate there is a default argument.
+ QualType ParamTy = NewDI->getType();
+ NewDefArg = new (SemaRef.Context)
+ OpaqueValueExpr(OldParam->getDefaultArg()->getBeginLoc(),
+ ParamTy.getNonLValueExprType(SemaRef.Context),
+ ParamTy->isLValueReferenceType() ? VK_LValue :
+ ParamTy->isRValueReferenceType() ? VK_XValue :
+ VK_RValue);
}
ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC,
@@ -2139,10 +2286,11 @@ private:
return NewParam;
}
- NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
- ExplicitSpecifier ES, TypeSourceInfo *TInfo,
- SourceLocation LocStart, SourceLocation Loc,
- SourceLocation LocEnd) {
+ FunctionTemplateDecl *buildDeductionGuide(
+ TemplateParameterList *TemplateParams, ExplicitSpecifier ES,
+ TypeSourceInfo *TInfo, SourceLocation LocStart, SourceLocation Loc,
+ SourceLocation LocEnd,
+ llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) {
DeclarationNameInfo Name(DeductionGuideName, Loc);
ArrayRef<ParmVarDecl *> Params =
TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams();
@@ -2156,6 +2304,8 @@ private:
for (auto *Param : Params)
Param->setDeclContext(Guide);
+ for (auto *TD : MaterializedTypedefs)
+ TD->setDeclContext(Guide);
auto *GuideTemplate = FunctionTemplateDecl::Create(
SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
@@ -2762,7 +2912,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
- bool &IsMemberSpecialization, bool &Invalid) {
+ bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
IsMemberSpecialization = false;
Invalid = false;
@@ -2870,8 +3020,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
if (SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << !Recovery << Range;
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << !Recovery << Range;
Invalid = true;
IsMemberSpecialization = false;
return true;
@@ -2892,9 +3043,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
else
ExpectedTemplateLoc = DeclStartLoc;
- Diag(DeclLoc, diag::err_template_spec_needs_header)
- << Range
- << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << Range
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
return false;
};
@@ -2984,12 +3136,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() > 0) {
// The header has template parameters when it shouldn't. Complain.
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- diag::err_template_param_list_matches_nontemplate)
- << T
- << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
- ParamLists[ParamIdx]->getRAngleLoc())
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << T
+ << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc())
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
return nullptr;
}
@@ -3025,7 +3178,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ExpectedTemplateParams &&
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
- true, TPL_TemplateMatch))
+ !SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@@ -3037,9 +3190,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
continue;
}
- Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
- << T
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
+ << T
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
continue;
}
@@ -3075,16 +3229,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
AllExplicitSpecHeaders = false;
}
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[ParamLists.size() - 2]->getRAngleLoc());
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[ParamLists.size() - 2]->getRAngleLoc());
// If there was a specialization somewhere, such that 'template<>' is
// not required, and there were any 'template<>' headers, note where the
// specialization occurred.
- if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
+ if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader &&
+ !SuppressDiagnostic)
Diag(ExplicitSpecLoc,
diag::note_explicit_template_spec_does_not_need_header)
<< NestedTypes.back();
@@ -3360,6 +3516,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
DTN->getIdentifier(),
TemplateArgs);
+ if (Name.getAsAssumedTemplateName() &&
+ resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
+ return QualType();
+
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
@@ -3399,9 +3559,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
- unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
- for (unsigned I = 0; I < Depth; ++I)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterRetainedLevels(
+ AliasTemplate->getTemplateParameters()->getDepth());
LocalInstantiationScope Scope(*this);
InstantiatingTemplate Inst(*this, TemplateLoc, Template);
@@ -3707,6 +3866,9 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
+ if (SS.isInvalid())
+ return TypeResult(true);
+
TemplateName Template = TemplateD.get();
// Translate the parser's template argument list in our AST format.
@@ -4044,7 +4206,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
Converted) &&
- (!Context.getLangOpts().ConceptsTS ||
+ (!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
@@ -4510,21 +4672,28 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs);
}
-/// Form a dependent template name.
+/// Form a template name from a name that is syntactically required to name a
+/// template, either due to use of the 'template' keyword or because a name in
+/// this syntactic context is assumed to name a template (C++ [temp.names]p2-4).
+///
+/// This action forms a template name given the name of the template and its
+/// optional scope specifier. This is used when the 'template' keyword is used
+/// or when the parsing context unambiguously treats a following '<' as
+/// introducing a template argument list. Note that this may produce a
+/// non-dependent template name if we can perform the lookup now and identify
+/// the named template.
///
-/// This action forms a dependent template name given the template
-/// name and its (presumably dependent) scope specifier. For
-/// example, given "MetaFun::template apply", the scope specifier \p
-/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
+/// For example, given "x.MetaFun::template apply", the scope specifier
+/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
-TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
- CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- const UnqualifiedId &Name,
- ParsedType ObjectType,
- bool EnteringContext,
- TemplateTy &Result,
- bool AllowInjectedClassName) {
+TemplateNameKind Sema::ActOnTemplateName(Scope *S,
+ CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ const UnqualifiedId &Name,
+ ParsedType ObjectType,
+ bool EnteringContext,
+ TemplateTy &Result,
+ bool AllowInjectedClassName) {
if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TemplateKWLoc,
getLangOpts().CPlusPlus11 ?
@@ -4532,95 +4701,115 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
diag::ext_template_outside_of_template)
<< FixItHint::CreateRemoval(TemplateKWLoc);
+ if (SS.isInvalid())
+ return TNK_Non_template;
+
+ // Figure out where isTemplateName is going to look.
DeclContext *LookupCtx = nullptr;
- if (SS.isSet())
+ if (SS.isNotEmpty())
LookupCtx = computeDeclContext(SS, EnteringContext);
- if (!LookupCtx && ObjectType)
- LookupCtx = computeDeclContext(ObjectType.get());
- if (LookupCtx) {
- // C++0x [temp.names]p5:
- // If a name prefixed by the keyword template is not the name of
- // a template, the program is ill-formed. [Note: the keyword
- // template may not be applied to non-template members of class
- // templates. -end note ] [ Note: as is the case with the
- // typename prefix, the template prefix is allowed in cases
- // where it is not strictly necessary; i.e., when the
- // nested-name-specifier or the expression on the left of the ->
- // or . is not dependent on a template-parameter, or the use
- // does not appear in the scope of a template. -end note]
- //
- // Note: C++03 was more strict here, because it banned the use of
- // the "template" keyword prior to a template-name that was not a
- // dependent name. C++ DR468 relaxed this requirement (the
- // "template" keyword is now permitted). We follow the C++0x
- // rules, even in C++03 mode with a warning, retroactively applying the DR.
- bool MemberOfUnknownSpecialization;
- TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
- ObjectType, EnteringContext, Result,
- MemberOfUnknownSpecialization);
- if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) {
- // This is a dependent template. Handle it below.
- } else if (TNK == TNK_Non_template) {
- // Do the lookup again to determine if this is a "nothing found" case or
- // a "not a template" case. FIXME: Refactor isTemplateName so we don't
- // need to do this.
- DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
- LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
- LookupOrdinaryName);
- bool MOUS;
- if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext,
- MOUS, TemplateKWLoc) && !R.isAmbiguous())
+ else if (ObjectType)
+ LookupCtx = computeDeclContext(GetTypeFromParser(ObjectType));
+
+ // C++0x [temp.names]p5:
+ // If a name prefixed by the keyword template is not the name of
+ // a template, the program is ill-formed. [Note: the keyword
+ // template may not be applied to non-template members of class
+ // templates. -end note ] [ Note: as is the case with the
+ // typename prefix, the template prefix is allowed in cases
+ // where it is not strictly necessary; i.e., when the
+ // nested-name-specifier or the expression on the left of the ->
+ // or . is not dependent on a template-parameter, or the use
+ // does not appear in the scope of a template. -end note]
+ //
+ // Note: C++03 was more strict here, because it banned the use of
+ // the "template" keyword prior to a template-name that was not a
+ // dependent name. C++ DR468 relaxed this requirement (the
+ // "template" keyword is now permitted). We follow the C++0x
+ // rules, even in C++03 mode with a warning, retroactively applying the DR.
+ bool MemberOfUnknownSpecialization;
+ TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
+ ObjectType, EnteringContext, Result,
+ MemberOfUnknownSpecialization);
+ if (TNK != TNK_Non_template) {
+ // We resolved this to a (non-dependent) template name. Return it.
+ auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx);
+ if (!AllowInjectedClassName && SS.isNotEmpty() && LookupRD &&
+ Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
+ Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) {
+ // C++14 [class.qual]p2:
+ // In a lookup in which function names are not ignored and the
+ // nested-name-specifier nominates a class C, if the name specified
+ // [...] is the injected-class-name of C, [...] the name is instead
+ // considered to name the constructor
+ //
+ // We don't get here if naming the constructor would be valid, so we
+ // just reject immediately and recover by treating the
+ // injected-class-name as naming the template.
+ Diag(Name.getBeginLoc(),
+ diag::ext_out_of_line_qualified_id_type_names_constructor)
+ << Name.Identifier
+ << 0 /*injected-class-name used as template name*/
+ << TemplateKWLoc.isValid();
+ }
+ return TNK;
+ }
+
+ if (!MemberOfUnknownSpecialization) {
+ // Didn't find a template name, and the lookup wasn't dependent.
+ // Do the lookup again to determine if this is a "nothing found" case or
+ // a "not a template" case. FIXME: Refactor isTemplateName so we don't
+ // need to do this.
+ DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name);
+ LookupResult R(*this, DNI.getName(), Name.getBeginLoc(),
+ LookupOrdinaryName);
+ bool MOUS;
+ // Tell LookupTemplateName that we require a template so that it diagnoses
+ // cases where it finds a non-template.
+ RequiredTemplateKind RTK = TemplateKWLoc.isValid()
+ ? RequiredTemplateKind(TemplateKWLoc)
+ : TemplateNameIsRequired;
+ if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS,
+ RTK, nullptr, /*AllowTypoCorrection=*/false) &&
+ !R.isAmbiguous()) {
+ if (LookupCtx)
Diag(Name.getBeginLoc(), diag::err_no_member)
<< DNI.getName() << LookupCtx << SS.getRange();
- return TNK_Non_template;
- } else {
- // We found something; return it.
- auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx);
- if (!AllowInjectedClassName && SS.isSet() && LookupRD &&
- Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
- Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) {
- // C++14 [class.qual]p2:
- // In a lookup in which function names are not ignored and the
- // nested-name-specifier nominates a class C, if the name specified
- // [...] is the injected-class-name of C, [...] the name is instead
- // considered to name the constructor
- //
- // We don't get here if naming the constructor would be valid, so we
- // just reject immediately and recover by treating the
- // injected-class-name as naming the template.
- Diag(Name.getBeginLoc(),
- diag::ext_out_of_line_qualified_id_type_names_constructor)
- << Name.Identifier
- << 0 /*injected-class-name used as template name*/
- << 1 /*'template' keyword was used*/;
- }
- return TNK;
+ else
+ Diag(Name.getBeginLoc(), diag::err_undeclared_use)
+ << DNI.getName() << SS.getRange();
}
+ return TNK_Non_template;
}
NestedNameSpecifier *Qualifier = SS.getScopeRep();
switch (Name.getKind()) {
case UnqualifiedIdKind::IK_Identifier:
- Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
- Name.Identifier));
+ Result = TemplateTy::make(
+ Context.getDependentTemplateName(Qualifier, Name.Identifier));
return TNK_Dependent_template_name;
case UnqualifiedIdKind::IK_OperatorFunctionId:
- Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
- Name.OperatorFunctionId.Operator));
+ Result = TemplateTy::make(Context.getDependentTemplateName(
+ Qualifier, Name.OperatorFunctionId.Operator));
return TNK_Function_template;
case UnqualifiedIdKind::IK_LiteralOperatorId:
- llvm_unreachable("literal operator id cannot have a dependent scope");
+ // This is a kind of template name, but can never occur in a dependent
+ // scope (literal operators can only be declared at namespace scope).
+ break;
default:
break;
}
- Diag(Name.getBeginLoc(), diag::err_template_kw_refers_to_non_template)
+ // This name cannot possibly name a dependent template. Diagnose this now
+ // rather than building a dependent template name that can never be valid.
+ Diag(Name.getBeginLoc(),
+ diag::err_template_kw_refers_to_dependent_non_template)
<< GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange()
- << TemplateKWLoc;
+ << TemplateKWLoc.isValid() << TemplateKWLoc;
return TNK_Non_template;
}
@@ -4655,10 +4844,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
CXXScopeSpec SS;
DeclarationNameInfo NameInfo;
- if (DeclRefExpr *ArgExpr = dyn_cast<DeclRefExpr>(Arg.getAsExpr())) {
- SS.Adopt(ArgExpr->getQualifierLoc());
- NameInfo = ArgExpr->getNameInfo();
- } else if (DependentScopeDeclRefExpr *ArgExpr =
+ if (DependentScopeDeclRefExpr *ArgExpr =
dyn_cast<DependentScopeDeclRefExpr>(Arg.getAsExpr())) {
SS.Adopt(ArgExpr->getQualifierLoc());
NameInfo = ArgExpr->getNameInfo();
@@ -4677,6 +4863,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
if (Result.getAsSingle<TypeDecl>() ||
Result.getResultKind() ==
LookupResult::NotFoundInCurrentInstantiation) {
+ assert(SS.getScopeRep() && "dependent scope expr must has a scope!");
// Suggest that the user add 'typename' before the NNS.
SourceLocation Loc = AL.getSourceRange().getBegin();
Diag(Loc, getLangOpts().MSVCCompat
@@ -5716,6 +5903,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType(
return Visit(T->getElementType());
}
+bool UnnamedLocalNoLinkageFinder::VisitDependentSizedMatrixType(
+ const DependentSizedMatrixType *T) {
+ return Visit(T->getElementType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType(
const DependentAddressSpaceType *T) {
return Visit(T->getPointeeType());
@@ -5734,6 +5926,11 @@ bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) {
return Visit(T->getElementType());
}
+bool UnnamedLocalNoLinkageFinder::VisitConstantMatrixType(
+ const ConstantMatrixType *T) {
+ return Visit(T->getElementType());
+}
+
bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType(
const FunctionProtoType* T) {
for (const auto &A : T->param_types()) {
@@ -5815,7 +6012,9 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentNameType(
bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType* T) {
- return VisitNestedNameSpecifier(T->getQualifier());
+ if (auto *Q = T->getQualifier())
+ return VisitNestedNameSpecifier(Q);
+ return false;
}
bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType(
@@ -5845,6 +6044,15 @@ bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) {
return false;
}
+bool UnnamedLocalNoLinkageFinder::VisitExtIntType(const ExtIntType *T) {
+ return false;
+}
+
+bool UnnamedLocalNoLinkageFinder::VisitDependentExtIntType(
+ const DependentExtIntType *T) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
@@ -5869,6 +6077,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
NestedNameSpecifier *NNS) {
+ assert(NNS);
if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix()))
return true;
@@ -6177,8 +6386,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg = subst->getReplacement()->IgnoreImpCasts();
}
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
- ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr;
+ ValueDecl *Entity = nullptr;
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg))
+ Entity = DRE->getDecl();
+ else if (CXXUuidofExpr *CUE = dyn_cast<CXXUuidofExpr>(Arg))
+ Entity = CUE->getGuidDecl();
// If our parameter has pointer type, check for a null template value.
if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
@@ -6205,16 +6417,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return false;
}
- if (isa<CXXUuidofExpr>(Arg)) {
- if (CheckTemplateArgumentIsCompatibleWithParameter(S, Param, ParamType,
- ArgIn, Arg, ArgType))
- return true;
-
- Converted = TemplateArgument(ArgIn);
- return false;
- }
-
- if (!DRE) {
+ if (!Entity) {
S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
S.Diag(Param->getLocation(), diag::note_template_param_here);
@@ -6241,13 +6444,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
FunctionDecl *Func = dyn_cast<FunctionDecl>(Entity);
VarDecl *Var = dyn_cast<VarDecl>(Entity);
+ MSGuidDecl *Guid = dyn_cast<MSGuidDecl>(Entity);
// A non-type template argument must refer to an object or function.
- if (!Func && !Var) {
+ if (!Func && !Var && !Guid) {
// We found something, but we don't know specifically what it is.
S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_object_or_func)
<< Arg->getSourceRange();
- S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
+ S.Diag(Entity->getLocation(), diag::note_template_arg_refers_here);
return true;
}
@@ -6268,30 +6472,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
- if (Func) {
- // If the template parameter has pointer type, the function decays.
- if (ParamType->isPointerType() && !AddressTaken)
- ArgType = S.Context.getPointerType(Func->getType());
- else if (AddressTaken && ParamType->isReferenceType()) {
- // If we originally had an address-of operator, but the
- // parameter has reference type, complain and (if things look
- // like they will work) drop the address-of operator.
- if (!S.Context.hasSameUnqualifiedType(Func->getType(),
- ParamType.getNonReferenceType())) {
- S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
- << ParamType;
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
-
- S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
- << ParamType
- << FixItHint::CreateRemoval(AddrOpLoc);
- S.Diag(Param->getLocation(), diag::note_template_param_here);
-
- ArgType = Func->getType();
- }
- } else {
+ if (Var) {
// A value of reference type is not an object.
if (Var->getType()->isReferenceType()) {
S.Diag(Arg->getBeginLoc(), diag::err_template_arg_reference_var)
@@ -6307,50 +6488,53 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
S.Diag(Var->getLocation(), diag::note_template_arg_refers_here);
return true;
}
+ }
- // If the template parameter has pointer type, we must have taken
- // the address of this object.
- if (ParamType->isReferenceType()) {
- if (AddressTaken) {
- // If we originally had an address-of operator, but the
- // parameter has reference type, complain and (if things look
- // like they will work) drop the address-of operator.
- if (!S.Context.hasSameUnqualifiedType(Var->getType(),
- ParamType.getNonReferenceType())) {
- S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
- << ParamType;
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
+ if (AddressTaken && ParamType->isReferenceType()) {
+ // If we originally had an address-of operator, but the
+ // parameter has reference type, complain and (if things look
+ // like they will work) drop the address-of operator.
+ if (!S.Context.hasSameUnqualifiedType(Entity->getType(),
+ ParamType.getNonReferenceType())) {
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType;
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
- S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
- << ParamType
- << FixItHint::CreateRemoval(AddrOpLoc);
- S.Diag(Param->getLocation(), diag::note_template_param_here);
+ S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+ << ParamType
+ << FixItHint::CreateRemoval(AddrOpLoc);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
- ArgType = Var->getType();
- }
- } else if (!AddressTaken && ParamType->isPointerType()) {
- if (Var->getType()->isArrayType()) {
- // Array-to-pointer decay.
- ArgType = S.Context.getArrayDecayedType(Var->getType());
- } else {
- // If the template parameter has pointer type but the address of
- // this object was not taken, complain and (possibly) recover by
- // taking the address of the entity.
- ArgType = S.Context.getPointerType(Var->getType());
- if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
- S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of)
- << ParamType;
- S.Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
- }
+ ArgType = Entity->getType();
+ }
+ // If the template parameter has pointer type, either we must have taken the
+ // address or the argument must decay to a pointer.
+ if (!AddressTaken && ParamType->isPointerType()) {
+ if (Func) {
+ // Function-to-pointer decay.
+ ArgType = S.Context.getPointerType(Func->getType());
+ } else if (Entity->getType()->isArrayType()) {
+ // Array-to-pointer decay.
+ ArgType = S.Context.getArrayDecayedType(Entity->getType());
+ } else {
+ // If the template parameter has pointer type but the address of
+ // this object was not taken, complain and (possibly) recover by
+ // taking the address of the entity.
+ ArgType = S.Context.getPointerType(Entity->getType());
+ if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of)
- << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&");
-
+ << ParamType;
S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
}
+
+ S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of)
+ << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&");
+
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
}
}
@@ -6530,7 +6714,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeductionArg = PE->getPattern();
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
- DeductionArg, ParamType, Depth) == DAR_Failed) {
+ 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()
@@ -6670,12 +6859,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a predefined __func__ variable
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
- if (Base && !VD) {
- auto *E = Base.dyn_cast<const Expr *>();
- if (E && isa<CXXUuidofExpr>(E)) {
- Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
- break;
- }
+ if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
@@ -6762,7 +6946,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType IntegerType = ParamType;
if (const EnumType *Enum = IntegerType->getAs<EnumType>())
IntegerType = Enum->getDecl()->getIntegerType();
- Value = Value.extOrTrunc(Context.getTypeSize(IntegerType));
+ Value = Value.extOrTrunc(IntegerType->isExtIntType()
+ ? Context.getIntWidth(IntegerType)
+ : Context.getTypeSize(IntegerType));
Converted = TemplateArgument(Context, Value,
Context.getCanonicalType(ParamType));
@@ -6856,7 +7042,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Coerce the template argument's value to the value it will have
// based on the template parameter's type.
- unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ unsigned AllowedBits = IntegerType->isExtIntType()
+ ? Context.getIntWidth(IntegerType)
+ : Context.getTypeSize(IntegerType);
if (Value.getBitWidth() != AllowedBits)
Value = Value.extOrTrunc(AllowedBits);
Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType());
@@ -7102,6 +7290,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// [temp.constr.order].
SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
+ // C++2a[temp.arg.template]p3
+ // [...] In this comparison, if P is unconstrained, the constraints on A
+ // are not considered.
+ if (ParamsAC.empty())
+ return false;
Template->getAssociatedConstraints(TemplateAC);
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
@@ -7872,13 +8065,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs(
DeclResult Sema::ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
- SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId,
- const ParsedAttributesView &Attr,
+ SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
+ TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {
assert(TUK != TUK_Reference && "References are not specializations");
- CXXScopeSpec &SS = TemplateId.SS;
-
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
@@ -8048,7 +8239,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization()) &&
- (!Context.getLangOpts().ConceptsTS ||
+ (!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
@@ -8274,7 +8465,7 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
TemplateParameterLists.front(),
ConstraintExpr);
-
+
if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
// A concept shall not have associated constraints.
@@ -10012,24 +10203,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
<< FixItHint::CreateRemoval(TypenameLoc);
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ TypeSourceInfo *TSI = nullptr;
QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
- TypenameLoc, QualifierLoc, II, IdLoc);
+ TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
+ /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
-
- TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
- TL.setElaboratedKeywordLoc(TypenameLoc);
- TL.setQualifierLoc(QualifierLoc);
- TL.setNameLoc(IdLoc);
- } else {
- ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
- TL.setElaboratedKeywordLoc(TypenameLoc);
- TL.setQualifierLoc(QualifierLoc);
- TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
- }
-
return CreateParsedType(T, TSI);
}
@@ -10166,6 +10345,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
return true;
}
+QualType
+Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
+ SourceLocation KeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ const IdentifierInfo &II,
+ SourceLocation IILoc,
+ TypeSourceInfo **TSI,
+ bool DeducedTSTContext) {
+ QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc,
+ DeducedTSTContext);
+ if (T.isNull())
+ return QualType();
+
+ *TSI = Context.CreateTypeSourceInfo(T);
+ if (isa<DependentNameType>(T)) {
+ DependentNameTypeLoc TL =
+ (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>();
+ TL.setElaboratedKeywordLoc(KeywordLoc);
+ TL.setQualifierLoc(QualifierLoc);
+ TL.setNameLoc(IILoc);
+ } else {
+ ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ TL.setElaboratedKeywordLoc(KeywordLoc);
+ TL.setQualifierLoc(QualifierLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc);
+ }
+ return T;
+}
+
/// Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType
@@ -10173,32 +10381,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
SourceLocation KeywordLoc,
NestedNameSpecifierLoc QualifierLoc,
const IdentifierInfo &II,
- SourceLocation IILoc) {
+ SourceLocation IILoc, bool DeducedTSTContext) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- DeclContext *Ctx = computeDeclContext(SS);
- if (!Ctx) {
- // If the nested-name-specifier is dependent and couldn't be
- // resolved to a type, build a typename type.
- assert(QualifierLoc.getNestedNameSpecifier()->isDependent());
- return Context.getDependentNameType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- &II);
+ DeclContext *Ctx = nullptr;
+ if (QualifierLoc) {
+ Ctx = computeDeclContext(SS);
+ if (!Ctx) {
+ // If the nested-name-specifier is dependent and couldn't be
+ // resolved to a type, build a typename type.
+ assert(QualifierLoc.getNestedNameSpecifier()->isDependent());
+ return Context.getDependentNameType(Keyword,
+ QualifierLoc.getNestedNameSpecifier(),
+ &II);
+ }
+
+ // If the nested-name-specifier refers to the current instantiation,
+ // the "typename" keyword itself is superfluous. In C++03, the
+ // program is actually ill-formed. However, DR 382 (in C++0x CD1)
+ // allows such extraneous "typename" keywords, and we retroactively
+ // apply this DR to C++03 code with only a warning. In any case we continue.
+
+ if (RequireCompleteDeclContext(SS, Ctx))
+ return QualType();
}
- // If the nested-name-specifier refers to the current instantiation,
- // the "typename" keyword itself is superfluous. In C++03, the
- // program is actually ill-formed. However, DR 382 (in C++0x CD1)
- // allows such extraneous "typename" keywords, and we retroactively
- // apply this DR to C++03 code with only a warning. In any case we continue.
-
- if (RequireCompleteDeclContext(SS, Ctx))
- return QualType();
-
DeclarationName Name(&II);
LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
- LookupQualifiedName(Result, Ctx, SS);
+ if (Ctx)
+ LookupQualifiedName(Result, Ctx, SS);
+ else
+ LookupName(Result, CurScope);
unsigned DiagID = 0;
Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
@@ -10207,7 +10421,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// a more specific diagnostic.
SourceRange CondRange;
Expr *Cond = nullptr;
- if (isEnableIf(QualifierLoc, II, CondRange, Cond)) {
+ if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) {
// If we have a condition, narrow it down to the specific failed
// condition.
if (Cond) {
@@ -10223,12 +10437,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
return QualType();
}
- Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if)
+ Diag(CondRange.getBegin(),
+ diag::err_typename_nested_not_found_enable_if)
<< Ctx << CondRange;
return QualType();
}
- DiagID = diag::err_typename_nested_not_found;
+ DiagID = Ctx ? diag::err_typename_nested_not_found
+ : diag::err_unknown_typename;
break;
}
@@ -10294,6 +10510,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// is a placeholder for a deduced class type [...].
if (getLangOpts().CPlusPlus17) {
if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) {
+ if (!DeducedTSTContext) {
+ QualType T(QualifierLoc
+ ? QualifierLoc.getNestedNameSpecifier()->getAsType()
+ : nullptr, 0);
+ if (!T.isNull())
+ Diag(IILoc, diag::err_dependent_deduced_tst)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T;
+ else
+ Diag(IILoc, diag::err_deduced_tst)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD));
+ Diag(TD->getLocation(), diag::note_template_decl_here);
+ return QualType();
+ }
return Context.getElaboratedType(
Keyword, QualifierLoc.getNestedNameSpecifier(),
Context.getDeducedTemplateSpecializationType(TemplateName(TD),
@@ -10301,12 +10530,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
}
- DiagID = diag::err_typename_nested_not_type;
+ DiagID = Ctx ? diag::err_typename_nested_not_type
+ : diag::err_typename_not_type;
Referenced = Result.getFoundDecl();
break;
case LookupResult::FoundOverloaded:
- DiagID = diag::err_typename_nested_not_type;
+ DiagID = Ctx ? diag::err_typename_nested_not_type
+ : diag::err_typename_not_type;
Referenced = *Result.begin();
break;
@@ -10318,9 +10549,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
// type. Emit an appropriate diagnostic and return an error.
SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(),
IILoc);
- Diag(IILoc, DiagID) << FullRange << Name << Ctx;
+ if (Ctx)
+ Diag(IILoc, DiagID) << FullRange << Name << Ctx;
+ else
+ Diag(IILoc, DiagID) << FullRange << Name;
if (Referenced)
- Diag(Referenced->getLocation(), diag::note_typename_refers_here)
+ Diag(Referenced->getLocation(),
+ Ctx ? diag::note_typename_member_refers_here
+ : diag::note_typename_refers_here)
<< Name;
return QualType();
}
@@ -10515,7 +10751,7 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
}
Out << ']';
- return Out.str();
+ return std::string(Out.str());
}
void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1b9f1b2144d1..5392be57a3aa 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -355,7 +355,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
TemplateArgument Merged = checkDeducedTemplateArguments(
Context, DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()),
DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound()));
- if (Merged.isNull())
+ if (Merged.isNull() && !(XA->isNull() && YA->isNull()))
return DeducedTemplateArgument();
NewPack.push_back(Merged);
}
@@ -724,38 +724,49 @@ private:
// Compute the set of template parameter indices that correspond to
// parameter packs expanded by the pack expansion.
llvm::SmallBitVector SawIndices(TemplateParams->size());
+ llvm::SmallVector<TemplateArgument, 4> ExtraDeductions;
auto AddPack = [&](unsigned Index) {
if (SawIndices[Index])
return;
SawIndices[Index] = true;
addPack(Index);
+
+ // Deducing a parameter pack that is a pack expansion also constrains the
+ // packs appearing in that parameter to have the same deduced arity. Also,
+ // in C++17 onwards, deducing a non-type template parameter deduces its
+ // type, so we need to collect the pending deduced values for those packs.
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
+ TemplateParams->getParam(Index))) {
+ if (!NTTP->isExpandedParameterPack())
+ if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType()))
+ ExtraDeductions.push_back(Expansion->getPattern());
+ }
+ // FIXME: Also collect the unexpanded packs in any type and template
+ // parameter packs that are pack expansions.
};
- // First look for unexpanded packs in the pattern.
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == Info.getDeducedDepth())
- AddPack(Index);
- }
+ auto Collect = [&](TemplateArgument Pattern) {
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ if (Depth == Info.getDeducedDepth())
+ AddPack(Index);
+ }
+ };
+
+ // Look for unexpanded packs in the pattern.
+ Collect(Pattern);
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
unsigned NumNamedPacks = Packs.size();
- // We can also have deduced template parameters that do not actually
- // appear in the pattern, but can be deduced by it (the type of a non-type
- // template parameter pack, in particular). These won't have prevented us
- // from partially expanding the pack.
- llvm::SmallBitVector Used(TemplateParams->size());
- MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
- Info.getDeducedDepth(), Used);
- for (int Index = Used.find_first(); Index != -1;
- Index = Used.find_next(Index))
- if (TemplateParams->getParam(Index)->isParameterPack())
- AddPack(Index);
+ // Also look for unexpanded packs that are indirectly deduced by deducing
+ // the sizes of the packs in this pattern.
+ while (!ExtraDeductions.empty())
+ Collect(ExtraDeductions.pop_back_val());
return NumNamedPacks;
}
@@ -1505,6 +1516,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
+ case Type::ExtInt:
if (TDF & TDF_SkipNonDependent)
return Sema::TDK_Success;
@@ -1808,7 +1820,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// If this is a base class, try to perform template argument
// deduction from it.
if (NextT != RecordT) {
- TemplateDeductionInfo BaseInfo(Info.getLocation());
+ TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
Sema::TemplateDeductionResult BaseResult =
DeduceTemplateArguments(S, TemplateParams, SpecParam,
QualType(NextT, 0), BaseInfo, Deduced);
@@ -2046,6 +2058,101 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// (clang extension)
//
+ // T __attribute__((matrix_type(<integral constant>,
+ // <integral constant>)))
+ case Type::ConstantMatrix: {
+ const ConstantMatrixType *MatrixArg = dyn_cast<ConstantMatrixType>(Arg);
+ if (!MatrixArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ const ConstantMatrixType *MatrixParam = cast<ConstantMatrixType>(Param);
+ // Check that the dimensions are the same
+ if (MatrixParam->getNumRows() != MatrixArg->getNumRows() ||
+ MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) {
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ // Perform deduction on element types.
+ return DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, MatrixParam->getElementType(),
+ MatrixArg->getElementType(), Info, Deduced, TDF);
+ }
+
+ case Type::DependentSizedMatrix: {
+ const MatrixType *MatrixArg = dyn_cast<MatrixType>(Arg);
+ if (!MatrixArg)
+ return Sema::TDK_NonDeducedMismatch;
+
+ // Check the element type of the matrixes.
+ const DependentSizedMatrixType *MatrixParam =
+ cast<DependentSizedMatrixType>(Param);
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, MatrixParam->getElementType(),
+ MatrixArg->getElementType(), Info, Deduced, TDF))
+ return Result;
+
+ // Try to deduce a matrix dimension.
+ auto DeduceMatrixArg =
+ [&S, &Info, &Deduced, &TemplateParams](
+ Expr *ParamExpr, const MatrixType *Arg,
+ unsigned (ConstantMatrixType::*GetArgDimension)() const,
+ Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) {
+ const auto *ArgConstMatrix = dyn_cast<ConstantMatrixType>(Arg);
+ const auto *ArgDepMatrix = dyn_cast<DependentSizedMatrixType>(Arg);
+ if (!ParamExpr->isValueDependent()) {
+ llvm::APSInt ParamConst(
+ S.Context.getTypeSize(S.Context.getSizeType()));
+ if (!ParamExpr->isIntegerConstantExpr(ParamConst, S.Context))
+ return Sema::TDK_NonDeducedMismatch;
+
+ if (ArgConstMatrix) {
+ if ((ArgConstMatrix->*GetArgDimension)() == ParamConst)
+ return Sema::TDK_Success;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)();
+ llvm::APSInt ArgConst(
+ S.Context.getTypeSize(S.Context.getSizeType()));
+ if (!ArgExpr->isValueDependent() &&
+ ArgExpr->isIntegerConstantExpr(ArgConst, S.Context) &&
+ ArgConst == ParamConst)
+ return Sema::TDK_Success;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, ParamExpr);
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ if (ArgConstMatrix) {
+ llvm::APSInt ArgConst(
+ S.Context.getTypeSize(S.Context.getSizeType()));
+ ArgConst = (ArgConstMatrix->*GetArgDimension)();
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(),
+ /*ArrayBound=*/true, Info, Deduced);
+ }
+
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(),
+ Info, Deduced);
+ };
+
+ auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg,
+ &ConstantMatrixType::getNumRows,
+ &DependentSizedMatrixType::getRowExpr);
+ if (Result)
+ return Result;
+
+ return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg,
+ &ConstantMatrixType::getNumColumns,
+ &DependentSizedMatrixType::getColumnExpr);
+ }
+
+ // (clang extension)
+ //
// T __attribute__(((address_space(N))))
case Type::DependentAddressSpace: {
const DependentAddressSpaceType *AddressSpaceParam =
@@ -2096,6 +2203,33 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
}
+ case Type::DependentExtInt: {
+ const auto *IntParam = cast<DependentExtIntType>(Param);
+
+ if (const auto *IntArg = dyn_cast<ExtIntType>(Arg)){
+ if (IntParam->isUnsigned() != IntArg->isUnsigned())
+ return Sema::TDK_NonDeducedMismatch;
+
+ NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
+ ArgSize = IntArg->getNumBits();
+
+ return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
+ S.Context.IntTy, true, Info,
+ Deduced);
+ }
+
+ if (const auto *IntArg = dyn_cast<DependentExtIntType>(Arg)) {
+ if (IntParam->isUnsigned() != IntArg->isUnsigned())
+ return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_Success;
+ }
+ return Sema::TDK_NonDeducedMismatch;
+ }
case Type::TypeOfExpr:
case Type::TypeOf:
@@ -2478,7 +2612,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN =
@@ -2504,27 +2638,10 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
}
TemplateArgumentLoc
-Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm,
+Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
SourceLocation Location) {
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
- return getTrivialTemplateArgumentLoc(
- TemplateArgument(
- Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(),
- TTP->isParameterPack(), TTP)),
- QualType(), Location.isValid() ? Location : TTP->getLocation());
- else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
- return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
- QualType(),
- Location.isValid() ? Location :
- TTP->getLocation());
- auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
- CXXScopeSpec SS;
- DeclarationNameInfo Info(NTTP->getDeclName(),
- Location.isValid() ? Location : NTTP->getLocation());
- Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get();
- return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
- Location.isValid() ? Location :
- NTTP->getLocation());
+ return getTrivialTemplateArgumentLoc(
+ Context.getInjectedTemplateArg(TemplateParm), QualType(), Location);
}
/// Convert the given deduced template argument and add it to the set of
@@ -2754,8 +2871,8 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
/// Complete template argument deduction for a partial specialization.
template <typename T>
-static typename std::enable_if<IsPartialSpecialization<T>::value,
- Sema::TemplateDeductionResult>::type
+static std::enable_if_t<IsPartialSpecialization<T>::value,
+ Sema::TemplateDeductionResult>
FinishTemplateArgumentDeduction(
Sema &S, T *Partial, bool IsPartialOrdering,
const TemplateArgumentList &TemplateArgs,
@@ -2924,8 +3041,13 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- return ::FinishTemplateArgumentDeduction(
- *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = ::FinishTemplateArgumentDeduction(*this, Partial,
+ /*IsPartialOrdering=*/false,
+ TemplateArgs, Deduced, Info);
+ });
+ return Result;
}
/// Perform template argument deduction to determine whether
@@ -2965,8 +3087,13 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- return ::FinishTemplateArgumentDeduction(
- *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info);
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = ::FinishTemplateArgumentDeduction(*this, Partial,
+ /*IsPartialOrdering=*/false,
+ TemplateArgs, Deduced, Info);
+ });
+ return Result;
}
/// Determine whether the given type T is a simple-template-id type.
@@ -3446,13 +3573,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.decl]), those constraints are checked for satisfaction
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
- if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
- Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
- return TDK_MiscellaneousDeductionFailure;
+ if (!PartialOverloading ||
+ (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) {
+ if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
+ Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ return TDK_MiscellaneousDeductionFailure;
- if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
- return TDK_ConstraintsNotSatisfied;
+ if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ return TDK_ConstraintsNotSatisfied;
+ }
}
if (OriginalCallArgs) {
@@ -3912,13 +4042,12 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
SmallVector<QualType, 8> ParamTypes;
unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
- TemplateDeductionResult Result =
- SubstituteExplicitTemplateArguments(FunctionTemplate,
- *ExplicitTemplateArgs,
- Deduced,
- ParamTypes,
- nullptr,
- Info);
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = SubstituteExplicitTemplateArguments(
+ FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, nullptr,
+ Info);
+ });
if (Result)
return Result;
@@ -4020,12 +4149,16 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// that is needed when the accessibility of template arguments is checked.
DeclContext *CallingCtx = CurContext;
- return FinishTemplateArgumentDeduction(
- FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
- &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
- ContextRAII SavedContext(*this, CallingCtx);
- return CheckNonDependent(ParamTypesForArgChecking);
- });
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = FinishTemplateArgumentDeduction(
+ FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
+ &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
+ ContextRAII SavedContext(*this, CallingCtx);
+ return CheckNonDependent(ParamTypesForArgChecking);
+ });
+ });
+ return Result;
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
@@ -4111,11 +4244,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
unsigned NumExplicitlySpecified = 0;
SmallVector<QualType, 4> ParamTypes;
if (ExplicitTemplateArgs) {
- if (TemplateDeductionResult Result
- = SubstituteExplicitTemplateArguments(FunctionTemplate,
- *ExplicitTemplateArgs,
- Deduced, ParamTypes,
- &FunctionType, Info))
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = SubstituteExplicitTemplateArguments(
+ FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes,
+ &FunctionType, Info);
+ });
+ if (Result)
return Result;
NumExplicitlySpecified = Deduced.size();
@@ -4157,10 +4292,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
return Result;
}
- if (TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
- NumExplicitlySpecified,
- Specialization, Info))
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+ NumExplicitlySpecified,
+ Specialization, Info);
+ });
+ if (Result)
return Result;
// If the function has a deduced return type, deduce it now, so we can check
@@ -4317,9 +4455,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
LocalInstantiationScope InstScope(*this);
// Finish template argument deduction.
FunctionDecl *ConversionSpecialized = nullptr;
- TemplateDeductionResult Result
- = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
- ConversionSpecialized, Info);
+ TemplateDeductionResult Result;
+ runWithSufficientStackSpace(Info.getLocation(), [&] {
+ Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
+ ConversionSpecialized, Info);
+ });
Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
return Result;
}
@@ -4404,9 +4544,10 @@ namespace {
QualType Result = SemaRef.Context.getAutoType(
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
- ReplacementIsPack);
+ ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(),
+ TL.getTypePtr()->getTypeConstraintArguments());
auto NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.copy(TL);
return Result;
}
@@ -4441,9 +4582,10 @@ namespace {
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth);
+ DependentDeductionDepth, IgnoreConstraints);
}
/// Attempt to produce an informative diagostic explaining why auto deduction
@@ -4471,6 +4613,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
}
}
+static Sema::DeduceAutoResult
+CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc, QualType Deduced) {
+ ConstraintSatisfaction Satisfaction;
+ ConceptDecl *Concept = Type.getTypeConstraintConcept();
+ TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
+ TypeLoc.getRAngleLoc());
+ TemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(Deduced),
+ S.Context.getTrivialTypeSourceInfo(
+ Deduced, TypeLoc.getNameLoc())));
+ for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
+ TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
+ /*PartialTemplateArgs=*/false, Converted))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
+ Converted, TypeLoc.getLocalSourceRange(),
+ Satisfaction))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (!Satisfaction.IsSatisfied) {
+ std::string Buf;
+ llvm::raw_string_ostream OS(Buf);
+ OS << "'" << Concept->getName();
+ if (TypeLoc.hasExplicitTemplateArgs()) {
+ OS << "<";
+ for (const auto &Arg : Type.getTypeConstraintArguments())
+ Arg.print(S.getPrintingPolicy(), OS);
+ OS << ">";
+ }
+ OS << "'";
+ OS.flush();
+ S.Diag(TypeLoc.getConceptNameLoc(),
+ diag::err_placeholder_constraints_not_satisfied)
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ }
+ return Sema::DAR_Succeeded;
+}
+
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4485,9 +4670,14 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
/// 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.
+/// \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) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
+ if (Init->containsErrors())
+ return DAR_FailedAlreadyDiagnosed;
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
@@ -4528,6 +4718,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
+ 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;
@@ -4635,6 +4833,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
+ if (const auto *AT = Type.getType()->getAs<AutoType>()) {
+ if (AT->isConstrained() && !IgnoreConstraints) {
+ auto ConstraintsResult =
+ CheckDeducedPlaceholderConstraints(*this, *AT,
+ Type.getContainedAutoTypeLoc(),
+ DeducedType);
+ if (ConstraintsResult != DAR_Succeeded)
+ return ConstraintsResult;
+ }
+ }
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
@@ -4787,7 +4996,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments1) {
+ unsigned NumCallArguments1,
+ bool Reversed) {
+ assert(!Reversed || TPOC == TPOC_Call);
+
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
@@ -4836,6 +5048,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
} else if (!Method1 && Method2 && !Method2->isStatic()) {
// Compare 'this' from Method2 against first parameter from Method1.
AddImplicitObjectParameterType(S.Context, Method2, Args2);
+ } else if (Method1 && Method2 && Reversed) {
+ // Compare 'this' from Method1 against second parameter from Method2
+ // and 'this' from Method2 against second parameter from Method1.
+ AddImplicitObjectParameterType(S.Context, Method1, Args1);
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
+ ++NumComparedArguments;
}
Args1.insert(Args1.end(), Proto1->param_type_begin(),
@@ -4850,6 +5068,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
Args1.resize(NumComparedArguments);
if (Args2.size() > NumComparedArguments)
Args2.resize(NumComparedArguments);
+ if (Reversed)
+ std::reverse(Args2.begin(), Args2.end());
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true))
@@ -4968,6 +5188,10 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// \param NumCallArguments2 The number of arguments in the call to FT2, used
/// only when \c TPOC is \c TPOC_Call.
///
+/// \param Reversed If \c true, exactly one of FT1 and FT2 is an overload
+/// candidate with a reversed parameter order. In this case, the corresponding
+/// P/A pairs between FT1 and FT2 are reversed.
+///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *
@@ -4976,7 +5200,8 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments1,
- unsigned NumCallArguments2) {
+ unsigned NumCallArguments2,
+ bool Reversed) {
auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
llvm::SmallVector<const Expr *, 3> AC1, AC2;
@@ -4993,9 +5218,9 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
};
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
- NumCallArguments1);
+ NumCallArguments1, Reversed);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
- NumCallArguments2);
+ NumCallArguments2, Reversed);
if (Better1 != Better2) // We have a clear winner
return Better1 ? FT1 : FT2;
@@ -5174,14 +5399,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
Info);
auto *TST1 = T1->castAs<TemplateSpecializationType>();
- if (FinishTemplateArgumentDeduction(
- S, P2, /*IsPartialOrdering=*/true,
- TemplateArgumentList(TemplateArgumentList::OnStack,
- TST1->template_arguments()),
- Deduced, Info))
- return false;
-
- return true;
+ bool AtLeastAsSpecialized;
+ S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+ AtLeastAsSpecialized = !FinishTemplateArgumentDeduction(
+ S, P2, /*IsPartialOrdering=*/true,
+ TemplateArgumentList(TemplateArgumentList::OnStack,
+ TST1->template_arguments()),
+ Deduced, Info);
+ });
+ return AtLeastAsSpecialized;
}
/// Returns the more specialized class template partial specialization
@@ -5616,6 +5842,24 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
break;
}
+ case Type::ConstantMatrix: {
+ const ConstantMatrixType *MatType = cast<ConstantMatrixType>(T);
+ MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced,
+ Depth, Used);
+ break;
+ }
+
+ case Type::DependentSizedMatrix: {
+ const DependentSizedMatrixType *MatType = cast<DependentSizedMatrixType>(T);
+ MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced,
+ Depth, Used);
+ MarkUsedTemplateParameters(Ctx, MatType->getRowExpr(), OnlyDeduced, Depth,
+ Used);
+ MarkUsedTemplateParameters(Ctx, MatType->getColumnExpr(), OnlyDeduced,
+ Depth, Used);
+ break;
+ }
+
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,
@@ -5771,6 +6015,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
cast<DeducedType>(T)->getDeducedType(),
OnlyDeduced, Depth, Used);
break;
+ case Type::DependentExtInt:
+ MarkUsedTemplateParameters(Ctx,
+ cast<DependentExtIntType>(T)->getNumBitsExpr(),
+ OnlyDeduced, Depth, Used);
+ break;
// None of these types have any template parameters in them.
case Type::Builtin:
@@ -5783,6 +6032,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
case Type::Pipe:
+ case Type::ExtInt:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index af41e231134d..11e03c517d01 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -9,7 +9,6 @@
//
//===----------------------------------------------------------------------===/
-#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -18,11 +17,15 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.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"
@@ -199,8 +202,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
case ConstraintsCheck:
+ case NestedRequirementConstraintsCheck:
return true;
+ case RequirementInstantiation:
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DeclaringImplicitEqualityComparison:
@@ -210,6 +215,8 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case ParameterMappingSubstitution:
case ConstraintNormalization:
case RewritingOperatorAsSpaceship:
+ case InitializingStructuredBinding:
+ case MarkingClassDllexported:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -247,7 +254,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Inst.InstantiationRange = InstantiationRange;
SemaRef.pushCodeSynthesisContext(Inst);
- AlreadyInstantiating =
+ AlreadyInstantiating = !Inst.Entity ? false :
!SemaRef.InstantiatingSpecializations
.insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))
.second;
@@ -366,6 +373,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::RequirementInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {}
+
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ concepts::NestedRequirement *Req, ConstraintsCheck,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/None) {}
+
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
ConstraintsCheck, NamedDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
@@ -446,8 +473,9 @@ void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
if (!AlreadyInstantiating) {
auto &Active = SemaRef.CodeSynthesisContexts.back();
- SemaRef.InstantiatingSpecializations.erase(
- std::make_pair(Active.Entity, Active.Kind));
+ if (Active.Entity)
+ SemaRef.InstantiatingSpecializations.erase(
+ std::make_pair(Active.Entity, Active.Kind));
}
atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef,
@@ -684,6 +712,18 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::RequirementInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_requirement_instantiation_here)
+ << Active->InstantiationRange;
+ break;
+
+ case CodeSynthesisContext::NestedRequirementConstraintsCheck:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_nested_requirement_here)
+ << Active->InstantiationRange;
+ break;
+
case CodeSynthesisContext::DeclaringSpecialMember:
Diags.Report(Active->PointOfInstantiation,
diag::note_in_declaration_of_implicit_special_member)
@@ -722,26 +762,47 @@ void Sema::PrintInstantiationStack() {
diag::note_rewriting_operator_as_spaceship);
break;
+ case CodeSynthesisContext::InitializingStructuredBinding:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_in_binding_decl_init)
+ << cast<BindingDecl>(Active->Entity);
+ break;
+
+ case CodeSynthesisContext::MarkingClassDllexported:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_due_to_dllexported_class)
+ << cast<CXXRecordDecl>(Active->Entity) << !getLangOpts().CPlusPlus11;
+ break;
+
case CodeSynthesisContext::Memoization:
break;
-
+
case CodeSynthesisContext::ConstraintsCheck: {
unsigned DiagID = 0;
+ if (!Active->Entity) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_nested_requirement_here)
+ << Active->InstantiationRange;
+ break;
+ }
if (isa<ConceptDecl>(Active->Entity))
DiagID = diag::note_concept_specialization_here;
else if (isa<TemplateDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_template_id_here;
else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_var_spec_id_here;
- else {
- assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity));
+ else if (isa<ClassTemplatePartialSpecializationDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_class_spec_id_here;
+ else {
+ assert(isa<FunctionDecl>(Active->Entity));
+ DiagID = diag::note_checking_constraints_for_function_here;
}
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
cast<NamedDecl>(Active->Entity)->printName(OS);
- printTemplateArgumentList(OS, Active->template_arguments(),
- getPrintingPolicy());
+ if (!isa<FunctionDecl>(Active->Entity))
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str()
<< Active->InstantiationRange;
break;
@@ -788,6 +849,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ConstraintsCheck:
case CodeSynthesisContext::ParameterMappingSubstitution:
case CodeSynthesisContext::ConstraintNormalization:
+ case CodeSynthesisContext::NestedRequirementConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -802,9 +864,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
case CodeSynthesisContext::ConstraintSubstitution:
- // We're either substituting explicitly-specified template arguments
- // or deduced template arguments or a constraint expression, so SFINAE
- // applies.
+ case CodeSynthesisContext::RequirementInstantiation:
+ // We're either substituting explicitly-specified template arguments,
+ // deduced template arguments, a constraint expression or a requirement
+ // in a requires expression, so SFINAE applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
@@ -812,6 +875,8 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
case CodeSynthesisContext::DefiningSynthesizedFunction:
case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+ case CodeSynthesisContext::InitializingStructuredBinding:
+ case CodeSynthesisContext::MarkingClassDllexported:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
@@ -874,6 +939,10 @@ namespace {
this->Entity = Entity;
}
+ unsigned TransformTemplateDepth(unsigned Depth) {
+ return TemplateArgs.getNewDepth(Depth);
+ }
+
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
@@ -1010,6 +1079,8 @@ namespace {
NonTypeTemplateParmDecl *D);
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E);
+ ExprResult TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E);
/// Rebuild a DeclRefExpr for a VarDecl reference.
ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc);
@@ -1056,6 +1127,41 @@ namespace {
return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
}
+ ExprResult TransformRequiresExpr(RequiresExpr *E) {
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ return TreeTransform<TemplateInstantiator>::TransformRequiresExpr(E);
+ }
+
+ bool TransformRequiresExprRequirements(
+ ArrayRef<concepts::Requirement *> Reqs,
+ SmallVectorImpl<concepts::Requirement *> &Transformed) {
+ bool SatisfactionDetermined = false;
+ for (concepts::Requirement *Req : Reqs) {
+ concepts::Requirement *TransReq = nullptr;
+ if (!SatisfactionDetermined) {
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+ TransReq = TransformTypeRequirement(TypeReq);
+ else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+ TransReq = TransformExprRequirement(ExprReq);
+ else
+ TransReq = TransformNestedRequirement(
+ cast<concepts::NestedRequirement>(Req));
+ if (!TransReq)
+ return true;
+ if (!TransReq->isDependent() && !TransReq->isSatisfied())
+ // [expr.prim.req]p6
+ // [...] The substitution and semantic constraint checking
+ // proceeds in lexical order and stops when a condition that
+ // determines the result of the requires-expression is
+ // encountered. [..]
+ SatisfactionDetermined = true;
+ } else
+ TransReq = Req;
+ Transformed.push_back(TransReq);
+ }
+ return false;
+ }
+
TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
@@ -1065,6 +1171,14 @@ namespace {
/* DeclContext *Owner */ Owner, TemplateArgs);
return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
+
+ concepts::TypeRequirement *
+ TransformTypeRequirement(concepts::TypeRequirement *Req);
+ concepts::ExprRequirement *
+ TransformExprRequirement(concepts::ExprRequirement *Req);
+ concepts::NestedRequirement *
+ TransformNestedRequirement(concepts::NestedRequirement *Req);
+
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
@@ -1248,6 +1362,19 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
+ if (TemplateArgs.isRewrite()) {
+ // We're rewriting the template parameter as a reference to another
+ // template parameter.
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
+ "unexpected pack arguments in template rewrite");
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+ assert(Arg.getKind() == TemplateArgument::Template &&
+ "unexpected nontype template argument kind in template rewrite");
+ return Arg.getAsTemplate();
+ }
+
if (TTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1287,11 +1414,47 @@ TemplateName TemplateInstantiator::TransformTemplateName(
AllowInjectedClassName);
}
+static ExprResult TransformUniqueStableName(TemplateInstantiator &TI,
+ PredefinedExpr *E) {
+ if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) {
+ TypeSourceInfo *Info =
+ TI.getDerived().TransformType(E->getTypeSourceInfo());
+
+ if (!Info)
+ return ExprError();
+
+ if (!TI.getDerived().AlwaysRebuild() && Info == E->getTypeSourceInfo())
+ return E;
+
+ return TI.getSema().BuildUniqueStableName(E->getLocation(), Info);
+ }
+
+ if (E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) {
+ EnterExpressionEvaluationContext Unevaluated(
+ TI.getSema(), Sema::ExpressionEvaluationContext::Unevaluated);
+ ExprResult SubExpr = TI.getDerived().TransformExpr(E->getExpr());
+
+ if (SubExpr.isInvalid())
+ return ExprError();
+
+ if (!TI.getDerived().AlwaysRebuild() && SubExpr.get() == E->getExpr())
+ return E;
+
+ return TI.getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get());
+ }
+
+ llvm_unreachable("Only valid for UniqueStableNameType/Expr");
+}
+
ExprResult
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
return E;
+ if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType ||
+ E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr)
+ return TransformUniqueStableName(*this, E);
+
return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind());
}
@@ -1308,19 +1471,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
- if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) {
- // We're performing a partial substitution, so the substituted argument
- // could be dependent. As a result we can't create a SubstNonType*Expr
- // node now, since that represents a fully-substituted argument.
- // FIXME: We should have some AST representation for this.
+ if (TemplateArgs.isRewrite()) {
+ // We're rewriting the template parameter as a reference to another
+ // template parameter.
if (Arg.getKind() == TemplateArgument::Pack) {
- // FIXME: This won't work for alias templates.
assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
- "unexpected pack arguments in partial substitution");
+ "unexpected pack arguments in template rewrite");
Arg = Arg.pack_begin()->getPackExpansionPattern();
}
assert(Arg.getKind() == TemplateArgument::Expression &&
- "unexpected nontype template argument kind in partial substitution");
+ "unexpected nontype template argument kind in template rewrite");
+ // FIXME: This can lead to the same subexpression appearing multiple times
+ // in a complete expression.
return Arg.getAsExpr();
}
@@ -1445,6 +1607,44 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
Arg);
}
+ExprResult
+TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ ExprResult SubstReplacement = TransformExpr(E->getReplacement());
+ if (SubstReplacement.isInvalid())
+ return true;
+ QualType SubstType = TransformType(E->getType());
+ if (SubstType.isNull())
+ return true;
+ // The type may have been previously dependent and not now, which means we
+ // might have to implicit cast the argument to the new type, for example:
+ // template<auto T, decltype(T) U>
+ // concept C = sizeof(U) == 4;
+ // void foo() requires C<2, 'a'> { }
+ // When normalizing foo(), we first form the normalized constraints of C:
+ // AtomicExpr(sizeof(U) == 4,
+ // U=SubstNonTypeTemplateParmExpr(Param=U,
+ // Expr=DeclRef(U),
+ // Type=decltype(T)))
+ // Then we substitute T = 2, U = 'a' into the parameter mapping, and need to
+ // produce:
+ // AtomicExpr(sizeof(U) == 4,
+ // U=SubstNonTypeTemplateParmExpr(Param=U,
+ // Expr=ImpCast(
+ // decltype(2),
+ // SubstNTTPE(Param=U, Expr='a',
+ // 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())
+ return true;
+ return transformNonTypeTemplateParmRef(E->getParameter(),
+ E->getExprLoc(), Converted);
+}
+
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
SourceLocation Loc) {
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
@@ -1594,6 +1794,24 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
+ if (TemplateArgs.isRewrite()) {
+ // We're rewriting the template parameter as a reference to another
+ // template parameter.
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
+ "unexpected pack arguments in template rewrite");
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+ assert(Arg.getKind() == TemplateArgument::Type &&
+ "unexpected nontype template argument kind in template rewrite");
+ QualType NewT = Arg.getAsType();
+ assert(isa<TemplateTypeParmType>(NewT) &&
+ "type parm not rewritten to type parm");
+ auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return NewT;
+ }
+
if (T->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1669,6 +1887,163 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
return Result;
}
+template<typename EntityPrinter>
+static concepts::Requirement::SubstitutionDiagnostic *
+createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
+ SmallString<128> Message;
+ SourceLocation ErrorLoc;
+ if (Info.hasSFINAEDiagnostic()) {
+ PartialDiagnosticAt PDA(SourceLocation(),
+ PartialDiagnostic::NullDiagnostic{});
+ Info.takeSFINAEDiagnostic(PDA);
+ PDA.second.EmitToString(S.getDiagnostics(), Message);
+ ErrorLoc = PDA.first;
+ } else {
+ ErrorLoc = Info.getLocation();
+ }
+ char *MessageBuf = new (S.Context) char[Message.size()];
+ std::copy(Message.begin(), Message.end(), MessageBuf);
+ SmallString<128> Entity;
+ llvm::raw_svector_ostream OS(Entity);
+ Printer(OS);
+ char *EntityBuf = new (S.Context) char[Entity.size()];
+ std::copy(Entity.begin(), Entity.end(), EntityBuf);
+ return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+ StringRef(EntityBuf, Entity.size()), ErrorLoc,
+ StringRef(MessageBuf, Message.size())};
+}
+
+concepts::TypeRequirement *
+TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+ if (Req->isSubstitutionFailure()) {
+ if (AlwaysRebuild())
+ return RebuildTypeRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+
+ Sema::SFINAETrap Trap(SemaRef);
+ TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc());
+ Sema::InstantiatingTemplate TypeInst(SemaRef,
+ Req->getType()->getTypeLoc().getBeginLoc(), Req, Info,
+ Req->getType()->getTypeLoc().getSourceRange());
+ if (TypeInst.isInvalid())
+ return nullptr;
+ TypeSourceInfo *TransType = TransformType(Req->getType());
+ if (!TransType || Trap.hasErrorOccurred())
+ return RebuildTypeRequirement(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy());
+ }));
+ return RebuildTypeRequirement(TransType);
+}
+
+concepts::ExprRequirement *
+TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+
+ Sema::SFINAETrap Trap(SemaRef);
+ TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc());
+
+ llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *>
+ TransExpr;
+ if (Req->isExprSubstitutionFailure())
+ TransExpr = Req->getExprSubstitutionDiagnostic();
+ else {
+ Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(),
+ Req, Info,
+ Req->getExpr()->getSourceRange());
+ if (ExprInst.isInvalid())
+ return nullptr;
+ ExprResult TransExprRes = TransformExpr(Req->getExpr());
+ if (TransExprRes.isInvalid() || Trap.hasErrorOccurred())
+ TransExpr = createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ });
+ else
+ TransExpr = TransExprRes.get();
+ }
+
+ llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ const auto &RetReq = Req->getReturnTypeRequirement();
+ if (RetReq.isEmpty())
+ TransRetReq.emplace();
+ else if (RetReq.isSubstitutionFailure())
+ TransRetReq.emplace(RetReq.getSubstitutionDiagnostic());
+ else if (RetReq.isTypeConstraint()) {
+ TemplateParameterList *OrigTPL =
+ RetReq.getTypeConstraintTemplateParameterList();
+ Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(),
+ Req, Info, OrigTPL->getSourceRange());
+ if (TPLInst.isInvalid())
+ return nullptr;
+ TemplateParameterList *TPL =
+ TransformTemplateParameterList(OrigTPL);
+ if (!TPL)
+ TransRetReq.emplace(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()
+ ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+ }));
+ else {
+ TPLInst.Clear();
+ TransRetReq.emplace(TPL);
+ }
+ }
+ assert(TransRetReq.hasValue() &&
+ "All code paths leading here must set TransRetReq");
+ if (Expr *E = TransExpr.dyn_cast<Expr *>())
+ return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(),
+ std::move(*TransRetReq));
+ return RebuildExprRequirement(
+ TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
+ Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+}
+
+concepts::NestedRequirement *
+TemplateInstantiator::TransformNestedRequirement(
+ concepts::NestedRequirement *Req) {
+ if (!Req->isDependent() && !AlwaysRebuild())
+ return Req;
+ if (Req->isSubstitutionFailure()) {
+ if (AlwaysRebuild())
+ return RebuildNestedRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ Sema::InstantiatingTemplate ReqInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req,
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ Req->getConstraintExpr()->getSourceRange());
+
+ ExprResult TransConstraint;
+ TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc());
+ {
+ EnterExpressionEvaluationContext ContextRAII(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ Sema::SFINAETrap Trap(SemaRef);
+ Sema::InstantiatingTemplate ConstrInst(SemaRef,
+ Req->getConstraintExpr()->getBeginLoc(), Req, Info,
+ Req->getConstraintExpr()->getSourceRange());
+ if (ConstrInst.isInvalid())
+ return nullptr;
+ TransConstraint = TransformExpr(Req->getConstraintExpr());
+ if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
+ return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
+ [&] (llvm::raw_ostream& OS) {
+ Req->getConstraintExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ }));
+ }
+ return RebuildNestedRequirement(TransConstraint.get());
+}
+
+
/// Perform substitution on the type T with a given set of template
/// arguments.
///
@@ -1858,6 +2233,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
UpdateExceptionSpec(New, ESI);
}
+namespace {
+
+ struct GetContainedInventedTypeParmVisitor :
+ public TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *> {
+ using TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *>::Visit;
+
+ TemplateTypeParmDecl *Visit(QualType T) {
+ if (T.isNull())
+ return nullptr;
+ return Visit(T.getTypePtr());
+ }
+ // The deduced type itself.
+ TemplateTypeParmDecl *VisitTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ if (!T->getDecl() || !T->getDecl()->isImplicit())
+ return nullptr;
+ return T->getDecl();
+ }
+
+ // Only these types can contain 'auto' types, and subsequently be replaced
+ // by references to invented parameters.
+
+ TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) {
+ return Visit(T->getNamedType());
+ }
+
+ TemplateTypeParmDecl *VisitPointerType(const PointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) {
+ return Visit(T->getPointeeTypeAsWritten());
+ }
+
+ TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitVectorType(const VectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) {
+ return VisitFunctionType(T);
+ }
+
+ TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) {
+ return Visit(T->getReturnType());
+ }
+
+ TemplateTypeParmDecl *VisitParenType(const ParenType *T) {
+ return Visit(T->getInnerType());
+ }
+
+ TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) {
+ return Visit(T->getModifiedType());
+ }
+
+ TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) {
+ return Visit(T->getUnderlyingType());
+ }
+
+ TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) {
+ return Visit(T->getOriginalType());
+ }
+
+ TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) {
+ return Visit(T->getPattern());
+ }
+ };
+
+} // namespace
+
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -1905,6 +2368,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
return nullptr;
}
+ // In abbreviated templates, TemplateTypeParmDecls with possible
+ // TypeConstraints are created when the parameter list is originally parsed.
+ // The TypeConstraints can therefore reference other functions parameters in
+ // the abbreviated function template, which is why we must instantiate them
+ // here, when the instantiated versions of those referenced parameters are in
+ // scope.
+ if (TemplateTypeParmDecl *TTP =
+ GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) {
+ if (const TypeConstraint *TC = TTP->getTypeConstraint()) {
+ auto *Inst = cast_or_null<TemplateTypeParmDecl>(
+ FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs));
+ // We will first get here when instantiating the abbreviated function
+ // 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)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ TTP->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
+ return nullptr;
+ }
+ }
+ }
+
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
OldParm->getInnerLocStart(),
OldParm->getLocation(),
@@ -1923,7 +2426,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
} else if (Expr *Arg = OldParm->getDefaultArg()) {
FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
- if (OwningFunc->isLexicallyWithinFunctionOrMethod()) {
+ if (OwningFunc->isInLocalScopeForInstantiation()) {
// Instantiate default arguments for methods of local classes (DR1484)
// and non-defining declarations.
Sema::ContextRAII SavedContext(*this, OwningFunc);
@@ -1932,7 +2435,12 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
if (NewArg.isUsable()) {
// It would be nice if we still had this.
SourceLocation EqualLoc = NewArg.get()->getBeginLoc();
- SetParamDefaultArgument(NewParm, NewArg.get(), EqualLoc);
+ 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
@@ -3101,6 +3609,12 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
if (isa<EnumDecl>(D))
return nullptr;
+ // Materialized typedefs/type alias for implicit deduction guides may require
+ // instantiation.
+ if (isa<TypedefNameDecl>(D) &&
+ isa<CXXDeductionGuideDecl>(D->getDeclContext()))
+ return nullptr;
+
// If we didn't find the decl, then we either have a sema bug, or we have a
// forward reference to a label declaration. Return null to indicate that
// we have an uninstantiated label.
@@ -3152,6 +3666,13 @@ void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
ArgumentPacks.push_back(Pack);
}
+bool LocalInstantiationScope::isLocalPackExpansion(const Decl *D) {
+ for (DeclArgumentPack *Pack : ArgumentPacks)
+ if (std::find(Pack->begin(), Pack->end(), D) != Pack->end())
+ return true;
+ return false;
+}
+
void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack,
const TemplateArgument *ExplicitArgs,
unsigned NumExplicitArgs) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 64500d0a26d5..2efb7acb9724 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -8,7 +8,7 @@
// This file implements C++ template instantiation for declarations.
//
//===----------------------------------------------------------------------===/
-#include "clang/Sema/SemaInternal.h"
+
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -19,8 +19,11 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
@@ -393,50 +396,39 @@ static void instantiateOMPDeclareVariantAttr(
VariantFuncRef = Subst(E);
}
+ // Copy the template version of the OMPTraitInfo and run substitute on all
+ // score and condition expressiosn.
+ OMPTraitInfo &TI = S.getASTContext().getNewOMPTraitInfo();
+ TI = *Attr.getTraitInfos();
+
+ // Try to substitute template parameters in score and condition expressions.
+ auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) {
+ if (E) {
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult ER = Subst(E);
+ if (ER.isUsable())
+ E = ER.get();
+ else
+ return true;
+ }
+ return false;
+ };
+ if (TI.anyScoreOrCondition(SubstScoreOrConditionExpr))
+ return;
+
// Check function/variant ref.
Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
- S.checkOpenMPDeclareVariantFunction(
- S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
+ S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New),
+ VariantFuncRef.get(), TI,
+ Attr.getRange());
+
if (!DeclVarData)
return;
- SmallVector<Sema::OMPCtxSelectorData, 4> Data;
- for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) {
- ExprResult Score;
- if (Expr *E = *std::next(Attr.scores_begin(), I))
- Score = Subst(E);
- // Instantiate the attribute.
- auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
- *std::next(Attr.ctxSelectorSets_begin(), I));
- auto Ctx = static_cast<OpenMPContextSelectorKind>(
- *std::next(Attr.ctxSelectors_begin(), I));
- switch (CtxSet) {
- case OMP_CTX_SET_implementation:
- switch (Ctx) {
- case OMP_CTX_vendor:
- Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors());
- break;
- case OMP_CTX_kind:
- case OMP_CTX_unknown:
- llvm_unreachable("Unexpected context selector kind.");
- }
- break;
- case OMP_CTX_SET_device:
- switch (Ctx) {
- case OMP_CTX_kind:
- Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds());
- break;
- case OMP_CTX_vendor:
- case OMP_CTX_unknown:
- llvm_unreachable("Unexpected context selector kind.");
- }
- break;
- case OMP_CTX_SET_unknown:
- llvm_unreachable("Unexpected context selector set kind.");
- }
- }
+
S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
- DeclVarData.getValue().second,
- Attr.getRange(), Data);
+ DeclVarData.getValue().second, TI,
+ Attr.getRange());
}
static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
@@ -706,6 +698,10 @@ TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) {
llvm_unreachable("extern \"C\" context cannot be instantiated");
}
+Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) {
+ llvm_unreachable("GUID declaration cannot be instantiated");
+}
+
Decl *
TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(),
@@ -1837,6 +1833,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
+ if (TemplateParams && TemplateParams->size()) {
+ auto *LastParam =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+ if (LastParam && LastParam->isImplicit() &&
+ LastParam->hasTypeConstraint()) {
+ // In abbreviated templates, the type-constraints of invented template
+ // type parameters are instantiated with the function type, invalidating
+ // the TemplateParameterList which relied on the template type parameter
+ // not having a type constraint. Recreate the TemplateParameterList with
+ // the updated parameter list.
+ TemplateParams = TemplateParameterList::Create(
+ SemaRef.Context, TemplateParams->getTemplateLoc(),
+ TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+ TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+ }
+ }
+
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -1848,6 +1861,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// 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())
@@ -1896,6 +1911,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->hasWrittenPrototype(), D->getConstexprKind(),
TrailingRequiresClause);
Function->setRangeEnd(D->getSourceRange().getEnd());
+ Function->setUsesFPIntrin(D->usesFPIntrin());
}
if (D->isInlined())
@@ -2029,7 +2045,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
- SemaRef.LookupQualifiedName(Previous, DC);
+ SemaRef.LookupQualifiedName(Previous, DC->getRedeclContext());
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
@@ -2175,6 +2191,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
+ if (TemplateParams && TemplateParams->size()) {
+ auto *LastParam =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+ if (LastParam && LastParam->isImplicit() &&
+ LastParam->hasTypeConstraint()) {
+ // In abbreviated templates, the type-constraints of invented template
+ // type parameters are instantiated with the function type, invalidating
+ // the TemplateParameterList which relied on the template type parameter
+ // not having a type constraint. Recreate the TemplateParameterList with
+ // the updated parameter list.
+ TemplateParams = TemplateParameterList::Create(
+ SemaRef.Context, TemplateParams->getTemplateLoc(),
+ TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+ TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+ }
+ }
+
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -2186,6 +2219,11 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
// 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())
@@ -2518,28 +2556,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- const ASTTemplateArgumentListInfo *TemplArgInfo
- = TC->getTemplateArgsAsWritten();
- TemplateArgumentListInfo InstArgs;
-
- if (TemplArgInfo) {
- InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
- InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
- if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
- TemplArgInfo->NumTemplateArgs,
- InstArgs, TemplateArgs))
+ 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)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ D->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
return nullptr;
}
- if (SemaRef.AttachTypeConstraint(
- TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &InstArgs, Inst,
- D->isParameterPack()
- ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
- ->getEllipsisLoc()
- : SourceLocation()))
- return nullptr;
}
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
@@ -2685,6 +2729,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
+ if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
+ if (AutoLoc.isConstrained())
+ if (SemaRef.AttachTypeConstraint(
+ AutoLoc, Param,
+ IsExpandedParameterPack
+ ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>()
+ .getEllipsisLoc()
+ : SourceLocation()))
+ Invalid = true;
+
Param->setAccess(AS_public);
Param->setImplicit(D->isImplicit());
if (Invalid)
@@ -3571,6 +3625,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (InsertPos)
VarTemplate->AddSpecialization(Var, InsertPos);
+ if (SemaRef.getLangOpts().OpenCL)
+ SemaRef.deduceOpenCLAddressSpace(Var);
+
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
return nullptr;
@@ -3600,6 +3657,12 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
+Decl *
+TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
+ return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
+ D->getBeginLoc());
+}
+
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
llvm_unreachable("Unexpected decl");
}
@@ -3659,6 +3722,8 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
// access and function-definition and in the same class scope as the
// three-way comparison operator function
MultiLevelTemplateArgumentList NoTemplateArgs;
+ NoTemplateArgs.setKind(TemplateSubstitutionKind::Rewrite);
+ NoTemplateArgs.addOuterRetainedLevels(RD->getTemplateDepth());
TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs);
Decl *R;
if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
@@ -3713,6 +3778,8 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
// 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;
@@ -4163,6 +4230,94 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
return false;
}
+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.
+ //
+ // FIXME: Pass in a correct Pattern argument, otherwise
+ // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
+ //
+ // template<typename T>
+ // struct A {
+ // static int FooImpl();
+ //
+ // template<typename Tp>
+ // // bug: default argument A<T>::FooImpl() is evaluated with 2-level
+ // // template argument list [[T], [Tp]], should be [[Tp]].
+ // friend A<Tp> Foo(int a);
+ // };
+ //
+ // template<typename T>
+ // A<T> Foo(int a = A<T>::FooImpl());
+ MultiLevelTemplateArgumentList TemplateArgs
+ = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
+
+ InstantiatingTemplate Inst(*this, CallLoc, 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);
+ LocalInstantiationScope Local(*this);
+
+ FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
+ /*ForDefinition*/ false);
+ if (addInstantiatedParametersToScope(*this, 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);
+
+ return false;
+}
+
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Decl) {
const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();
@@ -4193,6 +4348,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+ // FIXME: We can't use getTemplateInstantiationPattern(false) in general
+ // here, because for a non-defining friend declaration in a class template,
+ // we don't store enough information to map back to the friend declaration in
+ // the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
TemplateArgs)) {
@@ -4224,24 +4383,29 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- MultiLevelTemplateArgumentList MLTAL =
- getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
-
// 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(),
- MLTAL.getInnermost(), SourceRange());
+ TemplateArgs, SourceRange());
if (Inst.isInvalid())
return true;
- if (addInstantiatedParametersToScope(*this, Decl,
- Decl->getTemplateInstantiationPattern(),
- Scope, MLTAL))
+ MultiLevelTemplateArgumentList MLTAL(
+ *Decl->getTemplateSpecializationArgs());
+ if (addInstantiatedParametersToScope(
+ *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(),
+ Scope, MLTAL))
return true;
}
-
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = Method->getParent();
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
PointOfInstantiation, Satisfaction);
}
@@ -4297,7 +4461,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpec.Type != EST_None &&
EPI.ExceptionSpec.Type != EST_DynamicNone &&
EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
- !Tmpl->isLexicallyWithinFunctionOrMethod()) {
+ !Tmpl->isInLocalScopeForInstantiation()) {
FunctionDecl *ExceptionSpecTemplate = Tmpl;
if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
@@ -4734,6 +4898,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
// Instantiate the initializer.
InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
+ if (getLangOpts().OpenCL)
+ deduceOpenCLAddressSpace(VarSpec);
+
return VarSpec;
}
@@ -4774,6 +4941,7 @@ void Sema::BuildVariableInstantiation(
NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl());
NewVar->setObjCForDecl(OldVar->isObjCForDecl());
NewVar->setConstexpr(OldVar->isConstexpr());
+ MaybeAddCUDAConstantAttr(NewVar);
NewVar->setInitCapture(OldVar->isInitCapture());
NewVar->setPreviousDeclInSameBlockScope(
OldVar->isPreviousDeclInSameBlockScope());
@@ -5537,6 +5705,20 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
} else return DC;
}
+/// Determine whether the given context is dependent on template parameters at
+/// level \p Level or below.
+///
+/// Sometimes we only substitute an inner set of template arguments and leave
+/// the outer templates alone. In such cases, contexts dependent only on the
+/// outer levels are not effectively dependent.
+static bool isDependentContextAtLevel(DeclContext *DC, unsigned Level) {
+ if (!DC->isDependentContext())
+ return false;
+ if (!Level)
+ return true;
+ return cast<Decl>(DC)->getTemplateDepth() > Level;
+}
+
/// Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -5567,6 +5749,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool FindingInstantiatedContext) {
DeclContext *ParentDC = D->getDeclContext();
+ // Determine whether our parent context depends on any of the tempalte
+ // arguments we're currently substituting.
+ bool ParentDependsOnArgs = isDependentContextAtLevel(
+ ParentDC, TemplateArgs.getNumRetainedOuterLevels());
// FIXME: Parmeters of pointer to functions (y below) that are themselves
// parameters (p below) can have their ParentDC set to the translation-unit
// - thus we can not consistently check if the ParentDC of such a parameter
@@ -5583,15 +5769,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// - as long as we have a ParmVarDecl whose parent is non-dependent and
// whose type is not instantiation dependent, do nothing to the decl
// - otherwise find its instantiated decl.
- if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
+ if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
!cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
return D;
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
- ((ParentDC->isFunctionOrMethod() ||
- isa<OMPDeclareReductionDecl>(ParentDC) ||
- isa<OMPDeclareMapperDecl>(ParentDC)) &&
- ParentDC->isDependentContext()) ||
+ (ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
+ isa<OMPDeclareReductionDecl>(ParentDC) ||
+ isa<OMPDeclareMapperDecl>(ParentDC))) ||
(isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
@@ -5634,6 +5819,9 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
bool NeedInstantiate = false;
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
NeedInstantiate = RD->isLocalClass();
+ else if (isa<TypedefNameDecl>(D) &&
+ isa<CXXDeductionGuideDecl>(D->getDeclContext()))
+ NeedInstantiate = true;
else
NeedInstantiate = isa<EnumDecl>(D);
if (NeedInstantiate) {
@@ -5742,7 +5930,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// anonymous unions in class templates).
}
- if (!ParentDC->isDependentContext())
+ if (!ParentDependsOnArgs)
return D;
ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);
@@ -5811,10 +5999,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
if (!Result) {
if (isa<UsingShadowDecl>(D)) {
// UsingShadowDecls can instantiate to nothing because of using hiding.
- } else if (Diags.hasErrorOccurred()) {
- // We've already complained about something, so most likely this
- // declaration failed to instantiate. There's no point in complaining
- // further, since this is normal in invalid code.
+ } else if (Diags.hasUncompilableErrorOccurred()) {
+ // We've already complained about some ill-formed code, so most likely
+ // this declaration failed to instantiate. There's no point in
+ // complaining further, since this is normal in invalid code.
+ // FIXME: Use more fine-grained 'invalid' tracking for this.
} else if (IsBeingInstantiated) {
// The class in which this member exists is currently being
// instantiated, and we haven't gotten around to instantiating this
@@ -5854,6 +6043,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingInstantiations(bool LocalOnly) {
+ std::deque<PendingImplicitInstantiation> delayedPCHInstantiations;
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -5884,6 +6074,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
if (Function->isDefined())
Function->setInstantiationIsPending(false);
}
+ // Definition of a PCH-ed template declaration may be available only in the TU.
+ if (!LocalOnly && LangOpts.PCHInstantiateTemplates &&
+ TUKind == TU_Prefix && Function->instantiationIsPending())
+ delayedPCHInstantiations.push_back(Inst);
continue;
}
@@ -5929,6 +6123,9 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
DefinitionRequired, true);
}
+
+ if (!LocalOnly && LangOpts.PCHInstantiateTemplates)
+ PendingInstantiations.swap(delayedPCHInstantiations);
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index d947d6d282be..7b77d1cb482a 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -847,6 +847,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_typeofExpr:
case TST_decltype:
+ case TST_extint:
if (DS.getRepAsExpr() &&
DS.getRepAsExpr()->containsUnexpandedParameterPack())
return true;
@@ -880,6 +881,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_auto:
case TST_auto_type:
case TST_decltype_auto:
+ case TST_BFloat16:
#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
case TST_unknown_anytype:
@@ -940,7 +942,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
if (Expr *TRC = D.getTrailingRequiresClause())
if (TRC->containsUnexpandedParameterPack())
return true;
-
+
return false;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3884fdae8fe7..b8f7f1a58159 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -27,6 +27,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
@@ -34,6 +35,7 @@
#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"
using namespace clang;
@@ -128,6 +130,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_NSReturnsRetained: \
case ParsedAttr::AT_NoReturn: \
case ParsedAttr::AT_Regparm: \
+ case ParsedAttr::AT_CmseNSCall: \
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \
case ParsedAttr::AT_AnyX86NoCfCheck: \
CALLING_CONV_ATTRS_CASELIST
@@ -1251,6 +1254,26 @@ getImageAccess(const ParsedAttributesView &Attrs) {
return OpenCLAccessAttr::Keyword_read_only;
}
+static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS,
+ AutoTypeKeyword AutoKW) {
+ assert(DS.isConstrainedAuto());
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
+ for (auto &ArgLoc : TemplateArgsInfo.arguments())
+ TemplateArgs.push_back(ArgLoc.getArgument());
+ return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false,
+ /*IsPack=*/false,
+ cast<ConceptDecl>(TemplateId->Template.get()
+ .getAsTemplateDecl()),
+ TemplateArgs);
+}
+
/// Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1419,6 +1442,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
+ case DeclSpec::TST_extint: {
+ if (!S.Context.getTargetInfo().hasExtIntType())
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
+ << "_ExtInt";
+ Result = S.BuildExtIntType(DS.getTypeSpecSign() == TSS_unsigned,
+ DS.getRepAsExpr(), DS.getBeginLoc());
+ if (Result.isNull()) {
+ Result = Context.IntTy;
+ declarator.setInvalidType(true);
+ }
+ break;
+ }
case DeclSpec::TST_accum: {
switch (DS.getTypeSpecWidth()) {
case DeclSpec::TSW_short:
@@ -1486,6 +1521,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.Float16Ty;
break;
case DeclSpec::TST_half: Result = Context.HalfTy; break;
+ case DeclSpec::TST_BFloat16:
+ if (!S.Context.getTargetInfo().hasBFloat16Type())
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
+ << "__bf16";
+ Result = Context.BFloat16Ty;
+ break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
@@ -1495,6 +1536,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_float128:
if (!S.Context.getTargetInfo().hasFloat128Type() &&
+ !S.getLangOpts().SYCLIsDevice &&
!(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
<< "__float128";
@@ -1595,6 +1637,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_auto:
+ if (DS.isConstrainedAuto()) {
+ Result = ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::Auto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
break;
@@ -1603,6 +1650,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_decltype_auto:
+ if (DS.isConstrainedAuto()) {
+ Result =
+ ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::DecltypeAuto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,
/*IsDependent*/ false);
break;
@@ -1645,6 +1698,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
+ // FIXME: we want resulting declarations to be marked invalid, but claiming
+ // the type is invalid is too strong - e.g. it causes ActOnTypeName to return
+ // a null type.
+ if (Result->containsErrors())
+ declarator.setInvalidType();
+
if (S.getLangOpts().OpenCL &&
S.checkOpenCLDisabledTypeDeclSpec(DS, Result))
declarator.setInvalidType(true);
@@ -1700,7 +1759,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// The effect of a cv-qualifier-seq in a function declarator is not the
// same as adding cv-qualification on top of the function type. In the
// latter case, the cv-qualifiers are ignored.
- if (TypeQuals && Result->isFunctionType()) {
+ if (Result->isFunctionType()) {
diagnoseAndRemoveTypeQualifiers(
S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile,
S.getLangOpts().CPlusPlus
@@ -2121,6 +2180,45 @@ QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) {
return Context.getWritePipeType(T);
}
+/// Build a extended int type.
+///
+/// \param IsUnsigned Boolean representing the signedness of the type.
+///
+/// \param BitWidth Size of this int type in bits, or an expression representing
+/// that.
+///
+/// \param Loc Location of the keyword.
+QualType Sema::BuildExtIntType(bool IsUnsigned, Expr *BitWidth,
+ SourceLocation Loc) {
+ if (BitWidth->isInstantiationDependent())
+ return Context.getDependentExtIntType(IsUnsigned, BitWidth);
+
+ llvm::APSInt Bits(32);
+ ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Bits);
+
+ if (ICE.isInvalid())
+ return QualType();
+
+ int64_t NumBits = Bits.getSExtValue();
+ if (!IsUnsigned && NumBits < 2) {
+ Diag(Loc, diag::err_ext_int_bad_size) << 0;
+ return QualType();
+ }
+
+ if (IsUnsigned && NumBits < 1) {
+ Diag(Loc, diag::err_ext_int_bad_size) << 1;
+ return QualType();
+ }
+
+ if (NumBits > llvm::IntegerType::MAX_INT_BITS) {
+ Diag(Loc, diag::err_ext_int_max_size) << IsUnsigned
+ << llvm::IntegerType::MAX_INT_BITS;
+ return QualType();
+ }
+
+ return Context.getExtIntType(IsUnsigned, NumBits);
+}
+
/// Check whether the specified array size makes the array type a VLA. If so,
/// return true, if not, return the size of the array in SizeVal.
static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
@@ -2182,7 +2280,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
if (T->isVoidType() || T->isIncompleteArrayType()) {
- Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T;
+ Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 0 << T;
return QualType();
}
@@ -2200,11 +2298,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
} else {
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
- if (RequireCompleteType(Loc, T,
- diag::err_illegal_decl_array_incomplete_type))
+ if (RequireCompleteSizedType(Loc, T,
+ diag::err_array_incomplete_or_sizeless_type))
return QualType();
}
+ if (T->isSizelessType()) {
+ Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
+ return QualType();
+ }
+
if (T->isFunctionType()) {
Diag(Loc, diag::err_illegal_decl_array_of_functions)
<< getPrintableNameForEntity(Entity) << T;
@@ -2290,13 +2393,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
? diag::err_typecheck_zero_array_size
: diag::ext_typecheck_zero_array_size)
<< ArraySize->getSourceRange();
-
- if (ASM == ArrayType::Static) {
- Diag(ArraySize->getBeginLoc(),
- diag::warn_typecheck_zero_static_array_size)
- << ArraySize->getSourceRange();
- ASM = ArrayType::Normal;
- }
} else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
!T->isIncompleteType() && !T->isUndeducedType()) {
// Is the array too large?
@@ -2392,28 +2488,35 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr,
return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc,
VectorType::GenericVector);
- unsigned VectorSize = static_cast<unsigned>(VecSize.getZExtValue() * 8);
+ // vecSize is specified in bytes - convert to bits.
+ if (!VecSize.isIntN(61)) {
+ // Bit size will overflow uint64.
+ Diag(AttrLoc, diag::err_attribute_size_too_large)
+ << SizeExpr->getSourceRange() << "vector";
+ return QualType();
+ }
+ uint64_t VectorSizeBits = VecSize.getZExtValue() * 8;
unsigned TypeSize = static_cast<unsigned>(Context.getTypeSize(CurType));
- if (VectorSize == 0) {
- Diag(AttrLoc, diag::err_attribute_zero_size) << SizeExpr->getSourceRange();
+ if (VectorSizeBits == 0) {
+ Diag(AttrLoc, diag::err_attribute_zero_size)
+ << SizeExpr->getSourceRange() << "vector";
return QualType();
}
- // vecSize is specified in bytes - convert to bits.
- if (VectorSize % TypeSize) {
+ if (VectorSizeBits % TypeSize) {
Diag(AttrLoc, diag::err_attribute_invalid_size)
<< SizeExpr->getSourceRange();
return QualType();
}
- if (VectorType::isVectorSizeTooLarge(VectorSize / TypeSize)) {
+ if (VectorSizeBits / TypeSize > std::numeric_limits<uint32_t>::max()) {
Diag(AttrLoc, diag::err_attribute_size_too_large)
- << SizeExpr->getSourceRange();
+ << SizeExpr->getSourceRange() << "vector";
return QualType();
}
- return Context.getVectorType(CurType, VectorSize / TypeSize,
+ return Context.getVectorType(CurType, VectorSizeBits / TypeSize,
VectorType::GenericVector);
}
@@ -2445,19 +2548,18 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
+ if (!vecSize.isIntN(32)) {
+ Diag(AttrLoc, diag::err_attribute_size_too_large)
+ << ArraySize->getSourceRange() << "vector";
+ return QualType();
+ }
// Unlike gcc's vector_size attribute, the size is specified as the
// number of elements, not the number of bytes.
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
if (vectorSize == 0) {
Diag(AttrLoc, diag::err_attribute_zero_size)
- << ArraySize->getSourceRange();
- return QualType();
- }
-
- if (VectorType::isVectorSizeTooLarge(vectorSize)) {
- Diag(AttrLoc, diag::err_attribute_size_too_large)
- << ArraySize->getSourceRange();
+ << ArraySize->getSourceRange() << "vector";
return QualType();
}
@@ -2467,6 +2569,84 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
}
+QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols,
+ SourceLocation AttrLoc) {
+ assert(Context.getLangOpts().MatrixTypes &&
+ "Should never build a matrix type when it is disabled");
+
+ // Check element type, if it is not dependent.
+ if (!ElementTy->isDependentType() &&
+ !MatrixType::isValidElementType(ElementTy)) {
+ Diag(AttrLoc, diag::err_attribute_invalid_matrix_type) << ElementTy;
+ return QualType();
+ }
+
+ if (NumRows->isTypeDependent() || NumCols->isTypeDependent() ||
+ NumRows->isValueDependent() || NumCols->isValueDependent())
+ return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols,
+ AttrLoc);
+
+ // Both row and column values can only be 20 bit wide currently.
+ llvm::APSInt ValueRows(32), ValueColumns(32);
+
+ bool const RowsIsInteger = NumRows->isIntegerConstantExpr(ValueRows, Context);
+ bool const ColumnsIsInteger =
+ NumCols->isIntegerConstantExpr(ValueColumns, Context);
+
+ auto const RowRange = NumRows->getSourceRange();
+ auto const ColRange = NumCols->getSourceRange();
+
+ // Both are row and column expressions are invalid.
+ if (!RowsIsInteger && !ColumnsIsInteger) {
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "matrix_type" << AANT_ArgumentIntegerConstant << RowRange
+ << ColRange;
+ return QualType();
+ }
+
+ // Only the row expression is invalid.
+ if (!RowsIsInteger) {
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "matrix_type" << AANT_ArgumentIntegerConstant << RowRange;
+ return QualType();
+ }
+
+ // Only the column expression is invalid.
+ if (!ColumnsIsInteger) {
+ Diag(AttrLoc, diag::err_attribute_argument_type)
+ << "matrix_type" << AANT_ArgumentIntegerConstant << ColRange;
+ return QualType();
+ }
+
+ // Check the matrix dimensions.
+ unsigned MatrixRows = static_cast<unsigned>(ValueRows.getZExtValue());
+ unsigned MatrixColumns = static_cast<unsigned>(ValueColumns.getZExtValue());
+ if (MatrixRows == 0 && MatrixColumns == 0) {
+ Diag(AttrLoc, diag::err_attribute_zero_size)
+ << "matrix" << RowRange << ColRange;
+ return QualType();
+ }
+ if (MatrixRows == 0) {
+ Diag(AttrLoc, diag::err_attribute_zero_size) << "matrix" << RowRange;
+ return QualType();
+ }
+ if (MatrixColumns == 0) {
+ Diag(AttrLoc, diag::err_attribute_zero_size) << "matrix" << ColRange;
+ return QualType();
+ }
+ if (!ConstantMatrixType::isDimensionValid(MatrixRows)) {
+ Diag(AttrLoc, diag::err_attribute_size_too_large)
+ << RowRange << "matrix row";
+ return QualType();
+ }
+ if (!ConstantMatrixType::isDimensionValid(MatrixColumns)) {
+ Diag(AttrLoc, diag::err_attribute_size_too_large)
+ << ColRange << "matrix column";
+ return QualType();
+ }
+ return Context.getConstantMatrixType(ElementTy, MatrixRows, MatrixColumns);
+}
+
bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
@@ -2496,7 +2676,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
// C++2a [dcl.fct]p12:
// A volatile-qualified return type is deprecated
- if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ if (T.isVolatileQualified() && getLangOpts().CPlusPlus20)
Diag(Loc, diag::warn_deprecated_volatile_return) << T;
return false;
@@ -2581,7 +2761,7 @@ QualType Sema::BuildFunctionType(QualType T,
// C++2a [dcl.fct]p4:
// A parameter with volatile-qualified type is deprecated
- if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus20)
Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType;
ParamTypes[Idx] = ParamType;
@@ -2921,6 +3101,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
D.getDeclSpec().getUnalignedSpecLoc());
}
+static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto,
+ AutoTypeLoc AutoLoc,
+ TemplateTypeParmDecl *TP,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc());
+ for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx)
+ TAL.addArgument(AutoLoc.getArgLoc(Idx));
+
+ SemaRef.AttachTypeConstraint(
+ AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
+ AutoLoc.getNamedConcept(),
+ AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc);
+}
+
+static QualType InventTemplateParameter(
+ TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto,
+ InventedTemplateParameterInfo &Info) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = Info.TemplateParams.size();
+ const bool IsParameterPack = D.hasEllipsis();
+
+ // If auto is mentioned in a lambda parameter or abbreviated function
+ // template context, convert it to a template parameter type.
+
+ // Create the TemplateTypeParmDecl here to retrieve the corresponding
+ // template parameter type. Template parameters are temporarily added
+ // to the TU until the associated TemplateDecl is created.
+ TemplateTypeParmDecl *InventedTemplateParam =
+ TemplateTypeParmDecl::Create(
+ S.Context, S.Context.getTranslationUnitDecl(),
+ /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(),
+ /*NameLoc=*/D.getIdentifierLoc(),
+ TemplateParameterDepth, AutoParameterPosition,
+ S.InventAbbreviatedTemplateParameterTypeName(
+ D.getIdentifier(), AutoParameterPosition), false,
+ IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained());
+ InventedTemplateParam->setImplicit();
+ Info.TemplateParams.push_back(InventedTemplateParam);
+ // Attach type constraints
+ if (Auto->isConstrained()) {
+ if (TSI) {
+ CopyTypeConstraintFromAutoType(
+ S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(),
+ InventedTemplateParam, D.getEllipsisLoc());
+ } else {
+ TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ if (TemplateId->LAngleLoc.isValid()) {
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ }
+ S.AttachTypeConstraint(
+ D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
+ DeclarationNameInfo(DeclarationName(TemplateId->Name),
+ TemplateId->TemplateNameLoc),
+ cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()),
+ TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
+ InventedTemplateParam, D.getEllipsisLoc());
+ }
+ }
+
+ // If TSI is nullptr, this is a constrained declspec auto and the type
+ // constraint will be attached later in TypeSpecLocFiller
+
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ // FIXME: Retain some type sugar to indicate that this was written
+ // as 'auto'?
+ return state.ReplaceAutoType(
+ T, QualType(InventedTemplateParam->getTypeForDecl(), 0));
+}
+
+static TypeSourceInfo *
+GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
+ QualType T, TypeSourceInfo *ReturnTypeInfo);
+
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
TypeSourceInfo *&ReturnTypeInfo) {
Sema &SemaRef = state.getSema();
@@ -2991,54 +3252,58 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
case DeclaratorContext::ObjCParameterContext:
case DeclaratorContext::ObjCResultContext:
- case DeclaratorContext::PrototypeContext:
Error = 0;
break;
- case DeclaratorContext::LambdaExprParameterContext:
- // In C++14, generic lambdas allow 'auto' in their parameters.
- if (!SemaRef.getLangOpts().CPlusPlus14 ||
- !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
- Error = 16;
- else {
- // If auto is mentioned in a lambda parameter context, convert it to a
- // template parameter type.
- sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
- assert(LSI && "No LambdaScopeInfo on the stack!");
- const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->TemplateParams.size();
- const bool IsParameterPack = D.hasEllipsis();
-
- // Create the TemplateTypeParmDecl here to retrieve the corresponding
- // template parameter type. Template parameters are temporarily added
- // to the TU until the associated TemplateDecl is created.
- TemplateTypeParmDecl *CorrespondingTemplateParam =
- TemplateTypeParmDecl::Create(
- SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
- /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
- TemplateParameterDepth, AutoParameterPosition,
- /*Identifier*/ nullptr, false, IsParameterPack,
- /*HasTypeConstraint=*/false);
- CorrespondingTemplateParam->setImplicit();
- LSI->TemplateParams.push_back(CorrespondingTemplateParam);
- // Replace the 'auto' in the function parameter with this invented
- // template type parameter.
- // FIXME: Retain some type sugar to indicate that this was written
- // as 'auto'.
- T = state.ReplaceAutoType(
- T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
+ case DeclaratorContext::RequiresExprContext:
+ Error = 22;
+ break;
+ case DeclaratorContext::PrototypeContext:
+ case DeclaratorContext::LambdaExprParameterContext: {
+ InventedTemplateParameterInfo *Info = nullptr;
+ if (D.getContext() == DeclaratorContext::PrototypeContext) {
+ // With concepts we allow 'auto' in function parameters.
+ if (!SemaRef.getLangOpts().CPlusPlus20 || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 0;
+ break;
+ } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) {
+ Error = 21;
+ break;
+ } else if (D.hasTrailingReturnType()) {
+ // This might be OK, but we'll need to convert the trailing return
+ // type later.
+ break;
+ }
+
+ Info = &SemaRef.InventedParameterInfos.back();
+ } else {
+ // In C++14, generic lambdas allow 'auto' in their parameters.
+ if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 16;
+ break;
+ }
+ Info = SemaRef.getCurLambda();
+ assert(Info && "No LambdaScopeInfo on the stack!");
}
+ T = InventTemplateParameter(state, T, nullptr, Auto, *Info);
break;
+ }
case DeclaratorContext::MemberContext: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
D.isFunctionDeclarator())
break;
bool Cxx = SemaRef.getLangOpts().CPlusPlus;
- switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
- case TTK_Enum: llvm_unreachable("unhandled tag kind");
- case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break;
- case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break;
- case TTK_Class: Error = 5; /* Class member */ break;
- case TTK_Interface: Error = 6; /* Interface member */ break;
+ if (isa<ObjCContainerDecl>(SemaRef.CurContext)) {
+ Error = 6; // Interface member.
+ } else {
+ switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) {
+ case TTK_Enum: llvm_unreachable("unhandled tag kind");
+ case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break;
+ case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break;
+ case TTK_Class: Error = 5; /* Class member */ break;
+ case TTK_Interface: Error = 6; /* Interface member */ break;
+ }
}
if (D.getDeclSpec().isFriendSpecified())
Error = 20; // Friend type
@@ -3221,6 +3486,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::ObjCParameterContext:
case DeclaratorContext::ObjCResultContext:
case DeclaratorContext::KNRTypeListContext:
+ case DeclaratorContext::RequiresExprContext:
// C++ [dcl.fct]p6:
// Types shall not be defined in return or parameter types.
DiagID = diag::err_type_defined_in_param_type;
@@ -4028,10 +4294,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
return false;
}
-static TypeSourceInfo *
-GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
- QualType T, TypeSourceInfo *ReturnTypeInfo);
-
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -4279,6 +4541,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TemplateTypeArgContext:
case DeclaratorContext::TypeNameContext:
case DeclaratorContext::FunctionalCastContext:
+ case DeclaratorContext::RequiresExprContext:
// Don't infer in these contexts.
break;
}
@@ -4606,7 +4869,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (D.getContext() != DeclaratorContext::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
cast<AutoType>(T)->getKeyword() !=
- AutoTypeKeyword::Auto)) {
+ AutoTypeKeyword::Auto ||
+ cast<AutoType>(T)->isConstrained())) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -4617,7 +4881,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// An error occurred parsing the trailing return type.
T = Context.IntTy;
D.setInvalidType(true);
- }
+ } else if (S.getLangOpts().CPlusPlus20)
+ // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`.
+ if (AutoType *Auto = T->getContainedAutoType())
+ if (S.getCurScope()->isFunctionDeclarationScope())
+ T = InventTemplateParameter(state, T, TInfo, Auto,
+ S.InventedParameterInfos.back());
} else {
// This function type is not the type of the entity being declared,
// so checking the 'auto' is not the responsibility of this chunk.
@@ -4721,7 +4990,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++2a [dcl.fct]p12:
// A volatile-qualified return type is deprecated
- if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a)
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus20)
S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T;
}
@@ -4863,8 +5132,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// FIXME: This really should be in BuildFunctionType.
if (S.getLangOpts().OpenCL) {
if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
- S.Diag(Param->getLocation(),
- diag::err_opencl_half_param) << ParamTy;
+ S.Diag(Param->getLocation(), diag::err_opencl_invalid_param)
+ << ParamTy << 0;
D.setInvalidType();
Param->setInvalidDecl();
}
@@ -4883,6 +5152,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Param->setKNRPromoted(true);
}
}
+ } else if (S.getLangOpts().OpenCL && ParamTy->isBlockPointerType()) {
+ // OpenCL 2.0 s6.12.5: A block cannot be a parameter of a function.
+ S.Diag(Param->getLocation(), diag::err_opencl_invalid_param)
+ << ParamTy << 1 /*hint off*/;
+ D.setInvalidType();
}
if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) {
@@ -5212,7 +5486,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++2a [dcl.fct]p4:
// A parameter with volatile-qualified type is deprecated
- if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a &&
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus20 &&
(D.getContext() == DeclaratorContext::PrototypeContext ||
D.getContext() == DeclaratorContext::LambdaExprParameterContext))
S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T;
@@ -5227,6 +5501,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
switch (D.getContext()) {
case DeclaratorContext::PrototypeContext:
case DeclaratorContext::LambdaExprParameterContext:
+ case DeclaratorContext::RequiresExprContext:
// C++0x [dcl.fct]p13:
// [...] When it is part of a parameter-declaration-clause, the
// parameter pack is a function parameter pack (14.5.3). The type T
@@ -5236,7 +5511,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
//
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
- if (!T->containsUnexpandedParameterPack()) {
+ if (!T->containsUnexpandedParameterPack() &&
+ (!LangOpts.CPlusPlus20 || !T->getContainedAutoType())) {
S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
@@ -5444,14 +5720,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
+ Sema &SemaRef;
ASTContext &Context;
TypeProcessingState &State;
const DeclSpec &DS;
public:
- TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
+ TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State,
const DeclSpec &DS)
- : Context(Context), State(State), DS(DS) {}
+ : SemaRef(S), Context(Context), State(State), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Visit(TL.getModifiedLoc());
@@ -5579,6 +5856,34 @@ namespace {
TL.copy(
TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
}
+ void VisitAutoTypeLoc(AutoTypeLoc TL) {
+ assert(DS.getTypeSpecType() == TST_auto ||
+ DS.getTypeSpecType() == TST_decltype_auto ||
+ DS.getTypeSpecType() == TST_auto_type ||
+ DS.getTypeSpecType() == TST_unspecified);
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ if (!DS.isConstrainedAuto())
+ return;
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ if (DS.getTypeSpecScope().isNotEmpty())
+ TL.setNestedNameSpecifierLoc(
+ DS.getTypeSpecScope().getWithLocInContext(Context));
+ else
+ TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ TL.setTemplateKWLoc(TemplateId->TemplateKWLoc);
+ TL.setConceptNameLoc(TemplateId->TemplateNameLoc);
+ TL.setFoundDecl(nullptr);
+ TL.setLAngleLoc(TemplateId->LAngleLoc);
+ TL.setRAngleLoc(TemplateId->RAngleLoc);
+ if (TemplateId->NumArgs == 0)
+ return;
+ TemplateArgumentListInfo TemplateArgsInfo;
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ for (unsigned I = 0; I < TemplateId->NumArgs; ++I)
+ TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo());
+ }
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
@@ -5609,6 +5914,14 @@ namespace {
TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
}
+ void VisitExtIntTypeLoc(ExtIntTypeLoc TL) {
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+
+ void VisitDependentExtIntTypeLoc(DependentExtIntTypeLoc TL) {
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ }
+
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(Context, DS.getTypeSpecTypeLoc());
@@ -5692,7 +6005,7 @@ namespace {
}
// Finally fill in MemberPointerLocInfo fields.
- TL.setStarLoc(Chunk.Loc);
+ TL.setStarLoc(SourceLocation::getFromRawEncoding(Chunk.Mem.StarLoc));
TL.setClassTInfo(ClsTInfo);
}
void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
@@ -5735,6 +6048,9 @@ namespace {
assert(Chunk.Kind == DeclaratorChunk::Pipe);
TL.setKWLoc(Chunk.Loc);
}
+ void VisitExtIntTypeLoc(ExtIntTypeLoc TL) {
+ TL.setNameLoc(Chunk.Loc);
+ }
void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
TL.setExpansionLoc(Chunk.Loc);
}
@@ -5785,6 +6101,21 @@ 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.
@@ -5833,6 +6164,9 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc();
}
+ if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>())
+ fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs());
+
// FIXME: Ordering here?
while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
@@ -5848,7 +6182,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
} else {
- TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
+ TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL);
}
return TInfo;
@@ -6349,6 +6683,7 @@ namespace {
Desugar,
Attributed,
Parens,
+ Array,
Pointer,
BlockPointer,
Reference,
@@ -6369,6 +6704,10 @@ namespace {
} else if (isa<ParenType>(Ty)) {
T = cast<ParenType>(Ty)->getInnerType();
Stack.push_back(Parens);
+ } else if (isa<ConstantArrayType>(Ty) || isa<VariableArrayType>(Ty) ||
+ isa<IncompleteArrayType>(Ty)) {
+ T = cast<ArrayType>(Ty)->getElementType();
+ Stack.push_back(Array);
} else if (isa<PointerType>(Ty)) {
T = cast<PointerType>(Ty)->getPointeeType();
Stack.push_back(Pointer);
@@ -6446,6 +6785,27 @@ namespace {
case MacroQualified:
return wrap(C, cast<MacroQualifiedType>(Old)->getUnderlyingType(), I);
+ case Array: {
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(Old)) {
+ QualType New = wrap(C, CAT->getElementType(), I);
+ return C.getConstantArrayType(New, CAT->getSize(), CAT->getSizeExpr(),
+ CAT->getSizeModifier(),
+ CAT->getIndexTypeCVRQualifiers());
+ }
+
+ if (const auto *VAT = dyn_cast<VariableArrayType>(Old)) {
+ QualType New = wrap(C, VAT->getElementType(), I);
+ return C.getVariableArrayType(
+ New, VAT->getSizeExpr(), VAT->getSizeModifier(),
+ VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange());
+ }
+
+ const auto *IAT = cast<IncompleteArrayType>(Old);
+ QualType New = wrap(C, IAT->getElementType(), I);
+ return C.getIncompleteArrayType(New, IAT->getSizeModifier(),
+ IAT->getIndexTypeCVRQualifiers());
+ }
+
case Pointer: {
QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I);
return C.getPointerType(New);
@@ -6673,15 +7033,15 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
// attributes, require that the type be a single-level pointer.
if (isContextSensitive) {
// Make sure that the pointee isn't itself a pointer type.
- const Type *pointeeType;
+ const Type *pointeeType = nullptr;
if (desugared->isArrayType())
pointeeType = desugared->getArrayElementTypeNoTypeQual();
- else
+ else if (desugared->isAnyPointerType())
pointeeType = desugared->getPointeeType().getTypePtr();
- if (pointeeType->isAnyPointerType() ||
- pointeeType->isObjCObjectPointerType() ||
- pointeeType->isMemberPointerType()) {
+ if (pointeeType && (pointeeType->isAnyPointerType() ||
+ pointeeType->isObjCObjectPointerType() ||
+ pointeeType->isMemberPointerType())) {
S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
<< DiagNullabilityKind(nullability, true)
<< type;
@@ -6914,6 +7274,25 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
}
+ if (attr.getKind() == ParsedAttr::AT_CmseNSCall) {
+ // Delay if this is not a function type.
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ // Ignore if we don't have CMSE enabled.
+ if (!S.getLangOpts().Cmse) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_ignored) << attr;
+ attr.setInvalid();
+ return true;
+ }
+
+ // Otherwise we can process right away.
+ FunctionType::ExtInfo EI =
+ unwrapped.get()->getExtInfo().withCmseNSCall(true);
+ type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ return true;
+ }
+
// ns_returns_retained is not always a type attribute, but if we got
// here, we're treating it as one right now.
if (attr.getKind() == ParsedAttr::AT_NSReturnsRetained) {
@@ -7273,15 +7652,16 @@ static bool isPermittedNeonBaseType(QualType &Ty,
Triple.getArch() == llvm::Triple::aarch64_be;
if (VecKind == VectorType::NeonPolyVector) {
if (IsPolyUnsigned) {
- // AArch64 polynomial vectors are unsigned and support poly64.
+ // AArch64 polynomial vectors are unsigned.
return BTy->getKind() == BuiltinType::UChar ||
BTy->getKind() == BuiltinType::UShort ||
BTy->getKind() == BuiltinType::ULong ||
BTy->getKind() == BuiltinType::ULongLong;
} else {
- // AArch32 polynomial vector are signed.
+ // AArch32 polynomial vectors are signed.
return BTy->getKind() == BuiltinType::SChar ||
- BTy->getKind() == BuiltinType::Short;
+ BTy->getKind() == BuiltinType::Short ||
+ BTy->getKind() == BuiltinType::LongLong;
}
}
@@ -7302,7 +7682,8 @@ static bool isPermittedNeonBaseType(QualType &Ty,
BTy->getKind() == BuiltinType::LongLong ||
BTy->getKind() == BuiltinType::ULongLong ||
BTy->getKind() == BuiltinType::Float ||
- BTy->getKind() == BuiltinType::Half;
+ BTy->getKind() == BuiltinType::Half ||
+ BTy->getKind() == BuiltinType::BFloat16;
}
/// HandleNeonVectorTypeAttr - The "neon_vector_type" and
@@ -7360,6 +7741,23 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
CurType = S.Context.getVectorType(CurType, numElts, VecKind);
}
+static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State,
+ QualType &CurType,
+ ParsedAttr &Attr) {
+ const VectorType *VT = dyn_cast<VectorType>(CurType);
+ if (!VT || VT->getVectorKind() != VectorType::NeonVector) {
+ State.getSema().Diag(Attr.getLoc(),
+ diag::err_attribute_arm_mve_polymorphism);
+ Attr.setInvalid();
+ return;
+ }
+
+ CurType =
+ State.getAttributedType(createSimpleAttr<ArmMveStrictPolymorphismAttr>(
+ State.getSema().Context, Attr),
+ CurType, CurType);
+}
+
/// Handle OpenCL Access Qualifier Attribute.
static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
Sema &S) {
@@ -7416,6 +7814,68 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
}
}
+/// HandleMatrixTypeAttr - "matrix_type" attribute, like ext_vector_type
+static void HandleMatrixTypeAttr(QualType &CurType, const ParsedAttr &Attr,
+ Sema &S) {
+ if (!S.getLangOpts().MatrixTypes) {
+ S.Diag(Attr.getLoc(), diag::err_builtin_matrix_disabled);
+ return;
+ }
+
+ if (Attr.getNumArgs() != 2) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr << 2;
+ return;
+ }
+
+ Expr *RowsExpr = nullptr;
+ Expr *ColsExpr = nullptr;
+
+ // TODO: Refactor parameter extraction into separate function
+ // Get the number of rows
+ if (Attr.isArgIdent(0)) {
+ CXXScopeSpec SS;
+ SourceLocation TemplateKeywordLoc;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc());
+ ExprResult Rows = S.ActOnIdExpression(S.getCurScope(), SS,
+ TemplateKeywordLoc, id, false, false);
+
+ if (Rows.isInvalid())
+ // TODO: maybe a good error message would be nice here
+ return;
+ RowsExpr = Rows.get();
+ } else {
+ assert(Attr.isArgExpr(0) &&
+ "Argument to should either be an identity or expression");
+ RowsExpr = Attr.getArgAsExpr(0);
+ }
+
+ // Get the number of columns
+ if (Attr.isArgIdent(1)) {
+ CXXScopeSpec SS;
+ SourceLocation TemplateKeywordLoc;
+ UnqualifiedId id;
+ id.setIdentifier(Attr.getArgAsIdent(1)->Ident, Attr.getLoc());
+ ExprResult Columns = S.ActOnIdExpression(
+ S.getCurScope(), SS, TemplateKeywordLoc, id, false, false);
+
+ if (Columns.isInvalid())
+ // TODO: a good error message would be nice here
+ return;
+ RowsExpr = Columns.get();
+ } else {
+ assert(Attr.isArgExpr(1) &&
+ "Argument to should either be an identity or expression");
+ ColsExpr = Attr.getArgAsExpr(1);
+ }
+
+ // Create the matrix type.
+ QualType T = S.BuildMatrixType(CurType, RowsExpr, ColsExpr, Attr.getLoc());
+ if (!T.isNull())
+ CurType = T;
+}
+
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
@@ -7544,6 +8004,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
VectorType::NeonPolyVector);
attr.setUsedAsTypeAttr();
break;
+ case ParsedAttr::AT_ArmMveStrictPolymorphism: {
+ HandleArmMveStrictPolymorphismAttr(state, type, attr);
+ attr.setUsedAsTypeAttr();
+ break;
+ }
case ParsedAttr::AT_OpenCLAccess:
HandleOpenCLAccessAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
@@ -7562,6 +8027,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}
+ case ParsedAttr::AT_MatrixType:
+ HandleMatrixTypeAttr(type, attr, state.getSema());
+ attr.setUsedAsTypeAttr();
+ break;
+
MS_TYPE_ATTRS_CASELIST:
if (!handleMSPointerTypeQualifierAttr(state, attr, type))
attr.setUsedAsTypeAttr();
@@ -7638,6 +8108,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case ParsedAttr::AT_AcquireHandle: {
if (!type->isFunctionType())
return;
+
+ if (attr.getNumArgs() != 1) {
+ state.getSema().Diag(attr.getLoc(),
+ diag::err_attribute_wrong_number_arguments)
+ << attr << 1;
+ attr.setInvalid();
+ return;
+ }
+
StringRef HandleType;
if (!state.getSema().checkStringLiteralArgumentAttr(attr, 0, HandleType))
return;
@@ -7722,12 +8201,14 @@ void Sema::completeExprArrayBound(Expr *E) {
/// case of a reference type, the referred-to type).
///
/// \param E The expression whose type is required to be complete.
+/// \param Kind Selects which completeness rules should be applied.
/// \param Diagnoser The object that will emit a diagnostic if the type is
/// incomplete.
///
/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
/// otherwise.
-bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
+bool Sema::RequireCompleteExprType(Expr *E, CompleteTypeKind Kind,
+ TypeDiagnoser &Diagnoser) {
QualType T = E->getType();
// Incomplete array types may be completed by the initializer attached to
@@ -7742,12 +8223,12 @@ bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) {
// FIXME: Are there other cases which require instantiating something other
// than the type to complete the type of an expression?
- return RequireCompleteType(E->getExprLoc(), T, Diagnoser);
+ return RequireCompleteType(E->getExprLoc(), T, Kind, Diagnoser);
}
bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
BoundTypeDiagnoser<> Diagnoser(DiagID);
- return RequireCompleteExprType(E, Diagnoser);
+ return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser);
}
/// Ensure that the type T is a complete type.
@@ -7765,11 +8246,14 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
///
/// @param T The type that this routine is examining for completeness.
///
+/// @param Kind Selects which completeness rules should be applied.
+///
/// @returns @c true if @p T is incomplete and a diagnostic was emitted,
/// @c false otherwise.
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
+ CompleteTypeKind Kind,
TypeDiagnoser &Diagnoser) {
- if (RequireCompleteTypeImpl(Loc, T, &Diagnoser))
+ if (RequireCompleteTypeImpl(Loc, T, Kind, &Diagnoser))
return true;
if (const TagType *Tag = T->getAs<TagType>()) {
if (!Tag->getDecl()->isCompleteDefinitionRequired()) {
@@ -7823,10 +8307,12 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
} else if (auto *ED = dyn_cast<EnumDecl>(D)) {
if (auto *Pattern = ED->getTemplateInstantiationPattern())
ED = Pattern;
- if (OnlyNeedComplete && ED->isFixed()) {
- // If the enum has a fixed underlying type, and we're only looking for a
- // complete type (not a definition), any visible declaration of it will
- // do.
+ if (OnlyNeedComplete && (ED->isFixed() || getLangOpts().MSVCCompat)) {
+ // If the enum has a fixed underlying type, it may have been forward
+ // declared. In -fms-compatibility, `enum Foo;` will also forward declare
+ // the enum and assign it the underlying type of `int`. Since we're only
+ // looking for a complete type (not a definition), any visible declaration
+ // of it will do.
*Suggested = nullptr;
for (auto *Redecl : ED->redecls()) {
if (isVisible(Redecl))
@@ -7918,6 +8404,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
/// The implementation of RequireCompleteType
bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
+ CompleteTypeKind Kind,
TypeDiagnoser *Diagnoser) {
// FIXME: Add this assertion to make sure we always get instantiation points.
// assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType");
@@ -7931,7 +8418,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
if (!MPTy->getClass()->isDependentType()) {
if (getLangOpts().CompleteMemberPointers &&
!MPTy->getClass()->getAsCXXRecordDecl()->isBeingDefined() &&
- RequireCompleteType(Loc, QualType(MPTy->getClass(), 0),
+ RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), Kind,
diag::err_memptr_incomplete))
return true;
@@ -7945,7 +8432,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
}
NamedDecl *Def = nullptr;
- bool Incomplete = T->isIncompleteType(&Def);
+ bool AcceptSizeless = (Kind == CompleteTypeKind::AcceptSizeless);
+ bool Incomplete = (T->isIncompleteType(&Def) ||
+ (!AcceptSizeless && T->isSizelessBuiltinType()));
// Check that any necessary explicit specializations are visible. For an
// enum, we just need the declaration, so don't check this.
@@ -7999,7 +8488,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// If the external source completed the type, go through the motions
// again to ensure we're allowed to use the completed type.
if (!T->isIncompleteType())
- return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+ return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser);
}
}
@@ -8051,7 +8540,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// instantiation produced an error, so that repeated calls to this
// function give consistent answers.
if (!T->isIncompleteType())
- return RequireCompleteTypeImpl(Loc, T, Diagnoser);
+ return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser);
}
}
@@ -8065,14 +8554,14 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// If the type was a forward declaration of a class/struct/union
// type, produce a note.
- if (Tag && !Tag->isInvalidDecl())
+ if (Tag && !Tag->isInvalidDecl() && !Tag->getLocation().isInvalid())
Diag(Tag->getLocation(),
Tag->isBeingDefined() ? diag::note_type_being_defined
: diag::note_forward_declaration)
<< Context.getTagDeclType(Tag);
// If the Objective-C class was a forward declaration, produce a note.
- if (IFace && !IFace->isInvalidDecl())
+ if (IFace && !IFace->isInvalidDecl() && !IFace->getLocation().isInvalid())
Diag(IFace->getLocation(), diag::note_forward_class);
// If we have external information that we can use to suggest a fix,
@@ -8084,9 +8573,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
}
bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
- unsigned DiagID) {
+ CompleteTypeKind Kind, unsigned DiagID) {
BoundTypeDiagnoser<> Diagnoser(DiagID);
- return RequireCompleteType(Loc, T, Diagnoser);
+ return RequireCompleteType(Loc, T, Kind, Diagnoser);
}
/// Get diagnostic %select index for tag kind for
@@ -8184,7 +8673,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
return true;
}
}
- } else if (getLangOpts().CPlusPlus2a ? !RD->hasConstexprDestructor()
+ } else if (getLangOpts().CPlusPlus20 ? !RD->hasConstexprDestructor()
: !RD->hasTrivialDestructor()) {
// All fields and bases are of literal types, so have trivial or constexpr
// destructors. If this class's destructor is non-trivial / non-constexpr,
@@ -8194,7 +8683,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
if (!Dtor)
return true;
- if (getLangOpts().CPlusPlus2a) {
+ if (getLangOpts().CPlusPlus20) {
Diag(Dtor->getLocation(), diag::note_non_literal_non_constexpr_dtor)
<< RD;
} else {
@@ -8386,9 +8875,17 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
DisallowedKind = 4;
else if (T.hasQualifiers())
DisallowedKind = 5;
+ else if (T->isSizelessType())
+ DisallowedKind = 6;
else if (!T.isTriviallyCopyableType(Context))
// Some other non-trivially-copyable type (probably a C++ class)
- DisallowedKind = 6;
+ DisallowedKind = 7;
+ else if (auto *ExtTy = T->getAs<ExtIntType>()) {
+ if (ExtTy->getNumBits() < 8)
+ DisallowedKind = 8;
+ else if (!llvm::isPowerOf2_32(ExtTy->getNumBits()))
+ DisallowedKind = 9;
+ }
if (DisallowedKind != -1) {
Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3b827fbc950b..ae0e9f1119b4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -19,6 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
@@ -27,6 +28,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
@@ -156,6 +158,13 @@ public:
/// existing lambdas.
bool ReplacingOriginal() { return false; }
+ /// Wether CXXConstructExpr can be skipped when they are implicit.
+ /// They will be reconstructed when used if needed.
+ /// This is usefull when the user that cause rebuilding of the
+ /// CXXConstructExpr is outside of the expression at which the TreeTransform
+ /// started.
+ bool AllowSkippingCXXConstructExpr() { return true; }
+
/// Returns the location of the entity being transformed, if that
/// information was not available elsewhere in the AST.
///
@@ -211,6 +220,14 @@ public:
return T.isNull();
}
+ /// Transform a template parameter depth level.
+ ///
+ /// During a transformation that transforms template parameters, this maps
+ /// an old template parameter depth to a new depth.
+ unsigned TransformTemplateDepth(unsigned Depth) {
+ return Depth;
+ }
+
/// Determine whether the given call argument should be dropped, e.g.,
/// because it is a default argument.
///
@@ -509,6 +526,15 @@ public:
DeclarationNameInfo
TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo);
+ bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs,
+ llvm::SmallVectorImpl<concepts::Requirement *> &Transformed);
+ concepts::TypeRequirement *
+ TransformTypeRequirement(concepts::TypeRequirement *Req);
+ concepts::ExprRequirement *
+ TransformExprRequirement(concepts::ExprRequirement *Req);
+ concepts::NestedRequirement *
+ TransformNestedRequirement(concepts::NestedRequirement *Req);
+
/// Transform the given template name.
///
/// \param SS The nested-name-specifier that qualifies the template
@@ -704,10 +730,10 @@ public:
#define ABSTRACT_STMT(Stmt)
#include "clang/AST/StmtNodes.inc"
-#define OPENMP_CLAUSE(Name, Class) \
+#define OMP_CLAUSE_CLASS(Enum, Str, Class) \
LLVM_ATTRIBUTE_NOINLINE \
OMPClause *Transform ## Class(Class *S);
-#include "clang/Basic/OpenMPKinds.def"
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
/// Build a new qualified type given its unqualified type and type location.
///
@@ -868,6 +894,16 @@ public:
Expr *SizeExpr,
SourceLocation AttributeLoc);
+ /// Build a new matrix type given the element type and dimensions.
+ QualType RebuildConstantMatrixType(QualType ElementType, unsigned NumRows,
+ unsigned NumColumns);
+
+ /// Build a new matrix type given the type and dependently-defined
+ /// dimensions.
+ QualType RebuildDependentSizedMatrixType(QualType ElementType, Expr *RowExpr,
+ Expr *ColumnExpr,
+ SourceLocation AttributeLoc);
+
/// Build a new DependentAddressSpaceType or return the pointee
/// type variable with the correct address space (retrieved from
/// AddrSpaceExpr) applied to it. The former will be returned in cases
@@ -941,12 +977,16 @@ public:
/// Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
- QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) {
+ QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) {
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
return SemaRef.Context.getAutoType(Deduced, Keyword,
- /*IsDependent*/ false);
+ /*IsDependent*/ false, /*IsPack=*/false,
+ TypeConstraintConcept,
+ TypeConstraintArgs);
}
/// By default, builds a new DeducedTemplateSpecializationType with the given
@@ -1056,23 +1096,8 @@ public:
}
if (Keyword == ETK_None || Keyword == ETK_Typename) {
- QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
- *Id, IdLoc);
- // If a dependent name resolves to a deduced template specialization type,
- // check that we're in one of the syntactic contexts permitting it.
- if (!DeducedTSTContext) {
- if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>(
- T.isNull() ? nullptr : T->getContainedDeducedType())) {
- SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst)
- << (int)SemaRef.getTemplateNameKindForDiagnostics(
- Deduced->getTemplateName())
- << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0);
- if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl())
- SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here);
- return QualType();
- }
- }
- return T;
+ return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc,
+ *Id, IdLoc, DeducedTSTContext);
}
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
@@ -1168,6 +1193,14 @@ public:
QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc,
bool isReadPipe);
+ /// Build an extended int given its value type.
+ QualType RebuildExtIntType(bool IsUnsigned, unsigned NumBits,
+ SourceLocation Loc);
+
+ /// Build a dependent extended int given its value type.
+ QualType RebuildDependentExtIntType(bool IsUnsigned, Expr *NumBitsExpr,
+ SourceLocation Loc);
+
/// Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
@@ -1314,9 +1347,10 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildWhileStmt(SourceLocation WhileLoc,
- Sema::ConditionResult Cond, Stmt *Body) {
- return getSema().ActOnWhileStmt(WhileLoc, Cond, Body);
+ StmtResult RebuildWhileStmt(SourceLocation WhileLoc, SourceLocation LParenLoc,
+ Sema::ConditionResult Cond,
+ SourceLocation RParenLoc, Stmt *Body) {
+ return getSema().ActOnWhileStmt(WhileLoc, LParenLoc, Cond, RParenLoc, Body);
}
/// Build a new do-while statement.
@@ -1603,8 +1637,7 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind,
- SourceLocation KindKwLoc,
+ OMPClause *RebuildOMPDefaultClause(DefaultKind Kind, SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
@@ -1704,17 +1737,16 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPReductionClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation ColonLoc,
- SourceLocation EndLoc,
- CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId,
- ArrayRef<Expr *> UnresolvedReductions) {
+ OMPClause *RebuildOMPReductionClause(
+ ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
return getSema().ActOnOpenMPReductionClause(
- VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
- ReductionId, UnresolvedReductions);
+ VarList, Modifier, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc,
+ ReductionIdScopeSpec, ReductionId, UnresolvedReductions);
}
/// Build a new OpenMP 'task_reduction' clause.
@@ -1813,28 +1845,42 @@ public:
EndLoc);
}
+ /// Build a new OpenMP 'depobj' pseudo clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDepobjClause(Depobj, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Build a new OpenMP 'depend' pseudo clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *
- RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc,
- SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList,
- StartLoc, LParenLoc, EndLoc);
+ RebuildOMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
+ SourceLocation DepLoc, SourceLocation ColonLoc,
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDependClause(DepModifier, DepKind, DepLoc,
+ ColonLoc, VarList, StartLoc,
+ LParenLoc, EndLoc);
}
/// Build a new OpenMP 'device' clause.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPDeviceClause(Expr *Device, SourceLocation StartLoc,
+ OMPClause *RebuildOMPDeviceClause(OpenMPDeviceClauseModifier Modifier,
+ Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPDeviceClause(Modifier, Device, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
/// Build a new OpenMP 'map' clause.
@@ -1933,6 +1979,16 @@ public:
return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'detach' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPDetachClause(Expr *Evt, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc);
+ }
+
/// Build a new OpenMP 'dist_schedule' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -1981,6 +2037,15 @@ public:
return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs);
}
+ /// Build a new OpenMP 'use_device_addr' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPUseDeviceAddrClause(ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs) {
+ return getSema().ActOnOpenMPUseDeviceAddrClause(VarList, Locs);
+ }
+
/// Build a new OpenMP 'is_device_ptr' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2017,6 +2082,67 @@ public:
EndLoc);
}
+ /// Build a new OpenMP 'inclusive' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPInclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'exclusive' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPExclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'uses_allocators' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPUsesAllocatorsClause(
+ ArrayRef<Sema::UsesAllocatorsData> Data, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPUsesAllocatorClause(StartLoc, LParenLoc, EndLoc,
+ Data);
+ }
+
+ /// Build a new OpenMP 'affinity' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAffinityClause(SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc, Expr *Modifier,
+ ArrayRef<Expr *> Locators) {
+ return getSema().ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc,
+ EndLoc, Modifier, Locators);
+ }
+
+ /// Build a new OpenMP 'order' clause.
+ ///
+ /// 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);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -2294,16 +2420,53 @@ public:
RBracketLoc);
}
+ /// Build a new matrix subscript expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
+ Expr *ColumnIdx,
+ SourceLocation RBracketLoc) {
+ return getSema().CreateBuiltinMatrixSubscriptExpr(Base, RowIdx, ColumnIdx,
+ RBracketLoc);
+ }
+
/// Build a new array section expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc,
Expr *LowerBound,
- SourceLocation ColonLoc, Expr *Length,
+ SourceLocation ColonLocFirst,
+ SourceLocation ColonLocSecond,
+ Expr *Length, Expr *Stride,
SourceLocation RBracketLoc) {
return getSema().ActOnOMPArraySectionExpr(Base, LBracketLoc, LowerBound,
- ColonLoc, Length, RBracketLoc);
+ ColonLocFirst, ColonLocSecond,
+ Length, Stride, RBracketLoc);
+ }
+
+ /// Build a new array shaping expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
+ ArrayRef<Expr *> Dims,
+ ArrayRef<SourceRange> BracketsRanges) {
+ return getSema().ActOnOMPArrayShapingExpr(Base, LParenLoc, RParenLoc, Dims,
+ BracketsRanges);
+ }
+
+ /// Build a new iterator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildOMPIteratorExpr(
+ SourceLocation IteratorKwLoc, SourceLocation LLoc, SourceLocation RLoc,
+ ArrayRef<Sema::OMPIteratorData> Data) {
+ return getSema().ActOnOMPIteratorExpr(/*Scope=*/nullptr, IteratorKwLoc,
+ LLoc, RLoc, Data);
}
/// Build a new call expression.
@@ -2314,8 +2477,8 @@ public:
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig = nullptr) {
- return getSema().BuildCallExpr(/*Scope=*/nullptr, Callee, LParenLoc, Args,
- RParenLoc, ExecConfig);
+ return getSema().ActOnCallExpr(
+ /*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc, ExecConfig);
}
/// Build a new member access expression.
@@ -2527,10 +2690,10 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildStmtExpr(SourceLocation LParenLoc,
- Stmt *SubStmt,
- SourceLocation RParenLoc) {
- return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc);
+ ExprResult RebuildStmtExpr(SourceLocation LParenLoc, Stmt *SubStmt,
+ SourceLocation RParenLoc, unsigned TemplateDepth) {
+ return getSema().BuildStmtExpr(LParenLoc, SubStmt, RParenLoc,
+ TemplateDepth);
}
/// Build a new __builtin_choose_expr expression.
@@ -2609,6 +2772,10 @@ public:
RAngleLoc, LParenLoc,
SubExpr, RParenLoc);
+ case Stmt::CXXAddrspaceCastExprClass:
+ return getDerived().RebuildCXXAddrspaceCastExpr(
+ OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc);
+
default:
llvm_unreachable("Invalid C++ named cast");
}
@@ -2682,6 +2849,16 @@ public:
SourceRange(LParenLoc, RParenLoc));
}
+ ExprResult
+ RebuildCXXAddrspaceCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc,
+ TypeSourceInfo *TInfo, SourceLocation RAngleLoc,
+ SourceLocation LParenLoc, Expr *SubExpr,
+ SourceLocation RParenLoc) {
+ return getSema().BuildCXXNamedCast(
+ OpLoc, tok::kw_addrspace_cast, TInfo, SubExpr,
+ SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc));
+ }
+
/// Build a new C++ functional-style cast expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2735,24 +2912,19 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType,
- SourceLocation TypeidLoc,
- TypeSourceInfo *Operand,
- SourceLocation RParenLoc) {
- return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand,
- RParenLoc);
+ ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc,
+ TypeSourceInfo *Operand,
+ SourceLocation RParenLoc) {
+ return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc);
}
/// Build a new C++ __uuidof(expr) expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType,
- SourceLocation TypeidLoc,
- Expr *Operand,
- SourceLocation RParenLoc) {
- return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand,
- RParenLoc);
+ ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc,
+ Expr *Operand, SourceLocation RParenLoc) {
+ return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc);
}
/// Build a new C++ "this" expression.
@@ -2931,9 +3103,14 @@ public:
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
+ // Reconstruct the constructor we originally found, which might be
+ // different if this is a call to an inherited constructor.
+ CXXConstructorDecl *FoundCtor = Constructor;
+ if (Constructor->isInheritingConstructor())
+ FoundCtor = Constructor->getInheritedConstructor().getConstructor();
+
SmallVector<Expr*, 8> ConvertedArgs;
- if (getSema().CompleteConstructorCall(Constructor, Args, Loc,
- ConvertedArgs))
+ if (getSema().CompleteConstructorCall(FoundCtor, Args, Loc, ConvertedArgs))
return ExprError();
return getSema().BuildCXXConstructExpr(Loc, T, Constructor,
@@ -3078,7 +3255,56 @@ public:
return Result;
}
- /// \brief Build a new Objective-C boxed expression.
+ /// \brief Build a new requires expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc) {
+ return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body,
+ LocalParameters, Requirements, ClosingBraceLoc);
+ }
+
+ concepts::TypeRequirement *
+ RebuildTypeRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return SemaRef.BuildTypeRequirement(SubstDiag);
+ }
+
+ concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) {
+ return SemaRef.BuildTypeRequirement(T);
+ }
+
+ concepts::ExprRequirement *
+ RebuildExprRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple,
+ SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement Ret) {
+ return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc,
+ std::move(Ret));
+ }
+
+ concepts::ExprRequirement *
+ RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ concepts::ExprRequirement::ReturnTypeRequirement Ret) {
+ return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc,
+ std::move(Ret));
+ }
+
+ concepts::NestedRequirement *
+ RebuildNestedRequirement(
+ concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+ return SemaRef.BuildNestedRequirement(SubstDiag);
+ }
+
+ concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) {
+ return SemaRef.BuildNestedRequirement(Constraint);
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
@@ -3382,6 +3608,11 @@ public:
Sema::AtomicArgumentOrder::AST);
}
+ ExprResult RebuildRecoveryExpr(SourceLocation BeginLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> SubExprs) {
+ return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs);
+ }
+
private:
TypeLoc TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
@@ -3446,10 +3677,10 @@ OMPClause *TreeTransform<Derived>::TransformOMPClause(OMPClause *S) {
switch (S->getClauseKind()) {
default: break;
// Transform individual clause nodes
-#define OPENMP_CLAUSE(Name, Class) \
- case OMPC_ ## Name : \
+#define OMP_CLAUSE_CLASS(Enum, Str, Class) \
+ case Enum: \
return getDerived().Transform ## Class(cast<Class>(S));
-#include "clang/Basic/OpenMPKinds.def"
+#include "llvm/Frontend/OpenMP/OMPKinds.def"
}
return S;
@@ -3966,50 +4197,8 @@ template<typename Derived>
void TreeTransform<Derived>::InventTemplateArgumentLoc(
const TemplateArgument &Arg,
TemplateArgumentLoc &Output) {
- SourceLocation Loc = getDerived().getBaseLocation();
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("null template argument in TreeTransform");
- break;
-
- case TemplateArgument::Type:
- Output = TemplateArgumentLoc(Arg,
- SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
-
- break;
-
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion: {
- NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
- if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
- Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
- else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc);
-
- if (Arg.getKind() == TemplateArgument::Template)
- Output = TemplateArgumentLoc(Arg,
- Builder.getWithLocInContext(SemaRef.Context),
- Loc);
- else
- Output = TemplateArgumentLoc(Arg,
- Builder.getWithLocInContext(SemaRef.Context),
- Loc, Loc);
-
- break;
- }
-
- case TemplateArgument::Expression:
- Output = TemplateArgumentLoc(Arg, Arg.getAsExpr());
- break;
-
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::Pack:
- case TemplateArgument::NullPtr:
- Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
- break;
- }
+ Output = getSema().getTrivialTemplateArgumentLoc(
+ Arg, QualType(), getDerived().getBaseLocation());
}
template<typename Derived>
@@ -4019,12 +4208,45 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
const TemplateArgument &Arg = Input.getArgument();
switch (Arg.getKind()) {
case TemplateArgument::Null:
- case TemplateArgument::Integral:
case TemplateArgument::Pack:
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
llvm_unreachable("Unexpected TemplateArgument");
+ case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Declaration: {
+ // Transform a resolved template argument straight to a resolved template
+ // argument. We get here when substituting into an already-substituted
+ // template type argument during concept satisfaction checking.
+ QualType T = Arg.getNonTypeTemplateArgumentType();
+ QualType NewT = getDerived().TransformType(T);
+ if (NewT.isNull())
+ return true;
+
+ ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
+ ? Arg.getAsDecl()
+ : nullptr;
+ ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
+ getDerived().getBaseLocation(), D))
+ : nullptr;
+ if (D && !NewD)
+ return true;
+
+ if (NewT == T && D == NewD)
+ Output = Input;
+ else if (Arg.getKind() == TemplateArgument::Integral)
+ Output = TemplateArgumentLoc(
+ TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT),
+ TemplateArgumentLocInfo());
+ else if (Arg.getKind() == TemplateArgument::NullPtr)
+ Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
+ TemplateArgumentLocInfo());
+ else
+ Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
+ TemplateArgumentLocInfo());
+
+ return false;
+ }
+
case TemplateArgument::Type: {
TypeSourceInfo *DI = Input.getTypeSourceInfo();
if (!DI)
@@ -4456,7 +4678,10 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
Deduced =
SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);
T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
- AutoTy->isDependentType());
+ AutoTy->isDependentType(),
+ /*isPack=*/false,
+ AutoTy->getTypeConstraintConcept(),
+ AutoTy->getTypeConstraintArguments());
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
@@ -5016,6 +5241,86 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
}
template <typename Derived>
+QualType
+TreeTransform<Derived>::TransformConstantMatrixType(TypeLocBuilder &TLB,
+ ConstantMatrixTypeLoc TL) {
+ const ConstantMatrixType *T = TL.getTypePtr();
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) {
+ Result = getDerived().RebuildConstantMatrixType(
+ ElementType, T->getNumRows(), T->getNumColumns());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ ConstantMatrixTypeLoc NewTL = TLB.push<ConstantMatrixTypeLoc>(Result);
+ NewTL.setAttrNameLoc(TL.getAttrNameLoc());
+ NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
+ NewTL.setAttrRowOperand(TL.getAttrRowOperand());
+ NewTL.setAttrColumnOperand(TL.getAttrColumnOperand());
+
+ return Result;
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformDependentSizedMatrixType(
+ TypeLocBuilder &TLB, DependentSizedMatrixTypeLoc TL) {
+ const DependentSizedMatrixType *T = TL.getTypePtr();
+
+ QualType ElementType = getDerived().TransformType(T->getElementType());
+ if (ElementType.isNull()) {
+ return QualType();
+ }
+
+ // Matrix dimensions are constant expressions.
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ Expr *origRows = TL.getAttrRowOperand();
+ if (!origRows)
+ origRows = T->getRowExpr();
+ Expr *origColumns = TL.getAttrColumnOperand();
+ if (!origColumns)
+ origColumns = T->getColumnExpr();
+
+ ExprResult rowResult = getDerived().TransformExpr(origRows);
+ rowResult = SemaRef.ActOnConstantExpression(rowResult);
+ if (rowResult.isInvalid())
+ return QualType();
+
+ ExprResult columnResult = getDerived().TransformExpr(origColumns);
+ columnResult = SemaRef.ActOnConstantExpression(columnResult);
+ if (columnResult.isInvalid())
+ return QualType();
+
+ Expr *rows = rowResult.get();
+ Expr *columns = columnResult.get();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() ||
+ rows != origRows || columns != origColumns) {
+ Result = getDerived().RebuildDependentSizedMatrixType(
+ ElementType, rows, columns, T->getAttributeLoc());
+
+ if (Result.isNull())
+ return QualType();
+ }
+
+ // We might have any sort of matrix type now, but fortunately they
+ // all have the same location layout.
+ MatrixTypeLoc NewTL = TLB.push<MatrixTypeLoc>(Result);
+ NewTL.setAttrNameLoc(TL.getAttrNameLoc());
+ NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange());
+ NewTL.setAttrRowOperand(rows);
+ NewTL.setAttrColumnOperand(columns);
+ return Result;
+}
+
+template <typename Derived>
QualType TreeTransform<Derived>::TransformDependentAddressSpaceType(
TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) {
const DependentAddressSpaceType *T = TL.getTypePtr();
@@ -5189,21 +5494,29 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
- ExpansionTL.getTypePtr()->getNumExpansions();
- NumExpansions = OrigNumExpansions;
- if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
- Pattern.getSourceRange(),
- Unexpanded,
- ShouldExpand,
- RetainExpansion,
- NumExpansions)) {
- return true;
+ Optional<unsigned> OrigNumExpansions;
+ if (Unexpanded.size() > 0) {
+ OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
+ NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+ Pattern.getSourceRange(),
+ Unexpanded,
+ ShouldExpand,
+ RetainExpansion,
+ NumExpansions)) {
+ return true;
+ }
+ } else {
+#ifndef NDEBUG
+ const AutoType *AT =
+ Pattern.getType().getTypePtr()->getContainedAutoType();
+ assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) &&
+ "Could not find parameter packs or undeduced auto type!");
+#endif
}
if (ShouldExpand) {
@@ -5263,6 +5576,9 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
indexAdjustment,
NumExpansions,
/*ExpectParameterPack=*/true);
+ assert(NewParm->isParameterPack() &&
+ "Parameter pack no longer a parameter pack after "
+ "transformation.");
} else {
NewParm = getDerived().TransformFunctionTypeParam(
OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
@@ -5768,32 +6084,6 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
- AutoTypeLoc TL) {
- const AutoType *T = TL.getTypePtr();
- QualType OldDeduced = T->getDeducedType();
- QualType NewDeduced;
- if (!OldDeduced.isNull()) {
- NewDeduced = getDerived().TransformType(OldDeduced);
- if (NewDeduced.isNull())
- return QualType();
- }
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
- T->isDependentType()) {
- Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword());
- if (Result.isNull())
- return QualType();
- }
-
- AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
- return Result;
-}
-
-template<typename Derived>
QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
const DeducedTemplateSpecializationType *T = TL.getTypePtr();
@@ -5990,6 +6280,57 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
return Result;
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformExtIntType(TypeLocBuilder &TLB,
+ ExtIntTypeLoc TL) {
+ const ExtIntType *EIT = TL.getTypePtr();
+ QualType Result = TL.getType();
+
+ if (getDerived().AlwaysRebuild()) {
+ Result = getDerived().RebuildExtIntType(EIT->isUnsigned(),
+ EIT->getNumBits(), TL.getNameLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ ExtIntTypeLoc NewTL = TLB.push<ExtIntTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformDependentExtIntType(
+ TypeLocBuilder &TLB, DependentExtIntTypeLoc TL) {
+ const DependentExtIntType *EIT = TL.getTypePtr();
+
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ ExprResult BitsExpr = getDerived().TransformExpr(EIT->getNumBitsExpr());
+ BitsExpr = SemaRef.ActOnConstantExpression(BitsExpr);
+
+ if (BitsExpr.isInvalid())
+ return QualType();
+
+ QualType Result = TL.getType();
+
+ if (getDerived().AlwaysRebuild() || BitsExpr.get() != EIT->getNumBitsExpr()) {
+ Result = getDerived().RebuildDependentExtIntType(
+ EIT->isUnsigned(), BitsExpr.get(), TL.getNameLoc());
+
+ if (Result.isNull())
+ return QualType();
+ }
+
+ if (isa<DependentExtIntType>(Result)) {
+ DependentExtIntTypeLoc NewTL = TLB.push<DependentExtIntTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ } else {
+ ExtIntTypeLoc NewTL = TLB.push<ExtIntTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ }
+ return Result;
+}
+
/// Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
@@ -6054,6 +6395,71 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
}
};
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
+ AutoTypeLoc TL) {
+ const AutoType *T = TL.getTypePtr();
+ QualType OldDeduced = T->getDeducedType();
+ QualType NewDeduced;
+ if (!OldDeduced.isNull()) {
+ NewDeduced = getDerived().TransformType(OldDeduced);
+ if (NewDeduced.isNull())
+ return QualType();
+ }
+
+ ConceptDecl *NewCD = nullptr;
+ TemplateArgumentListInfo NewTemplateArgs;
+ NestedNameSpecifierLoc NewNestedNameSpec;
+ if (TL.getTypePtr()->isConstrained()) {
+ NewCD = cast_or_null<ConceptDecl>(
+ getDerived().TransformDecl(
+ TL.getConceptNameLoc(),
+ TL.getTypePtr()->getTypeConstraintConcept()));
+
+ NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
+ NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
+ typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator;
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ ArgIterator(TL,
+ TL.getNumArgs()),
+ NewTemplateArgs))
+ return QualType();
+
+ if (TL.getNestedNameSpecifierLoc()) {
+ NewNestedNameSpec
+ = getDerived().TransformNestedNameSpecifierLoc(
+ TL.getNestedNameSpecifierLoc());
+ if (!NewNestedNameSpec)
+ return QualType();
+ }
+ }
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
+ T->isDependentType()) {
+ llvm::SmallVector<TemplateArgument, 4> NewArgList;
+ NewArgList.reserve(NewArgList.size());
+ for (const auto &ArgLoc : NewTemplateArgs.arguments())
+ NewArgList.push_back(ArgLoc.getArgument());
+ Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
+ NewArgList);
+ if (Result.isNull())
+ return QualType();
+ }
+
+ AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec);
+ NewTL.setTemplateKWLoc(TL.getTemplateKWLoc());
+ NewTL.setConceptNameLoc(TL.getConceptNameLoc());
+ NewTL.setFoundDecl(TL.getFoundDecl());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned I = 0; I < TL.getNumArgs(); ++I)
+ NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
+
+ return Result;
+}
template <typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
@@ -6930,7 +7336,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
Body.get() == S->getBody())
return Owned(S);
- return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get());
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), S->getLParenLoc(),
+ Cond, S->getRParenLoc(), Body.get());
}
template<typename Derived>
@@ -7228,7 +7635,8 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
return StmtError();
StmtResult FinalSuspend =
getDerived().TransformStmt(S->getFinalSuspendStmt());
- if (FinalSuspend.isInvalid())
+ if (FinalSuspend.isInvalid() ||
+ !SemaRef.checkFinalSuspendNoThrow(FinalSuspend.get()))
return StmtError();
ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
assert(isa<Expr>(InitSuspend.get()) && isa<Expr>(FinalSuspend.get()));
@@ -7684,8 +8092,12 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
- if (NewStmt.isInvalid())
+ if (NewStmt.isInvalid() && LoopVar.get() != S->getLoopVarStmt()) {
+ // Might not have attached any initializer to the loop variable.
+ getSema().ActOnInitializerError(
+ cast<DeclStmt>(LoopVar.get())->getSingleDecl());
return StmtError();
+ }
}
StmtResult Body = getDerived().TransformStmt(S->getBody());
@@ -8152,6 +8564,28 @@ TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) {
template <typename Derived>
StmtResult
+TreeTransform<Derived>::TransformOMPDepobjDirective(OMPDepobjDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_depobj, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPScanDirective(OMPScanDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_scan, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr,
@@ -8638,6 +9072,19 @@ TreeTransform<Derived>::TransformOMPOrderedClause(OMPOrderedClause *C) {
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPDetachClause(OMPDetachClause *C) {
+ ExprResult E;
+ if (Expr *Evt = C->getEventHandler()) {
+ E = getDerived().TransformExpr(Evt);
+ if (E.isInvalid())
+ return nullptr;
+ }
+ return getDerived().RebuildOMPDetachClause(E.get(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPNowaitClause(OMPNowaitClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
@@ -8692,6 +9139,34 @@ TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) {
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPAcqRelClause(OMPAcqRelClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAcquireClause(OMPAcquireClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPReleaseClause(OMPReleaseClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPRelaxedClause(OMPRelaxedClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPThreadsClause(OMPThreadsClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
@@ -8711,6 +9186,13 @@ TreeTransform<Derived>::TransformOMPNogroupClause(OMPNogroupClause *C) {
}
template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPDestroyClause(OMPDestroyClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPUnifiedAddressClause(
OMPUnifiedAddressClause *C) {
llvm_unreachable("unified_address clause cannot appear in dependent context");
@@ -8847,8 +9329,9 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
UnresolvedReductions.push_back(nullptr);
}
return getDerived().RebuildOMPReductionClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(),
- C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
+ Vars, C->getModifier(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getColonLoc(), C->getEndLoc(),
+ ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
}
template <typename Derived>
@@ -9025,8 +9508,25 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) {
template <typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPDepobjClause(OMPDepobjClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getDepobj());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPDepobjClause(E.get(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
+ Expr *DepModifier = C->getModifier();
+ if (DepModifier) {
+ ExprResult DepModRes = getDerived().TransformExpr(DepModifier);
+ if (DepModRes.isInvalid())
+ return nullptr;
+ DepModifier = DepModRes.get();
+ }
Vars.reserve(C->varlist_size());
for (auto *VE : C->varlists()) {
ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
@@ -9035,8 +9535,9 @@ TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) {
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPDependClause(
- C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars,
- C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ DepModifier, C->getDependencyKind(), C->getDependencyLoc(),
+ C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
}
template <typename Derived>
@@ -9045,8 +9546,9 @@ TreeTransform<Derived>::TransformOMPDeviceClause(OMPDeviceClause *C) {
ExprResult E = getDerived().TransformExpr(C->getDevice());
if (E.isInvalid())
return nullptr;
- return getDerived().RebuildOMPDeviceClause(E.get(), C->getBeginLoc(),
- C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPDeviceClause(
+ C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getEndLoc());
}
template <typename Derived, class T>
@@ -9269,6 +9771,21 @@ OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause(
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPUseDeviceAddrClause(
+ OMPUseDeviceAddrClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPUseDeviceAddrClause(Vars, Locs);
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -9298,6 +9815,91 @@ TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *C) {
Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPInclusiveClause(OMPInclusiveClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPInclusiveClause(
+ Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPExclusiveClause(OMPExclusiveClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPExclusiveClause(
+ Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPUsesAllocatorsClause(
+ OMPUsesAllocatorsClause *C) {
+ SmallVector<Sema::UsesAllocatorsData, 16> Data;
+ Data.reserve(C->getNumberOfAllocators());
+ for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
+ ExprResult Allocator = getDerived().TransformExpr(D.Allocator);
+ if (Allocator.isInvalid())
+ continue;
+ ExprResult AllocatorTraits;
+ if (Expr *AT = D.AllocatorTraits) {
+ AllocatorTraits = getDerived().TransformExpr(AT);
+ if (AllocatorTraits.isInvalid())
+ continue;
+ }
+ Sema::UsesAllocatorsData &NewD = Data.emplace_back();
+ NewD.Allocator = Allocator.get();
+ NewD.AllocatorTraits = AllocatorTraits.get();
+ NewD.LParenLoc = D.LParenLoc;
+ NewD.RParenLoc = D.RParenLoc;
+ }
+ return getDerived().RebuildOMPUsesAllocatorsClause(
+ Data, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) {
+ SmallVector<Expr *, 4> Locators;
+ Locators.reserve(C->varlist_size());
+ ExprResult ModifierRes;
+ if (Expr *Modifier = C->getModifier()) {
+ ModifierRes = getDerived().TransformExpr(Modifier);
+ if (ModifierRes.isInvalid())
+ return nullptr;
+ }
+ for (Expr *E : C->varlists()) {
+ ExprResult Locator = getDerived().TransformExpr(E);
+ if (Locator.isInvalid())
+ continue;
+ Locators.push_back(Locator.get());
+ }
+ return getDerived().RebuildOMPAffinityClause(
+ C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(),
+ ModifierRes.get(), Locators);
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
+ return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(),
+ C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -9581,6 +10183,24 @@ TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) {
return E;
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformRecoveryExpr(RecoveryExpr *E) {
+ llvm::SmallVector<Expr *, 8> Children;
+ bool Changed = false;
+ for (Expr *C : E->subExpressions()) {
+ ExprResult NewC = getDerived().TransformExpr(C);
+ if (NewC.isInvalid())
+ return ExprError();
+ Children.push_back(NewC.get());
+
+ Changed |= NewC.get() != C;
+ }
+ if (!getDerived().AlwaysRebuild() && !Changed)
+ return E;
+ return getDerived().RebuildRecoveryExpr(E->getBeginLoc(), E->getEndLoc(),
+ Children);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
@@ -9680,6 +10300,29 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
template <typename Derived>
ExprResult
+TreeTransform<Derived>::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) {
+ ExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return ExprError();
+
+ ExprResult RowIdx = getDerived().TransformExpr(E->getRowIdx());
+ if (RowIdx.isInvalid())
+ return ExprError();
+
+ ExprResult ColumnIdx = getDerived().TransformExpr(E->getColumnIdx());
+ if (ColumnIdx.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
+ RowIdx.get() == E->getRowIdx() && ColumnIdx.get() == E->getColumnIdx())
+ return E;
+
+ return getDerived().RebuildMatrixSubscriptExpr(
+ Base.get(), RowIdx.get(), ColumnIdx.get(), E->getRBracketLoc());
+}
+
+template <typename Derived>
+ExprResult
TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) {
ExprResult Base = getDerived().TransformExpr(E->getBase());
if (Base.isInvalid())
@@ -9699,13 +10342,105 @@ TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) {
return ExprError();
}
+ ExprResult Stride;
+ if (Expr *Str = E->getStride()) {
+ Stride = getDerived().TransformExpr(Str);
+ if (Stride.isInvalid())
+ return ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() &&
LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength())
return E;
return getDerived().RebuildOMPArraySectionExpr(
- Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), E->getColonLoc(),
- Length.get(), E->getRBracketLoc());
+ Base.get(), E->getBase()->getEndLoc(), LowerBound.get(),
+ E->getColonLocFirst(), E->getColonLocSecond(), Length.get(), Stride.get(),
+ E->getRBracketLoc());
+}
+
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
+ ExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return ExprError();
+
+ SmallVector<Expr *, 4> Dims;
+ bool ErrorFound = false;
+ for (Expr *Dim : E->getDimensions()) {
+ ExprResult DimRes = getDerived().TransformExpr(Dim);
+ if (DimRes.isInvalid()) {
+ ErrorFound = true;
+ continue;
+ }
+ Dims.push_back(DimRes.get());
+ }
+
+ if (ErrorFound)
+ return ExprError();
+ return getDerived().RebuildOMPArrayShapingExpr(Base.get(), E->getLParenLoc(),
+ E->getRParenLoc(), Dims,
+ E->getBracketsRanges());
+}
+
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformOMPIteratorExpr(OMPIteratorExpr *E) {
+ unsigned NumIterators = E->numOfIterators();
+ SmallVector<Sema::OMPIteratorData, 4> Data(NumIterators);
+
+ bool ErrorFound = false;
+ bool NeedToRebuild = getDerived().AlwaysRebuild();
+ for (unsigned I = 0; I < NumIterators; ++I) {
+ auto *D = cast<VarDecl>(E->getIteratorDecl(I));
+ Data[I].DeclIdent = D->getIdentifier();
+ Data[I].DeclIdentLoc = D->getLocation();
+ if (D->getLocation() == D->getBeginLoc()) {
+ assert(SemaRef.Context.hasSameType(D->getType(), SemaRef.Context.IntTy) &&
+ "Implicit type must be int.");
+ } else {
+ TypeSourceInfo *TSI = getDerived().TransformType(D->getTypeSourceInfo());
+ QualType DeclTy = getDerived().TransformType(D->getType());
+ Data[I].Type = SemaRef.CreateParsedType(DeclTy, TSI);
+ }
+ OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I);
+ ExprResult Begin = getDerived().TransformExpr(Range.Begin);
+ ExprResult End = getDerived().TransformExpr(Range.End);
+ ExprResult Step = getDerived().TransformExpr(Range.Step);
+ ErrorFound = ErrorFound ||
+ !(!D->getTypeSourceInfo() || (Data[I].Type.getAsOpaquePtr() &&
+ !Data[I].Type.get().isNull())) ||
+ Begin.isInvalid() || End.isInvalid() || Step.isInvalid();
+ if (ErrorFound)
+ continue;
+ Data[I].Range.Begin = Begin.get();
+ Data[I].Range.End = End.get();
+ Data[I].Range.Step = Step.get();
+ Data[I].AssignLoc = E->getAssignLoc(I);
+ Data[I].ColonLoc = E->getColonLoc(I);
+ Data[I].SecColonLoc = E->getSecondColonLoc(I);
+ NeedToRebuild =
+ NeedToRebuild ||
+ (D->getTypeSourceInfo() && Data[I].Type.get().getTypePtrOrNull() !=
+ D->getType().getTypePtrOrNull()) ||
+ Range.Begin != Data[I].Range.Begin || Range.End != Data[I].Range.End ||
+ Range.Step != Data[I].Range.Step;
+ }
+ if (ErrorFound)
+ return ExprError();
+ if (!NeedToRebuild)
+ return E;
+
+ ExprResult Res = getDerived().RebuildOMPIteratorExpr(
+ E->getIteratorKwLoc(), E->getLParenLoc(), E->getRParenLoc(), Data);
+ if (!Res.isUsable())
+ return Res;
+ auto *IE = cast<OMPIteratorExpr>(Res.get());
+ for (unsigned I = 0; I < NumIterators; ++I)
+ getDerived().transformedLocalDecl(E->getIteratorDecl(I),
+ IE->getIteratorDecl(I));
+ return Res;
}
template<typename Derived>
@@ -9837,9 +10572,15 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
RHS.get() == E->getRHS())
return E;
- Sema::FPContractStateRAII FPContractState(getSema());
- getSema().FPFeatures = E->getFPFeatures();
-
+ if (E->isCompoundAssignmentOp())
+ // FPFeatures has already been established from trailing storage
+ return getDerived().RebuildBinaryOperator(
+ E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get());
+ Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+ FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ getSema().CurFPFeatures =
+ NewOverrides.applyOverrides(getSema().getLangOpts());
+ getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt();
return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
LHS.get(), RHS.get());
}
@@ -9892,6 +10633,11 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
CompoundAssignOperator *E) {
+ Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+ FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ getSema().CurFPFeatures =
+ NewOverrides.applyOverrides(getSema().getLangOpts());
+ getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt();
return getDerived().TransformBinaryOperator(E);
}
@@ -10245,16 +10991,18 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) {
return ExprError();
}
- if (!getDerived().AlwaysRebuild() &&
+ unsigned OldDepth = E->getTemplateDepth();
+ unsigned NewDepth = getDerived().TransformTemplateDepth(OldDepth);
+
+ if (!getDerived().AlwaysRebuild() && OldDepth == NewDepth &&
SubStmt.get() == E->getSubStmt()) {
// Calling this an 'error' is unintuitive, but it does the right thing.
SemaRef.ActOnStmtExprError();
return SemaRef.MaybeBindToTemporary(E);
}
- return getDerived().RebuildStmtExpr(E->getLParenLoc(),
- SubStmt.get(),
- E->getRParenLoc());
+ return getDerived().RebuildStmtExpr(E->getLParenLoc(), SubStmt.get(),
+ E->getRParenLoc(), NewDepth);
}
template<typename Derived>
@@ -10363,8 +11111,11 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
(E->getNumArgs() != 2 || Second.get() == E->getArg(1)))
return SemaRef.MaybeBindToTemporary(E);
- Sema::FPContractStateRAII FPContractState(getSema());
- getSema().FPFeatures = E->getFPFeatures();
+ Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
+ FPOptionsOverride NewOverrides(E->getFPFeatures());
+ getSema().CurFPFeatures =
+ NewOverrides.applyOverrides(getSema().getLangOpts());
+ getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt();
return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(),
E->getOperatorLoc(),
@@ -10491,6 +11242,12 @@ TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) {
+ return getDerived().TransformCXXNamedCastExpr(E);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
CXXFunctionalCastExpr *E) {
TypeSourceInfo *Type =
@@ -11179,6 +11936,146 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr(
&TransArgs);
}
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
+ SmallVector<ParmVarDecl*, 4> TransParams;
+ SmallVector<QualType, 4> TransParamTypes;
+ Sema::ExtParameterInfoBuilder ExtParamInfos;
+
+ // C++2a [expr.prim.req]p2
+ // Expressions appearing within a requirement-body are unevaluated operands.
+ EnterExpressionEvaluationContext Ctx(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(
+ getSema().Context, getSema().CurContext,
+ E->getBody()->getBeginLoc());
+
+ Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false);
+
+ if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(),
+ E->getLocalParameters(),
+ /*ParamTypes=*/nullptr,
+ /*ParamInfos=*/nullptr,
+ TransParamTypes, &TransParams,
+ ExtParamInfos))
+ return ExprError();
+
+ for (ParmVarDecl *Param : TransParams)
+ Param->setDeclContext(Body);
+
+ SmallVector<concepts::Requirement *, 4> TransReqs;
+ if (getDerived().TransformRequiresExprRequirements(E->getRequirements(),
+ TransReqs))
+ return ExprError();
+
+ for (concepts::Requirement *Req : TransReqs) {
+ if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) {
+ if (ER->getReturnTypeRequirement().isTypeConstraint()) {
+ ER->getReturnTypeRequirement()
+ .getTypeConstraintTemplateParameterList()->getParam(0)
+ ->setDeclContext(Body);
+ }
+ }
+ }
+
+ return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body,
+ TransParams, TransReqs,
+ E->getRBraceLoc());
+}
+
+template<typename Derived>
+bool TreeTransform<Derived>::TransformRequiresExprRequirements(
+ ArrayRef<concepts::Requirement *> Reqs,
+ SmallVectorImpl<concepts::Requirement *> &Transformed) {
+ for (concepts::Requirement *Req : Reqs) {
+ concepts::Requirement *TransReq = nullptr;
+ if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req))
+ TransReq = getDerived().TransformTypeRequirement(TypeReq);
+ else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req))
+ TransReq = getDerived().TransformExprRequirement(ExprReq);
+ else
+ TransReq = getDerived().TransformNestedRequirement(
+ cast<concepts::NestedRequirement>(Req));
+ if (!TransReq)
+ return true;
+ Transformed.push_back(TransReq);
+ }
+ return false;
+}
+
+template<typename Derived>
+concepts::TypeRequirement *
+TreeTransform<Derived>::TransformTypeRequirement(
+ concepts::TypeRequirement *Req) {
+ if (Req->isSubstitutionFailure()) {
+ if (getDerived().AlwaysRebuild())
+ return getDerived().RebuildTypeRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ TypeSourceInfo *TransType = getDerived().TransformType(Req->getType());
+ if (!TransType)
+ return nullptr;
+ return getDerived().RebuildTypeRequirement(TransType);
+}
+
+template<typename Derived>
+concepts::ExprRequirement *
+TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) {
+ llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr;
+ if (Req->isExprSubstitutionFailure())
+ TransExpr = Req->getExprSubstitutionDiagnostic();
+ else {
+ ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr());
+ if (TransExprRes.isInvalid())
+ return nullptr;
+ TransExpr = TransExprRes.get();
+ }
+
+ llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ const auto &RetReq = Req->getReturnTypeRequirement();
+ if (RetReq.isEmpty())
+ TransRetReq.emplace();
+ else if (RetReq.isSubstitutionFailure())
+ TransRetReq.emplace(RetReq.getSubstitutionDiagnostic());
+ else if (RetReq.isTypeConstraint()) {
+ TemplateParameterList *OrigTPL =
+ RetReq.getTypeConstraintTemplateParameterList();
+ TemplateParameterList *TPL =
+ getDerived().TransformTemplateParameterList(OrigTPL);
+ if (!TPL)
+ return nullptr;
+ TransRetReq.emplace(TPL);
+ }
+ assert(TransRetReq.hasValue() &&
+ "All code paths leading here must set TransRetReq");
+ if (Expr *E = TransExpr.dyn_cast<Expr *>())
+ return getDerived().RebuildExprRequirement(E, Req->isSimple(),
+ Req->getNoexceptLoc(),
+ std::move(*TransRetReq));
+ return getDerived().RebuildExprRequirement(
+ TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
+ Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+}
+
+template<typename Derived>
+concepts::NestedRequirement *
+TreeTransform<Derived>::TransformNestedRequirement(
+ concepts::NestedRequirement *Req) {
+ if (Req->isSubstitutionFailure()) {
+ if (getDerived().AlwaysRebuild())
+ return getDerived().RebuildNestedRequirement(
+ Req->getSubstitutionDiagnostic());
+ return Req;
+ }
+ ExprResult TransConstraint =
+ getDerived().TransformExpr(Req->getConstraintExpr());
+ if (TransConstraint.isInvalid())
+ return nullptr;
+ return getDerived().RebuildNestedRequirement(TransConstraint.get());
+}
template<typename Derived>
ExprResult
@@ -11303,10 +12200,11 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
// CXXConstructExprs other than for list-initialization and
// CXXTemporaryObjectExpr are always implicit, so when we have
// a 1-argument construction we just transform that argument.
- if ((E->getNumArgs() == 1 ||
- (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
- (!getDerived().DropCallArgument(E->getArg(0))) &&
- !E->isListInitialization())
+ if (getDerived().AllowSkippingCXXConstructExpr() &&
+ ((E->getNumArgs() == 1 ||
+ (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
+ (!getDerived().DropCallArgument(E->getArg(0))) &&
+ !E->isListInitialization()))
return getDerived().TransformExpr(E->getArg(0));
TemporaryBase Rebase(*this, /*FIXME*/ E->getBeginLoc(), DeclarationName());
@@ -11560,6 +12458,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
// Create the local class that will describe the lambda.
+ // FIXME: KnownDependent below is wrong when substituting inside a templated
+ // context that isn't a DeclContext (such as a variable template).
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
@@ -11584,19 +12484,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
LSI->CallOperator = NewCallOperator;
- for (unsigned I = 0, NumParams = NewCallOperator->getNumParams();
- I != NumParams; ++I) {
- auto *P = NewCallOperator->getParamDecl(I);
- if (P->hasUninstantiatedDefaultArg()) {
- EnterExpressionEvaluationContext Eval(
- getSema(),
- Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P);
- ExprResult R = getDerived().TransformExpr(
- E->getCallOperator()->getParamDecl(I)->getDefaultArg());
- P->setDefaultArg(R.get());
- }
- }
-
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
@@ -13092,6 +13979,21 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
return SemaRef.BuildExtVectorType(ElementType, SizeExpr, AttributeLoc);
}
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildConstantMatrixType(
+ QualType ElementType, unsigned NumRows, unsigned NumColumns) {
+ return SemaRef.Context.getConstantMatrixType(ElementType, NumRows,
+ NumColumns);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildDependentSizedMatrixType(
+ QualType ElementType, Expr *RowExpr, Expr *ColumnExpr,
+ SourceLocation AttributeLoc) {
+ return SemaRef.BuildMatrixType(ElementType, RowExpr, ColumnExpr,
+ AttributeLoc);
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::RebuildFunctionProtoType(
QualType T,
@@ -13206,6 +14108,23 @@ QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
: SemaRef.BuildWritePipeType(ValueType, KWLoc);
}
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildExtIntType(bool IsUnsigned,
+ unsigned NumBits,
+ SourceLocation Loc) {
+ llvm::APInt NumBitsAP(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy),
+ NumBits, true);
+ IntegerLiteral *Bits = IntegerLiteral::Create(SemaRef.Context, NumBitsAP,
+ SemaRef.Context.IntTy, Loc);
+ return SemaRef.BuildExtIntType(IsUnsigned, Bits, Loc);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::RebuildDependentExtIntType(
+ bool IsUnsigned, Expr *NumBitsExpr, SourceLocation Loc) {
+ return SemaRef.BuildExtIntType(IsUnsigned, NumBitsExpr, Loc);
+}
+
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
@@ -13227,11 +14146,10 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
- getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
- SS, TemplateKWLoc, TemplateName,
- ParsedType::make(ObjectType),
- /*EnteringContext=*/false,
- Template, AllowInjectedClassName);
+ getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc,
+ TemplateName, ParsedType::make(ObjectType),
+ /*EnteringContext=*/false, Template,
+ AllowInjectedClassName);
return Template.get();
}
@@ -13248,11 +14166,9 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc };
Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations);
Sema::TemplateTy Template;
- getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
- SS, TemplateKWLoc, Name,
- ParsedType::make(ObjectType),
- /*EnteringContext=*/false,
- Template, AllowInjectedClassName);
+ getSema().ActOnTemplateName(
+ /*Scope=*/nullptr, SS, TemplateKWLoc, Name, ParsedType::make(ObjectType),
+ /*EnteringContext=*/false, Template, AllowInjectedClassName);
return Template.get();
}
diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h
new file mode 100644
index 000000000000..d207e07f451a
--- /dev/null
+++ b/clang/lib/Sema/UsedDeclVisitor.h
@@ -0,0 +1,102 @@
+//===- UsedDeclVisitor.h - ODR-used declarations visitor --------*- C++ -*-===//
+//
+// 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 file defines UsedDeclVisitor, a CRTP class which visits all the
+// declarations that are ODR-used by an expression or statement.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H
+#define LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H
+
+#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/Sema/SemaInternal.h"
+
+namespace clang {
+template <class Derived>
+class UsedDeclVisitor : public EvaluatedExprVisitor<Derived> {
+protected:
+ Sema &S;
+
+public:
+ typedef EvaluatedExprVisitor<Derived> Inherited;
+
+ UsedDeclVisitor(Sema &S) : Inherited(S.Context), S(S) {}
+
+ Derived &asImpl() { return *static_cast<Derived *>(this); }
+
+ void VisitDeclRefExpr(DeclRefExpr *E) {
+ auto *D = E->getDecl();
+ if (isa<FunctionDecl>(D) || isa<VarDecl>(D)) {
+ asImpl().visitUsedDecl(E->getLocation(), D);
+ }
+ }
+
+ void VisitMemberExpr(MemberExpr *E) {
+ auto *D = E->getMemberDecl();
+ if (isa<FunctionDecl>(D) || isa<VarDecl>(D)) {
+ asImpl().visitUsedDecl(E->getMemberLoc(), D);
+ }
+ asImpl().Visit(E->getBase());
+ }
+
+ void VisitCapturedStmt(CapturedStmt *Node) {
+ asImpl().visitUsedDecl(Node->getBeginLoc(), Node->getCapturedDecl());
+ Inherited::VisitCapturedStmt(Node);
+ }
+
+ void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ asImpl().visitUsedDecl(
+ E->getBeginLoc(),
+ const_cast<CXXDestructorDecl *>(E->getTemporary()->getDestructor()));
+ asImpl().Visit(E->getSubExpr());
+ }
+
+ void VisitCXXNewExpr(CXXNewExpr *E) {
+ if (E->getOperatorNew())
+ asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorNew());
+ if (E->getOperatorDelete())
+ asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete());
+ Inherited::VisitCXXNewExpr(E);
+ }
+
+ void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+ if (E->getOperatorDelete())
+ asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete());
+ QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
+ if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
+ asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record));
+ }
+
+ Inherited::VisitCXXDeleteExpr(E);
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *E) {
+ asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor());
+ Inherited::VisitCXXConstructExpr(E);
+ }
+
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ asImpl().Visit(E->getExpr());
+ }
+
+ void visitUsedDecl(SourceLocation Loc, Decl *D) {
+ if (auto *CD = dyn_cast<CapturedDecl>(D)) {
+ if (auto *S = CD->getBody()) {
+ asImpl().Visit(S);
+ }
+ } else if (auto *CD = dyn_cast<BlockDecl>(D)) {
+ if (auto *S = CD->getBody()) {
+ asImpl().Visit(S);
+ }
+ }
+ }
+};
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H