]> granicus.if.org Git - clang/commitdiff
Add support for __wchar_t in -fms-extensions mode.
authorHans Wennborg <hans@hanshq.net>
Fri, 10 May 2013 10:08:40 +0000 (10:08 +0000)
committerHans Wennborg <hans@hanshq.net>
Fri, 10 May 2013 10:08:40 +0000 (10:08 +0000)
MSVC provides __wchar_t. This is the same as the built-in wchar_t type
from C++, but it is also available with -fno-wchar and in C.

The commit changes ASTContext to have two different types for this:

  - WCharTy is the built-in type used for wchar_t in C++ and __wchar_t.

  - WideCharTy is the type of a wide character literal. In C++ this is
    the same as WCharTy, and in C  it is an integer type compatible with
    the type in <stddef.h>.

This fixes PR15815.

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

15 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/PrettyPrinter.h
include/clang/Basic/TokenKinds.def
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/Analysis/FormatString.cpp
lib/Analysis/PrintfFormatString.cpp
lib/Analysis/ScanfFormatString.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/Sema/ms-wchar.c [new file with mode: 0644]
test/SemaCXX/ms-wchar.cpp [new file with mode: 0644]

index c5d3337fd22d36882cac8f7a40763b7472f20c4d..2d08c49e1d0fccd146af4ae570dfeb3e1f240d44 100644 (file)
@@ -740,7 +740,8 @@ public:
   CanQualType VoidTy;
   CanQualType BoolTy;
   CanQualType CharTy;
-  CanQualType WCharTy;  // [C++ 3.9.1p5], integer type in C99.
+  CanQualType WCharTy;  // [C++ 3.9.1p5].
+  CanQualType WideCharTy; // Same as WCharTy in C++, integer type in C99.
   CanQualType WIntTy;   // [C99 7.24.1], integer type unchanged by default promotions.
   CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99.
   CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99.
@@ -1130,11 +1131,15 @@ public:
   /// <stdint.h>.
   CanQualType getUIntMaxType() const;
 
-  /// \brief In C++, this returns the unique wchar_t type.  In C99, this
-  /// returns a type compatible with the type defined in <stddef.h> as defined
-  /// by the target.
+  /// \brief Return the unique wchar_t type available in C++ (and available as
+  /// __wchar_t as a Microsoft extension).
   QualType getWCharType() const { return WCharTy; }
 
+  /// \brief Return the type of wide characters. In C++, this returns the
+  /// unique wchar_t type. In C99, this returns a type compatible with the type
+  /// defined in <stddef.h> as defined by the target.
+  QualType getWideCharType() const { return WideCharTy; }
+
   /// \brief Return the type of "signed wchar_t".
   ///
   /// Used when in C++, as a GCC extension.
index e3c09e7b418f3930b3dc47e92fe5d3bf527209fb..adfd1ac936b9f2da4b2aff671b1134753bf02d75 100644 (file)
@@ -40,7 +40,8 @@ struct PrintingPolicy {
       SuppressUnwrittenScope(false), SuppressInitializers(false),
       ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
       SuppressStrongLifetime(false), Bool(LO.Bool),
-      TerseOutput(false), PolishForDeclaration(false) { }
+      TerseOutput(false), PolishForDeclaration(false),
+      MSWChar(LO.MicrosoftExt && !LO.WChar) { }
 
   /// \brief What language we're printing.
   LangOptions LangOpts;
@@ -146,6 +147,10 @@ struct PrintingPolicy {
   /// declaration tag; such as, do not print attributes attached to the declaration.
   ///
   unsigned PolishForDeclaration : 1;
+
+  /// \brief When true, print the built-in wchar_t type as __wchar_t. For use in
+  /// Microsoft mode when wchar_t is not available.
+  unsigned MSWChar : 1;
 };
 
 } // end namespace clang
index bcf0f31dcbf6f4b0830a81cbe3082aafd3b0d50b..0dbff81d3423bf631430b6340a1155550c488b99 100644 (file)
@@ -524,6 +524,7 @@ KEYWORD(__interface                   , KEYMS)
 ALIAS("__int8"           , char       , KEYMS)
 ALIAS("__int16"          , short      , KEYMS)
 ALIAS("__int32"          , int        , KEYMS)
+ALIAS("__wchar_t"        , wchar_t    , KEYMS)
 ALIAS("_asm"             , asm        , KEYMS)
 ALIAS("_alignof"         , __alignof  , KEYMS)
 ALIAS("__builtin_alignof", __alignof  , KEYMS)
index ffcf6b5d7a92a33d631847f9817e8a77013073f0..960f261816b12bc91ac885144ba4d5acbc7798ce 100644 (file)
@@ -897,13 +897,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
   InitBuiltinType(Int128Ty,            BuiltinType::Int128);
   InitBuiltinType(UnsignedInt128Ty,    BuiltinType::UInt128);
 
-  if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
-    if (TargetInfo::isTypeSigned(Target.getWCharType()))
-      InitBuiltinType(WCharTy,           BuiltinType::WChar_S);
-    else  // -fshort-wchar makes wchar_t be unsigned.
-      InitBuiltinType(WCharTy,           BuiltinType::WChar_U);
-  } else // C99 (or C++ using -fno-wchar)
-    WCharTy = getFromTargetType(Target.getWCharType());
+  // C++ 3.9.1p5
+  if (TargetInfo::isTypeSigned(Target.getWCharType()))
+    InitBuiltinType(WCharTy,           BuiltinType::WChar_S);
+  else  // -fshort-wchar makes wchar_t be unsigned.
+    InitBuiltinType(WCharTy,           BuiltinType::WChar_U);
+  if (LangOpts.CPlusPlus && LangOpts.WChar)
+    WideCharTy = WCharTy;
+  else {
+    // C99 (or C++ using -fno-wchar).
+    WideCharTy = getFromTargetType(Target.getWCharType());
+  }
 
   WIntTy = getFromTargetType(Target.getWIntType());
 
index fa16facb634fda7e372a0de9dfad37cf61863b35..a1f0b08494b014857d30f225aa552f2e4f8d10e0 100644 (file)
@@ -1521,7 +1521,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
   case Double:            return "double";
   case LongDouble:        return "long double";
   case WChar_S:
-  case WChar_U:           return "wchar_t";
+  case WChar_U:           return Policy.MSWChar ? "__wchar_t" : "wchar_t";
   case Char16:            return "char16_t";
   case Char32:            return "char32_t";
   case NullPtr:           return "nullptr_t";
index ad0dce4444b6ab36841c6ec4383efbb428a43768..382be24dca78bd946b73358a394c67a1c66b7827 100644 (file)
@@ -334,7 +334,7 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const {
         return false;
       QualType pointeeTy =
         C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
-      return pointeeTy == C.getWCharType();
+      return pointeeTy == C.getWideCharType();
     }
     
     case WIntTy: {
@@ -398,7 +398,7 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const {
       Res = C.getPointerType(C.CharTy);
       break;
     case WCStrTy:
-      Res = C.getPointerType(C.getWCharType());
+      Res = C.getPointerType(C.getWideCharType());
       break;
     case ObjCPointerTy:
       Res = C.ObjCBuiltinIdTy;
index 8f151b9358e6d1c23e8b864f5fd380e3d826d3e0..60f9517e7f91eecbf16ed2c07c208a6e0e8ea2e2 100644 (file)
@@ -372,7 +372,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
     case ConversionSpecifier::CArg:
       if (IsObjCLiteral)
         return ArgType(Ctx.UnsignedShortTy, "unichar");
-      return ArgType(Ctx.WCharTy, "wchar_t");
+      return ArgType(Ctx.WideCharTy, "wchar_t");
     case ConversionSpecifier::pArg:
       return ArgType::CPointerTy;
     case ConversionSpecifier::ObjCObjArg:
index 2dbc9e494881dfe635da3437596d2fcffa4a6420..676b68f391c5b1d811ba684dbc4861c8a3a0dbfa 100644 (file)
@@ -311,7 +311,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
         case LengthModifier::None:
           return ArgType::PtrTo(ArgType::AnyCharTy);
         case LengthModifier::AsLong:
-          return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
         case LengthModifier::AsAllocate:
         case LengthModifier::AsMAllocate:
           return ArgType::PtrTo(ArgType::CStrTy);
@@ -323,7 +323,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
       // FIXME: Mac OS X specific?
       switch (LM.getKind()) {
         case LengthModifier::None:
-          return ArgType::PtrTo(ArgType(Ctx.getWCharType(), "wchar_t"));
+          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
         case LengthModifier::AsAllocate:
         case LengthModifier::AsMAllocate:
           return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
index b86a2b92779d6fd44030a341edb3acfd8acc7ec6..e5d0316f738e4ae1d2bf4858726df5315ef8fd12 100644 (file)
@@ -10408,7 +10408,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
     if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
         Context.hasSameType(T, Context.LongDoubleTy) ||
         Context.hasSameType(T, Context.CharTy) ||
-        Context.hasSameType(T, Context.WCharTy) ||
+        Context.hasSameType(T, Context.WideCharTy) ||
         Context.hasSameType(T, Context.Char16Ty) ||
         Context.hasSameType(T, Context.Char32Ty)) {
       if (++Param == FnDecl->param_end())
@@ -10438,7 +10438,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
     // const char *, const wchar_t*, const char16_t*, and const char32_t*
     // are allowed as the first parameter to a two-parameter function
     if (!(Context.hasSameType(T, Context.CharTy) ||
-          Context.hasSameType(T, Context.WCharTy) ||
+          Context.hasSameType(T, Context.WideCharTy) ||
           Context.hasSameType(T, Context.Char16Ty) ||
           Context.hasSameType(T, Context.Char32Ty)))
       goto FinishedParams;
index 031a631f6c0a03e9ca79ac08372efea9743f74db..ef7e0f2e33d11b4c4675fab29d6b600dacfcaccc 100644 (file)
@@ -1448,7 +1448,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
 
   QualType StrTy = Context.CharTy;
   if (Literal.isWide())
-    StrTy = Context.getWCharType();
+    StrTy = Context.getWideCharType();
   else if (Literal.isUTF16())
     StrTy = Context.Char16Ty;
   else if (Literal.isUTF32())
@@ -2720,7 +2720,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
 
     llvm::APInt LengthI(32, Length + 1);
     if (IT == PredefinedExpr::LFunction)
-      ResTy = Context.WCharTy.withConst();
+      ResTy = Context.WideCharTy.withConst();
     else
       ResTy = Context.CharTy.withConst();
     ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
@@ -2742,7 +2742,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
 
   QualType Ty;
   if (Literal.isWide())
-    Ty = Context.WCharTy; // L'x' -> wchar_t in C and C++.
+    Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++.
   else if (Literal.isUTF16())
     Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11.
   else if (Literal.isUTF32())
index 0e3dc003ab128e4cb999638bfc377f2be4f8993c..d37f61ab8abddde2c35efd853575d0ee167902c8 100644 (file)
@@ -266,7 +266,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
       break;
       
     case CharacterLiteral::Wide:
-      NumberType = Context.getWCharType();
+      NumberType = Context.getWideCharType();
       break;
       
     case CharacterLiteral::UTF16:
@@ -521,7 +521,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
         break;
         
       case CharacterLiteral::Wide:
-        ValueType = Context.getWCharType();
+        ValueType = Context.getWideCharType();
         break;
         
       case CharacterLiteral::UTF16:
index 9e8936e17b8a6d4985c0057a50bc8b736551cb12..7016e565dabaf00a5b8ec7db9a4cc44f4c85e42e 100644 (file)
@@ -65,7 +65,7 @@ static Expr *IsStringInit(Expr *Init, const ArrayType *AT,
     // correction from DR343): "An array with element type compatible with a
     // qualified or unqualified version of wchar_t may be initialized by a wide
     // string literal, optionally enclosed in braces."
-    if (Context.typesAreCompatible(Context.getWCharType(),
+    if (Context.typesAreCompatible(Context.getWideCharType(),
                                    ElemTy.getUnqualifiedType()))
       return Init;
 
index 7ef04e964dc664759acb3d69a96d848ed837d6f0..862334a82a6044941a2317a20b1ec5599390570d 100644 (file)
@@ -1105,7 +1105,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
   llvm::APInt LengthI(32, Length + 1);
   QualType ResTy;
   if (IT == PredefinedExpr::LFunction)
-    ResTy = getSema().Context.WCharTy.withConst();
+    ResTy = getSema().Context.WideCharTy.withConst();
   else
     ResTy = getSema().Context.CharTy.withConst();
   ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI, 
diff --git a/test/Sema/ms-wchar.c b/test/Sema/ms-wchar.c
new file mode 100644 (file)
index 0000000..52a736c
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+// C++ mode with -fno-wchar works the same as C mode for wchar_t.
+// RUN: %clang_cc1 -x c++ -fno-wchar -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f(); // expected-error{{unknown type name 'wchar_t'}}
+
+// __wchar_t is available as an MS extension.
+__wchar_t g = L'a'; // expected-note {{previous}}
+
+// __wchar_t is a distinct type, separate from the target's integer type for wide chars.
+unsigned short g; // expected-error {{redefinition of 'g' with a different type: 'unsigned short' vs '__wchar_t'}}
+
+// The type of a wide string literal is actually not __wchar_t.
+__wchar_t s[] = L"Hello world!"; // expected-error {{array initializer must be an initializer list}}
diff --git a/test/SemaCXX/ms-wchar.cpp b/test/SemaCXX/ms-wchar.cpp
new file mode 100644 (file)
index 0000000..2cbf745
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions -triple i386-pc-win32 %s
+
+wchar_t f();
+__wchar_t f(); // No error, wchar_t and __wchar_t are the same type.
+
+__wchar_t g = L'a';
+__wchar_t s[] = L"Hello world!";
+
+unsigned short t[] = L"Hello world!"; // expected-error{{array initializer must be an initializer list}}