]> granicus.if.org Git - clang/commitdiff
[preprocessor] Allow comparing two macro definitions syntactically instead of only...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 3 Apr 2013 17:39:30 +0000 (17:39 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 3 Apr 2013 17:39:30 +0000 (17:39 +0000)
Syntactically means the function macro parameter names do not need to use the same
identifiers in order for the definitions to be considered identical.

Syntactic equivalence is a microsoft extension for macro redefinitions and we'll also
use this kind of comparison to check for ambiguous macros coming from modules.

rdar://13562254

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

include/clang/Lex/MacroInfo.h
lib/Frontend/CompilerInstance.cpp
lib/Lex/MacroInfo.cpp
lib/Lex/PPDirectives.cpp
lib/Serialization/ASTReader.cpp
test/Modules/Inputs/macros_left.h
test/Modules/Inputs/macros_right.h
test/Modules/macros.c
test/Preprocessor/macro_misc.c

index d7e72fb5c687f2273b5cd412ac0758311155ff72..64323b7c765f580bba05939e5bff3b9d7ec39a06 100644 (file)
@@ -145,9 +145,12 @@ public:
   /// \brief Return true if the specified macro definition is equal to
   /// this macro in spelling, arguments, and whitespace.
   ///
-  /// This is used to emit duplicate definition warnings.  This implements the rules
-  /// in C99 6.10.3.
-  bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const;
+  /// \param Syntactically if true, the macro definitions can be identical even
+  /// if they use different identifiers for the function macro parameters.
+  /// Otherwise the comparison is lexical and this implements the rules in
+  /// C99 6.10.3.
+  bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
+                     bool Syntactically) const;
 
   /// \brief Set or clear the isBuiltinMacro flag.
   void setIsBuiltinMacro(bool Val = true) {
index b27c06a19c39276dbc8cca6401bb0d7e2d171942..fce3d33780b7fd4d2702d226b0ad134cecb1f329 100644 (file)
@@ -991,7 +991,8 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
   // If the current macro definition is the same as the predefined macro
   // definition, it's okay.
   if (LatestDef.getMacroInfo() == PredefinedDef.getMacroInfo() ||
-      LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP))
+      LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP,
+                                              /*Syntactically=*/true))
     return;
 
   // The macro definitions differ.
index dc091f625b52987351c6450c83a75423744e44c9..5abafe1cb76d22ab935d2bf01c92b3e9f403052e 100644 (file)
@@ -61,11 +61,17 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
   return DefinitionLength;
 }
 
-// isIdenticalTo - Return true if the specified macro definition is equal to
-// this macro in spelling, arguments, and whitespace.  This is used to emit
-// duplicate definition warnings.  This implements the rules in C99 6.10.3.
-//
-bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
+/// \brief Return true if the specified macro definition is equal to
+/// this macro in spelling, arguments, and whitespace.
+///
+/// \param Syntactically if true, the macro definitions can be identical even
+/// if they use different identifiers for the function macro parameters.
+/// Otherwise the comparison is lexical and this implements the rules in
+/// C99 6.10.3.
+bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
+                              bool Syntactically) const {
+  bool Lexically = !Syntactically;
+
   // Check # tokens in replacement, number of args, and various flags all match.
   if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
       getNumArgs() != Other.getNumArgs() ||
@@ -74,10 +80,12 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
       isGNUVarargs() != Other.isGNUVarargs())
     return false;
 
-  // Check arguments.
-  for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
-       I != E; ++I, ++OI)
-    if (*I != *OI) return false;
+  if (Lexically) {
+    // Check arguments.
+    for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+         I != E; ++I, ++OI)
+      if (*I != *OI) return false;
+  }
 
   // Check all the tokens.
   for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
@@ -95,7 +103,15 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
 
     // If this is an identifier, it is easy.
     if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
-      if (A.getIdentifierInfo() != B.getIdentifierInfo())
+      if (A.getIdentifierInfo() == B.getIdentifierInfo())
+        continue;
+      if (Lexically)
+        return false;
+      // With syntactic equivalence the parameter names can be different as long
+      // as they are used in the same place.
+      int AArgNum = getArgumentNum(A.getIdentifierInfo());
+      int BArgNum = Other.getArgumentNum(B.getIdentifierInfo());
+      if (AArgNum == -1 || AArgNum != BArgNum)
         return false;
       continue;
     }
index 3fc19e41f818be8f5be5e86caf2461199ad26aa5..07c1867010009dbbe40e214c136f3e4de018ea49 100644 (file)
@@ -1949,9 +1949,9 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
       if (OtherMI->isBuiltinMacro())
         Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro);
       // Macros must be identical.  This means all tokens and whitespace
-      // separation must be the same.  C99 6.10.3.2.
+      // separation must be the same.  C99 6.10.3p2.
       else if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
-               !MI->isIdenticalTo(*OtherMI, *this)) {
+               !MI->isIdenticalTo(*OtherMI, *this, /*Syntactic=*/LangOpts.MicrosoftExt)) {
         Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
           << MacroNameTok.getIdentifierInfo();
         Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
index 4c2d2197e498a3b1dce0315978ce94fcb58720ec..4c4277c30fd0a4a244b8defb36de77c1e15032a8 100644 (file)
@@ -1604,7 +1604,8 @@ void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
     MacroDirective::DefInfo PrevDef = Prev->getDefinition();
     MacroInfo *PrevMI = PrevDef.getMacroInfo();
     MacroInfo *NewMI = DefMD->getInfo();
-    if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP)) {
+    if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP,
+                                                  /*Syntactically=*/true)) {
       // Before marking the macros as ambiguous, check if this is a case where
       // the system macro uses a not identical definition compared to a macro
       // from the clang headers. For example:
index a8aac75a2fda0cf850619fe13adb4269937f80a0..076b0464e6c6cdc8eb848aec11c868aaaf1f12c2 100644 (file)
@@ -12,3 +12,5 @@
 #define LEFT_RIGHT_DIFFERENT3 float
 
 #define LEFT_RIGHT_DIFFERENT float
+
+#define FN_ADD(a,b) (a+b)
index 445f579cf6d03da28b2b39c692f57c550a2a440d..dbbd2c364350339e9ff2b04614f6e7d40c8bc0f2 100644 (file)
@@ -15,3 +15,5 @@
 
 #undef TOP_RIGHT_REDEF
 #define TOP_RIGHT_REDEF float
+
+#define FN_ADD(x, y) (x+y)
index c715ec965177a182eeba7be20e8139308c95756c..fc448d998906c230e2831142cf8b46c9477e3a59 100644 (file)
@@ -125,6 +125,7 @@ void test2() {
 void test3() {
   double d;
   LEFT_RIGHT_DIFFERENT *dp = &d; // okay
+  int x = FN_ADD(1,2);
 }
 
 #ifndef TOP_RIGHT_UNDEF
index 53d99821ccd49eed6f63461f2371169a630d6dc4..3feaa210f7ddcc493082029ae04e58696157c588 100644 (file)
 #define FUNC_LIKE3(a) ( a)  // expected-note {{previous definition is here}}
 #define FUNC_LIKE3(a) (a) // expected-warning {{'FUNC_LIKE3' macro redefined}}
 
+// RUN: %clang_cc1 -fms-extensions -DMS_EXT %s -Eonly -verify
+#ifndef MS_EXT
+// This should under C99.
+#define FUNC_LIKE4(a,b) (a+b)  // expected-note {{previous definition is here}}
+#define FUNC_LIKE4(x,y) (x+y) // expected-warning {{'FUNC_LIKE4' macro redefined}}
+#else
+// This shouldn't under MS extensions.
+#define FUNC_LIKE4(a,b) (a+b)
+#define FUNC_LIKE4(x,y) (x+y)
+
+// This should.
+#define FUNC_LIKE5(a,b) (a+b) // expected-note {{previous definition is here}}
+#define FUNC_LIKE5(x,y) (y+x) // expected-warning {{'FUNC_LIKE5' macro redefined}}
+#endif