forked from OSchip/llvm-project
For DR712: store on a DeclRefExpr whether it constitutes an odr-use.
Begin restructuring to support the forms of non-odr-use reference permitted by DR712. llvm-svn: 363086
This commit is contained in:
parent
ef2d6d99c0
commit
715f7a1bd0
|
@ -1226,10 +1226,15 @@ public:
|
|||
|
||||
void setInit(Expr *I);
|
||||
|
||||
/// Determine whether this variable's value can be used in a
|
||||
/// Determine whether this variable's value might be usable in a
|
||||
/// constant expression, according to the relevant language standard.
|
||||
/// This only checks properties of the declaration, and does not check
|
||||
/// whether the initializer is in fact a constant expression.
|
||||
bool mightBeUsableInConstantExpressions(ASTContext &C) const;
|
||||
|
||||
/// Determine whether this variable's value can be used in a
|
||||
/// constant expression, according to the relevant language standard,
|
||||
/// including checking whether it was initialized by a constant expression.
|
||||
bool isUsableInConstantExpressions(ASTContext &C) const;
|
||||
|
||||
EvaluatedStmt *ensureEvaluatedStmt() const;
|
||||
|
|
|
@ -1115,7 +1115,7 @@ class DeclRefExpr final
|
|||
bool RefersToEnlosingVariableOrCapture,
|
||||
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
|
||||
const TemplateArgumentListInfo *TemplateArgs, QualType T,
|
||||
ExprValueKind VK);
|
||||
ExprValueKind VK, NonOdrUseReason NOUR);
|
||||
|
||||
/// Construct an empty declaration reference expression.
|
||||
explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {}
|
||||
|
@ -1128,14 +1128,16 @@ public:
|
|||
DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
|
||||
bool RefersToEnclosingVariableOrCapture, QualType T,
|
||||
ExprValueKind VK, SourceLocation L,
|
||||
const DeclarationNameLoc &LocInfo = DeclarationNameLoc());
|
||||
const DeclarationNameLoc &LocInfo = DeclarationNameLoc(),
|
||||
NonOdrUseReason NOUR = NOUR_None);
|
||||
|
||||
static DeclRefExpr *
|
||||
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *D,
|
||||
bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc,
|
||||
QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr,
|
||||
const TemplateArgumentListInfo *TemplateArgs = nullptr);
|
||||
const TemplateArgumentListInfo *TemplateArgs = nullptr,
|
||||
NonOdrUseReason NOUR = NOUR_None);
|
||||
|
||||
static DeclRefExpr *
|
||||
Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
|
||||
|
@ -1143,7 +1145,8 @@ public:
|
|||
bool RefersToEnclosingVariableOrCapture,
|
||||
const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK,
|
||||
NamedDecl *FoundD = nullptr,
|
||||
const TemplateArgumentListInfo *TemplateArgs = nullptr);
|
||||
const TemplateArgumentListInfo *TemplateArgs = nullptr,
|
||||
NonOdrUseReason NOUR = NOUR_None);
|
||||
|
||||
/// Construct an empty declaration reference expression.
|
||||
static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
|
||||
|
@ -1274,6 +1277,11 @@ public:
|
|||
DeclRefExprBits.HadMultipleCandidates = V;
|
||||
}
|
||||
|
||||
/// Is this expression a non-odr-use reference, and if so, why?
|
||||
NonOdrUseReason isNonOdrUse() const {
|
||||
return static_cast<NonOdrUseReason>(DeclRefExprBits.NonOdrUseReason);
|
||||
}
|
||||
|
||||
/// Does this DeclRefExpr refer to an enclosing local or a captured
|
||||
/// variable?
|
||||
bool refersToEnclosingVariableOrCapture() const {
|
||||
|
|
|
@ -351,6 +351,7 @@ protected:
|
|||
unsigned HasFoundDecl : 1;
|
||||
unsigned HadMultipleCandidates : 1;
|
||||
unsigned RefersToEnclosingVariableOrCapture : 1;
|
||||
unsigned NonOdrUseReason : 2;
|
||||
|
||||
/// The location of the declaration name itself.
|
||||
SourceLocation Loc;
|
||||
|
|
|
@ -148,6 +148,20 @@ namespace clang {
|
|||
OK_ObjCSubscript
|
||||
};
|
||||
|
||||
/// The reason why a DeclRefExpr does not constitute an odr-use.
|
||||
enum NonOdrUseReason {
|
||||
/// This is an odr-use.
|
||||
NOUR_None = 0,
|
||||
/// This name appears in an unevaluated operand.
|
||||
NOUR_Unevaluated,
|
||||
/// This name appears as a potential result of an lvalue-to-rvalue
|
||||
/// conversion that is a constant expression.
|
||||
NOUR_Constant,
|
||||
/// This name appears as a potential result of a discarded value
|
||||
/// expression.
|
||||
NOUR_Discarded,
|
||||
};
|
||||
|
||||
/// Describes the kind of template specialization that a
|
||||
/// particular template specialization declaration represents.
|
||||
enum TemplateSpecializationKind {
|
||||
|
|
|
@ -4185,7 +4185,7 @@ public:
|
|||
void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc,
|
||||
unsigned CapturingScopeIndex);
|
||||
|
||||
void UpdateMarkingForLValueToRValue(Expr *E);
|
||||
ExprResult CheckLValueToRValueConversionOperand(Expr *E);
|
||||
void CleanupVarDeclMarking();
|
||||
|
||||
enum TryCaptureKind {
|
||||
|
|
|
@ -38,15 +38,6 @@ FTIHasNonVoidParameters(const DeclaratorChunk::FunctionTypeInfo &FTI) {
|
|||
return FTI.NumParams && !FTIHasSingleVoidParameter(FTI);
|
||||
}
|
||||
|
||||
// This requires the variable to be non-dependent and the initializer
|
||||
// to not be value dependent.
|
||||
inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) {
|
||||
const VarDecl *DefVD = nullptr;
|
||||
return !isa<ParmVarDecl>(Var) &&
|
||||
Var->isUsableInConstantExpressions(Context) &&
|
||||
Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE();
|
||||
}
|
||||
|
||||
// Helper function to check whether D's attributes match current CUDA mode.
|
||||
// Decls with mismatched attributes and related diagnostics may have to be
|
||||
// ignored during this CUDA compilation pass.
|
||||
|
|
|
@ -6189,7 +6189,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
auto *ToE = DeclRefExpr::Create(
|
||||
Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl,
|
||||
E->refersToEnclosingVariableOrCapture(), ToLocation, ToType,
|
||||
E->getValueKind(), ToFoundD, ToResInfo);
|
||||
E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse());
|
||||
if (E->hadMultipleCandidates())
|
||||
ToE->setHadMultipleCandidates(true);
|
||||
return ToE;
|
||||
|
|
|
@ -2245,12 +2245,16 @@ void VarDecl::setInit(Expr *I) {
|
|||
Init = I;
|
||||
}
|
||||
|
||||
bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
|
||||
bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const {
|
||||
const LangOptions &Lang = C.getLangOpts();
|
||||
|
||||
if (!Lang.CPlusPlus)
|
||||
return false;
|
||||
|
||||
// Function parameters are never usable in constant expressions.
|
||||
if (isa<ParmVarDecl>(this))
|
||||
return false;
|
||||
|
||||
// In C++11, any variable of reference type can be used in a constant
|
||||
// expression if it is initialized by a constant expression.
|
||||
if (Lang.CPlusPlus11 && getType()->isReferenceType())
|
||||
|
@ -2272,6 +2276,22 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
|
|||
return Lang.CPlusPlus11 && isConstexpr();
|
||||
}
|
||||
|
||||
bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const {
|
||||
// C++2a [expr.const]p3:
|
||||
// A variable is usable in constant expressions after its initializing
|
||||
// declaration is encountered...
|
||||
const VarDecl *DefVD = nullptr;
|
||||
const Expr *Init = getAnyInitializer(DefVD);
|
||||
if (!Init || Init->isValueDependent())
|
||||
return false;
|
||||
// ... if it is a constexpr variable, or it is of reference type or of
|
||||
// const-qualified integral or enumeration type, ...
|
||||
if (!DefVD->mightBeUsableInConstantExpressions(Context))
|
||||
return false;
|
||||
// ... and its initializer is a constant initializer.
|
||||
return DefVD->checkInitIsICE();
|
||||
}
|
||||
|
||||
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
|
||||
/// form, which contains extra information on the evaluated value of the
|
||||
/// initializer.
|
||||
|
|
|
@ -344,7 +344,8 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
|
|||
DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
|
||||
bool RefersToEnclosingVariableOrCapture, QualType T,
|
||||
ExprValueKind VK, SourceLocation L,
|
||||
const DeclarationNameLoc &LocInfo)
|
||||
const DeclarationNameLoc &LocInfo,
|
||||
NonOdrUseReason NOUR)
|
||||
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
|
||||
D(D), DNLoc(LocInfo) {
|
||||
DeclRefExprBits.HasQualifier = false;
|
||||
|
@ -353,6 +354,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
|
|||
DeclRefExprBits.HadMultipleCandidates = false;
|
||||
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
|
||||
RefersToEnclosingVariableOrCapture;
|
||||
DeclRefExprBits.NonOdrUseReason = NOUR;
|
||||
DeclRefExprBits.Loc = L;
|
||||
computeDependence(Ctx);
|
||||
}
|
||||
|
@ -363,7 +365,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
|
|||
bool RefersToEnclosingVariableOrCapture,
|
||||
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
QualType T, ExprValueKind VK)
|
||||
QualType T, ExprValueKind VK, NonOdrUseReason NOUR)
|
||||
: Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false),
|
||||
D(D), DNLoc(NameInfo.getInfo()) {
|
||||
DeclRefExprBits.Loc = NameInfo.getLoc();
|
||||
|
@ -384,6 +386,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
|
|||
= (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0;
|
||||
DeclRefExprBits.RefersToEnclosingVariableOrCapture =
|
||||
RefersToEnclosingVariableOrCapture;
|
||||
DeclRefExprBits.NonOdrUseReason = NOUR;
|
||||
if (TemplateArgs) {
|
||||
bool Dependent = false;
|
||||
bool InstantiationDependent = false;
|
||||
|
@ -405,30 +408,27 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
|
|||
|
||||
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *D,
|
||||
bool RefersToEnclosingVariableOrCapture,
|
||||
SourceLocation NameLoc,
|
||||
QualType T,
|
||||
ExprValueKind VK,
|
||||
NamedDecl *FoundD,
|
||||
const TemplateArgumentListInfo *TemplateArgs) {
|
||||
SourceLocation NameLoc, QualType T,
|
||||
ExprValueKind VK, NamedDecl *FoundD,
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
NonOdrUseReason NOUR) {
|
||||
return Create(Context, QualifierLoc, TemplateKWLoc, D,
|
||||
RefersToEnclosingVariableOrCapture,
|
||||
DeclarationNameInfo(D->getDeclName(), NameLoc),
|
||||
T, VK, FoundD, TemplateArgs);
|
||||
T, VK, FoundD, TemplateArgs, NOUR);
|
||||
}
|
||||
|
||||
DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateKWLoc,
|
||||
ValueDecl *D,
|
||||
SourceLocation TemplateKWLoc, ValueDecl *D,
|
||||
bool RefersToEnclosingVariableOrCapture,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
QualType T,
|
||||
ExprValueKind VK,
|
||||
QualType T, ExprValueKind VK,
|
||||
NamedDecl *FoundD,
|
||||
const TemplateArgumentListInfo *TemplateArgs) {
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
NonOdrUseReason NOUR) {
|
||||
// Filter out cases where the found Decl is the same as the value refenenced.
|
||||
if (D == FoundD)
|
||||
FoundD = nullptr;
|
||||
|
@ -443,8 +443,8 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
|
|||
|
||||
void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
|
||||
return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
|
||||
RefersToEnclosingVariableOrCapture,
|
||||
NameInfo, FoundD, TemplateArgs, T, VK);
|
||||
RefersToEnclosingVariableOrCapture, NameInfo,
|
||||
FoundD, TemplateArgs, T, VK, NOUR);
|
||||
}
|
||||
|
||||
DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
|
||||
|
|
|
@ -805,6 +805,12 @@ void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) {
|
|||
if (DRE->getDecl() != DRE->getFoundDecl())
|
||||
JOS.attribute("foundReferencedDecl",
|
||||
createBareDeclRef(DRE->getFoundDecl()));
|
||||
switch (DRE->isNonOdrUse()) {
|
||||
case NOUR_None: break;
|
||||
case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
|
||||
case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
|
||||
case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
|
||||
}
|
||||
}
|
||||
|
||||
void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {
|
||||
|
|
|
@ -715,6 +715,12 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
|
|||
dumpBareDeclRef(Node->getFoundDecl());
|
||||
OS << ")";
|
||||
}
|
||||
switch (Node->isNonOdrUse()) {
|
||||
case NOUR_None: break;
|
||||
case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
|
||||
case NOUR_Constant: OS << " non_odr_use_constant"; break;
|
||||
case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
|
||||
}
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitUnresolvedLookupExpr(
|
||||
|
|
|
@ -1783,8 +1783,8 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
|
|||
}
|
||||
|
||||
llvm::Constant *constant = nullptr;
|
||||
if (emission.IsConstantAggregate || D.isConstexpr() ||
|
||||
D.isUsableInConstantExpressions(getContext())) {
|
||||
if (emission.IsConstantAggregate ||
|
||||
D.mightBeUsableInConstantExpressions(getContext())) {
|
||||
assert(!capturedByInit && "constant init contains a capturing block?");
|
||||
constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(D);
|
||||
if (constant && !constant->isZeroValue() &&
|
||||
|
|
|
@ -1398,7 +1398,7 @@ static bool isConstantEmittableObjectType(QualType type) {
|
|||
|
||||
/// Can we constant-emit a load of a reference to a variable of the
|
||||
/// given type? This is different from predicates like
|
||||
/// Decl::isUsableInConstantExpressions because we do want it to apply
|
||||
/// Decl::mightBeUsableInConstantExpressions because we do want it to apply
|
||||
/// in situations that don't necessarily satisfy the language's rules
|
||||
/// for this (e.g. C++'s ODR-use rules). For example, we want to able
|
||||
/// to do this with const float variables even if those variables
|
||||
|
@ -1492,11 +1492,17 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
|
|||
static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
|
||||
const MemberExpr *ME) {
|
||||
if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
|
||||
// FIXME: Copy this from the MemberExpr once we store it there.
|
||||
NonOdrUseReason NOUR = NOUR_None;
|
||||
if (VD->getType()->isReferenceType() &&
|
||||
VD->isUsableInConstantExpressions(CGF.getContext()))
|
||||
NOUR = NOUR_Constant;
|
||||
|
||||
// Try to emit static variable member expressions as DREs.
|
||||
return DeclRefExpr::Create(
|
||||
CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
|
||||
/*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
|
||||
ME->getType(), ME->getValueKind());
|
||||
ME->getType(), ME->getValueKind(), nullptr, nullptr, NOUR);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2462,12 +2468,11 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
|
||||
// A DeclRefExpr for a reference initialized by a constant expression can
|
||||
// appear without being odr-used. Directly emit the constant initializer.
|
||||
const Expr *Init = VD->getAnyInitializer(VD);
|
||||
VD->getAnyInitializer(VD);
|
||||
const auto *BD = dyn_cast_or_null<BlockDecl>(CurCodeDecl);
|
||||
if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
|
||||
VD->isUsableInConstantExpressions(getContext()) &&
|
||||
VD->checkInitIsICE() &&
|
||||
if (E->isNonOdrUse() == NOUR_Constant && VD->getType()->isReferenceType() &&
|
||||
// Do not emit if it is private OpenMP variable.
|
||||
// FIXME: This should be handled in odr-use marking, not here.
|
||||
!(E->refersToEnclosingVariableOrCapture() &&
|
||||
((CapturedStmtInfo &&
|
||||
(LocalDeclMap.count(VD->getCanonicalDecl()) ||
|
||||
|
@ -2489,6 +2494,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl);
|
||||
}
|
||||
|
||||
// FIXME: Handle other kinds of non-odr-use DeclRefExprs.
|
||||
|
||||
// Check for captured variables.
|
||||
if (E->refersToEnclosingVariableOrCapture()) {
|
||||
VD = VD->getCanonicalDecl();
|
||||
|
|
|
@ -587,7 +587,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
|
|||
// warn even if the variable isn't odr-used. (isReferenced doesn't
|
||||
// precisely reflect that, but it's a decent approximation.)
|
||||
if (VD->isReferenced() &&
|
||||
VD->isUsableInConstantExpressions(SemaRef->Context))
|
||||
VD->mightBeUsableInConstantExpressions(SemaRef->Context))
|
||||
return true;
|
||||
|
||||
if (VarTemplateDecl *Template = VD->getDescribedVarTemplate())
|
||||
|
|
|
@ -5231,15 +5231,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
|
|||
}
|
||||
|
||||
// Create a new DeclRefExpr to refer to the new decl.
|
||||
DeclRefExpr* NewDRE = DeclRefExpr::Create(
|
||||
Context,
|
||||
DRE->getQualifierLoc(),
|
||||
SourceLocation(),
|
||||
NewBuiltinDecl,
|
||||
/*enclosing*/ false,
|
||||
DRE->getLocation(),
|
||||
Context.BuiltinFnTy,
|
||||
DRE->getValueKind());
|
||||
DeclRefExpr *NewDRE = DeclRefExpr::Create(
|
||||
Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl,
|
||||
/*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
|
||||
DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
|
||||
|
||||
// Set the callee in the CallExpr.
|
||||
// FIXME: This loses syntactic information.
|
||||
|
|
|
@ -11994,7 +11994,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
|||
for (unsigned I = 0, N = Notes.size(); I != N; ++I)
|
||||
Diag(Notes[I].first, Notes[I].second);
|
||||
}
|
||||
} else if (var->isUsableInConstantExpressions(Context)) {
|
||||
} else if (var->mightBeUsableInConstantExpressions(Context)) {
|
||||
// Check whether the initializer of a const variable of integral or
|
||||
// enumeration type is an ICE now, since we can't tell whether it was
|
||||
// initialized by a constant expression if we check later.
|
||||
|
|
|
@ -625,15 +625,18 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
|
|||
Context.getTargetInfo().getCXXABI().isMicrosoft())
|
||||
(void)isCompleteType(E->getExprLoc(), T);
|
||||
|
||||
UpdateMarkingForLValueToRValue(E);
|
||||
ExprResult Res = CheckLValueToRValueConversionOperand(E);
|
||||
if (Res.isInvalid())
|
||||
return Res;
|
||||
E = Res.get();
|
||||
|
||||
// Loading a __weak object implicitly retains the value, so we need a cleanup to
|
||||
// balance that.
|
||||
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
|
||||
Cleanup.setExprNeedsCleanups(true);
|
||||
|
||||
ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
|
||||
nullptr, VK_RValue);
|
||||
Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E, nullptr,
|
||||
VK_RValue);
|
||||
|
||||
// C11 6.3.2.1p2:
|
||||
// ... if the lvalue has atomic type, the value has the non-atomic version
|
||||
|
@ -1794,9 +1797,19 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
|
|||
isa<VarDecl>(D) &&
|
||||
NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
|
||||
|
||||
NonOdrUseReason NOUR;
|
||||
if (isUnevaluatedContext())
|
||||
NOUR = NOUR_Unevaluated;
|
||||
else if (isa<VarDecl>(D) && D->getType()->isReferenceType() &&
|
||||
!(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
|
||||
cast<VarDecl>(D)->isUsableInConstantExpressions(Context))
|
||||
NOUR = NOUR_Constant;
|
||||
else
|
||||
NOUR = NOUR_None;
|
||||
|
||||
DeclRefExpr *E = DeclRefExpr::Create(Context, NNS, TemplateKWLoc, D,
|
||||
RefersToCapturedVariable, NameInfo, Ty,
|
||||
VK, FoundD, TemplateArgs);
|
||||
VK, FoundD, TemplateArgs, NOUR);
|
||||
MarkDeclRefReferenced(E);
|
||||
|
||||
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
|
||||
|
@ -5626,7 +5639,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
|
|||
NDecl = FDecl;
|
||||
Fn = DeclRefExpr::Create(
|
||||
Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false,
|
||||
SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl);
|
||||
SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl,
|
||||
nullptr, DRE->isNonOdrUse());
|
||||
}
|
||||
}
|
||||
} else if (isa<MemberExpr>(NakedFn))
|
||||
|
@ -15779,59 +15793,258 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
|
|||
return DeclRefType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If either the type of the variable or the initializer is dependent,
|
||||
// return false. Otherwise, determine whether the variable is a constant
|
||||
// expression. Use this if you need to know if a variable that might or
|
||||
// might not be dependent is truly a constant expression.
|
||||
static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
|
||||
ASTContext &Context) {
|
||||
|
||||
if (Var->getType()->isDependentType())
|
||||
return false;
|
||||
const VarDecl *DefVD = nullptr;
|
||||
Var->getAnyInitializer(DefVD);
|
||||
if (!DefVD)
|
||||
return false;
|
||||
EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
|
||||
Expr *Init = cast<Expr>(Eval->Value);
|
||||
if (Init->isValueDependent())
|
||||
return false;
|
||||
return IsVariableAConstantExpression(Var, Context);
|
||||
}
|
||||
|
||||
|
||||
void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
|
||||
/// Walk the set of potential results of an expression and mark them all as
|
||||
/// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason.
|
||||
///
|
||||
/// \return A new expression if we found any potential results, ExprEmpty() if
|
||||
/// not, and ExprError() if we diagnosed an error.
|
||||
static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
|
||||
NonOdrUseReason NOUR) {
|
||||
// Per C++11 [basic.def.odr], a variable is odr-used "unless it is
|
||||
// an object that satisfies the requirements for appearing in a
|
||||
// constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
|
||||
// is immediately applied." This function handles the lvalue-to-rvalue
|
||||
// conversion part.
|
||||
MaybeODRUseExprs.erase(E->IgnoreParens());
|
||||
//
|
||||
// If we encounter a node that claims to be an odr-use but shouldn't be, we
|
||||
// transform it into the relevant kind of non-odr-use node and rebuild the
|
||||
// tree of nodes leading to it.
|
||||
//
|
||||
// This is a mini-TreeTransform that only transforms a restricted subset of
|
||||
// nodes (and only certain operands of them).
|
||||
|
||||
// If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
|
||||
// to a variable that is a constant expression, and if so, identify it as
|
||||
// a reference to a variable that does not involve an odr-use of that
|
||||
// variable.
|
||||
if (LambdaScopeInfo *LSI = getCurLambda()) {
|
||||
Expr *SansParensExpr = E->IgnoreParens();
|
||||
VarDecl *Var;
|
||||
ArrayRef<VarDecl *> Vars(&Var, &Var + 1);
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
|
||||
Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
||||
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
|
||||
Var = dyn_cast<VarDecl>(ME->getMemberDecl());
|
||||
else if (auto *FPPE = dyn_cast<FunctionParmPackExpr>(SansParensExpr))
|
||||
Vars = llvm::makeArrayRef(FPPE->begin(), FPPE->end());
|
||||
else
|
||||
Vars = None;
|
||||
// Rebuild a subexpression.
|
||||
auto Rebuild = [&](Expr *Sub) {
|
||||
return rebuildPotentialResultsAsNonOdrUsed(S, Sub, NOUR);
|
||||
};
|
||||
|
||||
for (VarDecl *VD : Vars) {
|
||||
if (VD && IsVariableNonDependentAndAConstantExpression(VD, Context))
|
||||
LSI->markVariableExprAsNonODRUsed(SansParensExpr);
|
||||
// Check whether a potential result satisfies the requirements of NOUR.
|
||||
auto IsPotentialResultOdrUsed = [&](NamedDecl *D) {
|
||||
// Any entity other than a VarDecl is always odr-used whenever it's named
|
||||
// in a potentially-evaluated expression.
|
||||
auto *VD = dyn_cast<VarDecl>(D);
|
||||
if (!VD)
|
||||
return true;
|
||||
|
||||
// C++2a [basic.def.odr]p4:
|
||||
// A variable x whose name appears as a potentially-evalauted expression
|
||||
// e is odr-used by e unless
|
||||
// -- x is a reference that is usable in constant expressions, or
|
||||
// -- x is a variable of non-reference type that is usable in constant
|
||||
// expressions and has no mutable subobjects, and e is an element of
|
||||
// the set of potential results of an expression of
|
||||
// non-volatile-qualified non-class type to which the lvalue-to-rvalue
|
||||
// conversion is applied, or
|
||||
// -- x is a variable of non-reference type, and e is an element of the
|
||||
// set of potential results of a discarded-value expression to which
|
||||
// the lvalue-to-rvalue conversion is not applied
|
||||
//
|
||||
// We check the first bullet and the "potentially-evaluated" condition in
|
||||
// BuildDeclRefExpr. We check the type requirements in the second bullet
|
||||
// in CheckLValueToRValueConversionOperand below.
|
||||
switch (NOUR) {
|
||||
case NOUR_None:
|
||||
case NOUR_Unevaluated:
|
||||
llvm_unreachable("unexpected non-odr-use-reason");
|
||||
|
||||
case NOUR_Constant:
|
||||
// Constant references were handled when they were built.
|
||||
if (VD->getType()->isReferenceType())
|
||||
return true;
|
||||
if (auto *RD = VD->getType()->getAsCXXRecordDecl())
|
||||
if (RD->hasMutableFields())
|
||||
return true;
|
||||
if (!VD->isUsableInConstantExpressions(S.Context))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case NOUR_Discarded:
|
||||
if (VD->getType()->isReferenceType())
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Mark that this expression does not constitute an odr-use.
|
||||
auto MarkNotOdrUsed = [&] {
|
||||
S.MaybeODRUseExprs.erase(E);
|
||||
if (LambdaScopeInfo *LSI = S.getCurLambda())
|
||||
LSI->markVariableExprAsNonODRUsed(E);
|
||||
};
|
||||
|
||||
// C++2a [basic.def.odr]p2:
|
||||
// The set of potential results of an expression e is defined as follows:
|
||||
switch (E->getStmtClass()) {
|
||||
// -- If e is an id-expression, ...
|
||||
case Expr::DeclRefExprClass: {
|
||||
auto *DRE = cast<DeclRefExpr>(E);
|
||||
if (DRE->isNonOdrUse() || IsPotentialResultOdrUsed(DRE->getDecl()))
|
||||
break;
|
||||
|
||||
// Rebuild as a non-odr-use DeclRefExpr.
|
||||
MarkNotOdrUsed();
|
||||
TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
|
||||
if (DRE->hasExplicitTemplateArgs()) {
|
||||
DRE->copyTemplateArgumentsInto(TemplateArgStorage);
|
||||
TemplateArgs = &TemplateArgStorage;
|
||||
}
|
||||
return DeclRefExpr::Create(
|
||||
S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),
|
||||
DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),
|
||||
DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),
|
||||
DRE->getFoundDecl(), TemplateArgs, NOUR);
|
||||
}
|
||||
|
||||
case Expr::FunctionParmPackExprClass: {
|
||||
auto *FPPE = cast<FunctionParmPackExpr>(E);
|
||||
// If any of the declarations in the pack is odr-used, then the expression
|
||||
// as a whole constitutes an odr-use.
|
||||
for (VarDecl *D : *FPPE)
|
||||
if (IsPotentialResultOdrUsed(D))
|
||||
return ExprEmpty();
|
||||
|
||||
// FIXME: Rebuild as a non-odr-use FunctionParmPackExpr? In practice,
|
||||
// nothing cares about whether we marked this as an odr-use, but it might
|
||||
// be useful for non-compiler tools.
|
||||
MarkNotOdrUsed();
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: Implement these.
|
||||
// -- If e is a subscripting operation with an array operand...
|
||||
// -- If e is a class member access expression [...] naming a non-static
|
||||
// data member...
|
||||
|
||||
// -- If e is a class member access expression naming a static data member,
|
||||
// ...
|
||||
case Expr::MemberExprClass: {
|
||||
auto *ME = cast<MemberExpr>(E);
|
||||
if (ME->getMemberDecl()->isCXXInstanceMember())
|
||||
// FIXME: Recurse to the left-hand side.
|
||||
break;
|
||||
|
||||
// FIXME: Track whether a MemberExpr constitutes an odr-use; bail out here
|
||||
// if we've already marked it.
|
||||
if (IsPotentialResultOdrUsed(ME->getMemberDecl()))
|
||||
break;
|
||||
|
||||
// FIXME: Rebuild as a non-odr-use MemberExpr.
|
||||
MarkNotOdrUsed();
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
// FIXME: Implement this.
|
||||
// -- If e is a pointer-to-member expression of the form e1 .* e2 ...
|
||||
|
||||
// -- If e has the form (e1)...
|
||||
case Expr::ParenExprClass: {
|
||||
auto *PE = dyn_cast<ParenExpr>(E);
|
||||
ExprResult Sub = Rebuild(PE->getSubExpr());
|
||||
if (!Sub.isUsable())
|
||||
return Sub;
|
||||
return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get());
|
||||
}
|
||||
|
||||
// FIXME: Implement these.
|
||||
// -- If e is a glvalue conditional expression, ...
|
||||
// -- If e is a comma expression, ...
|
||||
|
||||
// [Clang extension]
|
||||
// -- If e has the form __extension__ e1...
|
||||
case Expr::UnaryOperatorClass: {
|
||||
auto *UO = cast<UnaryOperator>(E);
|
||||
if (UO->getOpcode() != UO_Extension)
|
||||
break;
|
||||
ExprResult Sub = Rebuild(UO->getSubExpr());
|
||||
if (!Sub.isUsable())
|
||||
return Sub;
|
||||
return S.BuildUnaryOp(nullptr, UO->getOperatorLoc(), UO_Extension,
|
||||
Sub.get());
|
||||
}
|
||||
|
||||
// [Clang extension]
|
||||
// -- If e has the form _Generic(...), the set of potential results is the
|
||||
// union of the sets of potential results of the associated expressions.
|
||||
case Expr::GenericSelectionExprClass: {
|
||||
auto *GSE = dyn_cast<GenericSelectionExpr>(E);
|
||||
|
||||
SmallVector<Expr *, 4> AssocExprs;
|
||||
bool AnyChanged = false;
|
||||
for (Expr *OrigAssocExpr : GSE->getAssocExprs()) {
|
||||
ExprResult AssocExpr = Rebuild(OrigAssocExpr);
|
||||
if (AssocExpr.isInvalid())
|
||||
return ExprError();
|
||||
if (AssocExpr.isUsable()) {
|
||||
AssocExprs.push_back(AssocExpr.get());
|
||||
AnyChanged = true;
|
||||
} else {
|
||||
AssocExprs.push_back(OrigAssocExpr);
|
||||
}
|
||||
}
|
||||
|
||||
return AnyChanged ? S.CreateGenericSelectionExpr(
|
||||
GSE->getGenericLoc(), GSE->getDefaultLoc(),
|
||||
GSE->getRParenLoc(), GSE->getControllingExpr(),
|
||||
GSE->getAssocTypeSourceInfos(), AssocExprs)
|
||||
: ExprEmpty();
|
||||
}
|
||||
|
||||
// [Clang extension]
|
||||
// -- If e has the form __builtin_choose_expr(...), the set of potential
|
||||
// results is the union of the sets of potential results of the
|
||||
// second and third subexpressions.
|
||||
case Expr::ChooseExprClass: {
|
||||
auto *CE = dyn_cast<ChooseExpr>(E);
|
||||
|
||||
ExprResult LHS = Rebuild(CE->getLHS());
|
||||
if (LHS.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
ExprResult RHS = Rebuild(CE->getLHS());
|
||||
if (RHS.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
if (!LHS.get() && !RHS.get())
|
||||
return ExprEmpty();
|
||||
if (!LHS.isUsable())
|
||||
LHS = CE->getLHS();
|
||||
if (!RHS.isUsable())
|
||||
RHS = CE->getRHS();
|
||||
|
||||
return S.ActOnChooseExpr(CE->getBuiltinLoc(), CE->getCond(), LHS.get(),
|
||||
RHS.get(), CE->getRParenLoc());
|
||||
}
|
||||
|
||||
// Step through non-syntactic nodes.
|
||||
case Expr::ConstantExprClass: {
|
||||
auto *CE = dyn_cast<ConstantExpr>(E);
|
||||
ExprResult Sub = Rebuild(CE->getSubExpr());
|
||||
if (!Sub.isUsable())
|
||||
return Sub;
|
||||
return ConstantExpr::Create(S.Context, Sub.get());
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Can't traverse through this node. Nothing to do.
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
|
||||
// C++2a [basic.def.odr]p4:
|
||||
// [...] an expression of non-volatile-qualified non-class type to which
|
||||
// the lvalue-to-rvalue conversion is applied [...]
|
||||
if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>())
|
||||
return E;
|
||||
|
||||
ExprResult Result =
|
||||
rebuildPotentialResultsAsNonOdrUsed(*this, E, NOUR_Constant);
|
||||
if (Result.isInvalid())
|
||||
return ExprError();
|
||||
return Result.get() ? Result : E;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
||||
|
@ -15844,8 +16057,7 @@ ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
|||
// deciding whether it is an odr-use, just assume we will apply the
|
||||
// lvalue-to-rvalue conversion. In the one case where this doesn't happen
|
||||
// (a non-type template argument), we have special handling anyway.
|
||||
UpdateMarkingForLValueToRValue(Res.get());
|
||||
return Res;
|
||||
return CheckLValueToRValueConversionOperand(Res.get());
|
||||
}
|
||||
|
||||
void Sema::CleanupVarDeclMarking() {
|
||||
|
@ -15889,7 +16101,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|||
|
||||
OdrUseContext OdrUse = isOdrUseContext(SemaRef);
|
||||
bool UsableInConstantExpr =
|
||||
Var->isUsableInConstantExpressions(SemaRef.Context);
|
||||
Var->mightBeUsableInConstantExpressions(SemaRef.Context);
|
||||
|
||||
// C++20 [expr.const]p12:
|
||||
// A variable [...] is needed for constant evaluation if it is [...] a
|
||||
|
@ -15964,7 +16176,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|||
}
|
||||
}
|
||||
|
||||
// C++20 [basic.def.odr]p4:
|
||||
// C++2a [basic.def.odr]p4:
|
||||
// A variable x whose name appears as a potentially-evaluated expression e
|
||||
// is odr-used by e unless
|
||||
// -- x is a reference that is usable in constant expressions
|
||||
|
@ -15978,11 +16190,14 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|||
// lvalue-to-rvalue conversion is not applied [FIXME]
|
||||
//
|
||||
// We check the first part of the second bullet here, and
|
||||
// Sema::UpdateMarkingForLValueToRValue deals with the second part.
|
||||
// Sema::CheckLValueToRValueConversionOperand deals with the second part.
|
||||
// FIXME: To get the third bullet right, we need to delay this even for
|
||||
// variables that are not usable in constant expressions.
|
||||
DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E);
|
||||
switch (OdrUse) {
|
||||
case OdrUseContext::None:
|
||||
assert((!DRE || DRE->isNonOdrUse() == NOUR_Unevaluated) &&
|
||||
"missing non-odr-use marking for unevaluated operand");
|
||||
break;
|
||||
|
||||
case OdrUseContext::FormallyOdrUsed:
|
||||
|
@ -15991,19 +16206,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|||
break;
|
||||
|
||||
case OdrUseContext::Used:
|
||||
if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
|
||||
// A reference initialized by a constant expression can never be
|
||||
// odr-used, so simply ignore it.
|
||||
if (!Var->getType()->isReferenceType() ||
|
||||
(SemaRef.LangOpts.OpenMP && SemaRef.isOpenMPCapturedDecl(Var)))
|
||||
SemaRef.MaybeODRUseExprs.insert(E);
|
||||
} else {
|
||||
MarkVarDeclODRUsed(Var, Loc, SemaRef,
|
||||
/*MaxFunctionScopeIndex ptr*/ nullptr);
|
||||
}
|
||||
// If we already know this isn't an odr-use, there's nothing more to do.
|
||||
if (DRE && DRE->isNonOdrUse())
|
||||
break;
|
||||
// If we might later find that this expression isn't actually an odr-use,
|
||||
// delay the marking.
|
||||
if (E && Var->isUsableInConstantExpressions(SemaRef.Context))
|
||||
SemaRef.MaybeODRUseExprs.insert(E);
|
||||
else
|
||||
MarkVarDeclODRUsed(Var, Loc, SemaRef);
|
||||
break;
|
||||
|
||||
case OdrUseContext::Dependent:
|
||||
// If we already know this isn't an odr-use, there's nothing more to do.
|
||||
if (DRE && DRE->isNonOdrUse())
|
||||
break;
|
||||
// If this is a dependent context, we don't need to mark variables as
|
||||
// odr-used, but we may still need to track them for lambda capture.
|
||||
// FIXME: Do we also need to do this inside dependent typeid expressions
|
||||
|
@ -16028,7 +16245,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|||
// FIXME: We can simplify this a lot after implementing P0588R1.
|
||||
assert(E && "Capture variable should be used in an expression.");
|
||||
if (!Var->getType()->isReferenceType() ||
|
||||
!IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
|
||||
!Var->isUsableInConstantExpressions(SemaRef.Context))
|
||||
LSI->addPotentialCapture(E->IgnoreParens());
|
||||
}
|
||||
}
|
||||
|
@ -16241,13 +16458,6 @@ namespace {
|
|||
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
|
||||
Visit(E->getExpr());
|
||||
}
|
||||
|
||||
void VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
||||
Inherited::VisitImplicitCastExpr(E);
|
||||
|
||||
if (E->getCastKind() == CK_LValueToRValue)
|
||||
S.UpdateMarkingForLValueToRValue(E->getSubExpr());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7395,7 +7395,7 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
|
|||
return false;
|
||||
}
|
||||
|
||||
return !IsVariableAConstantExpression(Var, Context);
|
||||
return !Var->isUsableInConstantExpressions(Context);
|
||||
}
|
||||
|
||||
/// Check if the current lambda has any potential captures
|
||||
|
|
|
@ -285,7 +285,7 @@ static void instantiateOMPDeclareSimdDeclAttr(
|
|||
SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
|
||||
SmallVector<unsigned, 4> LinModifiers;
|
||||
|
||||
auto &&Subst = [&](Expr *E) -> ExprResult {
|
||||
auto SubstExpr = [&](Expr *E) -> ExprResult {
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
|
||||
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
|
||||
Sema::ContextRAII SavedContext(S, FD);
|
||||
|
@ -300,6 +300,17 @@ static void instantiateOMPDeclareSimdDeclAttr(
|
|||
return S.SubstExpr(E, TemplateArgs);
|
||||
};
|
||||
|
||||
// Substitute a single OpenMP clause, which is a potentially-evaluated
|
||||
// full-expression.
|
||||
auto Subst = [&](Expr *E) -> ExprResult {
|
||||
EnterExpressionEvaluationContext Evaluated(
|
||||
S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
ExprResult Res = SubstExpr(E);
|
||||
if (Res.isInvalid())
|
||||
return Res;
|
||||
return S.ActOnFinishFullExpr(Res.get(), false);
|
||||
};
|
||||
|
||||
ExprResult Simdlen;
|
||||
if (auto *E = Attr.getSimdlen())
|
||||
Simdlen = Subst(E);
|
||||
|
@ -4714,8 +4725,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
|||
// of reference types, [...] explicit instantiation declarations
|
||||
// have the effect of suppressing the implicit instantiation of the entity
|
||||
// to which they refer.
|
||||
//
|
||||
// FIXME: That's not exactly the same as "might be usable in constant
|
||||
// expressions", which only allows constexpr variables and const integral
|
||||
// types, not arbitrary const literal types.
|
||||
if (TSK == TSK_ExplicitInstantiationDeclaration &&
|
||||
!Var->isUsableInConstantExpressions(getASTContext()))
|
||||
!Var->mightBeUsableInConstantExpressions(getASTContext()))
|
||||
return;
|
||||
|
||||
// Make sure to pass the instantiated variable to the consumer at the end.
|
||||
|
|
|
@ -554,6 +554,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record.readInt();
|
||||
E->DeclRefExprBits.HadMultipleCandidates = Record.readInt();
|
||||
E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record.readInt();
|
||||
E->DeclRefExprBits.NonOdrUseReason = Record.readInt();
|
||||
unsigned NumTemplateArgs = 0;
|
||||
if (E->hasTemplateKWAndArgsInfo())
|
||||
NumTemplateArgs = Record.readInt();
|
||||
|
@ -2524,7 +2525,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
|||
/*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
|
||||
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 2],
|
||||
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
|
||||
Record[ASTStmtReader::NumExprFields + 5] : 0);
|
||||
Record[ASTStmtReader::NumExprFields + 6] : 0);
|
||||
break;
|
||||
|
||||
case EXPR_INTEGER_LITERAL:
|
||||
|
|
|
@ -2212,8 +2212,8 @@ void ASTWriter::WriteDeclAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
|
||||
1)); // RefersToEnclosingVariableOrCapture
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // RefersToEnclosingVariableOrCapture
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // NonOdrUseReason
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
|
||||
DeclRefExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
|
||||
|
|
|
@ -456,6 +456,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
Record.push_back(E->hasTemplateKWAndArgsInfo());
|
||||
Record.push_back(E->hadMultipleCandidates());
|
||||
Record.push_back(E->refersToEnclosingVariableOrCapture());
|
||||
Record.push_back(E->isNonOdrUse());
|
||||
|
||||
if (E->hasTemplateKWAndArgsInfo()) {
|
||||
unsigned NumTemplateArgs = E->getNumTemplateArgs();
|
||||
|
@ -466,7 +467,8 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
|
||||
if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) &&
|
||||
(E->getDecl() == E->getFoundDecl()) &&
|
||||
nk == DeclarationName::Identifier) {
|
||||
nk == DeclarationName::Identifier &&
|
||||
!E->refersToEnclosingVariableOrCapture() && !E->isNonOdrUse()) {
|
||||
AbbrevToUse = Writer.getDeclRefExprAbbrev();
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ struct Invalid {
|
|||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void () noexcept'[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:26:1[[RESET]], [[Yellow]]col:5[[RESET]]> [[Yellow]]col:5[[RESET]][[CYAN]] TestExpr[[RESET]] [[Green]]'int'[[RESET]]
|
||||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[BLUE]]GuardedByAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:29[[RESET]], [[Yellow]]col:43[[RESET]]>{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'Mutex'[[RESET]]{{$}}
|
||||
//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'Mutex'[[RESET]] non_odr_use_unevaluated{{$}}
|
||||
//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:28:1[[RESET]], [[Yellow]]line:30:1[[RESET]]> [[Yellow]]line:28:8[[RESET]] struct[[CYAN]] Invalid[[RESET]] definition
|
||||
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:8[[RESET]]> [[Yellow]]col:8[[RESET]] implicit referenced struct[[CYAN]] Invalid[[RESET]]
|
||||
//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:29:3[[RESET]], [[Yellow]]col:42[[RESET]]> [[Yellow]]col:29[[RESET]] invalid[[CYAN]] Invalid[[RESET]] [[Green]]'void (int)'[[RESET]]
|
||||
|
|
|
@ -3877,7 +3877,8 @@ void PrimaryExpressions(int a) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
|
|
@ -1596,7 +1596,8 @@ void TestNonADLCall3() {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int *"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -1647,7 +1648,8 @@ void TestNonADLCall3() {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int *"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: }
|
||||
|
|
|
@ -1342,7 +1342,8 @@ void TestMiscStmts(void) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -1456,7 +1457,8 @@ void TestMiscStmts(void) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -1596,7 +1598,8 @@ void TestMiscStmts(void) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -1736,7 +1739,8 @@ void TestMiscStmts(void) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -1951,7 +1955,8 @@ void TestMiscStmts(void) {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
|
|
@ -70,7 +70,7 @@ void TestSwitch(int i) {
|
|||
}
|
||||
|
||||
void TestIf(bool b) {
|
||||
if (int i = 12; b)
|
||||
if (const int i = 12; i)
|
||||
;
|
||||
|
||||
if constexpr (sizeof(b) == 1)
|
||||
|
@ -2719,7 +2719,7 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "line": 72
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "isUsed": true,
|
||||
// CHECK-NEXT: "isReferenced": true,
|
||||
// CHECK-NEXT: "name": "b",
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "bool"
|
||||
|
@ -2768,7 +2768,7 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 17,
|
||||
// CHECK-NEXT: "col": 23,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
|
@ -2778,7 +2778,7 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "VarDecl",
|
||||
// CHECK-NEXT: "loc": {
|
||||
// CHECK-NEXT: "col": 11,
|
||||
// CHECK-NEXT: "col": 17,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
|
@ -2789,14 +2789,15 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 15,
|
||||
// CHECK-NEXT: "col": 21,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "isReferenced": true,
|
||||
// CHECK-NEXT: "name": "i",
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: "qualType": "const int"
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "init": "c",
|
||||
// CHECK-NEXT: "inner": [
|
||||
|
@ -2805,12 +2806,12 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "kind": "IntegerLiteral",
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "col": 15,
|
||||
// CHECK-NEXT: "col": 21,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 15,
|
||||
// CHECK-NEXT: "col": 21,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
|
@ -2830,12 +2831,12 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "kind": "ImplicitCastExpr",
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "col": 19,
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 19,
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
|
@ -2844,35 +2845,59 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "qualType": "bool"
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "valueCategory": "rvalue",
|
||||
// CHECK-NEXT: "castKind": "LValueToRValue",
|
||||
// CHECK-NEXT: "castKind": "IntegralToBoolean",
|
||||
// CHECK-NEXT: "inner": [
|
||||
// CHECK-NEXT: {
|
||||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "DeclRefExpr",
|
||||
// CHECK-NEXT: "kind": "ImplicitCastExpr",
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "col": 19,
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 19,
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "bool"
|
||||
// CHECK-NEXT: "qualType": "int"
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "valueCategory": "lvalue",
|
||||
// CHECK-NEXT: "referencedDecl": {
|
||||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "ParmVarDecl",
|
||||
// CHECK-NEXT: "name": "b",
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "bool"
|
||||
// CHECK-NEXT: "valueCategory": "rvalue",
|
||||
// CHECK-NEXT: "castKind": "LValueToRValue",
|
||||
// CHECK-NEXT: "inner": [
|
||||
// CHECK-NEXT: {
|
||||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "DeclRefExpr",
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "col": 25,
|
||||
// CHECK-NEXT: "file": "{{.*}}",
|
||||
// CHECK-NEXT: "line": 73
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "const int"
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "valueCategory": "lvalue",
|
||||
// CHECK-NEXT: "referencedDecl": {
|
||||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "VarDecl",
|
||||
// CHECK-NEXT: "name": "i",
|
||||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "const int"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "constant"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: },
|
||||
|
@ -3019,7 +3044,8 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "bool"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: }
|
||||
|
@ -3217,7 +3243,8 @@ void TestIteration() {
|
|||
// CHECK-NEXT: "type": {
|
||||
// CHECK-NEXT: "qualType": "bool"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "nonOdrUseReason": "unevaluated"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: }
|
||||
|
|
|
@ -29,7 +29,7 @@ dynamic_cast_result derived_ptr = d;
|
|||
// CHECK-NEXT: ParenExpr {{.*}} <col:{{.*}}, col:{{.*}}> 'Derived *'{{$}}
|
||||
// CHECK-NEXT: CXXDynamicCastExpr {{.*}} <col:{{.*}}, col:{{.*}}> 'Derived *' dynamic_cast<struct Derived *> <Dynamic>{{$}}
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'Base *' <LValueToRValue> part_of_explicit_cast{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'Base *' lvalue Var {{.*}} 'base_ptr' 'Base *'{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'Base *' lvalue Var {{.*}} 'base_ptr' 'Base *' non_odr_use_unevaluated{{$}}
|
||||
|
||||
// CXXReinterpretCastExpr
|
||||
reinterpret_cast_result void_ptr2 = &integer;
|
||||
|
@ -46,7 +46,7 @@ const_cast_result char_ptr = &character;
|
|||
// CHECK-NEXT: ParenExpr {{.*}} <col:{{.*}}, col:{{.*}}> 'char *'{{$}}
|
||||
// CHECK-NEXT: CXXConstCastExpr {{.*}} <col:{{.*}}, col:{{.*}}> 'char *' const_cast<char *> <NoOp>{{$}}
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'const char *' <LValueToRValue> part_of_explicit_cast{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'const char *' lvalue Var {{.*}} 'const_char_ptr_value' 'const char *'{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'const char *' lvalue Var {{.*}} 'const_char_ptr_value' 'const char *' non_odr_use_unevaluated{{$}}
|
||||
|
||||
// CXXFunctionalCastExpr
|
||||
functional_cast_result *double_ptr = &floating;
|
||||
|
@ -56,7 +56,7 @@ functional_cast_result *double_ptr = &floating;
|
|||
// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} <col:{{.*}}, col:{{.*}}> 'double' functional cast to double <NoOp>{{$}}
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'double' <IntegralToFloating> part_of_explicit_cast{{$}}
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} <col:{{.*}}> 'int' <LValueToRValue> part_of_explicit_cast{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue Var {{.*}} 'int_value' 'int'{{$}}
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} <col:{{.*}}> 'int' lvalue Var {{.*}} 'int_value' 'int' non_odr_use_unevaluated{{$}}
|
||||
|
||||
// CXXBoolLiteralExpr
|
||||
bool_literal_result *bool_ptr = &boolean;
|
||||
|
|
Loading…
Reference in New Issue