]> granicus.if.org Git - clang/commitdiff
Fix crash on switch conditions of non-integer types in templates
authorElizabeth Andrews <elizabeth.andrews@intel.com>
Tue, 13 Aug 2019 15:53:19 +0000 (15:53 +0000)
committerElizabeth Andrews <elizabeth.andrews@intel.com>
Tue, 13 Aug 2019 15:53:19 +0000 (15:53 +0000)
Clang currently crashes for switch statements inside a template when
the condition is a non-integer field. The crash is due to incorrect
type-dependency of field. Type-dependency of member expressions is
currently set based on the containing class. This patch changes this for
'members of the current instantiation' to set the type dependency based
on the member's type instead.

A few lit tests started to fail once I applied this patch because errors
are now diagnosed earlier (does not wait till instantiation). I've modified
these tests in this patch as well.

Patch fixes PR#40982

Differential Revision: https://reviews.llvm.org/D61027

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@368706 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Expr.cpp
lib/Sema/SemaChecking.cpp
test/SemaTemplate/dependent-names.cpp
test/SemaTemplate/enum-argument.cpp
test/SemaTemplate/member-access-expr.cpp
test/SemaTemplate/non-integral-switch-cond.cpp [new file with mode: 0644]

index d2730d3e26d5601163d44474bd08bb9451be97b1..70bd42cfa515aca324e4e5cd5677fa0dcde2c0ae 100644 (file)
@@ -1669,6 +1669,15 @@ MemberExpr *MemberExpr::Create(
   MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
                                        NameInfo, T, VK, OK, NOUR);
 
+  if (FieldDecl *Field = dyn_cast<FieldDecl>(MemberDecl)) {
+    DeclContext *DC = MemberDecl->getDeclContext();
+    // dyn_cast_or_null is used to handle objC variables which do not
+    // have a declaration context.
+    CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC);
+    if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC))
+      E->setTypeDependent(T->isDependentType());
+  }
+
   if (HasQualOrFound) {
     // FIXME: Wrong. We should be looking at the member declaration we found.
     if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) {
index 3225dffe9220a493c212abd6b9e8b72cc029ac2a..9df559972868f7d551dc8a082e70db6b2c7f6499 100644 (file)
@@ -14288,6 +14288,8 @@ void Sema::RefersToMemberWithReducedAlignment(
   bool AnyIsPacked = false;
   do {
     QualType BaseType = ME->getBase()->getType();
+    if (BaseType->isDependentType())
+      return;
     if (ME->isArrow())
       BaseType = BaseType->getPointeeType();
     RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
index 67ef238083f04630c35dc435a6fcaa762e726d79..a8de159a1d46397d79c3a6b45a724c6395ff2318 100644 (file)
@@ -273,9 +273,6 @@ namespace PR10187 {
       }
       int e[10];
     };
-    void g() {
-      S<int>().f(); // expected-note {{here}}
-    }
   }
 
   namespace A2 {
index 7ff41961399017ff9d8dc87e4c197cc7ef6a2c1e..a79ed8403e9f43b949c7b545c50a165a73effe77 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 enum Enum { val = 1 };
 template <Enum v> struct C {
@@ -31,7 +30,7 @@ namespace rdar8020920 {
     unsigned long long bitfield : e0;
 
     void f(int j) {
-      bitfield + j;
+      bitfield + j; // expected-warning {{expression result unused}}
     }
   };
 }
index 8dba2e68d65628f1358767707848a77b86cbb486..ef10d72a0ef80e3941b89af9f173b3f6bf75c0ef 100644 (file)
@@ -156,7 +156,7 @@ namespace test6 {
     void get(B **ptr) {
       // It's okay if at some point we figure out how to diagnose this
       // at instantiation time.
-      *ptr = field;
+      *ptr = field; // expected-error {{assigning to 'test6::B *' from incompatible type 'test6::A *}}
     }
   };
 }
diff --git a/test/SemaTemplate/non-integral-switch-cond.cpp b/test/SemaTemplate/non-integral-switch-cond.cpp
new file mode 100644 (file)
index 0000000..23c8e0e
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct NOT_AN_INTEGRAL_TYPE {};
+
+template <typename T>
+struct foo {
+  NOT_AN_INTEGRAL_TYPE Bad;
+  void run() {
+    switch (Bad) { // expected-error {{statement requires expression of integer type ('NOT_AN_INTEGRAL_TYPE' invalid)}}
+    case 0:
+      break;
+    }
+  }
+};