[cfe-commits] r149641 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/undefined-internal.cpp
Eli Friedman
eli.friedman at gmail.com
Thu Feb 2 15:15:15 PST 2012
Author: efriedma
Date: Thu Feb 2 17:15:15 2012
New Revision: 149641
URL: http://llvm.org/viewvc/llvm-project?rev=149641&view=rev
Log:
Add some code to accurately perform odr-used marking for variables per the C++11 rules.
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/undefined-internal.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=149641&r1=149640&r2=149641&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb 2 17:15:15 2012
@@ -233,6 +233,8 @@
/// element type here is ExprWithCleanups::Object.
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
+ llvm::SmallPtrSet<Expr*, 8> MaybeODRUseExprs;
+
/// \brief Stack containing information about each of the nested
/// function, block, and method scopes that are currently active.
///
@@ -556,6 +558,8 @@
/// this expression evaluation context.
unsigned NumCleanupObjects;
+ llvm::SmallPtrSet<Expr*, 8> SavedMaybeODRUseExprs;
+
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
bool ParentNeedsCleanups)
@@ -2278,6 +2282,10 @@
void MarkDeclRefReferenced(DeclRefExpr *E);
void MarkMemberReferenced(MemberExpr *E);
+ void UpdateMarkingForLValueToRValue(Expr *E);
+ void CleanupVarDeclMarking();
+
+
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=149641&r1=149640&r2=149641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb 2 17:15:15 2012
@@ -7299,6 +7299,8 @@
assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");
assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
+ assert(MaybeODRUseExprs.empty() &&
+ "Leftover expressions for odr-use checking");
}
if (!IsInstantiation)
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=149641&r1=149640&r2=149641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Feb 2 17:15:15 2012
@@ -404,6 +404,8 @@
if (T.hasQualifiers())
T = T.getUnqualifiedType();
+ UpdateMarkingForLValueToRValue(E);
+
ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
E, 0, VK_RValue));
@@ -9433,6 +9435,8 @@
ExprCleanupObjects.size(),
ExprNeedsCleanups));
ExprNeedsCleanups = false;
+ if (!MaybeODRUseExprs.empty())
+ std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
void Sema::PopExpressionEvaluationContext() {
@@ -9446,10 +9450,14 @@
ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
ExprCleanupObjects.end());
ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+ CleanupVarDeclMarking();
+ std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs);
// Otherwise, merge the contexts together.
} else {
ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(),
+ Rec.SavedMaybeODRUseExprs.end());
}
// Pop the current expression evaluation context off the stack.
@@ -9461,6 +9469,7 @@
ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects,
ExprCleanupObjects.end());
ExprNeedsCleanups = false;
+ MaybeODRUseExprs.clear();
}
ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
@@ -9604,16 +9613,62 @@
Func->setUsed(true);
}
-/// \brief Mark a variable referenced, and check whether it is odr-used
-/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
-/// used directly for normal expressions referring to VarDecl.
-void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
+static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
+ SourceLocation Loc) {
+ // Keep track of used but undefined variables.
+ if (Var->hasDefinition() == VarDecl::DeclarationOnly &&
+ Var->getLinkage() != ExternalLinkage) {
+ SourceLocation &old = SemaRef.UndefinedInternals[Var->getCanonicalDecl()];
+ if (old.isInvalid()) old = Loc;
+ }
+
+ Var->setUsed(true);
+}
+
+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());
+}
+
+void Sema::CleanupVarDeclMarking() {
+ for (llvm::SmallPtrSetIterator<Expr*> i = MaybeODRUseExprs.begin(),
+ e = MaybeODRUseExprs.end();
+ i != e; ++i) {
+ VarDecl *Var;
+ SourceLocation Loc;
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(*i)) {
+ Var = BDRE->getDecl();
+ Loc = BDRE->getLocation();
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*i)) {
+ Var = cast<VarDecl>(DRE->getDecl());
+ Loc = DRE->getLocation();
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(*i)) {
+ Var = cast<VarDecl>(ME->getMemberDecl());
+ Loc = ME->getMemberLoc();
+ } else {
+ llvm_unreachable("Unexpcted expression");
+ }
+
+ MarkVarDeclODRUsed(*this, Var, Loc);
+ }
+
+ MaybeODRUseExprs.clear();
+}
+
+// Mark a VarDecl referenced, and perform the necessary handling to compute
+// odr-uses.
+static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
+ VarDecl *Var, Expr *E) {
Var->setReferenced();
if (Var->isUsed(false))
return;
- if (!IsPotentiallyEvaluatedContext(*this))
+ if (!IsPotentiallyEvaluatedContext(SemaRef))
return;
// Implicit instantiation of static data members of class templates.
@@ -9625,35 +9680,47 @@
MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
MSInfo->setPointOfInstantiation(Loc);
// This is a modification of an existing AST node. Notify listeners.
- if (ASTMutationListener *L = getASTMutationListener())
+ if (ASTMutationListener *L = SemaRef.getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
if (Var->isUsableInConstantExpressions())
// Do not defer instantiations of variables which could be used in a
// constant expression.
- InstantiateStaticDataMemberDefinition(Loc, Var);
+ SemaRef.InstantiateStaticDataMemberDefinition(Loc, Var);
else
- PendingInstantiations.push_back(std::make_pair(Var, Loc));
+ SemaRef.PendingInstantiations.push_back(std::make_pair(Var, Loc));
}
}
- // Keep track of used but undefined variables. We make a hole in
- // the warning for static const data members with in-line
- // initializers.
- // FIXME: The hole we make for static const data members is too wide!
- // We need to implement the C++11 rules for odr-used.
- if (Var->hasDefinition() == VarDecl::DeclarationOnly
- && Var->getLinkage() != ExternalLinkage
- && !(Var->isStaticDataMember() && Var->hasInit())) {
- SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
- }
+ // 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." We check the first part here, and
+ // Sema::UpdateMarkingForLValueToRValue deals with the second part.
+ // Note that we use the C++11 definition everywhere because nothing in
+ // C++03 depends on whether we get the C++03 version correct.
+ const VarDecl *DefVD;
+ if (E && !isa<ParmVarDecl>(Var) &&
+ Var->isUsableInConstantExpressions() &&
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
+ SemaRef.MaybeODRUseExprs.insert(E);
+ else
+ MarkVarDeclODRUsed(SemaRef, Var, Loc);
+}
- Var->setUsed(true);
+/// \brief Mark a variable referenced, and check whether it is odr-used
+/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
+/// used directly for normal expressions referring to VarDecl.
+void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
+ DoMarkVarDeclReferenced(*this, Loc, Var, 0);
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
Decl *D, Expr *E) {
- // TODO: Add special handling for variables
+ if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
+ return;
+ }
+
SemaRef.MarkAnyDeclReferenced(Loc, D);
}
@@ -9789,6 +9856,13 @@
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=149641&r1=149640&r2=149641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 2 17:15:15 2012
@@ -4232,6 +4232,8 @@
Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
assert(SubExpr && "sub expression can't be null!");
+ CleanupVarDeclMarking();
+
unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
assert(ExprCleanupObjects.size() >= FirstCleanup);
assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
@@ -4251,6 +4253,8 @@
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
assert(SubStmt && "sub statement can't be null!");
+ CleanupVarDeclMarking();
+
if (!ExprNeedsCleanups)
return SubStmt;
Modified: cfe/trunk/test/SemaCXX/undefined-internal.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/undefined-internal.cpp?rev=149641&r1=149640&r2=149641&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/undefined-internal.cpp (original)
+++ cfe/trunk/test/SemaCXX/undefined-internal.cpp Thu Feb 2 17:15:15 2012
@@ -122,3 +122,48 @@
f(Uncopyable()); // expected-warning {{C++98 requires an accessible copy constructor}}
};
}
+
+
+namespace std { class type_info; };
+namespace cxx11_odr_rules {
+ // Note: the way this test is written isn't really ideal, but there really
+ // isn't any other way to check that the odr-used logic for constants
+ // is working without working implicit capture in lambda-expressions.
+ // (The more accurate used-but-not-defined warning is the only other visible
+ // effect of accurate odr-used computation.)
+ //
+ // Note that the warning in question can trigger in cases some people would
+ // consider false positives; hopefully that happens rarely in practice.
+
+ namespace {
+ struct A {
+ static const int unused = 10;
+ static const int used1 = 20; // expected-warning {{internal linkage}}
+ static const int used2 = 20; // expected-warning {{internal linkage}}
+ virtual ~A() {}
+ };
+ }
+
+ void a(int,int);
+ A& p(const int&) { static A a; return a; }
+
+ // Check handling of default arguments
+ void b(int = A::unused);
+
+ void tests() {
+ // Basic test
+ a(A::unused, A::unused);
+
+ // Check that nesting an unevaluated or constant-evaluated context does
+ // the right thing.
+ a(A::unused, sizeof(int[10]));
+
+ // Check that the checks work with unevaluated contexts
+ (void)sizeof(p(A::used1));
+ (void)typeid(p(A::used1)); // expected-note {{used here}}
+
+ // Misc other testing
+ a(A::unused, 1 ? A::used2 : A::used2); // expected-note {{used here}}
+ b();
+ }
+}
More information about the cfe-commits
mailing list