Skip to content

Commit

Permalink
Merged master:59ba19c56e1 into amd-gfx:7c9eaf391f7
Browse files Browse the repository at this point in the history
Local branch amd-gfx 7c9eaf3 Merged master:11c8c2a551c into amd-gfx:401de8383fd
Remote branch master 59ba19c [VirtualFileSystem] Add unit test that showcases YAMLVFSWriter bug
  • Loading branch information
Sw authored and Sw committed May 12, 2020
2 parents 7c9eaf3 + 59ba19c commit 6dda7cf
Show file tree
Hide file tree
Showing 12 changed files with 411 additions and 216 deletions.
7 changes: 1 addition & 6 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -6394,15 +6394,10 @@ class Sema final {
/// A diagnostic is emitted if it is not, false is returned, and
/// PossibleNonPrimary will be set to true if the failure might be due to a
/// non-primary expression being used as an atomic constraint.
bool CheckConstraintExpression(Expr *CE, Token NextToken = Token(),
bool CheckConstraintExpression(const Expr *CE, Token NextToken = Token(),
bool *PossibleNonPrimary = nullptr,
bool IsTrailingRequiresClause = false);

/// Check whether the given type-dependent expression will be the name of a
/// function or another callable function-like entity (e.g. a function
// template or overload set) for any substitution.
bool IsDependentFunctionNameExpr(Expr *E);

private:
/// Caches pairs of template-like decls whose associated constraints were
/// checked for subsumption and whether or not the first's constraints did in
Expand Down
121 changes: 71 additions & 50 deletions clang/lib/Sema/SemaConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,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);
Expand All @@ -60,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:
Expand Down Expand Up @@ -99,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);
Expand Down Expand Up @@ -725,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;
{
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18945,11 +18945,6 @@ 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) {
// FIXME: enable it for C++, RecoveryExpr is type-dependent to suppress
Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaTemplate/constraints.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// RUN: %clang_cc1 -std=c++20 -verify %s -DDEPENDENT_OR

#ifdef DEPENDENT_OR
// This causes the || below to be a CXXOperatorCallExpr not a BinaryOperator.
struct A {}; bool operator||(A, A);
#endif

namespace PR45589 {
template<typename T> struct X { static constexpr bool value = T::value; }; // expected-error {{cannot be used prior to '::'}}
struct False { static constexpr bool value = false; };
struct True { static constexpr bool value = true; };

template<typename T> concept C = true;

template<bool B, typename T> constexpr int test = 0;
template<bool B, typename T> requires C<T> constexpr int test<B, T> = 1;
template<bool B, typename T> requires (B && C<T>) || (X<T>::value && C<T>) constexpr int test<B, T> = 2; // expected-error {{non-constant expression}} expected-note {{subexpression}} expected-note {{instantiation of}} expected-note {{while substituting}}
static_assert(test<true, False> == 2);
static_assert(test<true, True> == 2);
static_assert(test<true, char> == 2); // satisfaction of second term of || not considered
static_assert(test<false, False> == 1);
static_assert(test<false, True> == 2); // constraints are partially ordered
// FIXME: These diagnostics are excessive.
static_assert(test<false, char> == 1); // expected-note 2{{while}} expected-note 2{{during}}
}
17 changes: 13 additions & 4 deletions libcxxabi/test/thread_local_destruction_order.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@
//
//===----------------------------------------------------------------------===//

// Darwin TLV finalization routines fail when creating a thread-local variable
// in the destructor for another thread-local variable:
// http://lists.llvm.org/pipermail/cfe-dev/2016-November/051376.html
// XFAIL: darwin
// Darwin TLV finalization routines used to fail when creating a thread-local
// variable in the destructor for another thread-local variable:
// - http://lists.llvm.org/pipermail/cfe-dev/2016-November/051376.html
// - rdar://29523281
// This was fixed in dyld in macos 10.15.
//
// XFAIL: macosx10.14
// XFAIL: macosx10.13
// XFAIL: macosx10.12
// XFAIL: macosx10.11
// XFAIL: macosx10.10
// XFAIL: macosx10.9

// UNSUPPORTED: c++98, c++03
// UNSUPPORTED: libcxxabi-no-threads

Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,15 +611,19 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
Name = getSectionPrefixForGlobal(Kind);
}

bool HasPrefix = false;
if (const auto *F = dyn_cast<Function>(GO)) {
if (Optional<StringRef> Prefix = F->getSectionPrefix())
if (Optional<StringRef> Prefix = F->getSectionPrefix()) {
Name += *Prefix;
HasPrefix = true;
}
}

if (UniqueSectionName) {
Name.push_back('.');
TM.getNameWithPrefix(Name, GO, Mang, /*MayAlwaysUsePrivate*/true);
}
} else if (HasPrefix)
Name.push_back('.');
return Name;
}

Expand Down
Loading

0 comments on commit 6dda7cf

Please sign in to comment.