Following up on PR48517, fix handling of template arguments that refer

to dependent declarations.

Treat an id-expression that names a local variable in a templated
function as being instantiation-dependent.

This addresses a language defect whereby a reference to a dependent
declaration can be formed without any construct being value-dependent.
Fixing that through value-dependence turns out to be problematic, so
instead this patch takes the approach (proposed on the core reflector)
of allowing the use of pointers or references to (but not values of)
dependent declarations inside value-dependent expressions, and instead
treating template arguments as dependent if they evaluate to a constant
involving such dependent declarations.

This ends up affecting a bunch of OpenMP tests, due to OpenMP
imprecisely handling instantiation-dependent constructs, bailing out
early instead of processing dependent constructs to the extent possible
when handling the template.

Previously committed as 8c1f2d15b8, and
reverted because a dependency commit was reverted.
This commit is contained in:
Richard Smith
2020-12-16 13:51:56 -08:00
parent fbb83f18b5
commit 5a391d38ac
32 changed files with 221 additions and 158 deletions

View File

@@ -578,12 +578,12 @@ public:
struct EvalStatus {
/// Whether the evaluated expression has side effects.
/// For example, (f() && 0) can be folded, but it still has side effects.
bool HasSideEffects;
bool HasSideEffects = false;
/// Whether the evaluation hit undefined behavior.
/// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior.
/// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
bool HasUndefinedBehavior;
bool HasUndefinedBehavior = false;
/// Diag - If this is non-null, it will be filled in with a stack of notes
/// indicating why evaluation failed (or why it failed to produce a constant
@@ -592,10 +592,7 @@ public:
/// foldable. If the expression is foldable, but not a constant expression,
/// the notes will describes why it isn't a constant expression. If the
/// expression *is* a constant expression, no notes will be produced.
SmallVectorImpl<PartialDiagnosticAt> *Diag;
EvalStatus()
: HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr;
// hasSideEffects - Return true if the evaluated expression has
// side effects.
@@ -606,8 +603,11 @@ public:
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult : EvalStatus {
/// Val - This is the value the expression can be folded to.
/// This is the value the expression can be folded to.
APValue Val;
/// Indicates whether Val contains a pointer or reference or pointer to
/// member naming a templated entity, and thus the value is dependent.
bool Dependent = false;
// isGlobalLValue - Return true if the evaluated lvalue expression
// is global.

View File

@@ -252,6 +252,12 @@ public:
/// Whether this template argument is dependent on a template
/// parameter such that its result can change from one instantiation to
/// another.
///
/// It's not always meaningful to ask whether a template argument is
/// dependent before it's been converted to match a template parameter;
/// whether a non-type template argument is dependent depends on the
/// corresponding parameter. For an unconverted template argument, this
/// returns true if the argument *might* be dependent.
bool isDependent() const;
/// Whether this template argument is dependent on a template
@@ -674,13 +680,6 @@ struct alignas(void *) ASTTemplateKWAndArgsInfo {
void initializeFrom(SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo &List,
TemplateArgumentLoc *OutArgArray);
// FIXME: The parameter Deps is the result populated by this method, the
// caller doesn't need it since it is populated by computeDependence. remove
// it.
void initializeFrom(SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo &List,
TemplateArgumentLoc *OutArgArray,
TemplateArgumentDependence &Deps);
void initializeFrom(SourceLocation TemplateKWLoc);
void copyInto(const TemplateArgumentLoc *ArgArray,

View File

@@ -3465,7 +3465,8 @@ public:
llvm::APSInt &Value, CCEKind CCE);
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
NamedDecl *Dest = nullptr);
NamedDecl *Dest = nullptr,
bool *ValueDependent = nullptr);
/// Abstract base class used to perform a contextual implicit
/// conversion from an expression to any type passing a filter.

View File

@@ -64,7 +64,7 @@ ExprDependence clang::computeDependence(UnaryOperator *E,
if (VD && VD->isTemplated()) {
auto *VarD = dyn_cast<VarDecl>(VD);
if (!VarD || !VarD->hasLocalStorage())
Dep |= ExprDependence::Value;
Dep |= ExprDependence::ValueInstantiation;
}
}
}
@@ -443,12 +443,21 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
if (auto *FirstArg = E->getTemplateArgs()) {
unsigned NumArgs = E->getNumTemplateArgs();
for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
Deps |= toExprDependence(Arg->getArgument().getDependence());
Deps |= toExprDependence(Arg->getArgument().getDependence() &
~TemplateArgumentDependence::Dependent);
}
auto *Decl = E->getDecl();
auto *Found = E->getFoundDecl();
auto Type = E->getType();
// FIXME: For a ParmVarDecl referenced in a function signature, we don't know
// its dependence yet!
if (!isa<ParmVarDecl>(Decl)) {
if (Decl->getDeclContext()->isDependentContext() ||
(Found && Found->getDeclContext()->isDependentContext()))
Deps |= ExprDependence::Instantiation;
}
if (Decl->isParameterPack())
Deps |= ExprDependence::UnexpandedPack;
Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error;

View File

@@ -416,12 +416,9 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
RefersToEnclosingVariableOrCapture;
DeclRefExprBits.NonOdrUseReason = NOUR;
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
Deps);
assert(!(Deps & TemplateArgumentDependence::Dependent) &&
"built a DeclRefExpr with dependent template args");
TemplateKWLoc, *TemplateArgs,
getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
@@ -1524,16 +1521,8 @@ MemberExpr *MemberExpr::Create(
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
NameInfo, T, VK, OK, NOUR);
// FIXME: remove remaining dependence computation to computeDependence().
auto Deps = E->getDependence();
// FIXME: Move this into the constructor.
if (HasQualOrFound) {
// FIXME: Wrong. We should be looking at the member declaration we found.
if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent())
Deps |= ExprDependence::TypeValueInstantiation;
else if (QualifierLoc &&
QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())
Deps |= ExprDependence::Instantiation;
E->MemberExprBits.HasQualifierOrFoundDecl = true;
MemberExprNameQualifier *NQ =
@@ -1546,16 +1535,26 @@ MemberExpr *MemberExpr::Create(
TemplateArgs || TemplateKWLoc.isValid();
if (TemplateArgs) {
auto TemplateArgDeps = TemplateArgumentDependence::None;
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *TemplateArgs,
E->getTrailingObjects<TemplateArgumentLoc>(), TemplateArgDeps);
if (TemplateArgDeps & TemplateArgumentDependence::Instantiation)
Deps |= ExprDependence::Instantiation;
E->getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
}
// FIXME: remove remaining dependence computation to computeDependence().
auto Deps = E->getDependence();
if (NestedNameSpecifier *Qual = E->getQualifier()) {
// FIXME: Wrong. We should be looking at the member declaration we found.
if (Qual->isDependent())
Deps |= ExprDependence::TypeValueInstantiation;
else if (Qual->isInstantiationDependent())
Deps |= ExprDependence::Instantiation;
}
if (TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
E->template_arguments()))
Deps |= ExprDependence::Instantiation;
E->setDependence(Deps);
return E;

View File

@@ -433,9 +433,8 @@ OverloadExpr::OverloadExpr(StmtClass SC, const ASTContext &Context,
}
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps);
TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc());
} else if (TemplateKWLoc.isValid()) {
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
@@ -464,9 +463,8 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(
DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo =
(Args != nullptr) || TemplateKWLoc.isValid();
if (Args) {
auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>(), Deps);
TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
@@ -1376,10 +1374,9 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
Deps);
TemplateKWLoc, *TemplateArgs,
getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);

View File

@@ -1819,7 +1819,8 @@ static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
EvalInfo &Info);
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
bool &Dependent);
/// Evaluate an integer or fixed point expression into an APResult.
static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
@@ -2107,7 +2108,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
CheckedTemporaries &CheckedTemps);
CheckedTemporaries &CheckedTemps,
bool &Dependent);
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
@@ -2115,7 +2117,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const LValue &LVal,
ConstantExprKind Kind,
CheckedTemporaries &CheckedTemps) {
CheckedTemporaries &CheckedTemps,
bool &Dependent) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
@@ -2200,6 +2203,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
}
if (BaseVD) {
Dependent |= BaseVD->isTemplated();
if (const VarDecl *Var = dyn_cast<const VarDecl>(BaseVD)) {
// Check if this is a thread-local variable.
if (Var->getTLSKind())
@@ -2230,6 +2235,9 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
}
} else if (const auto *MTE =
dyn_cast_or_null<MaterializeTemporaryExpr>(BaseE)) {
if (auto *Extending = MTE->getExtendingDecl())
Dependent |= Extending->isTemplated();
if (CheckedTemps.insert(MTE).second) {
QualType TempType = getType(Base);
if (TempType.isDestructedType()) {
@@ -2242,8 +2250,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
APValue *V = MTE->getOrCreateValue(false);
assert(V && "evasluation result refers to uninitialised temporary");
if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
Info, MTE->getExprLoc(), TempType, *V,
Kind, SourceLocation(), CheckedTemps))
Info, MTE->getExprLoc(), TempType, *V, Kind,
SourceLocation(), CheckedTemps, Dependent))
return false;
}
}
@@ -2272,13 +2280,15 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
/// Member pointers are constant expressions unless they point to a
/// non-virtual dllimport member function.
static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
SourceLocation Loc,
QualType Type,
const APValue &Value,
ConstantExprKind Kind) {
static bool
CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const APValue &Value,
ConstantExprKind Kind, bool &Dependent) {
const ValueDecl *Member = Value.getMemberPointerDecl();
const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
if (!Member)
return true;
Dependent |= Member->isTemplated();
const auto *FD = dyn_cast<CXXMethodDecl>(Member);
if (!FD)
return true;
if (FD->isConsteval()) {
@@ -2327,7 +2337,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
CheckedTemporaries &CheckedTemps) {
CheckedTemporaries &CheckedTemps,
bool &Dependent) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
@@ -2349,20 +2360,20 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayInitializedElt(I), Kind,
SubobjectLoc, CheckedTemps))
SubobjectLoc, CheckedTemps, Dependent))
return false;
}
if (!Value.hasArrayFiller())
return true;
return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayFiller(), Kind, SubobjectLoc,
CheckedTemps);
CheckedTemps, Dependent);
}
if (Value.isUnion() && Value.getUnionField()) {
return CheckEvaluationResult(
CERK, Info, DiagLoc, Value.getUnionField()->getType(),
Value.getUnionValue(), Kind, Value.getUnionField()->getLocation(),
CheckedTemps);
CheckedTemps, Dependent);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
@@ -2371,7 +2382,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
for (const CXXBaseSpecifier &BS : CD->bases()) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
Value.getStructBase(BaseIndex), Kind,
BS.getBeginLoc(), CheckedTemps))
BS.getBeginLoc(), CheckedTemps, Dependent))
return false;
++BaseIndex;
}
@@ -2381,8 +2392,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
continue;
if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex()),
Kind, I->getLocation(), CheckedTemps))
Value.getStructField(I->getFieldIndex()), Kind,
I->getLocation(), CheckedTemps, Dependent))
return false;
}
}
@@ -2392,12 +2403,13 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Kind,
CheckedTemps);
CheckedTemps, Dependent);
}
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
Kind, Dependent);
// Everything else is fine.
return true;
@@ -2408,7 +2420,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value,
ConstantExprKind Kind) {
ConstantExprKind Kind, bool &Dependent) {
// Nothing to check for a constant expression of type 'cv void'.
if (Type->isVoidType())
return true;
@@ -2416,17 +2428,18 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
Info, DiagLoc, Type, Value, Kind,
SourceLocation(), CheckedTemps);
SourceLocation(), CheckedTemps, Dependent);
}
/// Check that this evaluated value is fully-initialized and can be loaded by
/// an lvalue-to-rvalue conversion.
static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
bool Dependent = false;
CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(
CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
ConstantExprKind::Normal, SourceLocation(), CheckedTemps);
ConstantExprKind::Normal, SourceLocation(), CheckedTemps, Dependent);
}
/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
@@ -11098,7 +11111,9 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
ArgType->isAnyComplexType() || ArgType->isPointerType() ||
ArgType->isNullPtrType()) {
APValue V;
if (!::EvaluateAsRValue(Info, Arg, V) || Info.EvalStatus.HasSideEffects) {
bool Dependent = false;
if (!::EvaluateAsRValue(Info, Arg, V, Dependent) ||
Info.EvalStatus.HasSideEffects) {
Fold.keepDiagnostics();
return false;
}
@@ -11400,7 +11415,8 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
// It's possible for us to be given GLValues if we're called via
// Expr::tryEvaluateObjectSize.
APValue RVal;
if (!EvaluateAsRValue(Info, E, RVal))
bool Dependent = false;
if (!EvaluateAsRValue(Info, E, RVal, Dependent))
return false;
LVal.setFrom(Info.Ctx, RVal);
} else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info,
@@ -12829,8 +12845,9 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
LV.set(VD);
if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
return false;
bool Dependent = false;
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
ConstantExprKind::Normal);
ConstantExprKind::Normal, Dependent);
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
return ExprEvaluatorBaseTy::VisitBinCmp(E);
@@ -14594,7 +14611,8 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
bool &Dependent) {
assert(!E->isValueDependent());
if (Info.EnableNewConstInterp) {
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
@@ -14619,7 +14637,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
// Check this core constant expression is a constant expression.
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
ConstantExprKind::Normal) &&
ConstantExprKind::Normal, Dependent) &&
CheckMemoryLeaks(Info);
}
@@ -14665,7 +14683,7 @@ static bool EvaluateAsRValue(const Expr *E, Expr::EvalResult &Result,
if (FastEvaluateAsRValue(E, Result, Ctx, IsConst))
return IsConst;
return EvaluateAsRValue(Info, E, Result.Val);
return EvaluateAsRValue(Info, E, Result.Val, Result.Dependent);
}
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
@@ -14775,9 +14793,9 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
CheckedTemporaries CheckedTemps;
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
Ctx.getLValueReferenceType(getType()), LV,
ConstantExprKind::Normal, CheckedTemps))
!CheckLValueConstantExpression(
Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV,
ConstantExprKind::Normal, CheckedTemps, Result.Dependent))
return false;
LV.moveInto(Result.Val);
@@ -14836,7 +14854,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
if (!CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
Result.Val, Kind))
Result.Val, Kind, Result.Dependent))
return false;
if (!CheckMemoryLeaks(Info))
return false;
@@ -14900,8 +14918,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (!Info.discardCleanups())
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
}
bool Dependent = false;
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
ConstantExprKind::Normal) &&
ConstantExprKind::Normal, Dependent) &&
CheckMemoryLeaks(Info);
}
@@ -14968,7 +14987,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
Info.InConstantContext = true;
Info.CheckingForUndefinedBehavior = true;
bool Result = ::EvaluateAsRValue(Info, this, EVResult.Val);
bool Result = ::EvaluateAsRValue(this, EVResult, Ctx, Info);
(void)Result;
assert(Result && "Could not evaluate expression");
assert(EVResult.Val.isInt() && "Expression did not evaluate to integer");
@@ -14980,13 +14999,10 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
Info.CheckingForUndefinedBehavior = true;
(void)::EvaluateAsRValue(Info, this, EVResult.Val);
}
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
Info.CheckingForUndefinedBehavior = true;
(void)::EvaluateAsRValue(this, EVResult, Ctx, Info);
}
bool Expr::EvalResult::isGlobalLValue() const {
@@ -15536,8 +15552,9 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
bool Dependent = false;
bool IsConstExpr =
::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
::EvaluateAsRValue(Info, this, Result ? *Result : Scratch, Dependent) &&
// FIXME: We don't produce a diagnostic for this, but the callers that
// call us on arbitrary full-expressions should generally not care.
Info.discardCleanups() && !Status.HasSideEffects;

View File

@@ -131,25 +131,17 @@ TemplateArgumentDependence TemplateArgument::getDependence() const {
return TemplateArgumentDependence::Dependent |
TemplateArgumentDependence::Instantiation;
case Declaration: {
auto *DC = dyn_cast<DeclContext>(getAsDecl());
if (!DC)
DC = getAsDecl()->getDeclContext();
if (DC->isDependentContext())
Deps = TemplateArgumentDependence::Dependent |
TemplateArgumentDependence::Instantiation;
return Deps;
}
case NullPtr:
case Integral:
case Declaration:
return TemplateArgumentDependence::None;
case Expression:
Deps = toTemplateArgumentDependence(getAsExpr()->getDependence());
if (isa<PackExpansionExpr>(getAsExpr()))
Deps |= TemplateArgumentDependence::Dependent |
TemplateArgumentDependence::Instantiation;
// Instantiation-dependent expression arguments are considered dependent
// until they're resolved to another form.
if (Deps & TemplateArgumentDependence::Instantiation)
Deps |= TemplateArgumentDependence::Dependent;
return Deps;
case Pack:
@@ -544,8 +536,8 @@ ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
NumTemplateArgs = Info.size();
TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
for (unsigned i = 0; i != NumTemplateArgs; ++i)
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
ArgBuffer);
}
void ASTTemplateKWAndArgsInfo::initializeFrom(
@@ -555,9 +547,8 @@ void ASTTemplateKWAndArgsInfo::initializeFrom(
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
for (unsigned i = 0; i != NumTemplateArgs; ++i)
new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
OutArgArray);
}
void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
@@ -568,21 +559,6 @@ void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
NumTemplateArgs = 0;
}
void ASTTemplateKWAndArgsInfo::initializeFrom(
SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps) {
this->TemplateKWLoc = TemplateKWLoc;
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
for (unsigned i = 0; i != NumTemplateArgs; ++i) {
Deps |= Info[i].getArgument().getDependence();
new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
}
}
void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray,
TemplateArgumentListInfo &Info) const {
Info.setLAngleLoc(LAngleLoc);

View File

@@ -5619,7 +5619,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
QualType T, APValue &Value,
Sema::CCEKind CCE,
bool RequireInt,
NamedDecl *Dest) {
NamedDecl *Dest,
bool *ValueDependent) {
assert(S.getLangOpts().CPlusPlus11 &&
"converted constant expression outside C++11");
@@ -5743,6 +5744,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
if (Result.get()->isValueDependent()) {
Value = APValue();
if (ValueDependent)
*ValueDependent = true;
return Result;
}
@@ -5766,6 +5769,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
Result = ExprError();
} else {
Value = Eval.Val;
if (ValueDependent)
*ValueDependent = Eval.Dependent;
if (Notes.empty()) {
// It's a constant expression.
@@ -5796,9 +5801,10 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
NamedDecl *Dest) {
NamedDecl *Dest,
bool *ValueDependent) {
return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false,
Dest);
Dest, ValueDependent);
}
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
@@ -5808,7 +5814,8 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue V;
auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true,
/*Dest=*/nullptr);
/*Dest=*/nullptr,
/*ValueDependent=*/nullptr);
if (!R.isInvalid() && !R.get()->isValueDependent())
Value = V.getInt();
return R;

View File

@@ -6620,6 +6620,12 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg, ArgType))
return true;
// Don't build a resolved template argument naming a dependent declaration.
if (Entity->isTemplated()) {
Converted = TemplateArgument(ArgIn);
return false;
}
// Create the template argument.
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
S.Context.getCanonicalType(ParamType));
@@ -6634,8 +6640,6 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
QualType ParamType,
Expr *&ResultArg,
TemplateArgument &Converted) {
bool Invalid = false;
Expr *Arg = ResultArg;
bool ObjCLifetimeConversion;
@@ -6651,7 +6655,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
bool ExtraParens = false;
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid && !ExtraParens) {
if (!ExtraParens) {
S.Diag(Arg->getBeginLoc(),
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_template_arg_extra_parens
@@ -6680,13 +6684,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
ValueDecl *VD = DRE->getDecl();
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
} else {
VD = cast<ValueDecl>(VD->getCanonicalDecl());
Converted = TemplateArgument(VD, ParamType);
}
return Invalid;
Converted = TemplateArgument(Arg);
return false;
}
}
@@ -6745,7 +6744,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
}
return Invalid;
return false;
}
// We found something else, but we don't know specifically what it is.
@@ -6922,14 +6921,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// A template-argument for a non-type template parameter shall be
// a converted constant expression of the type of the template-parameter.
APValue Value;
bool ValueDependent = false;
ExprResult ArgResult = CheckConvertedConstantExpression(
Arg, ParamType, Value, CCEK_TemplateArg, Param);
Arg, ParamType, Value, CCEK_TemplateArg, Param, &ValueDependent);
if (ArgResult.isInvalid())
return ExprError();
// For a value-dependent argument, CheckConvertedConstantExpression is
// permitted (and expected) to be unable to determine a value.
if (ArgResult.get()->isValueDependent()) {
// permitted (and expected) to be unable to determine a value. We might find
// the evaluated result refers to a dependent declaration even though the
// template argument is not a value-dependent expression.
if (ValueDependent) {
Converted = TemplateArgument(ArgResult.get());
return ArgResult;
}

View File

@@ -3227,7 +3227,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (FunctionDecl *Pattern =
Function->getInstantiatedFromMemberFunction()) {
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
if (TSK != TSK_ImplicitInstantiation &&
Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo =
@@ -3272,7 +3273,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
continue;
if (Var->isStaticDataMember()) {
if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
if (TSK != TSK_ImplicitInstantiation &&
Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
@@ -3289,7 +3291,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
SuppressNew)
continue;
if (TSK == TSK_ExplicitInstantiationDefinition) {
if (TSK != TSK_ExplicitInstantiationDeclaration) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template

View File

@@ -35,7 +35,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}

View File

@@ -54,7 +54,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}

View File

@@ -55,7 +55,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}

View File

@@ -63,7 +63,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}

View File

@@ -46,7 +46,7 @@ T tmain(T argc, S **argv) {
#pragma omp target parallel for simd collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
// expected-error@+1 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
#pragma omp target parallel for simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target parallel for simd collapse (1)

View File

@@ -56,7 +56,7 @@ T tmain(T argc, S **argv) {
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
// expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
// expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp target parallel for simd' directive}}
#pragma omp target parallel for simd ordered(j = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];

View File

@@ -44,7 +44,7 @@ T tmain(T argc, S **argv) {
#pragma omp target simd collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
// expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
// expected-error@+1 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
#pragma omp target simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target simd collapse (1)

View File

@@ -45,7 +45,7 @@ T tmain(T argc) {
#pragma omp target teams distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -45,7 +45,7 @@ T tmain(T argc) {
#pragma omp target teams distribute parallel for dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -45,7 +45,7 @@ T tmain(T argc) {
#pragma omp target teams distribute parallel for simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -45,7 +45,7 @@ T tmain(T argc) {
#pragma omp target teams distribute simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -131,7 +131,7 @@ T tmain(T argc) {
#pragma omp target update from(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update from(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update from(s7.p[:10])
#pragma omp target update from(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'from' clause}}
#pragma omp target update from(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'from' clause}}
#pragma omp target update from(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
#pragma omp target data map(to: s7.i)
{

View File

@@ -138,7 +138,7 @@ T tmain(T argc) {
#pragma omp target update to(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update to(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update to(s7.p[:10])
#pragma omp target update to(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'to' clause}}
#pragma omp target update to(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'to' clause}}
#pragma omp target update to(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
#pragma omp target data map(to: s7.i)
{

View File

@@ -156,11 +156,11 @@ int foo() {
#pragma omp task detach(a) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'int'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'S'}}
;
#pragma omp task detach(evt) detach(evt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'const omp_event_handle_t' (aka 'const unsigned long')}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'omp_event_handle_t &' (aka 'unsigned long &')}}
#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
#pragma omp task detach(evt) mergeable // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'mergeable' and 'detach' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'detach' clause is specified here}}
;
#pragma omp task mergeable detach(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'detach' and 'mergeable' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'mergeable' clause is specified here}}
#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type}}
#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
;
#pragma omp task detach(evt) shared(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
#pragma omp task detach(evt) firstprivate(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}

View File

@@ -55,7 +55,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -55,7 +55,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -55,7 +55,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -55,7 +55,7 @@ T tmain(T argc) {
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();

View File

@@ -147,7 +147,7 @@ void test_templated() {
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}

View File

@@ -503,3 +503,13 @@ namespace PR48517 {
template<> struct Q<&R<int>::n> { static constexpr int X = 1; };
static_assert(R<int>().f() == 1);
}
namespace dependent_reference {
template<int &r> struct S { int *q = &r; };
template<int> auto f() { static int n; return S<n>(); }
auto v = f<0>();
auto w = f<1>();
static_assert(!is_same<decltype(v), decltype(w)>);
// Ensure that we can instantiate the definition of S<...>.
int n = *v.q + *w.q;
}

View File

@@ -292,3 +292,47 @@ namespace Predefined {
Y<B{__func__[0]}>(); // expected-error {{reference to subobject of predefined '__func__' variable}}
}
}
namespace dependent {
template<auto &V> struct R { static inline auto &v = V; };
template<auto &V, auto &W> constexpr bool operator==(R<V>, R<W>) { return &V == &W; }
template<auto *V> struct S { static inline auto *v = V; };
template<auto *V, auto *W> constexpr bool operator==(S<V>, S<W>) { return V == W; }
template<auto V> struct T { static inline const auto &v = V; };
template<auto V, auto W> constexpr bool operator==(T<V>, T<W>) { return &V == &W; }
template<typename T> struct V { T v; };
template<int N> auto f() {
static int n;
static V<int> vn;
if constexpr (N < 10)
return R<n>();
else if constexpr (N < 20)
return R<vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
else if constexpr (N < 30)
return S<&n>();
else if constexpr (N < 40)
return S<&vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
else if constexpr (N < 50)
return T<V<int&>{n}>();
else if constexpr (N < 60)
return T<V<int*>{&n}>();
else if constexpr (N < 70)
return T<V<int&>{vn.v}>();
else if constexpr (N < 80)
return T<V<int*>{&vn.v}>();
}
template<int Base> void check() {
auto v = f<Base + 0>(); // FIXME: expected-note 2{{instantiation of}}
auto w = f<Base + 1>(); // FIXME: expected-note 2{{instantiation of}}
static_assert(!__is_same(decltype(v), decltype(w)));
static_assert(v != w);
}
template void check<0>();
template void check<10>(); // FIXME: expected-note 2{{instantiation of}}
template void check<20>();
template void check<30>(); // FIXME: expected-note 2{{instantiation of}}
template void check<40>();
template void check<50>();
template void check<60>();
template void check<70>();
}