r235166 - Move fixit for const init from note to diag, weaken to warning in MS mode.

Nico Weber nicolasweber at gmx.de
Fri Apr 17 01:32:39 PDT 2015


Author: nico
Date: Fri Apr 17 03:32:38 2015
New Revision: 235166

URL: http://llvm.org/viewvc/llvm-project?rev=235166&view=rev
Log:
Move fixit for const init from note to diag, weaken to warning in MS mode.

r235046 turned "extern __declspec(selectany) int a;" from a declaration into
a definition to fix PR23242 (required for compatibility with mc.exe output).
However, this broke parsing Windows headers: A  d3d11 headers contain something
like

  struct SomeStruct {};
  extern const __declspec(selectany) SomeStruct some_struct;

This is now a definition, and const objects either need an explicit default
ctor or an initializer so this errors out with 

  d3d11.h(1065,48) :
    error: default initialization of an object of const type
           'const CD3D11_DEFAULT' without a user-provided default constructor

(cl.exe just doesn't implement this rule, independent of selectany.)

To work around this, weaken this error into a warning for selectany decls
in microsoft mode, and recover with zero-initialization.

Doing this is a bit hairy since it adds a fixit on an error emitted
by InitializationSequence – this means it needs to build a correct AST, which
in turn means InitializationSequence::Failed() cannot return true when this
fixit is applied. As a workaround, the patch adds a fixit member to
InitializationSequence, and InitializationSequence::Perform() prints the
diagnostic if the fixit member is set right after its call to Diagnose.
That function is usually called when InitializationSequences are used –
InitListChecker::PerformEmptyInit() doesn't call it, but the InitListChecker
case never performs default-initialization, so this is technically OK.

This is the alternative, original fix for PR20208 that got reviewed in the
thread "[patch] Improve diagnostic on default-initializing const variables
(PR20208)".  This change basically reverts r213725, adds the original fix for
PR20208, and makes the error a warning in Microsoft mode.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp
    cfe/trunk/test/CXX/drs/dr0xx.cpp
    cfe/trunk/test/CXX/drs/dr4xx.cpp
    cfe/trunk/test/FixIt/fixit.cpp
    cfe/trunk/test/SemaCXX/attr-selectany.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
    cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp
    cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Apr 17 03:32:38 2015
@@ -5470,8 +5470,11 @@ def err_address_space_qualified_delete :
 def err_default_init_const : Error<
   "default initialization of an object of const type %0"
   "%select{| without a user-provided default constructor}1">;
-def note_add_initializer : Note<
-  "add an explicit initializer to initialize %0">;
+def ext_default_init_const : ExtWarn<
+  "default initialization of an object of const type %0"
+  "%select{| without a user-provided default constructor}1 "
+  "is a Microsoft extension">,
+  InGroup<Microsoft>;
 def err_delete_operand : Error<"cannot delete expression of type %0">;
 def ext_delete_void_ptr_operand : ExtWarn<
   "cannot delete expression with pointer-to-'void' type %0">,

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Fri Apr 17 03:32:38 2015
@@ -844,6 +844,21 @@ private:
 
   /// \brief The incomplete type that caused a failure.
   QualType FailedIncompleteType;
+
+  /// \brief The fixit that needs to be applied to make this initialization
+  /// succeed.
+  std::string ZeroInitializationFixit;
+  SourceLocation ZeroInitializationFixitLoc;
+
+public:
+  /// \brief Call for initializations are invalid but that would be valid
+  /// zero initialzations if Fixit was applied.
+  void SetZeroInitializationFixit(const std::string& Fixit, SourceLocation L) {
+    ZeroInitializationFixit = Fixit;
+    ZeroInitializationFixitLoc = L;
+  }
+
+private:
   
   /// \brief Prints a follow-up note that highlights the location of
   /// the initialized entity, if it's remote.

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Apr 17 03:32:38 2015
@@ -3101,6 +3101,28 @@ void InitializationSequence::SetOverload
 // Attempt initialization
 //===----------------------------------------------------------------------===//
 
+/// Tries to add a zero initializer. Returns true if that worked.
+static bool
+maybeRecoverWithZeroInitialization(Sema &S, InitializationSequence &Sequence,
+                                   const InitializedEntity &Entity) {
+  if (Entity.getKind() != InitializedEntity::EK_Variable)
+    return false;
+
+  VarDecl *VD = cast<VarDecl>(Entity.getDecl());
+  if (VD->getInit() || VD->getLocEnd().isMacroID())
+    return false;
+
+  QualType VariableTy = VD->getType().getCanonicalType();
+  SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
+  std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
+  if (!Init.empty()) {
+    Sequence.AddZeroInitializationStep(Entity.getType());
+    Sequence.SetZeroInitializationFixit(Init, Loc);
+    return true;
+  }
+  return false;
+}
+
 static void MaybeProduceObjCObject(Sema &S,
                                    InitializationSequence &Sequence,
                                    const InitializedEntity &Entity) {
@@ -3339,7 +3361,8 @@ static void TryConstructorInitialization
   if (Kind.getKind() == InitializationKind::IK_Default &&
       Entity.getType().isConstQualified() &&
       !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) {
-    Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+    if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
+      Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
     return;
   }
 
@@ -4231,7 +4254,8 @@ static void TryDefaultInitialization(Sem
   //   a const-qualified type T, T shall be a class type with a user-provided
   //   default constructor.
   if (DestType.isConstQualified() && S.getLangOpts().CPlusPlus) {
-    Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+    if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
+      Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
     return;
   }
 
@@ -5749,6 +5773,21 @@ InitializationSequence::Perform(Sema &S,
     Diagnose(S, Entity, Kind, Args);
     return ExprError();
   }
+  if (!ZeroInitializationFixit.empty()) {
+    unsigned DiagID = diag::err_default_init_const;
+    if (Decl *D = Entity.getDecl())
+      if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
+        DiagID = diag::ext_default_init_const;
+
+    // The initialization would have succeeded with this fixit. Since the fixit
+    // is on the error, we need to build a valid AST in this case, so this isn't
+    // handled in the Failed() branch above.
+    QualType DestType = Entity.getType();
+    S.Diag(Kind.getLocation(), DiagID)
+        << DestType << (bool)DestType->getAs<RecordType>()
+        << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+                                      ZeroInitializationFixit);
+  }
 
   if (getKind() == DependentSequence) {
     // If the declaration is a non-dependent, incomplete array type
@@ -6549,26 +6588,6 @@ static void diagnoseListInit(Sema &S, co
          "Inconsistent init list check result.");
 }
 
-/// Prints a fixit for adding a null initializer for |Entity|. Call this only
-/// right after emitting a diagnostic.
-static void maybeEmitZeroInitializationFixit(Sema &S,
-                                             InitializationSequence &Sequence,
-                                             const InitializedEntity &Entity) {
-  if (Entity.getKind() != InitializedEntity::EK_Variable)
-    return;
-
-  VarDecl *VD = cast<VarDecl>(Entity.getDecl());
-  if (VD->getInit() || VD->getLocEnd().isMacroID())
-    return;
-
-  QualType VariableTy = VD->getType().getCanonicalType();
-  SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
-  std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
-
-  S.Diag(Loc, diag::note_add_initializer)
-      << VD << FixItHint::CreateInsertion(Loc, Init);
-}
-
 bool InitializationSequence::Diagnose(Sema &S,
                                       const InitializedEntity &Entity,
                                       const InitializationKind &Kind,
@@ -6900,7 +6919,6 @@ bool InitializationSequence::Diagnose(Se
     } else {
       S.Diag(Kind.getLocation(), diag::err_default_init_const)
           << DestType << (bool)DestType->getAs<RecordType>();
-      maybeEmitZeroInitializationFixit(S, *this, Entity);
     }
     break;
 

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Fri Apr 17 03:32:38 2015
@@ -17,7 +17,7 @@ extern int (*const d)(int);
 
 // A variable declaration which uses the constexpr specifier shall have an
 // initializer and shall be initialized by a constant expression.
-constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'ni1'}}
+constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
 constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
 constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
 
@@ -34,4 +34,4 @@ struct pixel {
   int x, y;
 };
 constexpr pixel ur = { 1294, 1024 }; // ok
-constexpr pixel origin;              // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'origin'}}
+constexpr pixel origin;              // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}}

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp Fri Apr 17 03:32:38 2015
@@ -36,7 +36,7 @@ struct S3 {
 constexpr S3 s3a = S3(0);
 constexpr S3 s3b = s3a;
 constexpr S3 s3c = S3();
-constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 's3d'}}
+constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}}
 
 struct S4 {
   S4() = default;
@@ -119,6 +119,6 @@ namespace PR13492 {
   };
 
   void f() {
-    const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b'}}
+    const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}}
   }
 }

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/p6.cpp Fri Apr 17 03:32:38 2015
@@ -10,15 +10,15 @@ struct NoUserDefault : public MakeNonPOD
 struct HasUserDefault { HasUserDefault(); };
 
 void test_const_default_init() {
-  const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'x1'}}
+  const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}}
   const HasUserDefault x2;
-  const int x3; // expected-error{{default initialization of an object of const type 'const int'}} expected-note{{add an explicit initializer to initialize 'x3'}}
+  const int x3; // expected-error{{default initialization of an object of const type 'const int'}}
 }
 
 // rdar://8501008
 struct s0 {};
 struct s1 { static const s0 foo; };
-const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'foo'}}
+const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}}
 
 template<typename T>
 struct s2 {

Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Fri Apr 17 03:32:38 2015
@@ -864,7 +864,7 @@ namespace dr77 { // dr77: yes
 namespace dr78 { // dr78: sup ????
   // Under DR78, this is valid, because 'k' has static storage duration, so is
   // zero-initialized.
-  const int k; // expected-error {{default initialization of an object of const}} expected-note{{add an explicit initializer to initialize 'k'}}
+  const int k; // expected-error {{default initialization of an object of const}}
 }
 
 // dr79: na

Modified: cfe/trunk/test/CXX/drs/dr4xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr4xx.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr4xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr4xx.cpp Fri Apr 17 03:32:38 2015
@@ -1202,9 +1202,9 @@ namespace dr497 { // dr497: yes
     struct S {
       mutable int i;
     };
-    const S cs; // expected-error {{default initialization}} expected-note {{add an explicit initializer}}
+    const S cs; // expected-error {{default initialization}}
     int S::*pm = &S::i;
-    cs.*pm = 88;
+    cs.*pm = 88; // expected-error {{not assignable}}
   }
 
   void after() {

Modified: cfe/trunk/test/FixIt/fixit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit.cpp (original)
+++ cfe/trunk/test/FixIt/fixit.cpp Fri Apr 17 03:32:38 2015
@@ -387,3 +387,11 @@ struct conversion_operator {
   // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:32}:""
   // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:44-[[@LINE-2]]:44}:" conversion_operator::* const"
 };
+
+struct const_zero_init {
+  int a;
+};
+const const_zero_init czi; // expected-error {{default initialization of an object of const type 'const const_zero_init'}}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}"
+int use_czi = czi.a;
+

Modified: cfe/trunk/test/SemaCXX/attr-selectany.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-selectany.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-selectany.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-selectany.cpp Fri Apr 17 03:32:38 2015
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
 // MSVC produces similar diagnostics.
 
 __declspec(selectany) void foo() { } // expected-error{{'selectany' can only be applied to data items with external linkage}}
@@ -34,3 +34,13 @@ __declspec(selectany) X x(1);
 
 namespace { class Internal {}; }
 __declspec(selectany) auto x8 = Internal(); // expected-error {{'selectany' can only be applied to data items with external linkage}}
+
+
+// The D3D11 headers do something like this.  MSVC doesn't error on this at
+// all, even without the __declspec(selectany), in violation of the standard.
+// We fall back to a warning for selectany to accept headers.
+struct SomeStruct {};
+extern const __declspec(selectany) SomeStruct some_struct; // expected-warning {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor is a Microsoft extension}}
+
+// Without selectany, this should stay an error.
+const SomeStruct some_struct2; // expected-error {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor}}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Apr 17 03:32:38 2015
@@ -1179,7 +1179,7 @@ namespace ExternConstexpr {
   void f() {
     extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}}
     constexpr int j = 0;
-    constexpr int k; // expected-error {{default initialization of an object of const type}} expected-note{{add an explicit initializer to initialize 'k'}}
+    constexpr int k; // expected-error {{default initialization of an object of const type}}
   }
 }
 

Modified: cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-value-init.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-value-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-value-init.cpp Fri Apr 17 03:32:38 2015
@@ -14,7 +14,7 @@ void f() {
   constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
 }
 
-constexpr B b1; // expected-error {{without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b1'}}
+constexpr B b1; // expected-error {{without a user-provided default constructor}}
 constexpr B b2 = B(); // ok
 static_assert(b2.a.a == 1, "");
 static_assert(b2.a.b == 2, "");
@@ -23,9 +23,9 @@ struct C {
   int c;
 };
 struct D : C { int d; };
-constexpr C c1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'c1'}}
+constexpr C c1; // expected-error {{without a user-provided default constructor}}
 constexpr C c2 = C(); // ok
-constexpr D d1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'd1'}}
+constexpr D d1; // expected-error {{without a user-provided default constructor}}
 constexpr D d2 = D(); // ok with DR1452
 static_assert(D().c == 0, "");
 static_assert(D().d == 0, "");

Modified: cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-cursory-default-delete.cpp Fri Apr 17 03:32:38 2015
@@ -25,7 +25,7 @@ void fn1 () {
   non_const_copy ncc2 = ncc;
   ncc = ncc2;
   const non_const_copy cncc{};
-  const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'cncc1'}}
+  const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}}
   non_const_copy ncc3 = cncc; // expected-error {{no matching}}
   ncc = cncc; // expected-error {{no viable overloaded}}
 };

Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=235166&r1=235165&r2=235166&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Fri Apr 17 03:32:38 2015
@@ -58,13 +58,13 @@ namespace out_of_line {
     template<typename T, typename T0> static CONST T b = T(100);
     template<typename T> static CONST T b<T,int>;
   };
-  template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'a<int, char>'}}
+  template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
   template<typename T> CONST T B4::a<T,int>;
   template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
   template CONST int B4::a<int,int>;
 
   template<typename T, typename T0> CONST T B4::b;
-  template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'b<int, int>'}}
+  template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
   template CONST int B4::b<int,char>;
   template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
 }






More information about the cfe-commits mailing list