Author: rsmith Date: Tue Jun 11 10:50:32 2019 New Revision: 363086 URL: http://llvm.org/viewvc/llvm-project?rev=363086&view=rev Log: 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. Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/AST/Stmt.h cfe/trunk/include/clang/Basic/Specifiers.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Sema/SemaInternal.h cfe/trunk/lib/AST/ASTImporter.cpp cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/Expr.cpp cfe/trunk/lib/AST/JSONNodeDumper.cpp cfe/trunk/lib/AST/TextNodeDumper.cpp cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CGExpr.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/lib/Serialization/ASTWriterStmt.cpp cfe/trunk/test/AST/ast-dump-color.cpp cfe/trunk/test/AST/ast-dump-expr-json.c cfe/trunk/test/AST/ast-dump-expr-json.cpp cfe/trunk/test/AST/ast-dump-stmt-json.c cfe/trunk/test/AST/ast-dump-stmt-json.cpp cfe/trunk/test/PCH/cxx_exprs.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Tue Jun 11 10:50:32 2019 @@ -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; Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Tue Jun 11 10:50:32 2019 @@ -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 { Modified: cfe/trunk/include/clang/AST/Stmt.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Stmt.h (original) +++ cfe/trunk/include/clang/AST/Stmt.h Tue Jun 11 10:50:32 2019 @@ -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; Modified: cfe/trunk/include/clang/Basic/Specifiers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Specifiers.h (original) +++ cfe/trunk/include/clang/Basic/Specifiers.h Tue Jun 11 10:50:32 2019 @@ -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 { Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Jun 11 10:50:32 2019 @@ -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 { Modified: cfe/trunk/include/clang/Sema/SemaInternal.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaInternal.h?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/SemaInternal.h (original) +++ cfe/trunk/include/clang/Sema/SemaInternal.h Tue Jun 11 10:50:32 2019 @@ -38,15 +38,6 @@ FTIHasNonVoidParameters(const Declarator 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. Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Jun 11 10:50:32 2019 @@ -6189,7 +6189,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclR 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; Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Tue Jun 11 10:50:32 2019 @@ -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::isUsableInConstantExpressi 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. Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Tue Jun 11 10:50:32 2019 @@ -344,7 +344,8 @@ void DeclRefExpr::computeDependence(cons 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 ASTContex DeclRefExprBits.HadMultipleCandidates = false; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; + DeclRefExprBits.NonOdrUseReason = NOUR; DeclRefExprBits.Loc = L; computeDependence(Ctx); } @@ -363,7 +365,7 @@ DeclRefExpr::DeclRefExpr(const ASTContex 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 ASTContex = (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 ASTContex 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 A 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, Modified: cfe/trunk/lib/AST/JSONNodeDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/JSONNodeDumper.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/AST/JSONNodeDumper.cpp (original) +++ cfe/trunk/lib/AST/JSONNodeDumper.cpp Tue Jun 11 10:50:32 2019 @@ -805,6 +805,12 @@ void JSONNodeDumper::VisitDeclRefExpr(co 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) { Modified: cfe/trunk/lib/AST/TextNodeDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TextNodeDumper.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/AST/TextNodeDumper.cpp (original) +++ cfe/trunk/lib/AST/TextNodeDumper.cpp Tue Jun 11 10:50:32 2019 @@ -715,6 +715,12 @@ void TextNodeDumper::VisitDeclRefExpr(co 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( Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Jun 11 10:50:32 2019 @@ -1783,8 +1783,8 @@ void CodeGenFunction::EmitAutoVarInit(co } 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() && Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Jun 11 10:50:32 2019 @@ -1398,7 +1398,7 @@ static bool isConstantEmittableObjectTyp /// 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(DeclR 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::EmitDeclRefLValu // 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::EmitDeclRefLValu 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(); Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Tue Jun 11 10:50:32 2019 @@ -587,7 +587,7 @@ static bool ShouldRemoveFromUnused(Sema // 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()) Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Jun 11 10:50:32 2019 @@ -5231,15 +5231,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprRe } // 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. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jun 11 10:50:32 2019 @@ -11994,7 +11994,7 @@ void Sema::CheckCompleteVariableDeclarat 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. Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 11 10:50:32 2019 @@ -625,15 +625,18 @@ ExprResult Sema::DefaultLvalueConversion 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, Qua 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 *Sc 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(Va return DeclRefType; } +/// 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. + // + // 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). + // Rebuild a subexpression. + auto Rebuild = [&](Expr *Sub) { + return rebuildPotentialResultsAsNonOdrUsed(S, Sub, NOUR); + }; -// 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) { + // 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; - 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()) + // 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; - return IsVariableAConstantExpression(Var, Context); -} + }; + // Mark that this expression does not constitute an odr-use. + auto MarkNotOdrUsed = [&] { + S.MaybeODRUseExprs.erase(E); + if (LambdaScopeInfo *LSI = S.getCurLambda()) + LSI->markVariableExprAsNonODRUsed(E); + }; -void Sema::UpdateMarkingForLValueToRValue(Expr *E) { - // 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()); + // 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; - // 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 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(); - for (VarDecl *VD : Vars) { - if (VD && IsVariableNonDependentAndAConstantExpression(VD, Context)) - LSI->markVariableExprAsNonODRUsed(SansParensExpr); + // 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 // 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 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 } } - // 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 // 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 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 // 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()); - } }; } Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jun 11 10:50:32 2019 @@ -7395,7 +7395,7 @@ static inline bool VariableCanNeverBeACo return false; } - return !IsVariableAConstantExpression(Var, Context); + return !Var->isUsableInConstantExpressions(Context); } /// Check if the current lambda has any potential captures Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Jun 11 10:50:32 2019 @@ -285,7 +285,7 @@ static void instantiateOMPDeclareSimdDec 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 instantiateOMPDeclareSimdDec 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 // 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. Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Jun 11 10:50:32 2019 @@ -554,6 +554,7 @@ void ASTStmtReader::VisitDeclRefExpr(Dec 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(Modu /*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: Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Tue Jun 11 10:50:32 2019 @@ -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)); Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Jun 11 10:50:32 2019 @@ -456,6 +456,7 @@ void ASTStmtWriter::VisitDeclRefExpr(Dec 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(Dec if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) && (E->getDecl() == E->getFoundDecl()) && - nk == DeclarationName::Identifier) { + nk == DeclarationName::Identifier && + !E->refersToEnclosingVariableOrCapture() && !E->isNonOdrUse()) { AbbrevToUse = Writer.getDeclRefExprAbbrev(); } Modified: cfe/trunk/test/AST/ast-dump-color.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-color.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/AST/ast-dump-color.cpp (original) +++ cfe/trunk/test/AST/ast-dump-color.cpp Tue Jun 11 10:50:32 2019 @@ -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]] Modified: cfe/trunk/test/AST/ast-dump-expr-json.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-expr-json.c?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/AST/ast-dump-expr-json.c (original) +++ cfe/trunk/test/AST/ast-dump-expr-json.c Tue Jun 11 10:50:32 2019 @@ -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: }, Modified: cfe/trunk/test/AST/ast-dump-expr-json.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-expr-json.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/AST/ast-dump-expr-json.cpp (original) +++ cfe/trunk/test/AST/ast-dump-expr-json.cpp Tue Jun 11 10:50:32 2019 @@ -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: } Modified: cfe/trunk/test/AST/ast-dump-stmt-json.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-stmt-json.c?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/AST/ast-dump-stmt-json.c (original) +++ cfe/trunk/test/AST/ast-dump-stmt-json.c Tue Jun 11 10:50:32 2019 @@ -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: }, Modified: cfe/trunk/test/AST/ast-dump-stmt-json.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-stmt-json.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/AST/ast-dump-stmt-json.cpp (original) +++ cfe/trunk/test/AST/ast-dump-stmt-json.cpp Tue Jun 11 10:50:32 2019 @@ -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: } Modified: cfe/trunk/test/PCH/cxx_exprs.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx_exprs.cpp?rev=363086&r1=363085&r2=363086&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx_exprs.cpp (original) +++ cfe/trunk/test/PCH/cxx_exprs.cpp Tue Jun 11 10:50:32 2019 @@ -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 = &fl // 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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits