Lay the ground work for resoving PR7047. This doesn't actually fix it because

default arguments to template parameters don't have a DeclContext when
instantiated, and so we can't detect that we're in an instantiation context as
opposed to the definition context. However, it fixes the more commonly-occuring
cases in TMP code that use devolve to this type of tautology after
substitution.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108044 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2010-07-10 12:30:03 +00:00
parent 6d00c1365d
commit 999194739e
2 changed files with 66 additions and 3 deletions

View File

@ -5292,6 +5292,16 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
return LHSTy;
}
static bool IsWithinTemplateSpecialization(Decl *D) {
if (DeclContext *DC = D->getDeclContext()) {
if (isa<ClassTemplateSpecializationDecl>(DC))
return true;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
return FD->isFunctionTemplateSpecialization();
}
return false;
}
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
unsigned OpaqueOpc, bool isRelational) {
@ -5310,13 +5320,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
// NOTE: Don't warn about comparisons of enum constants. These can arise
// from macro expansions, and are usually quite deliberate.
// from macro expansions, and are usually quite deliberate. Also don't
// warn about comparisons which are only self comparisons within
// a template specialization. The warnings should catch obvious cases in
// the definition of the template anyways.
Expr *LHSStripped = lex->IgnoreParens();
Expr *RHSStripped = rex->IgnoreParens();
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped))
if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) {
if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) {
if (DRL->getDecl() == DRR->getDecl() &&
!isa<EnumConstantDecl>(DRL->getDecl())) {
!isa<EnumConstantDecl>(DRL->getDecl()) &&
!IsWithinTemplateSpecialization(DRL->getDecl())) {
DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always)
<< 0 // self-
<< (Opc == BinaryOperator::EQ
@ -5344,6 +5358,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
<< always_evals_to);
}
}
}
if (isa<CastExpr>(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();

View File

@ -0,0 +1,48 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template <int A, int B> void foo() {
(void)(A == A); // expected-warning {{self-comparison always evaluates to true}}
(void)(A == B);
}
template <int A, int B> struct S1 {
void foo() {
(void)(A == A); // expected-warning {{self-comparison always evaluates to true}}
(void)(A == B);
}
};
template <int A, int B> struct S2 {
template <typename T> T foo() {
(void)(A == A); // expected-warning {{self-comparison always evaluates to true}}
(void)(A == B);
}
};
struct S3 {
template <int A, int B> void foo() {
(void)(A == A); // expected-warning {{self-comparison always evaluates to true}}
(void)(A == B);
}
};
template <int A> struct S4 {
template <int B> void foo() {
(void)(A == A); // expected-warning {{self-comparison always evaluates to true}}
(void)(A == B);
}
};
const int N = 42;
template <int X> void foo2() {
(void)(X == N);
(void)(N == X);
}
void test() {
foo<1, 1>();
S1<1, 1> s1; s1.foo();
S2<1, 1> s2; s2.foo<void>();
S3 s3; s3.foo<1, 1>();
S4<1> s4; s4.foo<1>();
foo2<N>();
}