]> granicus.if.org Git - clang/commitdiff
Fix handling of class member access into a vector type.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Aug 2019 22:57:50 +0000 (22:57 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Aug 2019 22:57:50 +0000 (22:57 +0000)
When handling a member access into a non-class, non-ObjC-object type, we
would perform a lookup into the surrounding scope as if for an
unqualified lookup. If the member access was followed by a '<' and this
lookup (or the typo-correction for it) found a template name, we'd treat
the member access as naming that template.

Now we treat such accesses as never naming a template if the type of the
object expression is of vector type, so that vector component accesses
are never misinterpreted as naming something else. This is not entirely
correct, since it is in fact valid to name a template from the enclosing
scope in this context, when invoking a pseudo-destructor for the vector
type via an alias template, but that's very much a corner case, and this
change leaves that case only as broken as the corresponding case for
Objective-C types is.

This incidentally adds support for dr2292, which permits a 'template'
keyword at the start of a member access naming a pseudo-destructor.

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

lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/drs/dr22xx.cpp
test/CXX/drs/dr4xx.cpp
test/SemaCXX/cxx2a-adl-only-template-id.cpp
test/SemaCXX/pseudo-destructors.cpp
test/SemaCXX/vector.cpp

index 8f882e4ca32f0b3bb4014c81398db7b2b63c57f4..7c68e4d91459c698c632c51a9af1ba7a8422c417 100644 (file)
@@ -6794,14 +6794,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
   // it's legal for the type to be incomplete if this is a pseudo-destructor
   // call.  We'll do more incomplete-type checks later in the lookup process,
   // so just skip this check for ObjC types.
-  if (BaseType->isObjCObjectOrInterfaceType()) {
+  if (!BaseType->isRecordType()) {
     ObjectType = ParsedType::make(BaseType);
     MayBePseudoDestructor = true;
     return Base;
-  } else if (!BaseType->isRecordType()) {
-    ObjectType = nullptr;
-    MayBePseudoDestructor = true;
-    return Base;
   }
 
   // The object type must be complete (or dependent), or
index 3df74edf2f9a202c4ddc2d9b81436adc05fff3a6..ce0c2ef402297366ceffb292e7e83446ec6f2bbd 100644 (file)
@@ -362,13 +362,27 @@ bool Sema::LookupTemplateName(LookupResult &Found,
     // x->B::f, and we are looking into the type of the object.
     assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
     LookupCtx = computeDeclContext(ObjectType);
-    IsDependent = !LookupCtx;
+    IsDependent = !LookupCtx && ObjectType->isDependentType();
     assert((IsDependent || !ObjectType->isIncompleteType() ||
             ObjectType->castAs<TagType>()->isBeingDefined()) &&
            "Caller should have completed object type");
 
-    // Template names cannot appear inside an Objective-C class or object type.
-    if (ObjectType->isObjCObjectOrInterfaceType()) {
+    // Template names cannot appear inside an Objective-C class or object type
+    // or a vector type.
+    //
+    // FIXME: This is wrong. For example:
+    //
+    //   template<typename T> using Vec = T __attribute__((ext_vector_type(4)));
+    //   Vec<int> vi;
+    //   vi.Vec<int>::~Vec<int>();
+    //
+    // ... should be accepted but we will not treat 'Vec' as a template name
+    // here. The right thing to do would be to check if the name is a valid
+    // vector component name, and look up a template name if not. And similarly
+    // for lookups into Objective-C class and object types, where the same
+    // problem can arise.
+    if (ObjectType->isObjCObjectOrInterfaceType() ||
+        ObjectType->isVectorType()) {
       Found.clear();
       return false;
     }
index 70a26db757c3e16821303c30b8cb227c44cdae9c..8896281e9ca4abf1c529cfc347f9d1f017766c5f 100644 (file)
@@ -26,3 +26,12 @@ void f() {
 }
 }
 #endif
+
+namespace dr2292 { // dr2292: 9
+#if __cplusplus >= 201103L
+  template<typename T> using id = T;
+  void test(int *p) {
+    p->template id<int>::~id<int>();
+  }
+#endif
+}
index 00393cc2e4c0512274a298cefc540516dc147a1d..8eeb7715cadf39ad9b54a1b182016a5ce5d5b162 100644 (file)
@@ -318,8 +318,8 @@ namespace dr420 { // dr420: yes
     q->~id<int>();
     p->id<int>::~id<int>();
     q->id<int>::~id<int>();
-    p->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}}
-    q->template id<int>::~id<int>(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}}
+    p->template id<int>::~id<int>(); // OK since dr2292
+    q->template id<int>::~id<int>(); // OK since dr2292
     p->A::template id<int>::~id<int>();
     q->A::template id<int>::~id<int>();
   }
index 4bd9a22f5f44c7ee06a11b1593becf26035efa84..28ecbade1b1a95e233cb3c06fe8e177d5d6669ed 100644 (file)
@@ -65,3 +65,11 @@ void xf(g<int> x); // expected-error {{variable has incomplete type 'void'}} exp
 struct B : g<int> { // expected-error {{expected class name}}
   B() : g<int>() {} // expected-error {{expected class member or base class name}}
 };
+
+namespace vector_components {
+  typedef __attribute__((__ext_vector_type__(2))) float vector_float2;
+  bool foo123(vector_float2 &A, vector_float2 &B)
+  {
+    return A.x < B.x && B.y > A.y;
+  }
+}
index 08938bf34a791ba0a7d750b416ef32d10604f72a..fb2d0afdc3fad3502698712284c7a8d4fd632a43 100644 (file)
@@ -34,7 +34,7 @@ void f(A* a, Foo *f, int *i, double *d, int ii) {
   g().~Bar(); // expected-error{{non-scalar}}
   
   f->::~Bar();
-  f->N::~Wibble(); // FIXME: technically, Wibble isn't a class-name
+  f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}}
   
   f->::~Bar(17, 42); // expected-error{{cannot have any arguments}}
 
@@ -79,7 +79,7 @@ namespace PR11339 {
   template<class T>
   void destroy(T* p) {
     p->~T(); // ok
-    p->~oops(); // expected-error{{expected the class name after '~' to name a destructor}}
+    p->~oops(); // expected-error{{identifier 'oops' in object destruction expression does not name a type}}
   }
 
   template void destroy(int*); // expected-note{{in instantiation of function template specialization}}
index 40dcd35c1bb64603bf67f7b0dab0a407a7ce63f1..295e1e173233de0831cd7c97751420b492dd8e99 100644 (file)
@@ -342,3 +342,19 @@ void test_vector_literal(inte4 res) {
   inte4 b = (inte4)(a, a); //expected-error{{C-style cast from vector 'inte2' (vector of 2 'int' values) to vector 'inte4' (vector of 4 'int' values) of different size}} //expected-warning{{expression result unused}}
 }
 
+typedef __attribute__((__ext_vector_type__(4))) float vector_float4;
+typedef __attribute__((__ext_vector_type__(4))) int vector_int4;
+
+namespace swizzle_template_confusion {
+  template<typename T> struct xyzw {};
+  vector_int4 foo123(vector_float4 &A, vector_float4 &B) {
+    return A.xyzw < B.x && B.y > A.y; // OK, not a template-id
+  }
+}
+
+namespace swizzle_typo_correction {
+  template<typename T> struct xyzv {};
+  vector_int4 foo123(vector_float4 &A, vector_float4 &B) {
+    return A.xyzw < B.x && B.y > A.y; // OK, not a typo for 'xyzv'
+  }
+}