summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:05 +0000
commitcf1b401909b5e54edfd80656b1a18eaa31f9f6f1 (patch)
treeedb0ffff2a43d84ba9b4c862b394cfeeebb36ddc /lib/Sema
parentef915aab0ac566c55bfb0d7a9f6635bb5d94d4af (diff)
downloadsrc-test2-cf1b401909b5e54edfd80656b1a18eaa31f9f6f1.tar.gz
src-test2-cf1b401909b5e54edfd80656b1a18eaa31f9f6f1.zip
Notes
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp6
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/SemaChecking.cpp25
-rw-r--r--lib/Sema/SemaDecl.cpp182
-rw-r--r--lib/Sema/SemaDeclAttr.cpp2
-rw-r--r--lib/Sema/SemaDeclCXX.cpp9
-rw-r--r--lib/Sema/SemaExprCXX.cpp46
-rw-r--r--lib/Sema/SemaOpenMP.cpp29
-rw-r--r--lib/Sema/SemaType.cpp15
9 files changed, 268 insertions, 51 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 934e13e72d05..fd2d07957c2b 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -305,10 +305,14 @@ static bool isThrowCaught(const CXXThrowExpr *Throw,
CaughtType = CaughtType->castAs<ReferenceType>()
->getPointeeType()
->getUnqualifiedDesugaredType();
+ if (ThrowType->isPointerType() && CaughtType->isPointerType()) {
+ ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType();
+ CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType();
+ }
if (CaughtType == ThrowType)
return true;
const CXXRecordDecl *CaughtAsRecordType =
- CaughtType->getPointeeCXXRecordDecl();
+ CaughtType->getAsCXXRecordDecl();
const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl();
if (CaughtAsRecordType && ThrowTypeAsRecordType)
return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 007a5e483e6c..34f5e26be810 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -1688,7 +1688,8 @@ bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) {
QT, OpenCLTypeExtMap);
}
-bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) {
- return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "",
+bool Sema::checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E) {
+ IdentifierInfo *FnName = D.getIdentifier();
+ return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), FnName,
OpenCLDeclExtMap, 1, D.getSourceRange());
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index b794628db738..845c4bf61b7a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -6000,6 +6000,7 @@ shouldNotPrintDirectly(const ASTContext &Context,
while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
QualType CastTy = llvm::StringSwitch<QualType>(Name)
+ .Case("CFIndex", Context.LongTy)
.Case("NSInteger", Context.LongTy)
.Case("NSUInteger", Context.UnsignedLongTy)
.Case("SInt32", Context.IntTy)
@@ -9935,6 +9936,28 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
::CheckBoolLikeConversion(*this, E, CC);
}
+/// Diagnose when expression is an integer constant expression and its evaluation
+/// results in integer overflow
+void Sema::CheckForIntOverflow (Expr *E) {
+ // Use a work list to deal with nested struct initializers.
+ SmallVector<Expr *, 2> Exprs(1, E);
+
+ do {
+ Expr *E = Exprs.pop_back_val();
+
+ if (isa<BinaryOperator>(E->IgnoreParenCasts())) {
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ continue;
+ }
+
+ if (auto InitList = dyn_cast<InitListExpr>(E))
+ Exprs.append(InitList->inits().begin(), InitList->inits().end());
+
+ if (isa<ObjCBoxedExpr>(E))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ } while (!Exprs.empty());
+}
+
namespace {
/// \brief Visitor for expressions which looks for unsequenced operations on the
/// same object.
@@ -10436,7 +10459,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
if (!E->isInstantiationDependent())
CheckUnsequencedOperations(E);
if (!IsConstexpr && !E->isValueDependent())
- E->EvaluateForOverflow(Context);
+ CheckForIntOverflow(E);
DiagnoseMisalignedMembers();
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e340456bc6da..ef8a408f90de 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1327,15 +1327,17 @@ void Sema::ActOnExitFunctionContext() {
/// overloaded function declaration or has the "overloadable"
/// attribute.
static bool AllowOverloadingOfFunction(LookupResult &Previous,
- ASTContext &Context) {
+ ASTContext &Context,
+ const FunctionDecl *New) {
if (Context.getLangOpts().CPlusPlus)
return true;
if (Previous.getResultKind() == LookupResult::FoundOverloaded)
return true;
- return (Previous.getResultKind() == LookupResult::Found
- && Previous.getFoundDecl()->hasAttr<OverloadableAttr>());
+ return Previous.getResultKind() == LookupResult::Found &&
+ (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
+ New->hasAttr<OverloadableAttr>());
}
/// Add this decl to the scope shadowed decl chains.
@@ -2933,6 +2935,41 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
New->dropAttr<InternalLinkageAttr>();
}
+ if (!getLangOpts().CPlusPlus) {
+ bool OldOvl = Old->hasAttr<OverloadableAttr>();
+ if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) {
+ Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch)
+ << New << OldOvl;
+
+ // Try our best to find a decl that actually has the overloadable
+ // attribute for the note. In most cases (e.g. programs with only one
+ // broken declaration/definition), this won't matter.
+ //
+ // FIXME: We could do this if we juggled some extra state in
+ // OverloadableAttr, rather than just removing it.
+ const Decl *DiagOld = Old;
+ if (OldOvl) {
+ auto OldIter = llvm::find_if(Old->redecls(), [](const Decl *D) {
+ const auto *A = D->getAttr<OverloadableAttr>();
+ return A && !A->isImplicit();
+ });
+ // If we've implicitly added *all* of the overloadable attrs to this
+ // chain, emitting a "previous redecl" note is pointless.
+ DiagOld = OldIter == Old->redecls_end() ? nullptr : *OldIter;
+ }
+
+ if (DiagOld)
+ Diag(DiagOld->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << OldOvl;
+
+ if (OldOvl)
+ New->addAttr(OverloadableAttr::CreateImplicit(Context));
+ else
+ New->dropAttr<OverloadableAttr>();
+ }
+ }
+
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
// convention of the first.
@@ -9179,6 +9216,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
bool Redeclaration = false;
NamedDecl *OldDecl = nullptr;
+ bool MayNeedOverloadableChecks = false;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -9187,13 +9225,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
- if (!AllowOverloadingOfFunction(Previous, Context)) {
+ if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) {
NamedDecl *Candidate = Previous.getRepresentativeDecl();
if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) {
Redeclaration = true;
OldDecl = Candidate;
}
} else {
+ MayNeedOverloadableChecks = true;
switch (CheckOverload(S, NewFD, Previous, OldDecl,
/*NewIsUsingDecl*/ false)) {
case Ovl_Match:
@@ -9208,18 +9247,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Redeclaration = false;
break;
}
-
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- // If a function name is overloadable in C, then every function
- // with that name must be marked "overloadable".
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- NamedDecl *OverloadedDecl =
- Redeclaration ? OldDecl : Previous.getRepresentativeDecl();
- Diag(OverloadedDecl->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
}
}
@@ -9234,15 +9261,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
MergeTypeWithPrevious = false;
// ... except in the presence of __attribute__((overloadable)).
- if (OldDecl->hasAttr<OverloadableAttr>()) {
- if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
- Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
- << Redeclaration << NewFD;
- Diag(Previous.getFoundDecl()->getLocation(),
- diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
+ if (OldDecl->hasAttr<OverloadableAttr>() ||
+ NewFD->hasAttr<OverloadableAttr>()) {
if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+ MayNeedOverloadableChecks = true;
Redeclaration = false;
OldDecl = nullptr;
}
@@ -9337,6 +9359,29 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
NewFD->setAccess(OldDecl->getAccess());
}
}
+ } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks &&
+ !NewFD->getAttr<OverloadableAttr>()) {
+ assert((Previous.empty() ||
+ llvm::any_of(Previous,
+ [](const NamedDecl *ND) {
+ return ND->hasAttr<OverloadableAttr>();
+ })) &&
+ "Non-redecls shouldn't happen without overloadable present");
+
+ auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) {
+ const auto *FD = dyn_cast<FunctionDecl>(ND);
+ return FD && !FD->hasAttr<OverloadableAttr>();
+ });
+
+ if (OtherUnmarkedIter != Previous.end()) {
+ Diag(NewFD->getLocation(),
+ diag::err_attribute_overloadable_multiple_unmarked_overloads);
+ Diag((*OtherUnmarkedIter)->getLocation(),
+ diag::note_attribute_overloadable_prev_overload)
+ << false;
+
+ NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
}
// Semantic checking for this function declaration (in isolation).
@@ -11100,9 +11145,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
bool IsGlobal = GlobalStorage && !var->isStaticLocal();
QualType baseType = Context.getBaseElementType(type);
- if (!var->getDeclContext()->isDependentContext() &&
- Init && !Init->isValueDependent()) {
-
+ if (Init && !Init->isValueDependent()) {
if (var->isConstexpr()) {
SmallVector<PartialDiagnosticAt, 8> Notes;
if (!var->evaluateValue(Notes) || !var->isInitICE()) {
@@ -11932,7 +11975,7 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
if (canRedefineFunction(Definition, getLangOpts()))
return;
- // Don't emit an error when this is redifinition of a typo-corrected
+ // Don't emit an error when this is redefinition of a typo-corrected
// definition.
if (TypoCorrectedFunctionDefinitions.count(Definition))
return;
@@ -13190,6 +13233,55 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (TUK == TUK_Friend || TUK == TUK_Reference)
Redecl = NotForRedeclaration;
+ /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C
+ /// implemented asks for structural equivalence checking, the returned decl
+ /// here is passed back to the parser, allowing the tag body to be parsed.
+ auto createTagFromNewDecl = [&]() -> TagDecl * {
+ assert(!getLangOpts().CPlusPlus && "not meant for C++ usage");
+ // If there is an identifier, use the location of the identifier as the
+ // location of the decl, otherwise use the location of the struct/union
+ // keyword.
+ SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
+ TagDecl *New = nullptr;
+
+ if (Kind == TTK_Enum) {
+ New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr,
+ ScopedEnum, ScopedEnumUsesClassTag,
+ !EnumUnderlying.isNull());
+ // If this is an undefined enum, bail.
+ if (TUK != TUK_Definition && !Invalid)
+ return nullptr;
+ if (EnumUnderlying) {
+ EnumDecl *ED = cast<EnumDecl>(New);
+ if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo *>())
+ ED->setIntegerTypeSourceInfo(TI);
+ else
+ ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
+ ED->setPromotionType(ED->getIntegerType());
+ }
+ } else { // struct/union
+ New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name,
+ nullptr);
+ }
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) {
+ // Add alignment attributes if necessary; these attributes are checked
+ // when the ASTContext lays out the structure.
+ //
+ // It is important for implementing the correct semantics that this
+ // happen here (in ActOnTag). The #pragma pack stack is
+ // maintained as a result of parser callbacks which can occur at
+ // many points during the parsing of a struct declaration (because
+ // the #pragma tokens are effectively skipped over during the
+ // parsing of the struct).
+ if (TUK == TUK_Definition) {
+ AddAlignmentAttributesForRecord(RD);
+ AddMsStructLayoutForRecord(RD);
+ }
+ }
+ return New;
+ };
+
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -13595,16 +13687,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TSK_ExplicitSpecialization;
}
+ // Note that clang allows ODR-like semantics for ObjC/C, i.e., do
+ // not keep more that one definition around (merge them). However,
+ // ensure the decl passes the structural compatibility check in
+ // C11 6.2.7/1 (or 6.1.2.6/1 in C89).
NamedDecl *Hidden = nullptr;
- if (SkipBody && getLangOpts().CPlusPlus &&
- !hasVisibleDefinition(Def, &Hidden)) {
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
// There is a definition of this tag, but it is not visible. We
// explicitly make use of C++'s one definition rule here, and
// assume that this definition is identical to the hidden one
// we already have. Make the existing definition visible and
// use it in place of this one.
- SkipBody->ShouldSkip = true;
- makeMergedDefinitionVisible(Hidden);
+ if (!getLangOpts().CPlusPlus) {
+ // Postpone making the old definition visible until after we
+ // complete parsing the new one and do the structural
+ // comparison.
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = createTagFromNewDecl();
+ SkipBody->Previous = Hidden;
+ } else {
+ SkipBody->ShouldSkip = true;
+ makeMergedDefinitionVisible(Hidden);
+ }
return Def;
} else if (!IsExplicitSpecializationAfterInstantiation) {
// A redeclaration in function prototype scope in C isn't
@@ -13832,7 +13936,7 @@ CreateNewDecl:
// the ASTContext lays out the structure.
//
// It is important for implementing the correct semantics that this
- // happen here (in act on tag decl). The #pragma pack stack is
+ // happen here (in ActOnTag). The #pragma pack stack is
// maintained as a result of parser callbacks which can occur at
// many points during the parsing of a struct declaration (because
// the #pragma tokens are effectively skipped over during the
@@ -13968,6 +14072,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
AddPushedVisibilityAttribute(Tag);
}
+bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
+ SkipBodyInfo &SkipBody) {
+ if (!hasStructuralCompatLayout(Prev, SkipBody.New))
+ return false;
+
+ // Make the previous decl visible.
+ makeMergedDefinitionVisible(SkipBody.Previous);
+ return true;
+}
+
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
assert(isa<ObjCContainerDecl>(IDecl) &&
"ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
@@ -15389,7 +15503,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// different from T:
// - every enumerator of every member of class T that is an unscoped
// enumerated type
- if (!TheEnumDecl->isScoped())
+ if (getLangOpts().CPlusPlus && !TheEnumDecl->isScoped())
DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(),
DeclarationNameInfo(Id, IdLoc));
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index e8503427536d..1929bc539188 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -6571,7 +6571,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
-// Helper for delayed proccessing TransparentUnion attribute.
+// Helper for delayed processing TransparentUnion attribute.
void Sema::ProcessDeclAttributeDelayed(Decl *D, const AttributeList *AttrList) {
for (const AttributeList *Attr = AttrList; Attr; Attr = Attr->getNext())
if (Attr->getKind() == AttributeList::AT_TransparentUnion) {
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 453ece9d9c4d..e9070881afe4 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3778,6 +3778,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull())
return true;
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ DependentNameTypeLoc TL =
+ TInfo->getTypeLoc().castAs<DependentNameTypeLoc>();
+ if (!TL.isNull()) {
+ TL.setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ }
+
R.clear();
R.setLookupName(MemberOrBase);
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 710ead30790f..a9cf3ec7990b 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1646,6 +1646,27 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
return false;
}
+// Emit a diagnostic if an aligned allocation/deallocation function that is not
+// implemented in the standard library is selected.
+static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
+ SourceLocation Loc, bool IsDelete,
+ Sema &S) {
+ if (!S.getLangOpts().AlignedAllocationUnavailable)
+ return;
+
+ // Return if there is a definition.
+ if (FD.isDefined())
+ return;
+
+ bool IsAligned = false;
+ if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) {
+ S.Diag(Loc, diag::warn_aligned_allocation_unavailable)
+ << IsDelete << FD.getType().getAsString()
+ << S.getASTContext().getTargetInfo().getTriple().str();
+ S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable);
+ }
+}
+
ExprResult
Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SourceLocation PlacementLParen,
@@ -2023,11 +2044,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorNew);
+ diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this);
}
if (OperatorDelete) {
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorDelete);
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this);
}
// C++0x [expr.new]p17:
@@ -3243,6 +3266,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
PDiag(diag::err_access_dtor) << PointeeElem);
}
}
+
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
+ *this);
}
CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(
@@ -4093,15 +4119,9 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
- ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
- LLVM_FALLTHROUGH;
-
- // C++1z [meta.unary.prop]:
- // T shall be a complete type, cv void, or an array of unknown bound.
- case UTT_IsDestructible:
- case UTT_IsNothrowDestructible:
- case UTT_IsTriviallyDestructible:
- // Per the GCC type traits documentation, the same constraints apply to these.
+ // Per the GCC type traits documentation, T shall be a complete type, cv void,
+ // or an array of unknown bound. But GCC actually imposes the same constraints
+ // as above.
case UTT_HasNothrowAssign:
case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor:
@@ -4113,6 +4133,14 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
+ ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
+ LLVM_FALLTHROUGH;
+
+ // C++1z [meta.unary.prop]:
+ // T shall be a complete type, cv void, or an array of unknown bound.
+ case UTT_IsDestructible:
+ case UTT_IsNothrowDestructible:
+ case UTT_IsTriviallyDestructible:
if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
return true;
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 2b7733d2adbd..49da0e499771 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -412,6 +412,30 @@ public:
return false;
}
+ /// Do the check specified in \a Check to all component lists at a given level
+ /// and return true if any issue is found.
+ bool checkMappableExprComponentListsForDeclAtLevel(
+ ValueDecl *VD, unsigned Level,
+ const llvm::function_ref<
+ bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind)> &Check) {
+ if (isStackEmpty())
+ return false;
+
+ auto StartI = Stack.back().first.begin();
+ auto EndI = Stack.back().first.end();
+ if (std::distance(StartI, EndI) <= (int)Level)
+ return false;
+ std::advance(StartI, Level);
+
+ auto MI = StartI->MappedExprComponents.find(VD);
+ if (MI != StartI->MappedExprComponents.end())
+ for (auto &L : MI->second.Components)
+ if (Check(L, MI->second.Kind))
+ return true;
+ return false;
+ }
+
/// Create a new mappable expression component list associated with a given
/// declaration and initialize it with the provided list of components.
void addMappableExpressionComponents(
@@ -994,9 +1018,8 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
- DSAStack->checkMappableExprComponentListsForDecl(
- D, /*CurrentRegionOnly=*/true,
- [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ DSAStack->checkMappableExprComponentListsForDeclAtLevel(
+ D, Level, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
// Only the map clause information influences how a variable is
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 8c8402e75e37..b19dcb2a5099 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -7111,6 +7112,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
+bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) {
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
+ if (!Suggested)
+ return false;
+
+ // FIXME: Add a specific mode for C11 6.2.7/1 in StructuralEquivalenceContext
+ // and isolate from other C++ specific checks.
+ StructuralEquivalenceContext Ctx(
+ D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls,
+ false /*StrictTypeSpelling*/, true /*Complain*/,
+ true /*ErrorOnTagTypeMismatch*/);
+ return Ctx.IsStructurallyEquivalent(D, Suggested);
+}
+
/// \brief Determine whether there is any declaration of \p D that was ever a
/// definition (perhaps before module merging) and is currently visible.
/// \param D The definition of the entity.