Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit c40b644

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@235166 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 8dcb102 commit c40b644

File tree

14 files changed

+97
-43
lines changed

14 files changed

+97
-43
lines changed

include/clang/Basic/DiagnosticSemaKinds.td

+5-2
Original file line numberDiff line numberDiff line change
@@ -5470,8 +5470,11 @@ def err_address_space_qualified_delete : Error<
54705470
def err_default_init_const : Error<
54715471
"default initialization of an object of const type %0"
54725472
"%select{| without a user-provided default constructor}1">;
5473-
def note_add_initializer : Note<
5474-
"add an explicit initializer to initialize %0">;
5473+
def ext_default_init_const : ExtWarn<
5474+
"default initialization of an object of const type %0"
5475+
"%select{| without a user-provided default constructor}1 "
5476+
"is a Microsoft extension">,
5477+
InGroup<Microsoft>;
54755478
def err_delete_operand : Error<"cannot delete expression of type %0">;
54765479
def ext_delete_void_ptr_operand : ExtWarn<
54775480
"cannot delete expression with pointer-to-'void' type %0">,

include/clang/Sema/Initialization.h

+15
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,21 @@ class InitializationSequence {
844844

845845
/// \brief The incomplete type that caused a failure.
846846
QualType FailedIncompleteType;
847+
848+
/// \brief The fixit that needs to be applied to make this initialization
849+
/// succeed.
850+
std::string ZeroInitializationFixit;
851+
SourceLocation ZeroInitializationFixitLoc;
852+
853+
public:
854+
/// \brief Call for initializations are invalid but that would be valid
855+
/// zero initialzations if Fixit was applied.
856+
void SetZeroInitializationFixit(const std::string& Fixit, SourceLocation L) {
857+
ZeroInitializationFixit = Fixit;
858+
ZeroInitializationFixitLoc = L;
859+
}
860+
861+
private:
847862

848863
/// \brief Prints a follow-up note that highlights the location of
849864
/// the initialized entity, if it's remote.

lib/Sema/SemaInit.cpp

+41-23
Original file line numberDiff line numberDiff line change
@@ -3101,6 +3101,28 @@ void InitializationSequence::SetOverloadFailure(FailureKind Failure,
31013101
// Attempt initialization
31023102
//===----------------------------------------------------------------------===//
31033103

3104+
/// Tries to add a zero initializer. Returns true if that worked.
3105+
static bool
3106+
maybeRecoverWithZeroInitialization(Sema &S, InitializationSequence &Sequence,
3107+
const InitializedEntity &Entity) {
3108+
if (Entity.getKind() != InitializedEntity::EK_Variable)
3109+
return false;
3110+
3111+
VarDecl *VD = cast<VarDecl>(Entity.getDecl());
3112+
if (VD->getInit() || VD->getLocEnd().isMacroID())
3113+
return false;
3114+
3115+
QualType VariableTy = VD->getType().getCanonicalType();
3116+
SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
3117+
std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
3118+
if (!Init.empty()) {
3119+
Sequence.AddZeroInitializationStep(Entity.getType());
3120+
Sequence.SetZeroInitializationFixit(Init, Loc);
3121+
return true;
3122+
}
3123+
return false;
3124+
}
3125+
31043126
static void MaybeProduceObjCObject(Sema &S,
31053127
InitializationSequence &Sequence,
31063128
const InitializedEntity &Entity) {
@@ -3339,7 +3361,8 @@ static void TryConstructorInitialization(Sema &S,
33393361
if (Kind.getKind() == InitializationKind::IK_Default &&
33403362
Entity.getType().isConstQualified() &&
33413363
!cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) {
3342-
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
3364+
if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
3365+
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
33433366
return;
33443367
}
33453368

@@ -4231,7 +4254,8 @@ static void TryDefaultInitialization(Sema &S,
42314254
// a const-qualified type T, T shall be a class type with a user-provided
42324255
// default constructor.
42334256
if (DestType.isConstQualified() && S.getLangOpts().CPlusPlus) {
4234-
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
4257+
if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
4258+
Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
42354259
return;
42364260
}
42374261

@@ -5749,6 +5773,21 @@ InitializationSequence::Perform(Sema &S,
57495773
Diagnose(S, Entity, Kind, Args);
57505774
return ExprError();
57515775
}
5776+
if (!ZeroInitializationFixit.empty()) {
5777+
unsigned DiagID = diag::err_default_init_const;
5778+
if (Decl *D = Entity.getDecl())
5779+
if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
5780+
DiagID = diag::ext_default_init_const;
5781+
5782+
// The initialization would have succeeded with this fixit. Since the fixit
5783+
// is on the error, we need to build a valid AST in this case, so this isn't
5784+
// handled in the Failed() branch above.
5785+
QualType DestType = Entity.getType();
5786+
S.Diag(Kind.getLocation(), DiagID)
5787+
<< DestType << (bool)DestType->getAs<RecordType>()
5788+
<< FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
5789+
ZeroInitializationFixit);
5790+
}
57525791

57535792
if (getKind() == DependentSequence) {
57545793
// If the declaration is a non-dependent, incomplete array type
@@ -6549,26 +6588,6 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
65496588
"Inconsistent init list check result.");
65506589
}
65516590

6552-
/// Prints a fixit for adding a null initializer for |Entity|. Call this only
6553-
/// right after emitting a diagnostic.
6554-
static void maybeEmitZeroInitializationFixit(Sema &S,
6555-
InitializationSequence &Sequence,
6556-
const InitializedEntity &Entity) {
6557-
if (Entity.getKind() != InitializedEntity::EK_Variable)
6558-
return;
6559-
6560-
VarDecl *VD = cast<VarDecl>(Entity.getDecl());
6561-
if (VD->getInit() || VD->getLocEnd().isMacroID())
6562-
return;
6563-
6564-
QualType VariableTy = VD->getType().getCanonicalType();
6565-
SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
6566-
std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
6567-
6568-
S.Diag(Loc, diag::note_add_initializer)
6569-
<< VD << FixItHint::CreateInsertion(Loc, Init);
6570-
}
6571-
65726591
bool InitializationSequence::Diagnose(Sema &S,
65736592
const InitializedEntity &Entity,
65746593
const InitializationKind &Kind,
@@ -6900,7 +6919,6 @@ bool InitializationSequence::Diagnose(Sema &S,
69006919
} else {
69016920
S.Diag(Kind.getLocation(), diag::err_default_init_const)
69026921
<< DestType << (bool)DestType->getAs<RecordType>();
6903-
maybeEmitZeroInitializationFixit(S, *this, Entity);
69046922
}
69056923
break;
69066924

test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extern int (*const d)(int);
1717

1818
// A variable declaration which uses the constexpr specifier shall have an
1919
// initializer and shall be initialized by a constant expression.
20-
constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} expected-note {{add an explicit initializer to initialize 'ni1'}}
20+
constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
2121
constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
2222
constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
2323

@@ -34,4 +34,4 @@ struct pixel {
3434
int x, y;
3535
};
3636
constexpr pixel ur = { 1294, 1024 }; // ok
37-
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'}}
37+
constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}}

test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct S3 {
3636
constexpr S3 s3a = S3(0);
3737
constexpr S3 s3b = s3a;
3838
constexpr S3 s3c = S3();
39-
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'}}
39+
constexpr S3 s3d; // expected-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}}
4040

4141
struct S4 {
4242
S4() = default;
@@ -119,6 +119,6 @@ namespace PR13492 {
119119
};
120120

121121
void f() {
122-
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'}}
122+
const B b; // expected-error {{default initialization of an object of const type 'const PR13492::B' without a user-provided default constructor}}
123123
}
124124
}

test/CXX/dcl.decl/dcl.init/p6.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ struct NoUserDefault : public MakeNonPOD { };
1010
struct HasUserDefault { HasUserDefault(); };
1111

1212
void test_const_default_init() {
13-
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'}}
13+
const NoUserDefault x1; // expected-error{{default initialization of an object of const type 'const NoUserDefault' without a user-provided default constructor}}
1414
const HasUserDefault x2;
15-
const int x3; // expected-error{{default initialization of an object of const type 'const int'}} expected-note{{add an explicit initializer to initialize 'x3'}}
15+
const int x3; // expected-error{{default initialization of an object of const type 'const int'}}
1616
}
1717

1818
// rdar://8501008
1919
struct s0 {};
2020
struct s1 { static const s0 foo; };
21-
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'}}
21+
const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}}
2222

2323
template<typename T>
2424
struct s2 {

test/CXX/drs/dr0xx.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ namespace dr77 { // dr77: yes
864864
namespace dr78 { // dr78: sup ????
865865
// Under DR78, this is valid, because 'k' has static storage duration, so is
866866
// zero-initialized.
867-
const int k; // expected-error {{default initialization of an object of const}} expected-note{{add an explicit initializer to initialize 'k'}}
867+
const int k; // expected-error {{default initialization of an object of const}}
868868
}
869869

870870
// dr79: na

test/CXX/drs/dr4xx.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1202,9 +1202,9 @@ namespace dr497 { // dr497: yes
12021202
struct S {
12031203
mutable int i;
12041204
};
1205-
const S cs; // expected-error {{default initialization}} expected-note {{add an explicit initializer}}
1205+
const S cs; // expected-error {{default initialization}}
12061206
int S::*pm = &S::i;
1207-
cs.*pm = 88;
1207+
cs.*pm = 88; // expected-error {{not assignable}}
12081208
}
12091209

12101210
void after() {

test/FixIt/fixit.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,11 @@ struct conversion_operator {
387387
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:32}:""
388388
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:44-[[@LINE-2]]:44}:" conversion_operator::* const"
389389
};
390+
391+
struct const_zero_init {
392+
int a;
393+
};
394+
const const_zero_init czi; // expected-error {{default initialization of an object of const type 'const const_zero_init'}}
395+
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}"
396+
int use_czi = czi.a;
397+

test/SemaCXX/attr-selectany.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -std=c++11 %s
1+
// RUN: %clang_cc1 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s
22
// MSVC produces similar diagnostics.
33

44
__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);
3434

3535
namespace { class Internal {}; }
3636
__declspec(selectany) auto x8 = Internal(); // expected-error {{'selectany' can only be applied to data items with external linkage}}
37+
38+
39+
// The D3D11 headers do something like this. MSVC doesn't error on this at
40+
// all, even without the __declspec(selectany), in violation of the standard.
41+
// We fall back to a warning for selectany to accept headers.
42+
struct SomeStruct {};
43+
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}}
44+
45+
// Without selectany, this should stay an error.
46+
const SomeStruct some_struct2; // expected-error {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor}}

test/SemaCXX/constant-expression-cxx11.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ namespace ExternConstexpr {
11791179
void f() {
11801180
extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}}
11811181
constexpr int j = 0;
1182-
constexpr int k; // expected-error {{default initialization of an object of const type}} expected-note{{add an explicit initializer to initialize 'k'}}
1182+
constexpr int k; // expected-error {{default initialization of an object of const type}}
11831183
}
11841184
}
11851185

test/SemaCXX/constexpr-value-init.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void f() {
1414
constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
1515
}
1616

17-
constexpr B b1; // expected-error {{without a user-provided default constructor}} expected-note {{add an explicit initializer to initialize 'b1'}}
17+
constexpr B b1; // expected-error {{without a user-provided default constructor}}
1818
constexpr B b2 = B(); // ok
1919
static_assert(b2.a.a == 1, "");
2020
static_assert(b2.a.b == 2, "");
@@ -23,9 +23,9 @@ struct C {
2323
int c;
2424
};
2525
struct D : C { int d; };
26-
constexpr C c1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'c1'}}
26+
constexpr C c1; // expected-error {{without a user-provided default constructor}}
2727
constexpr C c2 = C(); // ok
28-
constexpr D d1; // expected-error {{without a user-provided default constructor}} expected-note{{add an explicit initializer to initialize 'd1'}}
28+
constexpr D d1; // expected-error {{without a user-provided default constructor}}
2929
constexpr D d2 = D(); // ok with DR1452
3030
static_assert(D().c == 0, "");
3131
static_assert(D().d == 0, "");

test/SemaCXX/cxx0x-cursory-default-delete.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void fn1 () {
2525
non_const_copy ncc2 = ncc;
2626
ncc = ncc2;
2727
const non_const_copy cncc{};
28-
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'}}
28+
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}}
2929
non_const_copy ncc3 = cncc; // expected-error {{no matching}}
3030
ncc = cncc; // expected-error {{no viable overloaded}}
3131
};

test/SemaCXX/cxx1y-variable-templates_in_class.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ namespace out_of_line {
5858
template<typename T, typename T0> static CONST T b = T(100);
5959
template<typename T> static CONST T b<T,int>;
6060
};
61-
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>'}}
61+
template<typename T, typename T0> CONST T B4::a; // expected-error {{default initialization of an object of const type 'const int'}}
6262
template<typename T> CONST T B4::a<T,int>;
6363
template CONST int B4::a<int,char>; // expected-note {{in instantiation of}}
6464
template CONST int B4::a<int,int>;
6565

6666
template<typename T, typename T0> CONST T B4::b;
67-
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>'}}
67+
template<typename T> CONST T B4::b<T,int>; // expected-error {{default initialization of an object of const type 'const int'}}
6868
template CONST int B4::b<int,char>;
6969
template CONST int B4::b<int,int>; // expected-note {{in instantiation of}}
7070
}

0 commit comments

Comments
 (0)